feat: TR-069 per-device SOAP trace logging + log viewer UI
- Remove SOAP from Docker stdout; route to per-device trace files only - Fix trace service paths using process.cwd() (/app/data/, /app/logs/tr069/) - Fix Docker volume permissions: dedicated /app/data & /app/logs/tr069 dirs - Add GET /api/v1/tr069-trace/:id/log endpoint (tail N lines) - Rewrite Tr069Trace.vue: clickable rows, dark log viewer, 3s auto-refresh - Add simulator-ui-env.js to public/ (remove from config/) - TR-181/InternetGatewayDevice dataModel auto-detection - Parameter writability config with W/R fallback default - Fix device_action_executor for GetParameterNames detection flow Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
1 parent
847da1cdf5
commit
6082a0e610
23 files changed
+1360
-180
No files matched your search
Vendored
-5
@@ -5,11 +5,6 @@
|
||||
|
||||
/// <reference path="./manifest.d.ts" />
|
||||
import type { InferData, InferVariants } from '@adonisjs/core/types/transformers'
|
||||
import type UserTransformer from '#transformers/user_transformer'
|
||||
|
||||
export namespace Data {
|
||||
export type User = InferData<UserTransformer>
|
||||
export namespace User {
|
||||
export type Variants = InferVariants<UserTransformer>
|
||||
}
|
||||
}
|
||||
Vendored
-1
@@ -4,6 +4,5 @@
|
||||
*/
|
||||
|
||||
/// <reference path="../../adonisrc.ts" />
|
||||
/// <reference path="../../config/auth.ts" />
|
||||
/// <reference path="../../config/hash.ts" />
|
||||
/// <reference path="../../config/logger.ts" />
|
||||
@@ -6,29 +6,317 @@ import type { ApiDefinition } from './tree.d.ts'
|
||||
const placeholder: any = {}
|
||||
|
||||
const routes = {
|
||||
'auth.new_account.store': {
|
||||
'cwmp': {
|
||||
methods: ["POST"],
|
||||
pattern: '/api/v1/auth/signup',
|
||||
tokens: [{"old":"/api/v1/auth/signup","type":0,"val":"api","end":""},{"old":"/api/v1/auth/signup","type":0,"val":"v1","end":""},{"old":"/api/v1/auth/signup","type":0,"val":"auth","end":""},{"old":"/api/v1/auth/signup","type":0,"val":"signup","end":""}],
|
||||
types: placeholder as Registry['auth.new_account.store']['types'],
|
||||
pattern: '/cwmp10',
|
||||
tokens: [{"old":"/cwmp10","type":0,"val":"cwmp10","end":""}],
|
||||
types: placeholder as Registry['cwmp']['types'],
|
||||
},
|
||||
'auth.access_tokens.store': {
|
||||
methods: ["POST"],
|
||||
pattern: '/api/v1/auth/login',
|
||||
tokens: [{"old":"/api/v1/auth/login","type":0,"val":"api","end":""},{"old":"/api/v1/auth/login","type":0,"val":"v1","end":""},{"old":"/api/v1/auth/login","type":0,"val":"auth","end":""},{"old":"/api/v1/auth/login","type":0,"val":"login","end":""}],
|
||||
types: placeholder as Registry['auth.access_tokens.store']['types'],
|
||||
},
|
||||
'profile.profile.show': {
|
||||
'health.checklife': {
|
||||
methods: ["GET","HEAD"],
|
||||
pattern: '/api/v1/account/profile',
|
||||
tokens: [{"old":"/api/v1/account/profile","type":0,"val":"api","end":""},{"old":"/api/v1/account/profile","type":0,"val":"v1","end":""},{"old":"/api/v1/account/profile","type":0,"val":"account","end":""},{"old":"/api/v1/account/profile","type":0,"val":"profile","end":""}],
|
||||
types: placeholder as Registry['profile.profile.show']['types'],
|
||||
pattern: '/api/v1/checklife',
|
||||
tokens: [{"old":"/api/v1/checklife","type":0,"val":"api","end":""},{"old":"/api/v1/checklife","type":0,"val":"v1","end":""},{"old":"/api/v1/checklife","type":0,"val":"checklife","end":""}],
|
||||
types: placeholder as Registry['health.checklife']['types'],
|
||||
},
|
||||
'profile.access_tokens.destroy': {
|
||||
'health.checkservice': {
|
||||
methods: ["GET","HEAD"],
|
||||
pattern: '/api/v1/checkservice',
|
||||
tokens: [{"old":"/api/v1/checkservice","type":0,"val":"api","end":""},{"old":"/api/v1/checkservice","type":0,"val":"v1","end":""},{"old":"/api/v1/checkservice","type":0,"val":"checkservice","end":""}],
|
||||
types: placeholder as Registry['health.checkservice']['types'],
|
||||
},
|
||||
'devices.index': {
|
||||
methods: ["GET","HEAD"],
|
||||
pattern: '/api/v1/devices',
|
||||
tokens: [{"old":"/api/v1/devices","type":0,"val":"api","end":""},{"old":"/api/v1/devices","type":0,"val":"v1","end":""},{"old":"/api/v1/devices","type":0,"val":"devices","end":""}],
|
||||
types: placeholder as Registry['devices.index']['types'],
|
||||
},
|
||||
'devices.criteria_values': {
|
||||
methods: ["GET","HEAD"],
|
||||
pattern: '/api/v1/devices/criteria-values',
|
||||
tokens: [{"old":"/api/v1/devices/criteria-values","type":0,"val":"api","end":""},{"old":"/api/v1/devices/criteria-values","type":0,"val":"v1","end":""},{"old":"/api/v1/devices/criteria-values","type":0,"val":"devices","end":""},{"old":"/api/v1/devices/criteria-values","type":0,"val":"criteria-values","end":""}],
|
||||
types: placeholder as Registry['devices.criteria_values']['types'],
|
||||
},
|
||||
'devices.show': {
|
||||
methods: ["GET","HEAD"],
|
||||
pattern: '/api/v1/devices/:identifier',
|
||||
tokens: [{"old":"/api/v1/devices/:identifier","type":0,"val":"api","end":""},{"old":"/api/v1/devices/:identifier","type":0,"val":"v1","end":""},{"old":"/api/v1/devices/:identifier","type":0,"val":"devices","end":""},{"old":"/api/v1/devices/:identifier","type":1,"val":"identifier","end":""}],
|
||||
types: placeholder as Registry['devices.show']['types'],
|
||||
},
|
||||
'devices.destroy': {
|
||||
methods: ["DELETE"],
|
||||
pattern: '/api/v1/devices/:identifier',
|
||||
tokens: [{"old":"/api/v1/devices/:identifier","type":0,"val":"api","end":""},{"old":"/api/v1/devices/:identifier","type":0,"val":"v1","end":""},{"old":"/api/v1/devices/:identifier","type":0,"val":"devices","end":""},{"old":"/api/v1/devices/:identifier","type":1,"val":"identifier","end":""}],
|
||||
types: placeholder as Registry['devices.destroy']['types'],
|
||||
},
|
||||
'devices.execute_command': {
|
||||
methods: ["POST"],
|
||||
pattern: '/api/v1/account/logout',
|
||||
tokens: [{"old":"/api/v1/account/logout","type":0,"val":"api","end":""},{"old":"/api/v1/account/logout","type":0,"val":"v1","end":""},{"old":"/api/v1/account/logout","type":0,"val":"account","end":""},{"old":"/api/v1/account/logout","type":0,"val":"logout","end":""}],
|
||||
types: placeholder as Registry['profile.access_tokens.destroy']['types'],
|
||||
pattern: '/api/v1/devices/:identifier/command',
|
||||
tokens: [{"old":"/api/v1/devices/:identifier/command","type":0,"val":"api","end":""},{"old":"/api/v1/devices/:identifier/command","type":0,"val":"v1","end":""},{"old":"/api/v1/devices/:identifier/command","type":0,"val":"devices","end":""},{"old":"/api/v1/devices/:identifier/command","type":1,"val":"identifier","end":""},{"old":"/api/v1/devices/:identifier/command","type":0,"val":"command","end":""}],
|
||||
types: placeholder as Registry['devices.execute_command']['types'],
|
||||
},
|
||||
'devices.refresh': {
|
||||
methods: ["POST"],
|
||||
pattern: '/api/v1/devices/:identifier/refresh',
|
||||
tokens: [{"old":"/api/v1/devices/:identifier/refresh","type":0,"val":"api","end":""},{"old":"/api/v1/devices/:identifier/refresh","type":0,"val":"v1","end":""},{"old":"/api/v1/devices/:identifier/refresh","type":0,"val":"devices","end":""},{"old":"/api/v1/devices/:identifier/refresh","type":1,"val":"identifier","end":""},{"old":"/api/v1/devices/:identifier/refresh","type":0,"val":"refresh","end":""}],
|
||||
types: placeholder as Registry['devices.refresh']['types'],
|
||||
},
|
||||
'commands.index': {
|
||||
methods: ["GET","HEAD"],
|
||||
pattern: '/api/v1/commands',
|
||||
tokens: [{"old":"/api/v1/commands","type":0,"val":"api","end":""},{"old":"/api/v1/commands","type":0,"val":"v1","end":""},{"old":"/api/v1/commands","type":0,"val":"commands","end":""}],
|
||||
types: placeholder as Registry['commands.index']['types'],
|
||||
},
|
||||
'commands.show': {
|
||||
methods: ["GET","HEAD"],
|
||||
pattern: '/api/v1/commands/:id',
|
||||
tokens: [{"old":"/api/v1/commands/:id","type":0,"val":"api","end":""},{"old":"/api/v1/commands/:id","type":0,"val":"v1","end":""},{"old":"/api/v1/commands/:id","type":0,"val":"commands","end":""},{"old":"/api/v1/commands/:id","type":1,"val":"id","end":""}],
|
||||
types: placeholder as Registry['commands.show']['types'],
|
||||
},
|
||||
'commands.store': {
|
||||
methods: ["POST"],
|
||||
pattern: '/api/v1/commands',
|
||||
tokens: [{"old":"/api/v1/commands","type":0,"val":"api","end":""},{"old":"/api/v1/commands","type":0,"val":"v1","end":""},{"old":"/api/v1/commands","type":0,"val":"commands","end":""}],
|
||||
types: placeholder as Registry['commands.store']['types'],
|
||||
},
|
||||
'tr_069_trace.index': {
|
||||
methods: ["GET","HEAD"],
|
||||
pattern: '/api/v1/tr069-trace',
|
||||
tokens: [{"old":"/api/v1/tr069-trace","type":0,"val":"api","end":""},{"old":"/api/v1/tr069-trace","type":0,"val":"v1","end":""},{"old":"/api/v1/tr069-trace","type":0,"val":"tr069-trace","end":""}],
|
||||
types: placeholder as Registry['tr_069_trace.index']['types'],
|
||||
},
|
||||
'tr_069_trace.store': {
|
||||
methods: ["POST"],
|
||||
pattern: '/api/v1/tr069-trace',
|
||||
tokens: [{"old":"/api/v1/tr069-trace","type":0,"val":"api","end":""},{"old":"/api/v1/tr069-trace","type":0,"val":"v1","end":""},{"old":"/api/v1/tr069-trace","type":0,"val":"tr069-trace","end":""}],
|
||||
types: placeholder as Registry['tr_069_trace.store']['types'],
|
||||
},
|
||||
'tr_069_trace.destroy': {
|
||||
methods: ["DELETE"],
|
||||
pattern: '/api/v1/tr069-trace/:id',
|
||||
tokens: [{"old":"/api/v1/tr069-trace/:id","type":0,"val":"api","end":""},{"old":"/api/v1/tr069-trace/:id","type":0,"val":"v1","end":""},{"old":"/api/v1/tr069-trace/:id","type":0,"val":"tr069-trace","end":""},{"old":"/api/v1/tr069-trace/:id","type":1,"val":"id","end":""}],
|
||||
types: placeholder as Registry['tr_069_trace.destroy']['types'],
|
||||
},
|
||||
'configurations_v_1.index': {
|
||||
methods: ["GET","HEAD"],
|
||||
pattern: '/api/v1/configurations',
|
||||
tokens: [{"old":"/api/v1/configurations","type":0,"val":"api","end":""},{"old":"/api/v1/configurations","type":0,"val":"v1","end":""},{"old":"/api/v1/configurations","type":0,"val":"configurations","end":""}],
|
||||
types: placeholder as Registry['configurations_v_1.index']['types'],
|
||||
},
|
||||
'configurations_v_1.list_tags': {
|
||||
methods: ["GET","HEAD"],
|
||||
pattern: '/api/v1/configurations/tags',
|
||||
tokens: [{"old":"/api/v1/configurations/tags","type":0,"val":"api","end":""},{"old":"/api/v1/configurations/tags","type":0,"val":"v1","end":""},{"old":"/api/v1/configurations/tags","type":0,"val":"configurations","end":""},{"old":"/api/v1/configurations/tags","type":0,"val":"tags","end":""}],
|
||||
types: placeholder as Registry['configurations_v_1.list_tags']['types'],
|
||||
},
|
||||
'configurations_v_1.store': {
|
||||
methods: ["POST"],
|
||||
pattern: '/api/v1/configurations',
|
||||
tokens: [{"old":"/api/v1/configurations","type":0,"val":"api","end":""},{"old":"/api/v1/configurations","type":0,"val":"v1","end":""},{"old":"/api/v1/configurations","type":0,"val":"configurations","end":""}],
|
||||
types: placeholder as Registry['configurations_v_1.store']['types'],
|
||||
},
|
||||
'configurations_v_1.show': {
|
||||
methods: ["GET","HEAD"],
|
||||
pattern: '/api/v1/configurations/:id',
|
||||
tokens: [{"old":"/api/v1/configurations/:id","type":0,"val":"api","end":""},{"old":"/api/v1/configurations/:id","type":0,"val":"v1","end":""},{"old":"/api/v1/configurations/:id","type":0,"val":"configurations","end":""},{"old":"/api/v1/configurations/:id","type":1,"val":"id","end":""}],
|
||||
types: placeholder as Registry['configurations_v_1.show']['types'],
|
||||
},
|
||||
'configurations_v_1.update': {
|
||||
methods: ["PUT"],
|
||||
pattern: '/api/v1/configurations/:id',
|
||||
tokens: [{"old":"/api/v1/configurations/:id","type":0,"val":"api","end":""},{"old":"/api/v1/configurations/:id","type":0,"val":"v1","end":""},{"old":"/api/v1/configurations/:id","type":0,"val":"configurations","end":""},{"old":"/api/v1/configurations/:id","type":1,"val":"id","end":""}],
|
||||
types: placeholder as Registry['configurations_v_1.update']['types'],
|
||||
},
|
||||
'configurations_v_1.destroy': {
|
||||
methods: ["DELETE"],
|
||||
pattern: '/api/v1/configurations/:id',
|
||||
tokens: [{"old":"/api/v1/configurations/:id","type":0,"val":"api","end":""},{"old":"/api/v1/configurations/:id","type":0,"val":"v1","end":""},{"old":"/api/v1/configurations/:id","type":0,"val":"configurations","end":""},{"old":"/api/v1/configurations/:id","type":1,"val":"id","end":""}],
|
||||
types: placeholder as Registry['configurations_v_1.destroy']['types'],
|
||||
},
|
||||
'configurations_v_1.toggle_enabled': {
|
||||
methods: ["PATCH"],
|
||||
pattern: '/api/v1/configurations/:id/toggle',
|
||||
tokens: [{"old":"/api/v1/configurations/:id/toggle","type":0,"val":"api","end":""},{"old":"/api/v1/configurations/:id/toggle","type":0,"val":"v1","end":""},{"old":"/api/v1/configurations/:id/toggle","type":0,"val":"configurations","end":""},{"old":"/api/v1/configurations/:id/toggle","type":1,"val":"id","end":""},{"old":"/api/v1/configurations/:id/toggle","type":0,"val":"toggle","end":""}],
|
||||
types: placeholder as Registry['configurations_v_1.toggle_enabled']['types'],
|
||||
},
|
||||
'configurations_v_1.manage_tags': {
|
||||
methods: ["PATCH"],
|
||||
pattern: '/api/v1/configurations/:id/tags',
|
||||
tokens: [{"old":"/api/v1/configurations/:id/tags","type":0,"val":"api","end":""},{"old":"/api/v1/configurations/:id/tags","type":0,"val":"v1","end":""},{"old":"/api/v1/configurations/:id/tags","type":0,"val":"configurations","end":""},{"old":"/api/v1/configurations/:id/tags","type":1,"val":"id","end":""},{"old":"/api/v1/configurations/:id/tags","type":0,"val":"tags","end":""}],
|
||||
types: placeholder as Registry['configurations_v_1.manage_tags']['types'],
|
||||
},
|
||||
'configurations_v_1.history': {
|
||||
methods: ["GET","HEAD"],
|
||||
pattern: '/api/v1/configurations/:id/history',
|
||||
tokens: [{"old":"/api/v1/configurations/:id/history","type":0,"val":"api","end":""},{"old":"/api/v1/configurations/:id/history","type":0,"val":"v1","end":""},{"old":"/api/v1/configurations/:id/history","type":0,"val":"configurations","end":""},{"old":"/api/v1/configurations/:id/history","type":1,"val":"id","end":""},{"old":"/api/v1/configurations/:id/history","type":0,"val":"history","end":""}],
|
||||
types: placeholder as Registry['configurations_v_1.history']['types'],
|
||||
},
|
||||
'configurations_v_1.dry_run': {
|
||||
methods: ["POST"],
|
||||
pattern: '/api/v1/configurations/:id/dry-run',
|
||||
tokens: [{"old":"/api/v1/configurations/:id/dry-run","type":0,"val":"api","end":""},{"old":"/api/v1/configurations/:id/dry-run","type":0,"val":"v1","end":""},{"old":"/api/v1/configurations/:id/dry-run","type":0,"val":"configurations","end":""},{"old":"/api/v1/configurations/:id/dry-run","type":1,"val":"id","end":""},{"old":"/api/v1/configurations/:id/dry-run","type":0,"val":"dry-run","end":""}],
|
||||
types: placeholder as Registry['configurations_v_1.dry_run']['types'],
|
||||
},
|
||||
'configurations_v_1.compliance': {
|
||||
methods: ["GET","HEAD"],
|
||||
pattern: '/api/v1/configurations/:id/compliance',
|
||||
tokens: [{"old":"/api/v1/configurations/:id/compliance","type":0,"val":"api","end":""},{"old":"/api/v1/configurations/:id/compliance","type":0,"val":"v1","end":""},{"old":"/api/v1/configurations/:id/compliance","type":0,"val":"configurations","end":""},{"old":"/api/v1/configurations/:id/compliance","type":1,"val":"id","end":""},{"old":"/api/v1/configurations/:id/compliance","type":0,"val":"compliance","end":""}],
|
||||
types: placeholder as Registry['configurations_v_1.compliance']['types'],
|
||||
},
|
||||
'firmware_catalog.index': {
|
||||
methods: ["GET","HEAD"],
|
||||
pattern: '/api/v1/firmware-catalog',
|
||||
tokens: [{"old":"/api/v1/firmware-catalog","type":0,"val":"api","end":""},{"old":"/api/v1/firmware-catalog","type":0,"val":"v1","end":""},{"old":"/api/v1/firmware-catalog","type":0,"val":"firmware-catalog","end":""}],
|
||||
types: placeholder as Registry['firmware_catalog.index']['types'],
|
||||
},
|
||||
'firmware_catalog.list_entries': {
|
||||
methods: ["GET","HEAD"],
|
||||
pattern: '/api/v1/firmware-catalog/entries',
|
||||
tokens: [{"old":"/api/v1/firmware-catalog/entries","type":0,"val":"api","end":""},{"old":"/api/v1/firmware-catalog/entries","type":0,"val":"v1","end":""},{"old":"/api/v1/firmware-catalog/entries","type":0,"val":"firmware-catalog","end":""},{"old":"/api/v1/firmware-catalog/entries","type":0,"val":"entries","end":""}],
|
||||
types: placeholder as Registry['firmware_catalog.list_entries']['types'],
|
||||
},
|
||||
'firmware_catalog.show_entry': {
|
||||
methods: ["GET","HEAD"],
|
||||
pattern: '/api/v1/firmware-catalog/entries/:id',
|
||||
tokens: [{"old":"/api/v1/firmware-catalog/entries/:id","type":0,"val":"api","end":""},{"old":"/api/v1/firmware-catalog/entries/:id","type":0,"val":"v1","end":""},{"old":"/api/v1/firmware-catalog/entries/:id","type":0,"val":"firmware-catalog","end":""},{"old":"/api/v1/firmware-catalog/entries/:id","type":0,"val":"entries","end":""},{"old":"/api/v1/firmware-catalog/entries/:id","type":1,"val":"id","end":""}],
|
||||
types: placeholder as Registry['firmware_catalog.show_entry']['types'],
|
||||
},
|
||||
'firmware_catalog.list_routes': {
|
||||
methods: ["GET","HEAD"],
|
||||
pattern: '/api/v1/firmware-catalog/routes',
|
||||
tokens: [{"old":"/api/v1/firmware-catalog/routes","type":0,"val":"api","end":""},{"old":"/api/v1/firmware-catalog/routes","type":0,"val":"v1","end":""},{"old":"/api/v1/firmware-catalog/routes","type":0,"val":"firmware-catalog","end":""},{"old":"/api/v1/firmware-catalog/routes","type":0,"val":"routes","end":""}],
|
||||
types: placeholder as Registry['firmware_catalog.list_routes']['types'],
|
||||
},
|
||||
'firmware_catalog.create_entry': {
|
||||
methods: ["POST"],
|
||||
pattern: '/api/v1/firmware-catalog/entries',
|
||||
tokens: [{"old":"/api/v1/firmware-catalog/entries","type":0,"val":"api","end":""},{"old":"/api/v1/firmware-catalog/entries","type":0,"val":"v1","end":""},{"old":"/api/v1/firmware-catalog/entries","type":0,"val":"firmware-catalog","end":""},{"old":"/api/v1/firmware-catalog/entries","type":0,"val":"entries","end":""}],
|
||||
types: placeholder as Registry['firmware_catalog.create_entry']['types'],
|
||||
},
|
||||
'firmware_catalog.update_entry': {
|
||||
methods: ["PUT"],
|
||||
pattern: '/api/v1/firmware-catalog/entries/:id',
|
||||
tokens: [{"old":"/api/v1/firmware-catalog/entries/:id","type":0,"val":"api","end":""},{"old":"/api/v1/firmware-catalog/entries/:id","type":0,"val":"v1","end":""},{"old":"/api/v1/firmware-catalog/entries/:id","type":0,"val":"firmware-catalog","end":""},{"old":"/api/v1/firmware-catalog/entries/:id","type":0,"val":"entries","end":""},{"old":"/api/v1/firmware-catalog/entries/:id","type":1,"val":"id","end":""}],
|
||||
types: placeholder as Registry['firmware_catalog.update_entry']['types'],
|
||||
},
|
||||
'firmware_catalog.delete_entry': {
|
||||
methods: ["DELETE"],
|
||||
pattern: '/api/v1/firmware-catalog/entries/:id',
|
||||
tokens: [{"old":"/api/v1/firmware-catalog/entries/:id","type":0,"val":"api","end":""},{"old":"/api/v1/firmware-catalog/entries/:id","type":0,"val":"v1","end":""},{"old":"/api/v1/firmware-catalog/entries/:id","type":0,"val":"firmware-catalog","end":""},{"old":"/api/v1/firmware-catalog/entries/:id","type":0,"val":"entries","end":""},{"old":"/api/v1/firmware-catalog/entries/:id","type":1,"val":"id","end":""}],
|
||||
types: placeholder as Registry['firmware_catalog.delete_entry']['types'],
|
||||
},
|
||||
'firmware_catalog.create_route': {
|
||||
methods: ["POST"],
|
||||
pattern: '/api/v1/firmware-catalog/routes',
|
||||
tokens: [{"old":"/api/v1/firmware-catalog/routes","type":0,"val":"api","end":""},{"old":"/api/v1/firmware-catalog/routes","type":0,"val":"v1","end":""},{"old":"/api/v1/firmware-catalog/routes","type":0,"val":"firmware-catalog","end":""},{"old":"/api/v1/firmware-catalog/routes","type":0,"val":"routes","end":""}],
|
||||
types: placeholder as Registry['firmware_catalog.create_route']['types'],
|
||||
},
|
||||
'firmware_catalog.update_route': {
|
||||
methods: ["PUT"],
|
||||
pattern: '/api/v1/firmware-catalog/routes/:id',
|
||||
tokens: [{"old":"/api/v1/firmware-catalog/routes/:id","type":0,"val":"api","end":""},{"old":"/api/v1/firmware-catalog/routes/:id","type":0,"val":"v1","end":""},{"old":"/api/v1/firmware-catalog/routes/:id","type":0,"val":"firmware-catalog","end":""},{"old":"/api/v1/firmware-catalog/routes/:id","type":0,"val":"routes","end":""},{"old":"/api/v1/firmware-catalog/routes/:id","type":1,"val":"id","end":""}],
|
||||
types: placeholder as Registry['firmware_catalog.update_route']['types'],
|
||||
},
|
||||
'firmware_catalog.delete_route': {
|
||||
methods: ["DELETE"],
|
||||
pattern: '/api/v1/firmware-catalog/routes/:id',
|
||||
tokens: [{"old":"/api/v1/firmware-catalog/routes/:id","type":0,"val":"api","end":""},{"old":"/api/v1/firmware-catalog/routes/:id","type":0,"val":"v1","end":""},{"old":"/api/v1/firmware-catalog/routes/:id","type":0,"val":"firmware-catalog","end":""},{"old":"/api/v1/firmware-catalog/routes/:id","type":0,"val":"routes","end":""},{"old":"/api/v1/firmware-catalog/routes/:id","type":1,"val":"id","end":""}],
|
||||
types: placeholder as Registry['firmware_catalog.delete_route']['types'],
|
||||
},
|
||||
'pages.home': {
|
||||
methods: ["GET","HEAD"],
|
||||
pattern: '/',
|
||||
tokens: [{"old":"/","type":0,"val":"/","end":""}],
|
||||
types: placeholder as Registry['pages.home']['types'],
|
||||
},
|
||||
'pages.device_detail': {
|
||||
methods: ["GET","HEAD"],
|
||||
pattern: '/devices/:identifier',
|
||||
tokens: [{"old":"/devices/:identifier","type":0,"val":"devices","end":""},{"old":"/devices/:identifier","type":1,"val":"identifier","end":""}],
|
||||
types: placeholder as Registry['pages.device_detail']['types'],
|
||||
},
|
||||
'pages.refresh_device': {
|
||||
methods: ["POST"],
|
||||
pattern: '/devices/:identifier/refresh',
|
||||
tokens: [{"old":"/devices/:identifier/refresh","type":0,"val":"devices","end":""},{"old":"/devices/:identifier/refresh","type":1,"val":"identifier","end":""},{"old":"/devices/:identifier/refresh","type":0,"val":"refresh","end":""}],
|
||||
types: placeholder as Registry['pages.refresh_device']['types'],
|
||||
},
|
||||
'pages.get_model': {
|
||||
methods: ["POST"],
|
||||
pattern: '/devices/:identifier/get-model',
|
||||
tokens: [{"old":"/devices/:identifier/get-model","type":0,"val":"devices","end":""},{"old":"/devices/:identifier/get-model","type":1,"val":"identifier","end":""},{"old":"/devices/:identifier/get-model","type":0,"val":"get-model","end":""}],
|
||||
types: placeholder as Registry['pages.get_model']['types'],
|
||||
},
|
||||
'commands.page': {
|
||||
methods: ["GET","HEAD"],
|
||||
pattern: '/commands',
|
||||
tokens: [{"old":"/commands","type":0,"val":"commands","end":""}],
|
||||
types: placeholder as Registry['commands.page']['types'],
|
||||
},
|
||||
'pages.commands_fleet': {
|
||||
methods: ["GET","HEAD"],
|
||||
pattern: '/commands/fleet',
|
||||
tokens: [{"old":"/commands/fleet","type":0,"val":"commands","end":""},{"old":"/commands/fleet","type":0,"val":"fleet","end":""}],
|
||||
types: placeholder as Registry['pages.commands_fleet']['types'],
|
||||
},
|
||||
'pages.tr_069_trace': {
|
||||
methods: ["GET","HEAD"],
|
||||
pattern: '/tr069-trace',
|
||||
tokens: [{"old":"/tr069-trace","type":0,"val":"tr069-trace","end":""}],
|
||||
types: placeholder as Registry['pages.tr_069_trace']['types'],
|
||||
},
|
||||
'pages.store_fleet_devices': {
|
||||
methods: ["POST"],
|
||||
pattern: '/commands/fleet',
|
||||
tokens: [{"old":"/commands/fleet","type":0,"val":"commands","end":""},{"old":"/commands/fleet","type":0,"val":"fleet","end":""}],
|
||||
types: placeholder as Registry['pages.store_fleet_devices']['types'],
|
||||
},
|
||||
'pages.store_fleet_command': {
|
||||
methods: ["POST"],
|
||||
pattern: '/commands/fleet/command',
|
||||
tokens: [{"old":"/commands/fleet/command","type":0,"val":"commands","end":""},{"old":"/commands/fleet/command","type":0,"val":"fleet","end":""},{"old":"/commands/fleet/command","type":0,"val":"command","end":""}],
|
||||
types: placeholder as Registry['pages.store_fleet_command']['types'],
|
||||
},
|
||||
'pages.configurations_list': {
|
||||
methods: ["GET","HEAD"],
|
||||
pattern: '/configurations',
|
||||
tokens: [{"old":"/configurations","type":0,"val":"configurations","end":""}],
|
||||
types: placeholder as Registry['pages.configurations_list']['types'],
|
||||
},
|
||||
'pages.configuration_create': {
|
||||
methods: ["GET","HEAD"],
|
||||
pattern: '/configurations/create',
|
||||
tokens: [{"old":"/configurations/create","type":0,"val":"configurations","end":""},{"old":"/configurations/create","type":0,"val":"create","end":""}],
|
||||
types: placeholder as Registry['pages.configuration_create']['types'],
|
||||
},
|
||||
'pages.configuration_edit': {
|
||||
methods: ["GET","HEAD"],
|
||||
pattern: '/configurations/:id/edit',
|
||||
tokens: [{"old":"/configurations/:id/edit","type":0,"val":"configurations","end":""},{"old":"/configurations/:id/edit","type":1,"val":"id","end":""},{"old":"/configurations/:id/edit","type":0,"val":"edit","end":""}],
|
||||
types: placeholder as Registry['pages.configuration_edit']['types'],
|
||||
},
|
||||
'pages.configuration_detail': {
|
||||
methods: ["GET","HEAD"],
|
||||
pattern: '/configurations/:id/detail',
|
||||
tokens: [{"old":"/configurations/:id/detail","type":0,"val":"configurations","end":""},{"old":"/configurations/:id/detail","type":1,"val":"id","end":""},{"old":"/configurations/:id/detail","type":0,"val":"detail","end":""}],
|
||||
types: placeholder as Registry['pages.configuration_detail']['types'],
|
||||
},
|
||||
'pages.firmware_catalog': {
|
||||
methods: ["GET","HEAD"],
|
||||
pattern: '/firmware-catalog',
|
||||
tokens: [{"old":"/firmware-catalog","type":0,"val":"firmware-catalog","end":""}],
|
||||
types: placeholder as Registry['pages.firmware_catalog']['types'],
|
||||
},
|
||||
'pages.firmware_catalog_create': {
|
||||
methods: ["GET","HEAD"],
|
||||
pattern: '/firmware-catalog/create',
|
||||
tokens: [{"old":"/firmware-catalog/create","type":0,"val":"firmware-catalog","end":""},{"old":"/firmware-catalog/create","type":0,"val":"create","end":""}],
|
||||
types: placeholder as Registry['pages.firmware_catalog_create']['types'],
|
||||
},
|
||||
'pages.firmware_catalog_edit': {
|
||||
methods: ["GET","HEAD"],
|
||||
pattern: '/firmware-catalog/:id/edit',
|
||||
tokens: [{"old":"/firmware-catalog/:id/edit","type":0,"val":"firmware-catalog","end":""},{"old":"/firmware-catalog/:id/edit","type":1,"val":"id","end":""},{"old":"/firmware-catalog/:id/edit","type":0,"val":"edit","end":""}],
|
||||
types: placeholder as Registry['pages.firmware_catalog_edit']['types'],
|
||||
},
|
||||
} as const satisfies Record<string, AdonisEndpoint>
|
||||
|
||||
|
||||
+603
-27
@@ -7,52 +7,628 @@ import type { InferInput, SimpleError } from '@vinejs/vine/types'
|
||||
export type ParamValue = string | number | bigint | boolean
|
||||
|
||||
export interface Registry {
|
||||
'auth.new_account.store': {
|
||||
'cwmp': {
|
||||
methods: ["POST"]
|
||||
pattern: '/api/v1/auth/signup'
|
||||
pattern: '/cwmp10'
|
||||
types: {
|
||||
body: ExtractBody<InferInput<(typeof import('#validators/user').signupValidator)>>
|
||||
body: {}
|
||||
paramsTuple: []
|
||||
params: {}
|
||||
query: ExtractQuery<InferInput<(typeof import('#validators/user').signupValidator)>>
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/new_account_controller').default['store']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/new_account_controller').default['store']>>> | { status: 422; response: { errors: SimpleError[] } }
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/cwmp_controller').default['handle']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/cwmp_controller').default['handle']>>>
|
||||
}
|
||||
}
|
||||
'auth.access_tokens.store': {
|
||||
methods: ["POST"]
|
||||
pattern: '/api/v1/auth/login'
|
||||
types: {
|
||||
body: ExtractBody<InferInput<(typeof import('#validators/user').loginValidator)>>
|
||||
paramsTuple: []
|
||||
params: {}
|
||||
query: ExtractQuery<InferInput<(typeof import('#validators/user').loginValidator)>>
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/access_tokens_controller').default['store']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/access_tokens_controller').default['store']>>> | { status: 422; response: { errors: SimpleError[] } }
|
||||
}
|
||||
}
|
||||
'profile.profile.show': {
|
||||
'health.checklife': {
|
||||
methods: ["GET","HEAD"]
|
||||
pattern: '/api/v1/account/profile'
|
||||
pattern: '/api/v1/checklife'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: []
|
||||
params: {}
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/profile_controller').default['show']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/profile_controller').default['show']>>>
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/health_controller').default['checklife']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/health_controller').default['checklife']>>>
|
||||
}
|
||||
}
|
||||
'profile.access_tokens.destroy': {
|
||||
methods: ["POST"]
|
||||
pattern: '/api/v1/account/logout'
|
||||
'health.checkservice': {
|
||||
methods: ["GET","HEAD"]
|
||||
pattern: '/api/v1/checkservice'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: []
|
||||
params: {}
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/access_tokens_controller').default['destroy']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/access_tokens_controller').default['destroy']>>>
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/health_controller').default['checkservice']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/health_controller').default['checkservice']>>>
|
||||
}
|
||||
}
|
||||
'devices.index': {
|
||||
methods: ["GET","HEAD"]
|
||||
pattern: '/api/v1/devices'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: []
|
||||
params: {}
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/devices_controller').default['index']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/devices_controller').default['index']>>>
|
||||
}
|
||||
}
|
||||
'devices.criteria_values': {
|
||||
methods: ["GET","HEAD"]
|
||||
pattern: '/api/v1/devices/criteria-values'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: []
|
||||
params: {}
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/devices_controller').default['criteriaValues']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/devices_controller').default['criteriaValues']>>>
|
||||
}
|
||||
}
|
||||
'devices.show': {
|
||||
methods: ["GET","HEAD"]
|
||||
pattern: '/api/v1/devices/:identifier'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: [ParamValue]
|
||||
params: { identifier: ParamValue }
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/devices_controller').default['show']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/devices_controller').default['show']>>>
|
||||
}
|
||||
}
|
||||
'devices.destroy': {
|
||||
methods: ["DELETE"]
|
||||
pattern: '/api/v1/devices/:identifier'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: [ParamValue]
|
||||
params: { identifier: ParamValue }
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/devices_controller').default['destroy']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/devices_controller').default['destroy']>>>
|
||||
}
|
||||
}
|
||||
'devices.execute_command': {
|
||||
methods: ["POST"]
|
||||
pattern: '/api/v1/devices/:identifier/command'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: [ParamValue]
|
||||
params: { identifier: ParamValue }
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/devices_controller').default['executeCommand']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/devices_controller').default['executeCommand']>>>
|
||||
}
|
||||
}
|
||||
'devices.refresh': {
|
||||
methods: ["POST"]
|
||||
pattern: '/api/v1/devices/:identifier/refresh'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: [ParamValue]
|
||||
params: { identifier: ParamValue }
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/devices_controller').default['refresh']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/devices_controller').default['refresh']>>>
|
||||
}
|
||||
}
|
||||
'commands.index': {
|
||||
methods: ["GET","HEAD"]
|
||||
pattern: '/api/v1/commands'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: []
|
||||
params: {}
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/commands_controller').default['index']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/commands_controller').default['index']>>>
|
||||
}
|
||||
}
|
||||
'commands.show': {
|
||||
methods: ["GET","HEAD"]
|
||||
pattern: '/api/v1/commands/:id'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: [ParamValue]
|
||||
params: { id: ParamValue }
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/commands_controller').default['show']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/commands_controller').default['show']>>>
|
||||
}
|
||||
}
|
||||
'commands.store': {
|
||||
methods: ["POST"]
|
||||
pattern: '/api/v1/commands'
|
||||
types: {
|
||||
body: ExtractBody<InferInput<(typeof import('#validators/command').createCommandValidator)>>
|
||||
paramsTuple: []
|
||||
params: {}
|
||||
query: ExtractQuery<InferInput<(typeof import('#validators/command').createCommandValidator)>>
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/commands_controller').default['store']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/commands_controller').default['store']>>> | { status: 422; response: { errors: SimpleError[] } }
|
||||
}
|
||||
}
|
||||
'tr_069_trace.index': {
|
||||
methods: ["GET","HEAD"]
|
||||
pattern: '/api/v1/tr069-trace'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: []
|
||||
params: {}
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/tr069_trace_controller').default['index']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/tr069_trace_controller').default['index']>>>
|
||||
}
|
||||
}
|
||||
'tr_069_trace.store': {
|
||||
methods: ["POST"]
|
||||
pattern: '/api/v1/tr069-trace'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: []
|
||||
params: {}
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/tr069_trace_controller').default['store']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/tr069_trace_controller').default['store']>>>
|
||||
}
|
||||
}
|
||||
'tr_069_trace.destroy': {
|
||||
methods: ["DELETE"]
|
||||
pattern: '/api/v1/tr069-trace/:id'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: [ParamValue]
|
||||
params: { id: ParamValue }
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/tr069_trace_controller').default['destroy']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/tr069_trace_controller').default['destroy']>>>
|
||||
}
|
||||
}
|
||||
'configurations_v_1.index': {
|
||||
methods: ["GET","HEAD"]
|
||||
pattern: '/api/v1/configurations'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: []
|
||||
params: {}
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/configurations_v1_controller').default['index']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/configurations_v1_controller').default['index']>>>
|
||||
}
|
||||
}
|
||||
'configurations_v_1.list_tags': {
|
||||
methods: ["GET","HEAD"]
|
||||
pattern: '/api/v1/configurations/tags'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: []
|
||||
params: {}
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/configurations_v1_controller').default['listTags']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/configurations_v1_controller').default['listTags']>>>
|
||||
}
|
||||
}
|
||||
'configurations_v_1.store': {
|
||||
methods: ["POST"]
|
||||
pattern: '/api/v1/configurations'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: []
|
||||
params: {}
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/configurations_v1_controller').default['store']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/configurations_v1_controller').default['store']>>>
|
||||
}
|
||||
}
|
||||
'configurations_v_1.show': {
|
||||
methods: ["GET","HEAD"]
|
||||
pattern: '/api/v1/configurations/:id'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: [ParamValue]
|
||||
params: { id: ParamValue }
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/configurations_v1_controller').default['show']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/configurations_v1_controller').default['show']>>>
|
||||
}
|
||||
}
|
||||
'configurations_v_1.update': {
|
||||
methods: ["PUT"]
|
||||
pattern: '/api/v1/configurations/:id'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: [ParamValue]
|
||||
params: { id: ParamValue }
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/configurations_v1_controller').default['update']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/configurations_v1_controller').default['update']>>>
|
||||
}
|
||||
}
|
||||
'configurations_v_1.destroy': {
|
||||
methods: ["DELETE"]
|
||||
pattern: '/api/v1/configurations/:id'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: [ParamValue]
|
||||
params: { id: ParamValue }
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/configurations_v1_controller').default['destroy']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/configurations_v1_controller').default['destroy']>>>
|
||||
}
|
||||
}
|
||||
'configurations_v_1.toggle_enabled': {
|
||||
methods: ["PATCH"]
|
||||
pattern: '/api/v1/configurations/:id/toggle'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: [ParamValue]
|
||||
params: { id: ParamValue }
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/configurations_v1_controller').default['toggleEnabled']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/configurations_v1_controller').default['toggleEnabled']>>>
|
||||
}
|
||||
}
|
||||
'configurations_v_1.manage_tags': {
|
||||
methods: ["PATCH"]
|
||||
pattern: '/api/v1/configurations/:id/tags'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: [ParamValue]
|
||||
params: { id: ParamValue }
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/configurations_v1_controller').default['manageTags']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/configurations_v1_controller').default['manageTags']>>>
|
||||
}
|
||||
}
|
||||
'configurations_v_1.history': {
|
||||
methods: ["GET","HEAD"]
|
||||
pattern: '/api/v1/configurations/:id/history'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: [ParamValue]
|
||||
params: { id: ParamValue }
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/configurations_v1_controller').default['history']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/configurations_v1_controller').default['history']>>>
|
||||
}
|
||||
}
|
||||
'configurations_v_1.dry_run': {
|
||||
methods: ["POST"]
|
||||
pattern: '/api/v1/configurations/:id/dry-run'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: [ParamValue]
|
||||
params: { id: ParamValue }
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/configurations_v1_controller').default['dryRun']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/configurations_v1_controller').default['dryRun']>>>
|
||||
}
|
||||
}
|
||||
'configurations_v_1.compliance': {
|
||||
methods: ["GET","HEAD"]
|
||||
pattern: '/api/v1/configurations/:id/compliance'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: [ParamValue]
|
||||
params: { id: ParamValue }
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/configurations_v1_controller').default['compliance']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/configurations_v1_controller').default['compliance']>>>
|
||||
}
|
||||
}
|
||||
'firmware_catalog.index': {
|
||||
methods: ["GET","HEAD"]
|
||||
pattern: '/api/v1/firmware-catalog'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: []
|
||||
params: {}
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/firmware_catalog_controller').default['index']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/firmware_catalog_controller').default['index']>>>
|
||||
}
|
||||
}
|
||||
'firmware_catalog.list_entries': {
|
||||
methods: ["GET","HEAD"]
|
||||
pattern: '/api/v1/firmware-catalog/entries'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: []
|
||||
params: {}
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/firmware_catalog_controller').default['listEntries']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/firmware_catalog_controller').default['listEntries']>>>
|
||||
}
|
||||
}
|
||||
'firmware_catalog.show_entry': {
|
||||
methods: ["GET","HEAD"]
|
||||
pattern: '/api/v1/firmware-catalog/entries/:id'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: [ParamValue]
|
||||
params: { id: ParamValue }
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/firmware_catalog_controller').default['showEntry']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/firmware_catalog_controller').default['showEntry']>>>
|
||||
}
|
||||
}
|
||||
'firmware_catalog.list_routes': {
|
||||
methods: ["GET","HEAD"]
|
||||
pattern: '/api/v1/firmware-catalog/routes'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: []
|
||||
params: {}
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/firmware_catalog_controller').default['listRoutes']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/firmware_catalog_controller').default['listRoutes']>>>
|
||||
}
|
||||
}
|
||||
'firmware_catalog.create_entry': {
|
||||
methods: ["POST"]
|
||||
pattern: '/api/v1/firmware-catalog/entries'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: []
|
||||
params: {}
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/firmware_catalog_controller').default['createEntry']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/firmware_catalog_controller').default['createEntry']>>>
|
||||
}
|
||||
}
|
||||
'firmware_catalog.update_entry': {
|
||||
methods: ["PUT"]
|
||||
pattern: '/api/v1/firmware-catalog/entries/:id'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: [ParamValue]
|
||||
params: { id: ParamValue }
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/firmware_catalog_controller').default['updateEntry']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/firmware_catalog_controller').default['updateEntry']>>>
|
||||
}
|
||||
}
|
||||
'firmware_catalog.delete_entry': {
|
||||
methods: ["DELETE"]
|
||||
pattern: '/api/v1/firmware-catalog/entries/:id'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: [ParamValue]
|
||||
params: { id: ParamValue }
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/firmware_catalog_controller').default['deleteEntry']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/firmware_catalog_controller').default['deleteEntry']>>>
|
||||
}
|
||||
}
|
||||
'firmware_catalog.create_route': {
|
||||
methods: ["POST"]
|
||||
pattern: '/api/v1/firmware-catalog/routes'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: []
|
||||
params: {}
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/firmware_catalog_controller').default['createRoute']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/firmware_catalog_controller').default['createRoute']>>>
|
||||
}
|
||||
}
|
||||
'firmware_catalog.update_route': {
|
||||
methods: ["PUT"]
|
||||
pattern: '/api/v1/firmware-catalog/routes/:id'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: [ParamValue]
|
||||
params: { id: ParamValue }
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/firmware_catalog_controller').default['updateRoute']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/firmware_catalog_controller').default['updateRoute']>>>
|
||||
}
|
||||
}
|
||||
'firmware_catalog.delete_route': {
|
||||
methods: ["DELETE"]
|
||||
pattern: '/api/v1/firmware-catalog/routes/:id'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: [ParamValue]
|
||||
params: { id: ParamValue }
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/firmware_catalog_controller').default['deleteRoute']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/firmware_catalog_controller').default['deleteRoute']>>>
|
||||
}
|
||||
}
|
||||
'pages.home': {
|
||||
methods: ["GET","HEAD"]
|
||||
pattern: '/'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: []
|
||||
params: {}
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['home']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['home']>>>
|
||||
}
|
||||
}
|
||||
'pages.device_detail': {
|
||||
methods: ["GET","HEAD"]
|
||||
pattern: '/devices/:identifier'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: [ParamValue]
|
||||
params: { identifier: ParamValue }
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['deviceDetail']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['deviceDetail']>>>
|
||||
}
|
||||
}
|
||||
'pages.refresh_device': {
|
||||
methods: ["POST"]
|
||||
pattern: '/devices/:identifier/refresh'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: [ParamValue]
|
||||
params: { identifier: ParamValue }
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['refreshDevice']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['refreshDevice']>>>
|
||||
}
|
||||
}
|
||||
'pages.get_model': {
|
||||
methods: ["POST"]
|
||||
pattern: '/devices/:identifier/get-model'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: [ParamValue]
|
||||
params: { identifier: ParamValue }
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['getModel']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['getModel']>>>
|
||||
}
|
||||
}
|
||||
'commands.page': {
|
||||
methods: ["GET","HEAD"]
|
||||
pattern: '/commands'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: []
|
||||
params: {}
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['commands']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['commands']>>>
|
||||
}
|
||||
}
|
||||
'pages.commands_fleet': {
|
||||
methods: ["GET","HEAD"]
|
||||
pattern: '/commands/fleet'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: []
|
||||
params: {}
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['commandsFleet']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['commandsFleet']>>>
|
||||
}
|
||||
}
|
||||
'pages.tr_069_trace': {
|
||||
methods: ["GET","HEAD"]
|
||||
pattern: '/tr069-trace'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: []
|
||||
params: {}
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['tr069Trace']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['tr069Trace']>>>
|
||||
}
|
||||
}
|
||||
'pages.store_fleet_devices': {
|
||||
methods: ["POST"]
|
||||
pattern: '/commands/fleet'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: []
|
||||
params: {}
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['storeFleetDevices']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['storeFleetDevices']>>>
|
||||
}
|
||||
}
|
||||
'pages.store_fleet_command': {
|
||||
methods: ["POST"]
|
||||
pattern: '/commands/fleet/command'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: []
|
||||
params: {}
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['storeFleetCommand']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['storeFleetCommand']>>>
|
||||
}
|
||||
}
|
||||
'pages.configurations_list': {
|
||||
methods: ["GET","HEAD"]
|
||||
pattern: '/configurations'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: []
|
||||
params: {}
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['configurationsList']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['configurationsList']>>>
|
||||
}
|
||||
}
|
||||
'pages.configuration_create': {
|
||||
methods: ["GET","HEAD"]
|
||||
pattern: '/configurations/create'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: []
|
||||
params: {}
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['configurationCreate']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['configurationCreate']>>>
|
||||
}
|
||||
}
|
||||
'pages.configuration_edit': {
|
||||
methods: ["GET","HEAD"]
|
||||
pattern: '/configurations/:id/edit'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: [ParamValue]
|
||||
params: { id: ParamValue }
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['configurationEdit']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['configurationEdit']>>>
|
||||
}
|
||||
}
|
||||
'pages.configuration_detail': {
|
||||
methods: ["GET","HEAD"]
|
||||
pattern: '/configurations/:id/detail'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: [ParamValue]
|
||||
params: { id: ParamValue }
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['configurationDetail']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['configurationDetail']>>>
|
||||
}
|
||||
}
|
||||
'pages.firmware_catalog': {
|
||||
methods: ["GET","HEAD"]
|
||||
pattern: '/firmware-catalog'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: []
|
||||
params: {}
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['firmwareCatalog']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['firmwareCatalog']>>>
|
||||
}
|
||||
}
|
||||
'pages.firmware_catalog_create': {
|
||||
methods: ["GET","HEAD"]
|
||||
pattern: '/firmware-catalog/create'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: []
|
||||
params: {}
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['firmwareCatalogCreate']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['firmwareCatalogCreate']>>>
|
||||
}
|
||||
}
|
||||
'pages.firmware_catalog_edit': {
|
||||
methods: ["GET","HEAD"]
|
||||
pattern: '/firmware-catalog/:id/edit'
|
||||
types: {
|
||||
body: {}
|
||||
paramsTuple: [ParamValue]
|
||||
params: { id: ParamValue }
|
||||
query: {}
|
||||
response: ExtractResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['firmwareCatalogEdit']>>>
|
||||
errorResponse: ExtractErrorResponse<Awaited<ReturnType<import('#controllers/pages_controller').default['firmwareCatalogEdit']>>>
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+64
-14
@@ -2,20 +2,70 @@
|
||||
import type { routes } from './index.ts'
|
||||
|
||||
export interface ApiDefinition {
|
||||
auth: {
|
||||
newAccount: {
|
||||
store: typeof routes['auth.new_account.store']
|
||||
}
|
||||
accessTokens: {
|
||||
store: typeof routes['auth.access_tokens.store']
|
||||
}
|
||||
cwmp: typeof routes['cwmp']
|
||||
health: {
|
||||
checklife: typeof routes['health.checklife']
|
||||
checkservice: typeof routes['health.checkservice']
|
||||
}
|
||||
profile: {
|
||||
profile: {
|
||||
show: typeof routes['profile.profile.show']
|
||||
}
|
||||
accessTokens: {
|
||||
destroy: typeof routes['profile.access_tokens.destroy']
|
||||
}
|
||||
devices: {
|
||||
index: typeof routes['devices.index']
|
||||
criteriaValues: typeof routes['devices.criteria_values']
|
||||
show: typeof routes['devices.show']
|
||||
destroy: typeof routes['devices.destroy']
|
||||
executeCommand: typeof routes['devices.execute_command']
|
||||
refresh: typeof routes['devices.refresh']
|
||||
}
|
||||
commands: {
|
||||
index: typeof routes['commands.index']
|
||||
show: typeof routes['commands.show']
|
||||
store: typeof routes['commands.store']
|
||||
page: typeof routes['commands.page']
|
||||
}
|
||||
tr069Trace: {
|
||||
index: typeof routes['tr_069_trace.index']
|
||||
store: typeof routes['tr_069_trace.store']
|
||||
destroy: typeof routes['tr_069_trace.destroy']
|
||||
}
|
||||
configurationsV1: {
|
||||
index: typeof routes['configurations_v_1.index']
|
||||
listTags: typeof routes['configurations_v_1.list_tags']
|
||||
store: typeof routes['configurations_v_1.store']
|
||||
show: typeof routes['configurations_v_1.show']
|
||||
update: typeof routes['configurations_v_1.update']
|
||||
destroy: typeof routes['configurations_v_1.destroy']
|
||||
toggleEnabled: typeof routes['configurations_v_1.toggle_enabled']
|
||||
manageTags: typeof routes['configurations_v_1.manage_tags']
|
||||
history: typeof routes['configurations_v_1.history']
|
||||
dryRun: typeof routes['configurations_v_1.dry_run']
|
||||
compliance: typeof routes['configurations_v_1.compliance']
|
||||
}
|
||||
firmwareCatalog: {
|
||||
index: typeof routes['firmware_catalog.index']
|
||||
listEntries: typeof routes['firmware_catalog.list_entries']
|
||||
showEntry: typeof routes['firmware_catalog.show_entry']
|
||||
listRoutes: typeof routes['firmware_catalog.list_routes']
|
||||
createEntry: typeof routes['firmware_catalog.create_entry']
|
||||
updateEntry: typeof routes['firmware_catalog.update_entry']
|
||||
deleteEntry: typeof routes['firmware_catalog.delete_entry']
|
||||
createRoute: typeof routes['firmware_catalog.create_route']
|
||||
updateRoute: typeof routes['firmware_catalog.update_route']
|
||||
deleteRoute: typeof routes['firmware_catalog.delete_route']
|
||||
}
|
||||
pages: {
|
||||
home: typeof routes['pages.home']
|
||||
deviceDetail: typeof routes['pages.device_detail']
|
||||
refreshDevice: typeof routes['pages.refresh_device']
|
||||
getModel: typeof routes['pages.get_model']
|
||||
commandsFleet: typeof routes['pages.commands_fleet']
|
||||
tr069Trace: typeof routes['pages.tr_069_trace']
|
||||
storeFleetDevices: typeof routes['pages.store_fleet_devices']
|
||||
storeFleetCommand: typeof routes['pages.store_fleet_command']
|
||||
configurationsList: typeof routes['pages.configurations_list']
|
||||
configurationCreate: typeof routes['pages.configuration_create']
|
||||
configurationEdit: typeof routes['pages.configuration_edit']
|
||||
configurationDetail: typeof routes['pages.configuration_detail']
|
||||
firmwareCatalog: typeof routes['pages.firmware_catalog']
|
||||
firmwareCatalogCreate: typeof routes['pages.firmware_catalog_create']
|
||||
firmwareCatalogEdit: typeof routes['pages.firmware_catalog_edit']
|
||||
}
|
||||
}
|
||||
@@ -11,4 +11,5 @@ export const controllers = {
|
||||
FirmwareCatalog: () => import('#controllers/firmware_catalog_controller'),
|
||||
Health: () => import('#controllers/health_controller'),
|
||||
Pages: () => import('#controllers/pages_controller'),
|
||||
Tr069Trace: () => import('#controllers/tr069_trace_controller'),
|
||||
}
|
||||
Vendored
+143
-13
@@ -4,21 +4,151 @@ type ParamValue = string | number | bigint | boolean
|
||||
|
||||
export type ScannedRoutes = {
|
||||
ALL: {
|
||||
'auth.new_account.store': { paramsTuple?: []; params?: {} }
|
||||
'auth.access_tokens.store': { paramsTuple?: []; params?: {} }
|
||||
'profile.profile.show': { paramsTuple?: []; params?: {} }
|
||||
'profile.access_tokens.destroy': { paramsTuple?: []; params?: {} }
|
||||
}
|
||||
GET: {
|
||||
'profile.profile.show': { paramsTuple?: []; params?: {} }
|
||||
}
|
||||
HEAD: {
|
||||
'profile.profile.show': { paramsTuple?: []; params?: {} }
|
||||
'cwmp': { paramsTuple?: []; params?: {} }
|
||||
'health.checklife': { paramsTuple?: []; params?: {} }
|
||||
'health.checkservice': { paramsTuple?: []; params?: {} }
|
||||
'devices.index': { paramsTuple?: []; params?: {} }
|
||||
'devices.criteria_values': { paramsTuple?: []; params?: {} }
|
||||
'devices.show': { paramsTuple: [ParamValue]; params: {'identifier': ParamValue} }
|
||||
'devices.destroy': { paramsTuple: [ParamValue]; params: {'identifier': ParamValue} }
|
||||
'devices.execute_command': { paramsTuple: [ParamValue]; params: {'identifier': ParamValue} }
|
||||
'devices.refresh': { paramsTuple: [ParamValue]; params: {'identifier': ParamValue} }
|
||||
'commands.index': { paramsTuple?: []; params?: {} }
|
||||
'commands.show': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'commands.store': { paramsTuple?: []; params?: {} }
|
||||
'tr_069_trace.index': { paramsTuple?: []; params?: {} }
|
||||
'tr_069_trace.store': { paramsTuple?: []; params?: {} }
|
||||
'tr_069_trace.destroy': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'configurations_v_1.index': { paramsTuple?: []; params?: {} }
|
||||
'configurations_v_1.list_tags': { paramsTuple?: []; params?: {} }
|
||||
'configurations_v_1.store': { paramsTuple?: []; params?: {} }
|
||||
'configurations_v_1.show': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'configurations_v_1.update': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'configurations_v_1.destroy': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'configurations_v_1.toggle_enabled': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'configurations_v_1.manage_tags': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'configurations_v_1.history': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'configurations_v_1.dry_run': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'configurations_v_1.compliance': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'firmware_catalog.index': { paramsTuple?: []; params?: {} }
|
||||
'firmware_catalog.list_entries': { paramsTuple?: []; params?: {} }
|
||||
'firmware_catalog.show_entry': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'firmware_catalog.list_routes': { paramsTuple?: []; params?: {} }
|
||||
'firmware_catalog.create_entry': { paramsTuple?: []; params?: {} }
|
||||
'firmware_catalog.update_entry': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'firmware_catalog.delete_entry': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'firmware_catalog.create_route': { paramsTuple?: []; params?: {} }
|
||||
'firmware_catalog.update_route': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'firmware_catalog.delete_route': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'pages.home': { paramsTuple?: []; params?: {} }
|
||||
'pages.device_detail': { paramsTuple: [ParamValue]; params: {'identifier': ParamValue} }
|
||||
'pages.refresh_device': { paramsTuple: [ParamValue]; params: {'identifier': ParamValue} }
|
||||
'pages.get_model': { paramsTuple: [ParamValue]; params: {'identifier': ParamValue} }
|
||||
'commands.page': { paramsTuple?: []; params?: {} }
|
||||
'pages.commands_fleet': { paramsTuple?: []; params?: {} }
|
||||
'pages.tr_069_trace': { paramsTuple?: []; params?: {} }
|
||||
'pages.store_fleet_devices': { paramsTuple?: []; params?: {} }
|
||||
'pages.store_fleet_command': { paramsTuple?: []; params?: {} }
|
||||
'pages.configurations_list': { paramsTuple?: []; params?: {} }
|
||||
'pages.configuration_create': { paramsTuple?: []; params?: {} }
|
||||
'pages.configuration_edit': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'pages.configuration_detail': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'pages.firmware_catalog': { paramsTuple?: []; params?: {} }
|
||||
'pages.firmware_catalog_create': { paramsTuple?: []; params?: {} }
|
||||
'pages.firmware_catalog_edit': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
}
|
||||
POST: {
|
||||
'auth.new_account.store': { paramsTuple?: []; params?: {} }
|
||||
'auth.access_tokens.store': { paramsTuple?: []; params?: {} }
|
||||
'profile.access_tokens.destroy': { paramsTuple?: []; params?: {} }
|
||||
'cwmp': { paramsTuple?: []; params?: {} }
|
||||
'devices.execute_command': { paramsTuple: [ParamValue]; params: {'identifier': ParamValue} }
|
||||
'devices.refresh': { paramsTuple: [ParamValue]; params: {'identifier': ParamValue} }
|
||||
'commands.store': { paramsTuple?: []; params?: {} }
|
||||
'tr_069_trace.store': { paramsTuple?: []; params?: {} }
|
||||
'configurations_v_1.store': { paramsTuple?: []; params?: {} }
|
||||
'configurations_v_1.dry_run': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'firmware_catalog.create_entry': { paramsTuple?: []; params?: {} }
|
||||
'firmware_catalog.create_route': { paramsTuple?: []; params?: {} }
|
||||
'pages.refresh_device': { paramsTuple: [ParamValue]; params: {'identifier': ParamValue} }
|
||||
'pages.get_model': { paramsTuple: [ParamValue]; params: {'identifier': ParamValue} }
|
||||
'pages.store_fleet_devices': { paramsTuple?: []; params?: {} }
|
||||
'pages.store_fleet_command': { paramsTuple?: []; params?: {} }
|
||||
}
|
||||
GET: {
|
||||
'health.checklife': { paramsTuple?: []; params?: {} }
|
||||
'health.checkservice': { paramsTuple?: []; params?: {} }
|
||||
'devices.index': { paramsTuple?: []; params?: {} }
|
||||
'devices.criteria_values': { paramsTuple?: []; params?: {} }
|
||||
'devices.show': { paramsTuple: [ParamValue]; params: {'identifier': ParamValue} }
|
||||
'commands.index': { paramsTuple?: []; params?: {} }
|
||||
'commands.show': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'tr_069_trace.index': { paramsTuple?: []; params?: {} }
|
||||
'configurations_v_1.index': { paramsTuple?: []; params?: {} }
|
||||
'configurations_v_1.list_tags': { paramsTuple?: []; params?: {} }
|
||||
'configurations_v_1.show': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'configurations_v_1.history': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'configurations_v_1.compliance': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'firmware_catalog.index': { paramsTuple?: []; params?: {} }
|
||||
'firmware_catalog.list_entries': { paramsTuple?: []; params?: {} }
|
||||
'firmware_catalog.show_entry': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'firmware_catalog.list_routes': { paramsTuple?: []; params?: {} }
|
||||
'pages.home': { paramsTuple?: []; params?: {} }
|
||||
'pages.device_detail': { paramsTuple: [ParamValue]; params: {'identifier': ParamValue} }
|
||||
'commands.page': { paramsTuple?: []; params?: {} }
|
||||
'pages.commands_fleet': { paramsTuple?: []; params?: {} }
|
||||
'pages.tr_069_trace': { paramsTuple?: []; params?: {} }
|
||||
'pages.configurations_list': { paramsTuple?: []; params?: {} }
|
||||
'pages.configuration_create': { paramsTuple?: []; params?: {} }
|
||||
'pages.configuration_edit': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'pages.configuration_detail': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'pages.firmware_catalog': { paramsTuple?: []; params?: {} }
|
||||
'pages.firmware_catalog_create': { paramsTuple?: []; params?: {} }
|
||||
'pages.firmware_catalog_edit': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
}
|
||||
HEAD: {
|
||||
'health.checklife': { paramsTuple?: []; params?: {} }
|
||||
'health.checkservice': { paramsTuple?: []; params?: {} }
|
||||
'devices.index': { paramsTuple?: []; params?: {} }
|
||||
'devices.criteria_values': { paramsTuple?: []; params?: {} }
|
||||
'devices.show': { paramsTuple: [ParamValue]; params: {'identifier': ParamValue} }
|
||||
'commands.index': { paramsTuple?: []; params?: {} }
|
||||
'commands.show': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'tr_069_trace.index': { paramsTuple?: []; params?: {} }
|
||||
'configurations_v_1.index': { paramsTuple?: []; params?: {} }
|
||||
'configurations_v_1.list_tags': { paramsTuple?: []; params?: {} }
|
||||
'configurations_v_1.show': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'configurations_v_1.history': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'configurations_v_1.compliance': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'firmware_catalog.index': { paramsTuple?: []; params?: {} }
|
||||
'firmware_catalog.list_entries': { paramsTuple?: []; params?: {} }
|
||||
'firmware_catalog.show_entry': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'firmware_catalog.list_routes': { paramsTuple?: []; params?: {} }
|
||||
'pages.home': { paramsTuple?: []; params?: {} }
|
||||
'pages.device_detail': { paramsTuple: [ParamValue]; params: {'identifier': ParamValue} }
|
||||
'commands.page': { paramsTuple?: []; params?: {} }
|
||||
'pages.commands_fleet': { paramsTuple?: []; params?: {} }
|
||||
'pages.tr_069_trace': { paramsTuple?: []; params?: {} }
|
||||
'pages.configurations_list': { paramsTuple?: []; params?: {} }
|
||||
'pages.configuration_create': { paramsTuple?: []; params?: {} }
|
||||
'pages.configuration_edit': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'pages.configuration_detail': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'pages.firmware_catalog': { paramsTuple?: []; params?: {} }
|
||||
'pages.firmware_catalog_create': { paramsTuple?: []; params?: {} }
|
||||
'pages.firmware_catalog_edit': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
}
|
||||
DELETE: {
|
||||
'devices.destroy': { paramsTuple: [ParamValue]; params: {'identifier': ParamValue} }
|
||||
'tr_069_trace.destroy': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'configurations_v_1.destroy': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'firmware_catalog.delete_entry': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'firmware_catalog.delete_route': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
}
|
||||
PUT: {
|
||||
'configurations_v_1.update': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'firmware_catalog.update_entry': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'firmware_catalog.update_route': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
}
|
||||
PATCH: {
|
||||
'configurations_v_1.toggle_enabled': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
'configurations_v_1.manage_tags': { paramsTuple: [ParamValue]; params: {'id': ParamValue} }
|
||||
}
|
||||
}
|
||||
declare module '@adonisjs/core/types/http' {
|
||||
|
||||
+3
-1
@@ -22,7 +22,9 @@ COPY --from=builder /app/build ./
|
||||
RUN npm install --omit=dev
|
||||
|
||||
RUN addgroup -g 1001 -S appgroup && \
|
||||
adduser -u 1001 -S appuser -G appgroup
|
||||
adduser -u 1001 -S appuser -G appgroup && \
|
||||
mkdir -p /app/data /app/logs/tr069 && \
|
||||
chown -R appuser:appgroup /app/data /app/logs
|
||||
|
||||
USER appuser
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { HttpContext } from '@adonisjs/core/http'
|
||||
import { buildSoapEnvelope } from '../protocol/soap.js'
|
||||
import { CWMPMessageBuilder } from '../protocol/common/cwmp_message_builder.js'
|
||||
import { StateMachineManager } from '../services/cwmp/state_machine_manager.js'
|
||||
import { Device } from '../domain/device/device.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'
|
||||
@@ -122,6 +122,15 @@ export default class CwmpController {
|
||||
}
|
||||
device.setTmpParamValues(paramValues)
|
||||
|
||||
// Detect TR data model from Inform parameter names (Device.* = TR-181, InternetGatewayDevice.* = TR-098)
|
||||
// Only update if currently unknown — once detected, keep it stable across sessions
|
||||
if (device.dataModel === 'unknown') {
|
||||
const detectedModel = detectDataModelFromParams(paramValues)
|
||||
if (detectedModel !== 'unknown') {
|
||||
device.setDataModel(detectedModel)
|
||||
}
|
||||
}
|
||||
|
||||
// Persist device
|
||||
const hashId = getDeviceHashIdentifier({
|
||||
manufacturer: deviceId.manufacturer,
|
||||
@@ -135,6 +144,7 @@ export default class CwmpController {
|
||||
properties: device.getProperties().map((p) => p.toSnapshot()),
|
||||
parameters: device.getParameters().map((p) => p.toSnapshot()),
|
||||
gpnStatus: device.gpnStatus,
|
||||
dataModel: device.dataModel,
|
||||
updatedAt: new Date(),
|
||||
})
|
||||
logger.info({ hashId }, 'Inform received')
|
||||
@@ -152,16 +162,19 @@ export default class CwmpController {
|
||||
await manager.startStateMachine(device, session, { events })
|
||||
manager.bindRemoteToDevice(remoteKey, device.deviceId)
|
||||
|
||||
// After Inform for onboarding events, enqueue critical reads
|
||||
// After Inform for onboarding events, enqueue critical reads using the detected data model
|
||||
const onlyConnReq = events.length > 0 && events.every((e) => e === '6 CONNECTION REQUEST')
|
||||
if (!onlyConnReq) {
|
||||
try {
|
||||
const isTr181 = device.dataModel === 'tr-181'
|
||||
const root = isTr181 ? 'Device' : 'InternetGatewayDevice'
|
||||
const criticalPaths = [
|
||||
'InternetGatewayDevice.DeviceInfo.SpecVersion',
|
||||
'InternetGatewayDevice.DeviceInfo.HardwareVersion',
|
||||
'InternetGatewayDevice.DeviceInfo.SoftwareVersion',
|
||||
'InternetGatewayDevice.ManagementServer.ConnectionRequestURL',
|
||||
`${root}.DeviceInfo.HardwareVersion`,
|
||||
`${root}.DeviceInfo.SoftwareVersion`,
|
||||
`${root}.ManagementServer.ConnectionRequestURL`,
|
||||
...(isTr181 ? [] : [`${root}.DeviceInfo.SpecVersion`]),
|
||||
]
|
||||
logger.debug({ dataModel: device.dataModel, criticalPaths }, 'Enqueueing critical reads')
|
||||
await manager.enqueueImmediate(device, 'get_parameter_values', criticalPaths)
|
||||
} catch (_e) {
|
||||
// Non-critical
|
||||
@@ -223,6 +236,7 @@ export default class CwmpController {
|
||||
device.setParameter(new DeviceParameter(p.name, p.value, p.type))
|
||||
)
|
||||
device.setGpnStatus(record.gpnStatus ?? 'unknown')
|
||||
device.setDataModel(record.dataModel ?? 'unknown')
|
||||
|
||||
return device
|
||||
} catch (_error) {
|
||||
|
||||
@@ -2,6 +2,11 @@ import type { HttpContext } from '@adonisjs/core/http'
|
||||
import logger from '@adonisjs/core/services/logger'
|
||||
import DeviceModel from '#models/device'
|
||||
import { Tr069TraceService } from '#services/tr069_trace_service'
|
||||
import { readFileSync, existsSync } from 'node:fs'
|
||||
import { join } from 'node:path'
|
||||
|
||||
const LOG_DIR = join(process.cwd(), 'logs', 'tr069')
|
||||
const MAX_TAIL_LINES = 1000
|
||||
|
||||
export default class Tr069TraceController {
|
||||
private get service(): Tr069TraceService {
|
||||
@@ -52,4 +57,24 @@ export default class Tr069TraceController {
|
||||
logger.info({ deviceId: params.id }, 'TR-069 trace disabled for device')
|
||||
return response.status(204).send('')
|
||||
}
|
||||
|
||||
async showLog({ params, request, response }: HttpContext) {
|
||||
const deviceId = params.id
|
||||
const lines = Math.min(Number(request.qs().lines ?? 200), MAX_TAIL_LINES)
|
||||
|
||||
if (!this.service.isTraced(deviceId)) {
|
||||
return response.status(404).json({ error: `Device ${deviceId} is not being traced` })
|
||||
}
|
||||
|
||||
const filePath = join(LOG_DIR, `${deviceId}.log`)
|
||||
if (!existsSync(filePath)) {
|
||||
return response.status(200).json({ deviceId, content: '', lines: 0 })
|
||||
}
|
||||
|
||||
const raw = readFileSync(filePath, 'utf-8')
|
||||
const allLines = raw.split('\n')
|
||||
const tail = allLines.slice(-lines).join('\n')
|
||||
|
||||
return response.status(200).json({ deviceId, content: tail, lines: allLines.length })
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,20 @@ import { createHash } from 'node:crypto'
|
||||
|
||||
export type GpnStatus = 'supported' | 'unsupported' | 'unknown'
|
||||
|
||||
/** TR-098: InternetGatewayDevice.* root — TR-181: Device.* root */
|
||||
export type DataModel = 'tr-181' | 'tr-098' | 'unknown'
|
||||
|
||||
/** Detect which TR data model a device uses from a ParameterValueStruct list */
|
||||
export function detectDataModelFromParams(paramValues: any[]): DataModel {
|
||||
for (const pv of paramValues ?? []) {
|
||||
const name: unknown = pv?.Name
|
||||
if (typeof name !== 'string') continue
|
||||
if (name.startsWith('Device.')) return 'tr-181'
|
||||
if (name.startsWith('InternetGatewayDevice.')) return 'tr-098'
|
||||
}
|
||||
return 'unknown'
|
||||
}
|
||||
|
||||
export enum OnboardingStatus {
|
||||
PENDING = 'PENDING',
|
||||
DISCOVERING = 'DISCOVERING',
|
||||
@@ -22,6 +36,7 @@ export class Device {
|
||||
private _lastSeen: Date = new Date()
|
||||
private _onboardingStatus: OnboardingStatus = OnboardingStatus.PENDING
|
||||
private _gpnStatus: GpnStatus = 'unknown'
|
||||
private _dataModel: DataModel = 'unknown'
|
||||
|
||||
constructor(
|
||||
public readonly deviceId: DeviceId,
|
||||
@@ -48,6 +63,14 @@ export class Device {
|
||||
this._gpnStatus = status
|
||||
}
|
||||
|
||||
public get dataModel(): DataModel {
|
||||
return this._dataModel
|
||||
}
|
||||
|
||||
public setDataModel(model: DataModel): void {
|
||||
this._dataModel = model
|
||||
}
|
||||
|
||||
public get identifier(): string {
|
||||
const raw = `${this.deviceId.manufacturer}-${this.deviceId.oui}-${this.deviceId.productClass}-${this.deviceId.serialNumber}`
|
||||
return createHash('sha256').update(raw).digest('hex').substring(0, 24)
|
||||
@@ -239,6 +262,7 @@ export class Device {
|
||||
onboardingStatus: this._onboardingStatus,
|
||||
isOnline: this.isOnline(),
|
||||
gpnStatus: this._gpnStatus,
|
||||
dataModel: this._dataModel,
|
||||
parameters: this.getParameters().map((p) => p.toSnapshot()),
|
||||
properties: this.getProperties().map((p) => p.toSnapshot()),
|
||||
}
|
||||
@@ -257,6 +281,7 @@ export interface DeviceSnapshot {
|
||||
onboardingStatus: OnboardingStatus
|
||||
isOnline: boolean
|
||||
gpnStatus: GpnStatus
|
||||
dataModel: DataModel
|
||||
parameters: ParameterSnapshot[]
|
||||
properties: PropertySnapshot[]
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { DeviceId } from './device_id.js'
|
||||
import { PropertySnapshot, ParameterSnapshot } from './device_parameter.js'
|
||||
import { DeviceComplianceInfo } from '../configuration/compliance.js'
|
||||
import { GpnStatus } from './device.js'
|
||||
import { DataModel, GpnStatus } from './device.js'
|
||||
|
||||
export interface DeviceRecord {
|
||||
identifier?: string
|
||||
@@ -9,6 +9,7 @@ export interface DeviceRecord {
|
||||
properties: PropertySnapshot[]
|
||||
parameters: ParameterSnapshot[]
|
||||
gpnStatus?: GpnStatus
|
||||
dataModel?: DataModel
|
||||
compliance?: DeviceComplianceInfo
|
||||
provisioningCode?: string
|
||||
updatedAt?: Date
|
||||
|
||||
@@ -3,11 +3,13 @@ import type { NextFn } from '@adonisjs/core/types/http'
|
||||
// @ts-ignore - xml-formatter types conflict with ESM interop
|
||||
import formatXml from 'xml-formatter'
|
||||
import { Tr069TraceService } from '#services/tr069_trace_service'
|
||||
import logger from '@adonisjs/core/services/logger'
|
||||
|
||||
/**
|
||||
* CWMP Logger Middleware
|
||||
*
|
||||
* - Logs all SOAP exchanges to stdout for debugging.
|
||||
* Buffers SOAP request/response. After next():
|
||||
* - Always logs a brief summary (INFO) to the app logger.
|
||||
* - For traced devices, writes full SOAP payloads to logs/tr069/{deviceId}.log.
|
||||
*/
|
||||
export default class CwmpLoggerMiddleware {
|
||||
@@ -23,18 +25,6 @@ export default class CwmpLoggerMiddleware {
|
||||
}
|
||||
}
|
||||
|
||||
private logToStdout(direction: string, sessionId: string, xml: string) {
|
||||
const timestamp = new Date().toISOString()
|
||||
const separator = '─'.repeat(80)
|
||||
process.stdout.write(
|
||||
`\n${separator}\n` +
|
||||
`[TR-069] ${direction} | ${timestamp} | ${sessionId}\n` +
|
||||
`${separator}\n` +
|
||||
`${xml}\n` +
|
||||
`${separator}\n\n`
|
||||
)
|
||||
}
|
||||
|
||||
async handle(ctx: HttpContext, next: NextFn) {
|
||||
const { request, response } = ctx
|
||||
const rawBody = request.raw() || ''
|
||||
@@ -46,15 +36,10 @@ export default class CwmpLoggerMiddleware {
|
||||
const localPort = socket?.localPort || 0
|
||||
const sessionId = `${remoteIp}:${remotePort}->${localAddress}:${localPort}`
|
||||
|
||||
if (rawBody && rawBody.trim() !== '') {
|
||||
this.logToStdout('CPE→ACS', sessionId, this.prettyXml(rawBody))
|
||||
}
|
||||
|
||||
let capturedResponseXml: string | null = null
|
||||
const originalSend = response.send.bind(response)
|
||||
response.send = (body: any) => {
|
||||
if (typeof body === 'string' && body.includes('soap-env:Envelope')) {
|
||||
this.logToStdout('ACS→CPE', sessionId, this.prettyXml(body))
|
||||
capturedResponseXml = body
|
||||
}
|
||||
return originalSend(body)
|
||||
@@ -63,20 +48,19 @@ export default class CwmpLoggerMiddleware {
|
||||
await next()
|
||||
|
||||
const deviceId = ctx.cwmpDeviceId
|
||||
if (!deviceId) {
|
||||
return
|
||||
}
|
||||
|
||||
const traceService = Tr069TraceService.getInstance()
|
||||
if (!traceService.isTraced(deviceId)) {
|
||||
return
|
||||
}
|
||||
const isTraced = deviceId ? traceService.isTraced(deviceId) : false
|
||||
|
||||
if (rawBody && rawBody.trim() !== '') {
|
||||
traceService.writeExchange(deviceId, 'CPE→ACS', this.prettyXml(rawBody))
|
||||
}
|
||||
if (capturedResponseXml) {
|
||||
traceService.writeExchange(deviceId, 'ACS→CPE', this.prettyXml(capturedResponseXml))
|
||||
if (isTraced && deviceId) {
|
||||
if (rawBody && rawBody.trim() !== '') {
|
||||
traceService.writeExchange(deviceId, 'CPE→ACS', sessionId, this.prettyXml(rawBody))
|
||||
}
|
||||
if (capturedResponseXml) {
|
||||
traceService.writeExchange(deviceId, 'ACS→CPE', sessionId, this.prettyXml(capturedResponseXml))
|
||||
}
|
||||
} else if (rawBody && rawBody.trim() !== '') {
|
||||
// Brief app-level log only (no SOAP body)
|
||||
logger.debug({ sessionId, deviceId: deviceId ?? 'unknown' }, 'TR-069 exchange (not traced)')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -255,6 +255,7 @@ export default class ConfigurationEngine {
|
||||
* Uses glob matching for each criterion.
|
||||
*/
|
||||
private matchesCriteria(device: Device, config: Configuration): boolean {
|
||||
if (!device?.deviceId) return false
|
||||
const criteria = config.criteria
|
||||
|
||||
// manufacturer
|
||||
|
||||
@@ -74,6 +74,7 @@ export class DeviceActionExecutor {
|
||||
properties: snapshot.properties,
|
||||
parameters: snapshot.parameters,
|
||||
gpnStatus: snapshot.gpnStatus,
|
||||
dataModel: snapshot.dataModel,
|
||||
updatedAt: new Date(),
|
||||
})
|
||||
} catch (e) {
|
||||
@@ -365,11 +366,19 @@ export class DeviceActionExecutor {
|
||||
|
||||
const knownPC = [...allParams, ...allProps].find((p: any) => /(^|\.)ProvisioningCode$/.test(p?.name))
|
||||
|
||||
const hasDeviceTree = [...allParams, ...allProps].some((p: any) => typeof p?.name === 'string' && p.name.startsWith('Device.'))
|
||||
const hasIgdTree = [...allParams, ...allProps].some((p: any) => typeof p?.name === 'string' && p.name.startsWith('InternetGatewayDevice.'))
|
||||
|
||||
const inferredPath = hasDeviceTree ? 'Device.DeviceInfo.ProvisioningCode' : 'InternetGatewayDevice.DeviceInfo.ProvisioningCode'
|
||||
const provisioningPath = knownPC?.name || (hasIgdTree && !hasDeviceTree ? 'InternetGatewayDevice.DeviceInfo.ProvisioningCode' : inferredPath)
|
||||
// Use the detected data model stored on the device; fall back to scanning known params
|
||||
let provisioningPath: string
|
||||
if (knownPC) {
|
||||
provisioningPath = knownPC.name
|
||||
} else if (device.dataModel === 'tr-181') {
|
||||
provisioningPath = 'Device.DeviceInfo.ProvisioningCode'
|
||||
} else if (device.dataModel === 'tr-098') {
|
||||
provisioningPath = 'InternetGatewayDevice.DeviceInfo.ProvisioningCode'
|
||||
} else {
|
||||
// Legacy fallback: scan stored params
|
||||
const hasDeviceTree = [...allParams, ...allProps].some((p: any) => typeof p?.name === 'string' && p.name.startsWith('Device.'))
|
||||
provisioningPath = hasDeviceTree ? 'Device.DeviceInfo.ProvisioningCode' : 'InternetGatewayDevice.DeviceInfo.ProvisioningCode'
|
||||
}
|
||||
|
||||
const parameterKey = `SetPValues_${device.deviceId.serialNumber}_${Date.now()}`
|
||||
const pvStructs = [{ Name: provisioningPath, Value: { _: device.tmpPC, $: { Type: 'xsd:string' } } }]
|
||||
|
||||
@@ -282,6 +282,7 @@ class CompletedState extends DeviceState {
|
||||
properties: snapshot.properties,
|
||||
parameters: snapshot.parameters,
|
||||
gpnStatus: snapshot.gpnStatus,
|
||||
dataModel: snapshot.dataModel,
|
||||
updatedAt: new Date(),
|
||||
})
|
||||
} catch (e) {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { appendFileSync, mkdirSync, readFileSync, renameSync, statSync } from 'node:fs'
|
||||
import { writeFile } from 'node:fs/promises'
|
||||
import { join } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const CONFIG_PATH = fileURLToPath(new URL('../../config/tr069-trace.json', import.meta.url))
|
||||
const LOG_DIR = fileURLToPath(new URL('../../logs/tr069', import.meta.url))
|
||||
const APP_ROOT = process.cwd()
|
||||
const CONFIG_PATH = join(APP_ROOT, 'data', 'tr069-trace.json')
|
||||
const LOG_DIR = join(APP_ROOT, 'logs', 'tr069')
|
||||
const MAX_FILE_BYTES = 10 * 1024 * 1024
|
||||
const MAX_ROTATED_FILES = 5
|
||||
|
||||
@@ -91,14 +91,14 @@ export class Tr069TraceService {
|
||||
return existed
|
||||
}
|
||||
|
||||
writeExchange(deviceId: string, direction: TraceDirection, xml: string): void {
|
||||
writeExchange(deviceId: string, direction: TraceDirection, sessionId: string, xml: string): void {
|
||||
const tail = this.writeQueues.get(deviceId) ?? Promise.resolve()
|
||||
const next = tail.then(() => this.doWrite(deviceId, direction, xml)).catch(() => undefined)
|
||||
const next = tail.then(() => this.doWrite(deviceId, direction, sessionId, xml)).catch(() => undefined)
|
||||
|
||||
this.writeQueues.set(deviceId, next)
|
||||
}
|
||||
|
||||
private async doWrite(deviceId: string, direction: TraceDirection, xml: string): Promise<void> {
|
||||
private async doWrite(deviceId: string, direction: TraceDirection, sessionId: string, xml: string): Promise<void> {
|
||||
mkdirSync(LOG_DIR, { recursive: true })
|
||||
|
||||
const filePath = join(LOG_DIR, `${deviceId}.log`)
|
||||
@@ -106,7 +106,7 @@ export class Tr069TraceService {
|
||||
|
||||
const timestamp = new Date().toISOString()
|
||||
const separator = '═'.repeat(80)
|
||||
const entry = `\n${separator}\n[${timestamp}] ${direction}\n${separator}\n${xml}\n`
|
||||
const entry = `\n${separator}\n[${timestamp}] ${direction} | ${sessionId}\n${separator}\n${xml}\n`
|
||||
|
||||
appendFileSync(filePath, entry, 'utf-8')
|
||||
}
|
||||
|
||||
@@ -25,7 +25,9 @@ services:
|
||||
PROXY: "false"
|
||||
BSE_PROXY: "false"
|
||||
AUTO_DELETE_ENABLED: "false"
|
||||
INFORM_ACCEPTED_PARAMS: "HardwareVersion,SoftwareVersion,ProvisioningCode,ConnectionRequestURL,ParameterKey,ExternalIPAddress"
|
||||
# Vide = mode permissif : envoie tous les paramètres dans l'Inform (utile pour le dev/test)
|
||||
# Sinon, liste les catégories sémantiques du simulateur (ex: HardwareVersion,SoftwareVersion,...)
|
||||
INFORM_ACCEPTED_PARAMS: ""
|
||||
ADD_IP_AS_HEADER_NAME: ""
|
||||
IPV4_DENY_PREFIX: ""
|
||||
IPV6_PREFIXES: ""
|
||||
@@ -79,7 +81,7 @@ services:
|
||||
- "3000:3000"
|
||||
volumes:
|
||||
# env-config.js injecté au runtime pour configurer l'URL du backend côté navigateur
|
||||
- ./config/simulator-ui-env.js:/usr/share/nginx/html/env-config.js:ro
|
||||
- ./public/simulator-ui-env.js:/usr/share/nginx/html/env-config.js:ro
|
||||
depends_on:
|
||||
- simulator
|
||||
|
||||
|
||||
@@ -29,6 +29,9 @@ services:
|
||||
depends_on:
|
||||
mongodb:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- app_tr069_data:/app/data
|
||||
- app_tr069_logs:/app/logs/tr069
|
||||
healthcheck:
|
||||
test: ["CMD", "node", "-e", "fetch('http://localhost:8080/api/v1/checklife').then(r=>{process.exit(r.ok?0:1)}).catch(()=>process.exit(1))"]
|
||||
interval: 5s
|
||||
@@ -50,3 +53,5 @@ services:
|
||||
|
||||
volumes:
|
||||
mongo_data:
|
||||
app_tr069_data:
|
||||
app_tr069_logs:
|
||||
+120
-50
@@ -31,43 +31,69 @@ const entriesError = ref('')
|
||||
const actionError = ref('')
|
||||
let searchTimeout: ReturnType<typeof setTimeout> | null = null
|
||||
|
||||
// Log viewer state
|
||||
const selectedDeviceId = ref<string | null>(null)
|
||||
const logContent = ref('')
|
||||
const logLines = ref(0)
|
||||
const loadingLog = ref(false)
|
||||
const logError = ref('')
|
||||
let autoRefreshTimer: ReturnType<typeof setInterval> | null = null
|
||||
|
||||
const tracedDeviceIds = computed(() => new Set(tracedDevices.value.map((entry) => entry.deviceId)))
|
||||
const filteredSearchResults = computed(() =>
|
||||
searchResults.value.filter((device) => !tracedDeviceIds.value.has(device.identifier))
|
||||
)
|
||||
const selectedEntry = computed(() =>
|
||||
tracedDevices.value.find((e) => e.deviceId === selectedDeviceId.value) ?? null
|
||||
)
|
||||
|
||||
onMounted(async () => {
|
||||
await loadEntries()
|
||||
})
|
||||
|
||||
watch(searchTerm, (value) => {
|
||||
if (searchTimeout) {
|
||||
clearTimeout(searchTimeout)
|
||||
}
|
||||
|
||||
if (searchTimeout) clearTimeout(searchTimeout)
|
||||
if (!value.trim()) {
|
||||
searchResults.value = []
|
||||
actionError.value = ''
|
||||
return
|
||||
}
|
||||
|
||||
searchTimeout = setTimeout(() => {
|
||||
void searchDevices(value)
|
||||
}, 250)
|
||||
searchTimeout = setTimeout(() => { void searchDevices(value) }, 250)
|
||||
})
|
||||
|
||||
watch(selectedDeviceId, async (id) => {
|
||||
stopAutoRefresh()
|
||||
logContent.value = ''
|
||||
logLines.value = 0
|
||||
logError.value = ''
|
||||
if (id) {
|
||||
await loadLog(id)
|
||||
startAutoRefresh(id)
|
||||
}
|
||||
})
|
||||
|
||||
function startAutoRefresh(deviceId: string) {
|
||||
autoRefreshTimer = setInterval(() => { void loadLog(deviceId) }, 3000)
|
||||
}
|
||||
|
||||
function stopAutoRefresh() {
|
||||
if (autoRefreshTimer !== null) {
|
||||
clearInterval(autoRefreshTimer)
|
||||
autoRefreshTimer = null
|
||||
}
|
||||
}
|
||||
|
||||
async function loadEntries() {
|
||||
loadingEntries.value = true
|
||||
entriesError.value = ''
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/v1/tr069-trace')
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to load trace entries')
|
||||
}
|
||||
|
||||
if (!response.ok) throw new Error('Failed to load trace entries')
|
||||
const data = await response.json()
|
||||
tracedDevices.value = data.entries || []
|
||||
if (selectedDeviceId.value && !tracedDeviceIds.value.has(selectedDeviceId.value)) {
|
||||
selectedDeviceId.value = null
|
||||
}
|
||||
} catch (error) {
|
||||
entriesError.value = error instanceof Error ? error.message : 'Failed to load trace entries'
|
||||
} finally {
|
||||
@@ -78,25 +104,17 @@ async function loadEntries() {
|
||||
async function searchDevices(query: string) {
|
||||
loadingSearch.value = true
|
||||
actionError.value = ''
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/v1/devices?offset=0&limit=200')
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to search devices')
|
||||
}
|
||||
|
||||
if (!response.ok) throw new Error('Failed to search devices')
|
||||
const devices = (await response.json()) as DeviceRecord[]
|
||||
const normalizedQuery = query.trim().toLowerCase()
|
||||
|
||||
searchResults.value = devices.filter((device) => {
|
||||
const manufacturer = device.deviceId?.manufacturer?.toLowerCase() ?? ''
|
||||
const productClass = device.deviceId?.productClass?.toLowerCase() ?? ''
|
||||
const serialNumber = device.deviceId?.serialNumber?.toLowerCase() ?? ''
|
||||
const identifier = device.identifier.toLowerCase()
|
||||
|
||||
return [manufacturer, productClass, serialNumber, identifier].some((value) =>
|
||||
value.includes(normalizedQuery)
|
||||
)
|
||||
return [manufacturer, productClass, serialNumber, identifier].some((v) => v.includes(normalizedQuery))
|
||||
})
|
||||
} catch (error) {
|
||||
actionError.value = error instanceof Error ? error.message : 'Failed to search devices'
|
||||
@@ -109,19 +127,16 @@ async function searchDevices(query: string) {
|
||||
async function addDevice(deviceId: string) {
|
||||
savingDeviceId.value = deviceId
|
||||
actionError.value = ''
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/v1/tr069-trace', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ deviceId }),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const payload = await response.json().catch(() => ({}))
|
||||
throw new Error(payload.error || 'Failed to enable tracing')
|
||||
}
|
||||
|
||||
searchTerm.value = ''
|
||||
searchResults.value = []
|
||||
await loadEntries()
|
||||
@@ -135,17 +150,15 @@ async function addDevice(deviceId: string) {
|
||||
async function removeDevice(deviceId: string) {
|
||||
removingDeviceId.value = deviceId
|
||||
actionError.value = ''
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/v1/tr069-trace/${encodeURIComponent(deviceId)}`, {
|
||||
method: 'DELETE',
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const payload = await response.json().catch(() => ({}))
|
||||
throw new Error(payload.error || 'Failed to disable tracing')
|
||||
}
|
||||
|
||||
if (selectedDeviceId.value === deviceId) selectedDeviceId.value = null
|
||||
await loadEntries()
|
||||
} catch (error) {
|
||||
actionError.value = error instanceof Error ? error.message : 'Failed to disable tracing'
|
||||
@@ -153,6 +166,29 @@ async function removeDevice(deviceId: string) {
|
||||
removingDeviceId.value = null
|
||||
}
|
||||
}
|
||||
|
||||
async function loadLog(deviceId: string) {
|
||||
loadingLog.value = true
|
||||
logError.value = ''
|
||||
try {
|
||||
const response = await fetch(`/api/v1/tr069-trace/${encodeURIComponent(deviceId)}/log?lines=500`)
|
||||
if (!response.ok) {
|
||||
const payload = await response.json().catch(() => ({}))
|
||||
throw new Error(payload.error || 'Failed to load log')
|
||||
}
|
||||
const data = await response.json()
|
||||
logContent.value = data.content ?? ''
|
||||
logLines.value = data.lines ?? 0
|
||||
} catch (error) {
|
||||
logError.value = error instanceof Error ? error.message : 'Failed to load log'
|
||||
} finally {
|
||||
loadingLog.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function clearLog() {
|
||||
logContent.value = ''
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -160,7 +196,8 @@ async function removeDevice(deviceId: string) {
|
||||
|
||||
<div class="container-xxl py-4">
|
||||
<div class="row g-4">
|
||||
<div class="col-12 col-xl-5">
|
||||
<!-- Add device -->
|
||||
<div class="col-12 col-xl-4">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<div class="card-body">
|
||||
<h2 class="h4 mb-3">Add device</h2>
|
||||
@@ -177,7 +214,7 @@ async function removeDevice(deviceId: string) {
|
||||
placeholder="Search devices..."
|
||||
/>
|
||||
|
||||
<p v-if="loadingSearch" class="text-muted small mt-3 mb-0">Searching devices…</p>
|
||||
<p v-if="loadingSearch" class="text-muted small mt-3 mb-0">Searching devices…</p>
|
||||
<p
|
||||
v-else-if="searchTerm.trim() && filteredSearchResults.length === 0"
|
||||
class="text-muted small mt-3 mb-0"
|
||||
@@ -190,8 +227,8 @@ async function removeDevice(deviceId: string) {
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Manufacturer</th>
|
||||
<th>Product Class</th>
|
||||
<th>Serial Number</th>
|
||||
<th>Product</th>
|
||||
<th>Serial</th>
|
||||
<th class="text-end">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -206,7 +243,7 @@ async function removeDevice(deviceId: string) {
|
||||
:disabled="savingDeviceId === device.identifier"
|
||||
@click="addDevice(device.identifier)"
|
||||
>
|
||||
{{ savingDeviceId === device.identifier ? 'Adding…' : 'Add' }}
|
||||
{{ savingDeviceId === device.identifier ? 'Adding…' : 'Add' }}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -217,27 +254,22 @@ async function removeDevice(deviceId: string) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-xl-7">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<!-- Traced devices + log viewer -->
|
||||
<div class="col-12 col-xl-8">
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<div>
|
||||
<h2 class="h4 mb-1">Traced devices</h2>
|
||||
<p class="text-muted small mb-0">
|
||||
Full SOAP traces are written to per-device files.
|
||||
</p>
|
||||
<p class="text-muted small mb-0">Click a row to view its live SOAP log.</p>
|
||||
</div>
|
||||
<span class="badge bg-dark">{{ tracedDevices.length }}</span>
|
||||
</div>
|
||||
|
||||
<div v-if="entriesError" class="alert alert-danger" role="alert">
|
||||
{{ entriesError }}
|
||||
</div>
|
||||
<div v-if="actionError" class="alert alert-warning" role="alert">
|
||||
{{ actionError }}
|
||||
</div>
|
||||
<div v-if="entriesError" class="alert alert-danger" role="alert">{{ entriesError }}</div>
|
||||
<div v-if="actionError" class="alert alert-warning" role="alert">{{ actionError }}</div>
|
||||
|
||||
<p v-if="loadingEntries" class="text-muted small mb-0">Loading traced devices…</p>
|
||||
<p v-if="loadingEntries" class="text-muted small mb-0">Loading traced devices…</p>
|
||||
|
||||
<div v-else class="table-responsive">
|
||||
<table class="table table-sm table-hover align-middle mb-0">
|
||||
@@ -247,11 +279,17 @@ async function removeDevice(deviceId: string) {
|
||||
<th>Product Class</th>
|
||||
<th>Serial Number</th>
|
||||
<th>Started</th>
|
||||
<th class="text-end">Action</th>
|
||||
<th class="text-end">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="entry in tracedDevices" :key="entry.deviceId">
|
||||
<tr
|
||||
v-for="entry in tracedDevices"
|
||||
:key="entry.deviceId"
|
||||
:class="{ 'table-active': selectedDeviceId === entry.deviceId }"
|
||||
style="cursor: pointer"
|
||||
@click="selectedDeviceId = entry.deviceId"
|
||||
>
|
||||
<td>{{ entry.manufacturer || '—' }}</td>
|
||||
<td>{{ entry.productClass || '—' }}</td>
|
||||
<td>{{ entry.serialNumber || '—' }}</td>
|
||||
@@ -260,9 +298,9 @@ async function removeDevice(deviceId: string) {
|
||||
<button
|
||||
class="btn btn-sm btn-outline-danger"
|
||||
:disabled="removingDeviceId === entry.deviceId"
|
||||
@click="removeDevice(entry.deviceId)"
|
||||
@click.stop="removeDevice(entry.deviceId)"
|
||||
>
|
||||
{{ removingDeviceId === entry.deviceId ? 'Removing…' : 'Remove' }}
|
||||
{{ removingDeviceId === entry.deviceId ? 'Removing…' : 'Remove' }}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -276,6 +314,38 @@ async function removeDevice(deviceId: string) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Log viewer panel -->
|
||||
<div v-if="selectedDeviceId" class="card border-0 shadow-sm mt-4">
|
||||
<div
|
||||
class="card-header d-flex justify-content-between align-items-center bg-dark text-white py-2"
|
||||
>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<span class="badge bg-success">Live</span>
|
||||
<span class="small font-monospace">
|
||||
{{ selectedEntry?.manufacturer }} {{ selectedEntry?.productClass }} /
|
||||
{{ selectedEntry?.serialNumber }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<span class="small text-white-50">{{ logLines.toLocaleString() }} lines total</span>
|
||||
<button class="btn btn-sm btn-outline-light py-0" @click="clearLog">Clear view</button>
|
||||
<button class="btn btn-sm btn-outline-light py-0" @click="selectedDeviceId = null">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div v-if="loadingLog && !logContent" class="text-muted small p-3">Loading log…</div>
|
||||
<div v-else-if="logError" class="alert alert-danger m-3">{{ logError }}</div>
|
||||
<div v-else-if="!logContent" class="text-muted small p-3">
|
||||
No log entries yet. Waiting for SOAP exchanges…
|
||||
</div>
|
||||
<pre
|
||||
v-else
|
||||
class="mb-0 p-3 small font-monospace"
|
||||
style="background:#1e1e1e;color:#d4d4d4;max-height:600px;overflow-y:auto;white-space:pre-wrap;word-break:break-all"
|
||||
>{{ logContent }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
File renamed without changes.
@@ -37,6 +37,7 @@ router
|
||||
router.get('/tr069-trace', [Tr069TraceController, 'index'])
|
||||
router.post('/tr069-trace', [Tr069TraceController, 'store'])
|
||||
router.delete('/tr069-trace/:id', [Tr069TraceController, 'destroy'])
|
||||
router.get('/tr069-trace/:id/log', [Tr069TraceController, 'showLog'])
|
||||
|
||||
// Unified Configuration API (v1)
|
||||
router.get('/configurations', [ConfigurationsV1Controller, 'index'])
|
||||
|
||||
@@ -23,6 +23,7 @@ function makeSnapshot(
|
||||
onboardingStatus: OnboardingStatus.COMPLETED,
|
||||
isOnline: false,
|
||||
gpnStatus: 'unknown',
|
||||
dataModel: 'unknown',
|
||||
parameters: [],
|
||||
properties: [],
|
||||
...overrides,
|
||||
|
||||
Reference in new issue
Block a user