refactor: migrate all internal imports to package.json subpath aliases

- Add #domain, #protocol, #utils aliases to package.json imports map
- Replace all relative imports (./, ../, ../..) in app/ and
  database/mongo_migrations/ with the corresponding #alias imports,
  eliminating relative path traversal across the codebase
- Remove dead code: ConfigurationVersionModel.findByConfigurationIdentifier
  (unused, superseded by paginateVersions) and unused exception classes
  (NotFoundException, UnprocessableEntityException, DatabaseException)
  from app/exceptions/index.ts, keeping only BadRequestException
- Fix pre-existing syntax error in configuration_version.ts (mismatched
  parenthesis) that broke tsc
- Fix eqeqeq violation in configuration_service.ts and isNaN ->
  Number.isNaN in configuration_engine.ts / cwmp-1-0.ts / exchange_controller.ts
- Fix no-shadow violation in cwmp-1-0.ts EventStruct constructor
- Prettier formatting pass on touched files

Validated: tsc --noEmit clean, eslint app/ clean, full test suite green.
This commit is contained in:
Kevin L'Hereec committed 2026-07-22 11:45:14 +02:00
1 parent 4177f1adbd
commit f9e56c78b1
74 files changed
+1243 -863

No files matched your search

+45 -15
View File
@@ -6,7 +6,10 @@ import ConfigurationService, {
} from '#services/configuration_service'
import ConfigurationEngine from '#services/configuration_engine'
import ConfigurationModel from '#models/configuration'
import { createConfigurationValidator, updateConfigurationValidator } from '#validators/configuration'
import {
createConfigurationValidator,
updateConfigurationValidator,
} from '#validators/configuration'
import logger from '@adonisjs/core/services/logger'
/**
@@ -43,7 +46,8 @@ export default class ConfigurationsController {
perPage: Number(request.input('perPage', 20)),
tag: request.input('tag'),
name: request.input('name') || undefined,
enabled: request.input('enabled') !== undefined ? request.input('enabled') === 'true' : undefined,
enabled:
request.input('enabled') !== undefined ? request.input('enabled') === 'true' : undefined,
productClass: request.input('productClass'),
}
@@ -93,11 +97,21 @@ export default class ConfigurationsController {
*/
async store({ request, response }: HttpContext) {
try {
const data = await request.validateUsing(createConfigurationValidator) as CreateConfigurationDto
const data = (await request.validateUsing(
createConfigurationValidator
)) as CreateConfigurationDto
// Check for overlaps
const overlapResult = await this.configService.detectOverlap(data.criteria || {}, data.priority)
if (overlapResult && overlapResult.overlappingConfigurations && overlapResult.overlappingConfigurations.length > 0 && !request.input('ignoreOverlap')) {
const overlapResult = await this.configService.detectOverlap(
data.criteria || {},
data.priority
)
if (
overlapResult &&
overlapResult.overlappingConfigurations &&
overlapResult.overlappingConfigurations.length > 0 &&
!request.input('ignoreOverlap')
) {
return response.status(409).json({
message: 'Configuration overlaps with existing ones',
overlaps: overlapResult.overlappingConfigurations,
@@ -122,7 +136,9 @@ export default class ConfigurationsController {
*/
async update({ params, request, response }: HttpContext) {
try {
const data = await request.validateUsing(updateConfigurationValidator) as UpdateConfigurationDto
const data = (await request.validateUsing(
updateConfigurationValidator
)) as UpdateConfigurationDto
// Check for overlaps if priority changed
if (data.priority) {
@@ -131,13 +147,18 @@ export default class ConfigurationsController {
data.priority,
params.id
)
if (overlapResult && overlapResult.overlappingConfigurations && overlapResult.overlappingConfigurations.length > 0 && !request.input('ignoreOverlap')) {
return response.status(409).json({
message: 'Configuration overlaps with existing ones',
overlaps: overlapResult.overlappingConfigurations,
})
if (
overlapResult &&
overlapResult.overlappingConfigurations &&
overlapResult.overlappingConfigurations.length > 0 &&
!request.input('ignoreOverlap')
) {
return response.status(409).json({
message: 'Configuration overlaps with existing ones',
overlaps: overlapResult.overlappingConfigurations,
})
}
}
}
// Update configuration
const config = await this.configService.update(params.id, data)
@@ -147,7 +168,10 @@ export default class ConfigurationsController {
return response.ok(config)
} catch (error: any) {
logger.error({ error: error.message, id: params.id }, '[ConfigAPI] Update configuration failed')
logger.error(
{ error: error.message, id: params.id },
'[ConfigAPI] Update configuration failed'
)
if (error.field) {
return response.status(422).json({ message: error.message, field: error.field })
}
@@ -164,7 +188,10 @@ export default class ConfigurationsController {
await this.configService.delete(params.id)
return response.status(204).send(null)
} catch (error: any) {
logger.error({ error: error.message, id: params.id }, '[ConfigAPI] Delete configuration failed')
logger.error(
{ error: error.message, id: params.id },
'[ConfigAPI] Delete configuration failed'
)
return response.status(500).json({ message: 'Failed to delete configuration' })
}
}
@@ -182,7 +209,10 @@ export default class ConfigurationsController {
}
return response.ok(config)
} catch (error: any) {
logger.error({ error: error.message, id: params.id }, '[ConfigAPI] Toggle configuration failed')
logger.error(
{ error: error.message, id: params.id },
'[ConfigAPI] Toggle configuration failed'
)
return response.status(500).json({ message: 'Failed to toggle configuration' })
}
}
+12 -12
View File
@@ -1,17 +1,17 @@
import type { HttpContext } from '@adonisjs/core/http'
import { CWMPMessageBuilder } from '../protocol/common/cwmp_message_builder.js'
import { StateMachineManager } from '../services/cwmp/state_machine_manager.js'
import { Device, detectDataModelFromParams } from '../domain/device/device.js'
import { DeviceId } from '../domain/device/device_id.js'
import { DeviceParameter, DeviceProperty } from '../domain/device/device_parameter.js'
import DeviceModel from '../models/device.js'
import { getDeviceHashIdentifier } from '../utils/device_utils.js'
import { getReferenceEngine } from '../services/references/reference_engine.js'
import { normalizeEventCode } from '../utils/cwmp-events.js'
import { CWMPMessageBuilder } from '#protocol/common/cwmp_message_builder'
import { StateMachineManager } from '#services/cwmp/state_machine_manager'
import { Device, detectDataModelFromParams } from '#domain/device/device'
import { DeviceId } from '#domain/device/device_id'
import { DeviceParameter, DeviceProperty } from '#domain/device/device_parameter'
import DeviceModel from '#models/device'
import { getDeviceHashIdentifier } from '#utils/device_utils'
import { getReferenceEngine } from '#services/references/reference_engine'
import { normalizeEventCode } from '#utils/cwmp-events'
import logger from '@adonisjs/core/services/logger'
import type { Inform, CwmpMessage, ParameterValueStruct } from '../protocol/tr069_types.js'
import { ParameterType } from '../domain/shared/types.js'
import { FaultCodeType } from '../protocol/tr069_types.js'
import type { Inform, CwmpMessage, ParameterValueStruct } from '#protocol/tr069_types'
import { ParameterType } from '#domain/shared/types'
import { FaultCodeType } from '#protocol/tr069_types'
export default class CwmpController {
private static managerInitialized = false
+8 -4
View File
@@ -1,7 +1,7 @@
import type { HttpContext } from '@adonisjs/core/http'
import DeviceService from '#services/device_service'
import { PaginationData } from '#services/device_service'
import { CommandType } from '../domain/commands/command.js'
import { type PaginationData } from '#services/device_service'
import { type CommandType } from '#domain/commands/command'
import DeviceModel from '#models/device'
export default class DevicesController {
@@ -77,10 +77,14 @@ export default class DevicesController {
const parts: string[] = []
if (pager.first) {
parts.push(`<${baseUrl}?offset=${pager.first.offset}&limit=${pager.first.limit}>; rel="first"`)
parts.push(
`<${baseUrl}?offset=${pager.first.offset}&limit=${pager.first.limit}>; rel="first"`
)
}
if (pager.previous) {
parts.push(`<${baseUrl}?offset=${pager.previous.offset}&limit=${pager.previous.limit}>; rel="prev"`)
parts.push(
`<${baseUrl}?offset=${pager.previous.offset}&limit=${pager.previous.limit}>; rel="prev"`
)
}
if (pager.next) {
parts.push(`<${baseUrl}?offset=${pager.next.offset}&limit=${pager.next.limit}>; rel="next"`)
+6 -6
View File
@@ -247,7 +247,10 @@ export default class ExchangeController {
// Track SSE stream setup time
const setupDurationMs = performance.now() - startTime
ExchangeMetricsService.getInstance().recordApiResponseTime('GET /exchanges/stream', setupDurationMs)
ExchangeMetricsService.getInstance().recordApiResponseTime(
'GET /exchanges/stream',
setupDurationMs
)
const listener = (exchange: any) => {
if (closed) return
@@ -333,10 +336,7 @@ export default class ExchangeController {
*
* Requirement 6.9: Event id equals the exchange's sequenceNumber
*/
private sendSSEEvent(
res: import('node:http').ServerResponse,
exchange: any
): void {
private sendSSEEvent(res: import('node:http').ServerResponse, exchange: any): void {
const data = JSON.stringify(exchange)
res.write(`id: ${exchange.sequenceNumber}\ndata: ${data}\n\n`)
}
@@ -347,7 +347,7 @@ export default class ExchangeController {
*/
private isValidIso8601(value: string): boolean {
const date = new Date(value)
if (isNaN(date.getTime())) {
if (Number.isNaN(date.getTime())) {
return false
}
+11 -3
View File
@@ -3,7 +3,11 @@ import FirmwareCatalogService, {
type CreateFirmwareEntryDto,
type CreateMigrationRouteDto,
} from '#services/firmware_catalog_service'
import { createFirmwareEntryValidator, updateFirmwareEntryValidator, createMigrationRouteValidator } from '#validators/firmware_catalog'
import {
createFirmwareEntryValidator,
updateFirmwareEntryValidator,
createMigrationRouteValidator,
} from '#validators/firmware_catalog'
import logger from '@adonisjs/core/services/logger'
/**
@@ -105,7 +109,9 @@ export default class FirmwareCatalogController {
*/
async createEntry({ request, response }: HttpContext) {
try {
const data = await request.validateUsing(createFirmwareEntryValidator) as CreateFirmwareEntryDto
const data = (await request.validateUsing(
createFirmwareEntryValidator
)) as CreateFirmwareEntryDto
const entry = await this.catalogService.createEntry(data)
return response.status(201).json(entry)
@@ -135,7 +141,9 @@ export default class FirmwareCatalogController {
*/
async createRoute({ request, response }: HttpContext) {
try {
const data = await request.validateUsing(createMigrationRouteValidator) as CreateMigrationRouteDto
const data = (await request.validateUsing(
createMigrationRouteValidator
)) as CreateMigrationRouteDto
const route = await this.catalogService.createMigrationRoute(data)
return response.status(201).json(route)
+17 -3
View File
@@ -33,11 +33,25 @@ export default class PagesController {
// Predefined model paths for the "Get Model" modal
// Detect data model from device properties to suggest the right root
const isTr181 = (device as any).dataModel === 'tr-181' ||
const isTr181 =
(device as any).dataModel === 'tr-181' ||
(device as any).properties?.some((p: any) => p.name?.startsWith('Device.'))
const modelPaths = isTr181
? ['Device.', 'Device.DeviceInfo.', 'Device.IP.', 'Device.WiFi.', 'Device.ManagementServer.', 'Device.Hosts.']
: ['InternetGatewayDevice.', 'InternetGatewayDevice.DeviceInfo.', 'InternetGatewayDevice.LANDevice.', 'InternetGatewayDevice.WANDevice.', 'InternetGatewayDevice.ManagementServer.']
? [
'Device.',
'Device.DeviceInfo.',
'Device.IP.',
'Device.WiFi.',
'Device.ManagementServer.',
'Device.Hosts.',
]
: [
'InternetGatewayDevice.',
'InternetGatewayDevice.DeviceInfo.',
'InternetGatewayDevice.LANDevice.',
'InternetGatewayDevice.WANDevice.',
'InternetGatewayDevice.ManagementServer.',
]
return (inertia as any).render('DeviceDetail', { device, commands, modelPaths })
}
+11 -4
View File
@@ -1,6 +1,6 @@
import type { HttpContext } from '@adonisjs/core/http'
import DeviceModel from '#models/device'
import { getReferenceEngine } from '../services/references/reference_engine.js'
import { getReferenceEngine } from '#services/references/reference_engine'
export default class ReferencesController {
/**
@@ -24,7 +24,9 @@ export default class ReferencesController {
}
const ref = (device.references || []).find((r: any) => r.provider === params.provider)
if (!ref) {
return response.status(404).json({ message: `No reference from provider '${params.provider}'` })
return response
.status(404)
.json({ message: `No reference from provider '${params.provider}'` })
}
return response.json(ref)
}
@@ -51,7 +53,10 @@ export default class ReferencesController {
(r: any) => !results.some((nr) => nr.provider === r.provider)
)
const merged = [...existing, ...results]
await DeviceModel.updateOne({ identifier: params.identifier }, { $set: { references: merged, updatedAt: new Date() } })
await DeviceModel.updateOne(
{ identifier: params.identifier },
{ $set: { references: merged, updatedAt: new Date() } }
)
}
return response.json({ resolved: results.length, references: results })
@@ -72,7 +77,9 @@ export default class ReferencesController {
const result = await engine.resolveOne(params.provider, device, context)
if (!result) {
return response.status(404).json({ message: `Provider '${params.provider}' not found or cannot resolve` })
return response
.status(404)
.json({ message: `Provider '${params.provider}' not found or cannot resolve` })
}
// Merge into device references