@hotmeshio/long-tail 0.27.0 → 0.28.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -2
- package/build/api/files.d.ts +5 -0
- package/build/api/files.js +19 -2
- package/build/api/knowledge.d.ts +3 -1
- package/build/api/settings.d.ts +4 -1
- package/build/api/settings.js +7 -1
- package/build/index.js +9 -4
- package/build/lib/db/config-lock.d.ts +10 -0
- package/build/lib/db/config-lock.js +28 -0
- package/build/lib/db/schemas/041_machine_lines.sql +26 -0
- package/build/lib/db/schemas/042_knowledge_edition_labels.sql +9 -0
- package/build/lib/events/browser-view.js +8 -2
- package/build/lib/events/publish.d.ts +33 -0
- package/build/lib/events/publish.js +52 -1
- package/build/lib/machines/line.d.ts +7 -1
- package/build/lib/machines/line.js +25 -2
- package/build/lib/machines/protocol/codec.d.ts +14 -0
- package/build/lib/machines/protocol/codec.js +10 -1
- package/build/lib/machines/protocol/constants.d.ts +1 -1
- package/build/lib/machines/protocol/constants.js +1 -1
- package/build/lib/machines/protocol/contract.d.ts +2 -0
- package/build/lib/machines/protocol/contract.js +13 -8
- package/build/lib/machines/site/mosquitto-conf.d.ts +9 -4
- package/build/lib/machines/site/mosquitto-conf.js +32 -22
- package/build/lib/machines/site/site-conf.d.ts +13 -3
- package/build/lib/machines/site/site-conf.js +31 -8
- package/build/lib/machines/transport/callback-feed.d.ts +1 -0
- package/build/lib/machines/transport/callback-feed.js +4 -1
- package/build/lib/machines/transport/memory.d.ts +2 -0
- package/build/lib/machines/transport/memory.js +6 -0
- package/build/lib/machines/transport/mqtt-bus.d.ts +2 -0
- package/build/lib/machines/transport/mqtt-bus.js +4 -0
- package/build/lib/machines/transport/nats-bus.d.ts +3 -0
- package/build/lib/machines/transport/nats-bus.js +3 -0
- package/build/lib/machines/transport/nats-feed.d.ts +1 -0
- package/build/lib/machines/transport/nats-feed.js +4 -1
- package/build/lib/machines/transport/pubsub-feed.d.ts +1 -0
- package/build/lib/machines/transport/pubsub-feed.js +4 -1
- package/build/lib/machines/transport/stream-bus.d.ts +7 -1
- package/build/lib/machines/transport/stream-bus.js +17 -5
- package/build/lib/machines/transport/streams.d.ts +10 -2
- package/build/lib/machines/transport/streams.js +32 -5
- package/build/lib/messaging/memory.js +3 -0
- package/build/lib/messaging/nats/streams.d.ts +3 -0
- package/build/lib/messaging/nats/streams.js +16 -0
- package/build/lib/storage/local.d.ts +2 -0
- package/build/lib/storage/local.js +3 -0
- package/build/lib/storage/s3.d.ts +3 -2
- package/build/lib/storage/s3.js +6 -1
- package/build/lib/storage/types.d.ts +7 -1
- package/build/modules/machines.d.ts +8 -0
- package/build/modules/machines.js +16 -0
- package/build/routes/file-browser.js +3 -1
- package/build/routes/index.js +2 -0
- package/build/routes/knowledge.js +6 -5
- package/build/routes/machines.d.ts +2 -0
- package/build/routes/machines.js +253 -0
- package/build/services/knowledge/index.d.ts +4 -2
- package/build/services/knowledge/index.js +8 -2
- package/build/services/knowledge/lookup-cache.d.ts +8 -0
- package/build/services/knowledge/lookup-cache.js +30 -3
- package/build/services/knowledge/lookup-refs.js +1 -1
- package/build/services/knowledge/sql.d.ts +4 -2
- package/build/services/knowledge/sql.js +8 -3
- package/build/services/machines/commands.d.ts +5 -5
- package/build/services/machines/commands.js +3 -2
- package/build/services/machines/config.d.ts +4 -1
- package/build/services/machines/config.js +2 -1
- package/build/services/machines/contracts.d.ts +28 -0
- package/build/services/machines/contracts.js +15 -1
- package/build/services/machines/forms.d.ts +26 -1
- package/build/services/machines/forms.js +17 -1
- package/build/services/machines/gateway/actions.d.ts +14 -1
- package/build/services/machines/gateway/admission.d.ts +30 -4
- package/build/services/machines/gateway/admission.js +76 -14
- package/build/services/machines/gateway/api-escalations.js +4 -0
- package/build/services/machines/gateway/dispatcher.d.ts +12 -4
- package/build/services/machines/gateway/dispatcher.js +53 -17
- package/build/services/machines/gateway/executor.d.ts +13 -2
- package/build/services/machines/gateway/executor.js +84 -29
- package/build/services/machines/gateway/gateway.d.ts +21 -1
- package/build/services/machines/gateway/gateway.js +65 -25
- package/build/services/machines/gateway/index.d.ts +3 -0
- package/build/services/machines/gateway/index.js +3 -0
- package/build/services/machines/gateway/inspect.d.ts +17 -0
- package/build/services/machines/gateway/inspect.js +68 -0
- package/build/services/machines/gateway/log.d.ts +10 -0
- package/build/services/machines/gateway/log.js +20 -0
- package/build/services/machines/gateway/lt-http.js +11 -2
- package/build/services/machines/gateway/pacing.js +2 -1
- package/build/services/machines/gateway/plan-escalation.js +8 -3
- package/build/services/machines/gateway/plan-machine.js +41 -16
- package/build/services/machines/gateway/plan-shared.d.ts +5 -3
- package/build/services/machines/gateway/plan-shared.js +6 -4
- package/build/services/machines/gateway/project.d.ts +9 -0
- package/build/services/machines/gateway/project.js +55 -0
- package/build/services/machines/gateway/receipts.d.ts +3 -0
- package/build/services/machines/gateway/receipts.js +3 -1
- package/build/services/machines/gateway/reconcile.js +3 -3
- package/build/services/machines/gateway/registration.js +1 -1
- package/build/services/machines/gateway/reply-waiter.d.ts +8 -3
- package/build/services/machines/gateway/reply-waiter.js +37 -16
- package/build/services/machines/gateway/state.d.ts +53 -4
- package/build/services/machines/gateway/state.js +128 -13
- package/build/services/machines/gateway/wire-window.d.ts +21 -0
- package/build/services/machines/gateway/wire-window.js +61 -0
- package/build/services/machines/gateway/wire.d.ts +58 -0
- package/build/services/machines/gateway/wire.js +172 -0
- package/build/services/machines/index.d.ts +3 -0
- package/build/services/machines/index.js +2 -0
- package/build/services/machines/line-index.d.ts +16 -0
- package/build/services/machines/line-index.js +39 -0
- package/build/services/machines/registry-sql.d.ts +31 -0
- package/build/services/machines/registry-sql.js +110 -0
- package/build/services/machines/registry-sync.d.ts +31 -0
- package/build/services/machines/registry-sync.js +81 -0
- package/build/services/machines/registry.d.ts +77 -0
- package/build/services/machines/registry.js +158 -0
- package/build/services/machines/roles.d.ts +5 -4
- package/build/services/machines/roles.js +13 -4
- package/build/services/machines/rows.js +10 -1
- package/build/services/machines/select.d.ts +3 -2
- package/build/services/machines/select.js +4 -3
- package/build/services/machines/surface.d.ts +54 -5
- package/build/services/machines/surface.js +113 -17
- package/build/start/apply-report.d.ts +1 -1
- package/build/start/apply-report.js +3 -25
- package/build/start/index.js +16 -4
- package/build/system/activities/knowledge.d.ts +4 -0
- package/build/system/activities/knowledge.js +15 -0
- package/build/system/activities/sql.d.ts +2 -0
- package/build/system/activities/sql.js +6 -1
- package/build/system/index.js +13 -0
- package/build/system/mcp-servers/admin/schemas.d.ts +22 -22
- package/build/system/mcp-servers/human-queue-schemas.d.ts +7 -7
- package/build/system/mcp-servers/knowledge.js +4 -2
- package/build/system/mcp-servers/machines-schemas.d.ts +35 -0
- package/build/system/mcp-servers/machines-schemas.js +35 -0
- package/build/system/mcp-servers/machines.d.ts +20 -0
- package/build/system/mcp-servers/machines.js +154 -0
- package/build/system/seed/tool-manifests-machines.d.ts +2 -0
- package/build/system/seed/tool-manifests-machines.js +88 -0
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/escalation.d.ts +9 -6
- package/build/types/escalation.js +8 -2
- package/build/types/events.d.ts +6 -1
- package/build/types/index.d.ts +1 -0
- package/build/types/machines-view.d.ts +175 -0
- package/build/types/machines-view.js +7 -0
- package/build/types/machines.d.ts +5 -0
- package/build/types/messaging.d.ts +2 -0
- package/build/types/startup.d.ts +2 -0
- package/dashboard/dist/assets/{AdminDashboard-DlItqxFS.js → AdminDashboard-Bm7VG65H.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-DlItqxFS.js.map → AdminDashboard-Bm7VG65H.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-BUmT4a7n.js → AgentConfigPage-aJF7Sdbc.js} +6 -6
- package/dashboard/dist/assets/{AgentConfigPage-BUmT4a7n.js.map → AgentConfigPage-aJF7Sdbc.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-Cww8rlBi.js → AgentDetailPage-GwwghhxT.js} +3 -3
- package/dashboard/dist/assets/{AgentDetailPage-Cww8rlBi.js.map → AgentDetailPage-GwwghhxT.js.map} +1 -1
- package/dashboard/dist/assets/AgentsPage-DVvCzZyg.js +2 -0
- package/dashboard/dist/assets/{AgentsPage-C9UuUKhr.js.map → AgentsPage-DVvCzZyg.js.map} +1 -1
- package/dashboard/dist/assets/AvailableEscalationsPage-Cxmcji_K.js +2 -0
- package/dashboard/dist/assets/{AvailableEscalationsPage-DrvfXz70.js.map → AvailableEscalationsPage-Cxmcji_K.js.map} +1 -1
- package/dashboard/dist/assets/{BotPicker-CDq9XRMp.js → BotPicker-CofRxk4L.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-CDq9XRMp.js.map → BotPicker-CofRxk4L.js.map} +1 -1
- package/dashboard/dist/assets/{BulkAssignModal-jsvqtrEA.js → BulkAssignModal-BARWuz4L.js} +2 -2
- package/dashboard/dist/assets/{BulkAssignModal-jsvqtrEA.js.map → BulkAssignModal-BARWuz4L.js.map} +1 -1
- package/dashboard/dist/assets/{CapabilitiesPage-CSCrI6B1.js → CapabilitiesPage-BJAWVNEx.js} +2 -2
- package/dashboard/dist/assets/{CapabilitiesPage-CSCrI6B1.js.map → CapabilitiesPage-BJAWVNEx.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-uD9mn-CQ.js → CollapsibleSection-CtgoaG75.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-uD9mn-CQ.js.map → CollapsibleSection-CtgoaG75.js.map} +1 -1
- package/dashboard/dist/assets/{ConfirmDeleteModal-BRmx2hA4.js → ConfirmDeleteModal-BYXXBWs6.js} +2 -2
- package/dashboard/dist/assets/{ConfirmDeleteModal-BRmx2hA4.js.map → ConfirmDeleteModal-BYXXBWs6.js.map} +1 -1
- package/dashboard/dist/assets/{ConnectedAppsPage-DlMzE5a-.js → ConnectedAppsPage-D0JkzWa7.js} +2 -2
- package/dashboard/dist/assets/{ConnectedAppsPage-DlMzE5a-.js.map → ConnectedAppsPage-D0JkzWa7.js.map} +1 -1
- package/dashboard/dist/assets/{CountdownTimer-sRuM4eM5.js → CountdownTimer-BcFxdZYN.js} +2 -2
- package/dashboard/dist/assets/{CountdownTimer-sRuM4eM5.js.map → CountdownTimer-BcFxdZYN.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialsPage-bLYydwqa.js → CredentialsPage-DPSY20rV.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-bLYydwqa.js.map → CredentialsPage-DPSY20rV.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-D_ATDL2N.js → CronLabel-Dg_Oew_Y.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-D_ATDL2N.js.map → CronLabel-Dg_Oew_Y.js.map} +1 -1
- package/dashboard/dist/assets/{DropZone-u1JGfR9G.js → DropZone-Cl_Flb16.js} +2 -2
- package/dashboard/dist/assets/{DropZone-u1JGfR9G.js.map → DropZone-Cl_Flb16.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-groSMfqB.js → ElapsedCell-Dm3G5fK2.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-groSMfqB.js.map → ElapsedCell-Dm3G5fK2.js.map} +1 -1
- package/dashboard/dist/assets/{EntityTimelinePanel-D-F3_A9m.js → EntityTimelinePanel-CrEEP04e.js} +2 -2
- package/dashboard/dist/assets/{EntityTimelinePanel-D-F3_A9m.js.map → EntityTimelinePanel-CrEEP04e.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationListSchemaPage-Bad6Jrmr.js → EscalationListSchemaPage-wOInXcjs.js} +3 -3
- package/dashboard/dist/assets/{EscalationListSchemaPage-Bad6Jrmr.js.map → EscalationListSchemaPage-wOInXcjs.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationSchemaPage-BKi_npI9.js → EscalationSchemaPage-CrIj_g9d.js} +3 -3
- package/dashboard/dist/assets/{EscalationSchemaPage-BKi_npI9.js.map → EscalationSchemaPage-CrIj_g9d.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationTimeline-DQUUm3b1.js → EscalationTimeline-CeAsl5IT.js} +2 -2
- package/dashboard/dist/assets/{EscalationTimeline-DQUUm3b1.js.map → EscalationTimeline-CeAsl5IT.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationTitleSelect-3mhXh77a.js → EscalationTitleSelect-D8qpCYiy.js} +2 -2
- package/dashboard/dist/assets/{EscalationTitleSelect-3mhXh77a.js.map → EscalationTitleSelect-D8qpCYiy.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-Qaov-uML.js → EscalationsOverview-CvaqVPsr.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-Qaov-uML.js.map → EscalationsOverview-CvaqVPsr.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-V4RF_n58.js → EventTable-Be0JuEl6.js} +2 -2
- package/dashboard/dist/assets/{EventTable-V4RF_n58.js.map → EventTable-Be0JuEl6.js.map} +1 -1
- package/dashboard/dist/assets/FilterBar-BVyAjIgv.js +2 -0
- package/dashboard/dist/assets/FilterBar-BVyAjIgv.js.map +1 -0
- package/dashboard/dist/assets/{GraphInvokePage-Djslhf96.js → GraphInvokePage-D_QigJeD.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-Djslhf96.js.map → GraphInvokePage-D_QigJeD.js.map} +1 -1
- package/dashboard/dist/assets/{HomePage-EjcNxlKx.js → HomePage-C1haeuNy.js} +2 -2
- package/dashboard/dist/assets/{HomePage-EjcNxlKx.js.map → HomePage-C1haeuNy.js.map} +1 -1
- package/dashboard/dist/assets/LinePage-CWD5pv1g.js +5 -0
- package/dashboard/dist/assets/LinePage-CWD5pv1g.js.map +1 -0
- package/dashboard/dist/assets/LinesPage-NqChsKcO.js +3 -0
- package/dashboard/dist/assets/LinesPage-NqChsKcO.js.map +1 -0
- package/dashboard/dist/assets/{ListToolbar-RrEAePOX.js → ListToolbar-BZCNrTh6.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-RrEAePOX.js.map → ListToolbar-BZCNrTh6.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-8gqiL3Vj.js → McpOverview-yJTYnh1z.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-8gqiL3Vj.js.map → McpOverview-yJTYnh1z.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-COyn6Ak5.js → McpQueryDetailPage-ChuLpJ4u.js} +3 -3
- package/dashboard/dist/assets/{McpQueryDetailPage-COyn6Ak5.js.map → McpQueryDetailPage-ChuLpJ4u.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryPage-Dj6Qj72w.js → McpQueryPage-9S-v9soF.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-Dj6Qj72w.js.map → McpQueryPage-9S-v9soF.js.map} +1 -1
- package/dashboard/dist/assets/McpRunDetailPage-BhrcfxD5.js +2 -0
- package/dashboard/dist/assets/{McpRunDetailPage-80fQn9iX.js.map → McpRunDetailPage-BhrcfxD5.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-DaSsI-EM.js → McpRunsPage-C5_i8_Zx.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-DaSsI-EM.js.map → McpRunsPage-C5_i8_Zx.js.map} +1 -1
- package/dashboard/dist/assets/{NamespacePill-C5epAgq6.js → NamespacePill-OTZD2hzt.js} +2 -2
- package/dashboard/dist/assets/{NamespacePill-C5epAgq6.js.map → NamespacePill-OTZD2hzt.js.map} +1 -1
- package/dashboard/dist/assets/{OperationsPage-BSu1o2gB.js → OperationsPage-C03CeU5P.js} +2 -2
- package/dashboard/dist/assets/{OperationsPage-BSu1o2gB.js.map → OperationsPage-C03CeU5P.js.map} +1 -1
- package/dashboard/dist/assets/{OperatorDashboard-HFI4WGIV.js → OperatorDashboard-BzC134Jt.js} +2 -2
- package/dashboard/dist/assets/{OperatorDashboard-HFI4WGIV.js.map → OperatorDashboard-BzC134Jt.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeader-BSWIspNB.js → PageHeader-Hx8APPwE.js} +2 -2
- package/dashboard/dist/assets/{PageHeader-BSWIspNB.js.map → PageHeader-Hx8APPwE.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeaderWithStats-DDjopQ-k.js → PageHeaderWithStats-BEQYYBJv.js} +2 -2
- package/dashboard/dist/assets/{PageHeaderWithStats-DDjopQ-k.js.map → PageHeaderWithStats-BEQYYBJv.js.map} +1 -1
- package/dashboard/dist/assets/{PersonaDetailPage-D0qlBuGi.js → PersonaDetailPage-D0mY9L6j.js} +2 -2
- package/dashboard/dist/assets/{PersonaDetailPage-D0qlBuGi.js.map → PersonaDetailPage-D0mY9L6j.js.map} +1 -1
- package/dashboard/dist/assets/{PersonasPage-BJClu-5H.js → PersonasPage-FFlm5Eug.js} +2 -2
- package/dashboard/dist/assets/{PersonasPage-BJClu-5H.js.map → PersonasPage-FFlm5Eug.js.map} +1 -1
- package/dashboard/dist/assets/{PortalPage-CucNZn_w.js → PortalPage-Cpc25uO-.js} +2 -2
- package/dashboard/dist/assets/{PortalPage-CucNZn_w.js.map → PortalPage-Cpc25uO-.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessDetailPage-B9wMw0RV.js → ProcessDetailPage-Di2J7KwY.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-B9wMw0RV.js.map → ProcessDetailPage-Di2J7KwY.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-B6k4RpmR.js → ProcessesListPage-BEXwU3Z0.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-B6k4RpmR.js.map → ProcessesListPage-BEXwU3Z0.js.map} +1 -1
- package/dashboard/dist/assets/{ResolverForm-ZVufJ4G-.js → ResolverForm-2ks-3jXC.js} +6 -6
- package/dashboard/dist/assets/{ResolverForm-ZVufJ4G-.js.map → ResolverForm-2ks-3jXC.js.map} +1 -1
- package/dashboard/dist/assets/{RoleDetailPage-CTbq0mz4.js → RoleDetailPage-DqoOk0xc.js} +3 -3
- package/dashboard/dist/assets/{RoleDetailPage-CTbq0mz4.js.map → RoleDetailPage-DqoOk0xc.js.map} +1 -1
- package/dashboard/dist/assets/{RolePill-CoETDpjF.js → RolePill-R5_ctGFy.js} +2 -2
- package/dashboard/dist/assets/{RolePill-CoETDpjF.js.map → RolePill-R5_ctGFy.js.map} +1 -1
- package/dashboard/dist/assets/{RolesPage-DBKxeam4.js → RolesPage-CPmo8Srr.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-DBKxeam4.js.map → RolesPage-CPmo8Srr.js.map} +1 -1
- package/dashboard/dist/assets/{RosterWidget-BkLAwEYB.js → RosterWidget-D2yovCKw.js} +2 -2
- package/dashboard/dist/assets/{RosterWidget-BkLAwEYB.js.map → RosterWidget-D2yovCKw.js.map} +1 -1
- package/dashboard/dist/assets/{RunAsSelector-D2DC4iDf.js → RunAsSelector-CMv96On6.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-D2DC4iDf.js.map → RunAsSelector-CMv96On6.js.map} +1 -1
- package/dashboard/dist/assets/{ScanCodesPage-BlKleaT0.js → ScanCodesPage-CA6cTT-M.js} +2 -2
- package/dashboard/dist/assets/{ScanCodesPage-BlKleaT0.js.map → ScanCodesPage-CA6cTT-M.js.map} +1 -1
- package/dashboard/dist/assets/{ScanSchemeDetailPage-CTW6gofi.js → ScanSchemeDetailPage-DnctN5-H.js} +2 -2
- package/dashboard/dist/assets/{ScanSchemeDetailPage-CTW6gofi.js.map → ScanSchemeDetailPage-DnctN5-H.js.map} +1 -1
- package/dashboard/dist/assets/{ScanStationPage-DPRjSPyT.js → ScanStationPage-Bk8RwkKL.js} +2 -2
- package/dashboard/dist/assets/{ScanStationPage-DPRjSPyT.js.map → ScanStationPage-Bk8RwkKL.js.map} +1 -1
- package/dashboard/dist/assets/{ScopeBadge-CGsTtqFr.js → ScopeBadge-BXZ084nD.js} +2 -2
- package/dashboard/dist/assets/{ScopeBadge-CGsTtqFr.js.map → ScopeBadge-BXZ084nD.js.map} +1 -1
- package/dashboard/dist/assets/{StickyPagination-CkmX3-Gu.js → StickyPagination-B0FSuUgs.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-CkmX3-Gu.js.map → StickyPagination-B0FSuUgs.js.map} +1 -1
- package/dashboard/dist/assets/{StreamMessageDetail-Xm_n510s.js → StreamMessageDetail-BwZEvMpP.js} +2 -2
- package/dashboard/dist/assets/{StreamMessageDetail-Xm_n510s.js.map → StreamMessageDetail-BwZEvMpP.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-De48aJan.js → SwimlaneTimeline-BDVQEaMw.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-De48aJan.js.map → SwimlaneTimeline-BDVQEaMw.js.map} +1 -1
- package/dashboard/dist/assets/{TagInput-S7UuVT_M.js → TagInput-DjPUDp2M.js} +2 -2
- package/dashboard/dist/assets/{TagInput-S7UuVT_M.js.map → TagInput-DjPUDp2M.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-HycMx3O9.js → TaskDetailPage-BOlv3iGB.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-HycMx3O9.js.map → TaskDetailPage-BOlv3iGB.js.map} +1 -1
- package/dashboard/dist/assets/{TaskQueuePill-BlHNpYiZ.js → TaskQueuePill-D-4Ynf3K.js} +2 -2
- package/dashboard/dist/assets/{TaskQueuePill-BlHNpYiZ.js.map → TaskQueuePill-D-4Ynf3K.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-OIcFFp1C.js → TasksListPage-e2teY0bD.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-OIcFFp1C.js.map → TasksListPage-e2teY0bD.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-OTC_55oZ.js → TimeAgo-Cvkpf_b3.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-OTC_55oZ.js.map → TimeAgo-Cvkpf_b3.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-CAwIj_AI.js → TimestampCell-B3btAV0N.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-CAwIj_AI.js.map → TimestampCell-B3btAV0N.js.map} +1 -1
- package/dashboard/dist/assets/{ToolPill-D40uLM_v.js → ToolPill-GsKQ80CO.js} +2 -2
- package/dashboard/dist/assets/{ToolPill-D40uLM_v.js.map → ToolPill-GsKQ80CO.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-8Vf6pfw4.js → ToolTestPanel-B03nebR7.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-8Vf6pfw4.js.map → ToolTestPanel-B03nebR7.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-iZW8rK9L.js → TopicDetailPage-DBRWne3O.js} +3 -3
- package/dashboard/dist/assets/{TopicDetailPage-iZW8rK9L.js.map → TopicDetailPage-DBRWne3O.js.map} +1 -1
- package/dashboard/dist/assets/{TopicsPage-CqiEcj-W.js → TopicsPage-CVe2M9HD.js} +2 -2
- package/dashboard/dist/assets/{TopicsPage-CqiEcj-W.js.map → TopicsPage-CVe2M9HD.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-DQFjuoib.js → UserName-B_q_qp6V.js} +2 -2
- package/dashboard/dist/assets/{UserName-DQFjuoib.js.map → UserName-B_q_qp6V.js.map} +1 -1
- package/dashboard/dist/assets/WorkflowExecutionPage-Bh_dr9tM.js +2 -0
- package/dashboard/dist/assets/{WorkflowExecutionPage-Di08wCbs.js.map → WorkflowExecutionPage-Bh_dr9tM.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowPill-DJLcK_CM.js → WorkflowPill-D7244fKp.js} +2 -2
- package/dashboard/dist/assets/{WorkflowPill-DJLcK_CM.js.map → WorkflowPill-D7244fKp.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsDashboard-Bb8HlrTJ.js → WorkflowsDashboard-DA6Mj7qH.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-Bb8HlrTJ.js.map → WorkflowsDashboard-DA6Mj7qH.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-Dta1kurk.js → WorkflowsOverview-B1kBLj-a.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-Dta1kurk.js.map → WorkflowsOverview-B1kBLj-a.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-CfAajg68.js → YamlWorkflowDetailPage-6GJM8QIX.js} +8 -8
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-CfAajg68.js.map → YamlWorkflowDetailPage-6GJM8QIX.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-CQFUzT4t.js → YamlWorkflowsPage-Bu811C7f.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-CQFUzT4t.js.map → YamlWorkflowsPage-Bu811C7f.js.map} +1 -1
- package/dashboard/dist/assets/{agents-PuftRTB2.js → agents-MPk_GnYz.js} +2 -2
- package/dashboard/dist/assets/{agents-PuftRTB2.js.map → agents-MPk_GnYz.js.map} +1 -1
- package/dashboard/dist/assets/{bots-BmEiPAWY.js → bots-2RihE2Tc.js} +2 -2
- package/dashboard/dist/assets/{bots-BmEiPAWY.js.map → bots-2RihE2Tc.js.map} +1 -1
- package/dashboard/dist/assets/{capabilities-CRii4Soa.js → capabilities-CC4iwJ1P.js} +2 -2
- package/dashboard/dist/assets/{capabilities-CRii4Soa.js.map → capabilities-CC4iwJ1P.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-DO_czaYo.js → controlplane-Bmkic8BH.js} +2 -2
- package/dashboard/dist/assets/{controlplane-DO_czaYo.js.map → controlplane-Bmkic8BH.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-columns-CzCquCPh.js → escalation-columns-B0lhUUrQ.js} +2 -2
- package/dashboard/dist/assets/{escalation-columns-CzCquCPh.js.map → escalation-columns-B0lhUUrQ.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-items-Cy0ZgJqV.js → escalation-items-7WFpPo46.js} +2 -2
- package/dashboard/dist/assets/{escalation-items-Cy0ZgJqV.js.map → escalation-items-7WFpPo46.js.map} +1 -1
- package/dashboard/dist/assets/index-B9uv-euR.css +1 -0
- package/dashboard/dist/assets/{index-DhSCCpqM.js → index-B_XV1rwu.js} +2 -2
- package/dashboard/dist/assets/{index-DhSCCpqM.js.map → index-B_XV1rwu.js.map} +1 -1
- package/dashboard/dist/assets/{index-Cx8xb-oU.js → index-C2CLfGwL.js} +2 -2
- package/dashboard/dist/assets/{index-Cx8xb-oU.js.map → index-C2CLfGwL.js.map} +1 -1
- package/dashboard/dist/assets/{index-Cga5IW3D.js → index-C3AeFihz.js} +2 -2
- package/dashboard/dist/assets/{index-Cga5IW3D.js.map → index-C3AeFihz.js.map} +1 -1
- package/dashboard/dist/assets/{index-DiaRlFYI.js → index-CBri8fYM.js} +2 -2
- package/dashboard/dist/assets/{index-DiaRlFYI.js.map → index-CBri8fYM.js.map} +1 -1
- package/dashboard/dist/assets/{index-CL_1VpGb.js → index-CRWsB7ZC.js} +2 -2
- package/dashboard/dist/assets/{index-CL_1VpGb.js.map → index-CRWsB7ZC.js.map} +1 -1
- package/dashboard/dist/assets/{index-XntldBd0.js → index-CTOv3G7a.js} +2 -2
- package/dashboard/dist/assets/{index-XntldBd0.js.map → index-CTOv3G7a.js.map} +1 -1
- package/dashboard/dist/assets/{index-CfP2nKRc.js → index-CcArGkzI.js} +3 -3
- package/dashboard/dist/assets/{index-CfP2nKRc.js.map → index-CcArGkzI.js.map} +1 -1
- package/dashboard/dist/assets/{index-Dz6R8-Dw.js → index-CkMHS-hG.js} +25 -25
- package/dashboard/dist/assets/index-CkMHS-hG.js.map +1 -0
- package/dashboard/dist/assets/index-CmsmwCyv.js +2 -0
- package/dashboard/dist/assets/{index-4YaDUcKd.js.map → index-CmsmwCyv.js.map} +1 -1
- package/dashboard/dist/assets/{index-2SM2_onB.js → index-CvJsvqIc.js} +2 -2
- package/dashboard/dist/assets/{index-2SM2_onB.js.map → index-CvJsvqIc.js.map} +1 -1
- package/dashboard/dist/assets/{index-Rwqrflm-.js → index-D-ilRyfy.js} +2 -2
- package/dashboard/dist/assets/{index-Rwqrflm-.js.map → index-D-ilRyfy.js.map} +1 -1
- package/dashboard/dist/assets/{index-CZ7A3AcD.js → index-DSUtfDXx.js} +2 -2
- package/dashboard/dist/assets/{index-CZ7A3AcD.js.map → index-DSUtfDXx.js.map} +1 -1
- package/dashboard/dist/assets/{index-jL2K6us4.js → index-Da6ycKyf.js} +2 -2
- package/dashboard/dist/assets/{index-jL2K6us4.js.map → index-Da6ycKyf.js.map} +1 -1
- package/dashboard/dist/assets/{knowledge-CeUqGPuo.js → knowledge-Bpbg20DC.js} +2 -2
- package/dashboard/dist/assets/{knowledge-CeUqGPuo.js.map → knowledge-Bpbg20DC.js.map} +1 -1
- package/dashboard/dist/assets/machines-BqOZZU-3.js +2 -0
- package/dashboard/dist/assets/machines-BqOZZU-3.js.map +1 -0
- package/dashboard/dist/assets/{mcp-Cx96NTeD.js → mcp-CmcUXYce.js} +2 -2
- package/dashboard/dist/assets/{mcp-Cx96NTeD.js.map → mcp-CmcUXYce.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-XAzWl0gm.js → mcp-query-C8buQxN9.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-XAzWl0gm.js.map → mcp-query-C8buQxN9.js.map} +1 -1
- package/dashboard/dist/assets/{personas--4kjwyOw.js → personas-C2n5oDmY.js} +2 -2
- package/dashboard/dist/assets/{personas--4kjwyOw.js.map → personas-C2n5oDmY.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-PgkwvG7f.js → pipelines-RKpSkFz7.js} +2 -2
- package/dashboard/dist/assets/{pipelines-PgkwvG7f.js.map → pipelines-RKpSkFz7.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-CcYxdBa3.js → tasks-Dab4hExW.js} +2 -2
- package/dashboard/dist/assets/{tasks-CcYxdBa3.js.map → tasks-Dab4hExW.js.map} +1 -1
- package/dashboard/dist/assets/{topics-_lik7cNY.js → topics-FTMNP7r3.js} +2 -2
- package/dashboard/dist/assets/{topics-_lik7cNY.js.map → topics-FTMNP7r3.js.map} +1 -1
- package/dashboard/dist/assets/{useDebouncedValue-Bm_AoxVx.js → useDebouncedValue-B_1u1YIk.js} +2 -2
- package/dashboard/dist/assets/{useDebouncedValue-Bm_AoxVx.js.map → useDebouncedValue-B_1u1YIk.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-DgXXKdx5.js → useNamespace-HUeAI7Qb.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-DgXXKdx5.js.map → useNamespace-HUeAI7Qb.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-Dj2qtGSd.js → useYamlActivityEvents-Cax54qHH.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-Dj2qtGSd.js.map → useYamlActivityEvents-Cax54qHH.js.map} +1 -1
- package/dashboard/dist/assets/{validate-FlXCBBT6.js → validate-DxOaV7QS.js} +2 -2
- package/dashboard/dist/assets/{validate-FlXCBBT6.js.map → validate-DxOaV7QS.js.map} +1 -1
- package/dashboard/dist/assets/{vendor-icons-DUYcKTjP.js → vendor-icons-fxBvvHBi.js} +187 -182
- package/dashboard/dist/assets/vendor-icons-fxBvvHBi.js.map +1 -0
- package/dashboard/dist/assets/{yaml-workflows-B0_JxRYQ.js → yaml-workflows-BgY1XHJx.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-B0_JxRYQ.js.map → yaml-workflows-BgY1XHJx.js.map} +1 -1
- package/dashboard/dist/index.html +3 -3
- package/docs/architecture.md +1 -0
- package/docs/code-owned-configuration.md +6 -0
- package/docs/dashboard.md +2 -1
- package/docs/events.md +34 -1
- package/docs/hitl/lookups.md +6 -4
- package/docs/machines.md +114 -28
- package/docs/mcp.md +19 -0
- package/package.json +1 -1
- package/dashboard/dist/assets/AgentsPage-C9UuUKhr.js +0 -2
- package/dashboard/dist/assets/AvailableEscalationsPage-DrvfXz70.js +0 -2
- package/dashboard/dist/assets/FilterBar-BygWrnB1.js +0 -2
- package/dashboard/dist/assets/FilterBar-BygWrnB1.js.map +0 -1
- package/dashboard/dist/assets/McpRunDetailPage-80fQn9iX.js +0 -2
- package/dashboard/dist/assets/WorkflowExecutionPage-Di08wCbs.js +0 -2
- package/dashboard/dist/assets/index-4YaDUcKd.js +0 -2
- package/dashboard/dist/assets/index-CnU7Jjz3.css +0 -1
- package/dashboard/dist/assets/index-Dz6R8-Dw.js.map +0 -1
- package/dashboard/dist/assets/vendor-icons-DUYcKTjP.js.map +0 -1
|
@@ -10,6 +10,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.inspectMessage = inspectMessage;
|
|
13
|
+
exports.isUnreadableRead = isUnreadableRead;
|
|
13
14
|
const ajv_1 = __importDefault(require("ajv"));
|
|
14
15
|
const constants_1 = require("./constants");
|
|
15
16
|
const envelope_1 = require("./envelope");
|
|
@@ -35,13 +36,13 @@ const ENVELOPE = shape({
|
|
|
35
36
|
});
|
|
36
37
|
const RECIPE = { anyOf: [shape({ id: STR, version: STR }), { type: 'null' }] };
|
|
37
38
|
const BODY = {
|
|
38
|
-
[topics_1.MESSAGE_KIND.PRESENCE]: shape({ online: BOOL, software: STR }, ['software']),
|
|
39
|
+
[topics_1.MESSAGE_KIND.PRESENCE]: shape({ online: BOOL, software: STR, sessionId: STR, reason: STR }, ['software', 'sessionId', 'reason']),
|
|
39
40
|
[topics_1.MESSAGE_KIND.SNAPSHOT]: shape({
|
|
40
41
|
bootId: STR, software: STR, mode: oneOf(constants_1.MODE), enabled: BOOL, recipe: RECIPE,
|
|
41
42
|
jobs: { type: 'array', items: shape({ jobId: STR, units: { type: 'array', items: STR }, status: STR }) },
|
|
42
43
|
alarms: { type: 'array', items: STR },
|
|
43
44
|
cycles: INT0,
|
|
44
|
-
}),
|
|
45
|
+
}, ['bootId', 'software', 'recipe', 'cycles']),
|
|
45
46
|
[topics_1.MESSAGE_KIND.JOB]: shape({
|
|
46
47
|
event: oneOf(constants_1.JOB_EVENT), jobId: STR, unitId: STR, orderRef: STR, recipe: RECIPE, carrierId: STR_N, peer: STR_N,
|
|
47
48
|
result: oneOf(constants_1.JOB_RESULT), reason: STR_N,
|
|
@@ -52,15 +53,15 @@ const BODY = {
|
|
|
52
53
|
materials: { type: 'array', items: shape({ material: STR, lot: STR }) },
|
|
53
54
|
startedAt: TS, endedAt: TS, durationMs: INT0, failure: oneOf(constants_1.TRANSFER_FAILURE),
|
|
54
55
|
percent: { type: 'number', minimum: 0, maximum: 100 }, remainingSec: INT0, stage: STR, detail: { type: 'object' },
|
|
55
|
-
}, ['jobId', 'unitId', 'peer', 'result', 'reason', 'measurements', 'materials', 'startedAt', 'endedAt', 'durationMs', 'failure', 'percent', 'remainingSec', 'stage', 'detail']),
|
|
56
|
+
}, ['jobId', 'unitId', 'orderRef', 'peer', 'result', 'reason', 'measurements', 'materials', 'startedAt', 'endedAt', 'durationMs', 'failure', 'percent', 'remainingSec', 'stage', 'detail']),
|
|
56
57
|
[topics_1.MESSAGE_KIND.ALARM]: shape({
|
|
57
58
|
alarmId: STR, code: STR, level: oneOf(constants_1.LEVEL), text: STR, active: BOOL,
|
|
58
59
|
raisedAt: TS, clearedAt: TS_N, clearedBy: STR_N, ackedBy: STR_N, ackedAt: TS_N,
|
|
59
|
-
zone: STR_N, autoClears: BOOL, action: STR_N, jobId: STR_N,
|
|
60
|
-
}),
|
|
60
|
+
zone: STR_N, autoClears: BOOL, action: STR_N, jobId: STR_N, needsPerson: BOOL,
|
|
61
|
+
}, ['needsPerson']),
|
|
61
62
|
[topics_1.MESSAGE_KIND.TELEMETRY]: shape({ readings: { type: 'object', additionalProperties: NUM } }),
|
|
62
63
|
[topics_1.MESSAGE_KIND.CMD]: shape({ cmdId: STR, op: oneOf(constants_1.OP), args: { type: 'object' } }),
|
|
63
|
-
[topics_1.MESSAGE_KIND.REPLY]: shape({ cmdId: STR, status: oneOf(constants_1.REPLY_STATUS), reason: STR }),
|
|
64
|
+
[topics_1.MESSAGE_KIND.REPLY]: shape({ cmdId: STR, status: oneOf(constants_1.REPLY_STATUS), reason: STR, code: STR, preparing: BOOL }, ['code', 'preparing']),
|
|
64
65
|
[topics_1.MESSAGE_KIND.REPORT]: { type: 'object' },
|
|
65
66
|
};
|
|
66
67
|
const ajv = new ajv_1.default({ allErrors: true, strict: false });
|
|
@@ -95,6 +96,10 @@ function inspectMessage(root, topic, raw, retained) {
|
|
|
95
96
|
}
|
|
96
97
|
/** Job events a receiver may report naming only the carrier it scanned. */
|
|
97
98
|
const CARRIER_EVENTS = [constants_1.JOB_EVENT.ARRIVED, constants_1.JOB_EVENT.TRANSFER_FAILED];
|
|
99
|
+
/** A receiver's report that it could read no id at all: a transfer failure on the read, naming no unit and no carrier. */
|
|
100
|
+
function isUnreadableRead(b) {
|
|
101
|
+
return b.event === constants_1.JOB_EVENT.TRANSFER_FAILED && b.failure === constants_1.TRANSFER_FAILURE.UNREADABLE_ID && b.unitId === undefined && typeof b.carrierId !== 'string';
|
|
102
|
+
}
|
|
98
103
|
function crossFieldRules(parsed, env, retained) {
|
|
99
104
|
const out = [];
|
|
100
105
|
const b = env.body ?? {};
|
|
@@ -105,8 +110,8 @@ function crossFieldRules(parsed, env, retained) {
|
|
|
105
110
|
if (kind === topics_1.MESSAGE_KIND.ALARM && b.alarmId !== key)
|
|
106
111
|
out.push('alarmId disagrees with the topic');
|
|
107
112
|
if (kind === topics_1.MESSAGE_KIND.JOB) {
|
|
108
|
-
// A scan at a receiver may read only the carrier; every other job event names its unit and job.
|
|
109
|
-
const byCarrier = CARRIER_EVENTS.includes(b.event) && typeof b.carrierId === 'string';
|
|
113
|
+
// A scan at a receiver may read only the carrier, or nothing at all when the read failed; every other job event names its unit and job.
|
|
114
|
+
const byCarrier = CARRIER_EVENTS.includes(b.event) && (typeof b.carrierId === 'string' || isUnreadableRead(b));
|
|
110
115
|
if (b.unitId === undefined && !byCarrier)
|
|
111
116
|
out.push(`${b.event} without a unitId`);
|
|
112
117
|
if (b.jobId === undefined && !byCarrier)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The machine broker (Mosquitto), rendered from
|
|
2
|
+
* The machine broker (Mosquitto), rendered from its lines. Machines speak
|
|
3
3
|
* MQTT 5 to it over TLS, each with its own client certificate (the CN is
|
|
4
4
|
* its username). The ACL lets a machine publish only its own channels and
|
|
5
5
|
* read only its own commands, and lets the line controller command every
|
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { type LineCodec } from '../protocol/codec';
|
|
10
10
|
import { type LineDef } from '../line';
|
|
11
|
+
import { type Lines, type TopicRoot } from './site-conf';
|
|
11
12
|
export interface MosquittoConfOptions {
|
|
12
|
-
root:
|
|
13
|
+
root: TopicRoot;
|
|
13
14
|
/** Certificate directory as the broker sees it. */
|
|
14
15
|
certDir: string;
|
|
15
16
|
/** Where the site NATS MQTT listener is, host:port. */
|
|
@@ -17,11 +18,15 @@ export interface MosquittoConfOptions {
|
|
|
17
18
|
aclFile: string;
|
|
18
19
|
maxPacketBytes?: number;
|
|
19
20
|
}
|
|
20
|
-
|
|
21
|
+
/** The broker for one line or several: one listener, one bridge per line. */
|
|
22
|
+
export declare function renderMosquittoConf(lines: Lines, opts: MosquittoConfOptions): string;
|
|
21
23
|
/**
|
|
22
24
|
* The codec's channels decide the topics: a machine writes its events and telemetry and reads its commands.
|
|
23
25
|
* A station whose address the line learns has no user of its own: `pattern` rules give every certificate
|
|
24
26
|
* the channels under its own name (%u), so its certificate's common name must be its address. On a line
|
|
25
27
|
* that also declares addresses, a certificate named for a declared address is denied that station's channels.
|
|
26
28
|
*/
|
|
27
|
-
export
|
|
29
|
+
export type AclCodec = Pick<LineCodec, 'root' | 'channels' | 'topicFor'>;
|
|
30
|
+
/** One codec for every line, or the codec of each line. */
|
|
31
|
+
export type AclCodecs = AclCodec | ((line: LineDef) => AclCodec);
|
|
32
|
+
export declare function renderMosquittoAcl(lines: Lines, codec: AclCodecs): string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* The machine broker (Mosquitto), rendered from
|
|
3
|
+
* The machine broker (Mosquitto), rendered from its lines. Machines speak
|
|
4
4
|
* MQTT 5 to it over TLS, each with its own client certificate (the CN is
|
|
5
5
|
* its username). The ACL lets a machine publish only its own channels and
|
|
6
6
|
* read only its own commands, and lets the line controller command every
|
|
@@ -14,7 +14,26 @@ const envelope_1 = require("../protocol/envelope");
|
|
|
14
14
|
const codec_1 = require("../protocol/codec");
|
|
15
15
|
const line_1 = require("../line");
|
|
16
16
|
const site_conf_1 = require("./site-conf");
|
|
17
|
-
|
|
17
|
+
/** One bridge connection per line, carrying the line's topics out to the site NATS. */
|
|
18
|
+
function bridgeBlock(line, opts) {
|
|
19
|
+
return `connection ${line.siteId}-${line.lineId}-site-nats
|
|
20
|
+
address ${opts.siteNats}
|
|
21
|
+
bridge_protocol_version mqttv311
|
|
22
|
+
bridge_cafile ${opts.certDir}/ca.pem
|
|
23
|
+
bridge_certfile ${opts.certDir}/${(0, site_conf_1.bridgeId)(line)}.pem
|
|
24
|
+
bridge_keyfile ${opts.certDir}/${(0, site_conf_1.bridgeId)(line)}.key
|
|
25
|
+
remote_clientid ${(0, site_conf_1.bridgeId)(line)}
|
|
26
|
+
cleansession false
|
|
27
|
+
try_private false
|
|
28
|
+
notifications false
|
|
29
|
+
topic ${(0, site_conf_1.rootOf)(opts.root, line)}/${line.siteId}/${line.lineId}/# out 1
|
|
30
|
+
`;
|
|
31
|
+
}
|
|
32
|
+
/** The broker for one line or several: one listener, one bridge per line. */
|
|
33
|
+
function renderMosquittoConf(lines, opts) {
|
|
34
|
+
const list = (0, site_conf_1.linesOf)(lines);
|
|
35
|
+
if (!list.length)
|
|
36
|
+
throw new Error('renderMosquittoConf needs at least one line');
|
|
18
37
|
return `# Rendered from the line definition by site/setup.ts. Do not edit by hand.
|
|
19
38
|
persistence true
|
|
20
39
|
persistence_location /mosquitto/data/
|
|
@@ -32,26 +51,17 @@ use_identity_as_username true
|
|
|
32
51
|
acl_file ${opts.aclFile}
|
|
33
52
|
max_packet_size ${opts.maxPacketBytes ?? 262_144}
|
|
34
53
|
|
|
35
|
-
|
|
36
|
-
address ${opts.siteNats}
|
|
37
|
-
bridge_protocol_version mqttv311
|
|
38
|
-
bridge_cafile ${opts.certDir}/ca.pem
|
|
39
|
-
bridge_certfile ${opts.certDir}/${(0, site_conf_1.bridgeId)(line)}.pem
|
|
40
|
-
bridge_keyfile ${opts.certDir}/${(0, site_conf_1.bridgeId)(line)}.key
|
|
41
|
-
remote_clientid ${(0, site_conf_1.bridgeId)(line)}
|
|
42
|
-
cleansession false
|
|
43
|
-
try_private false
|
|
44
|
-
notifications false
|
|
45
|
-
topic ${opts.root}/${line.siteId}/${line.lineId}/# out 1
|
|
46
|
-
`;
|
|
54
|
+
${list.map((line) => bridgeBlock(line, opts)).join('\n')}`;
|
|
47
55
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
function renderMosquittoAcl(lines, codec) {
|
|
57
|
+
const list = (0, site_conf_1.linesOf)(lines);
|
|
58
|
+
if (!list.length)
|
|
59
|
+
throw new Error('renderMosquittoAcl needs at least one line');
|
|
60
|
+
const codecOf = (line) => (typeof codec === 'function' ? codec(line) : codec);
|
|
61
|
+
return `# Rendered from the line definition by site/setup.ts. Do not edit by hand.\n\n${list.map((line) => aclRules(line, codecOf(line))).join('\n\n')}\n`;
|
|
62
|
+
}
|
|
63
|
+
/** One line's rules: its stations, its controller, and the shadows a learning line needs. */
|
|
64
|
+
function aclRules(line, codec) {
|
|
55
65
|
const { siteId, lineId } = line;
|
|
56
66
|
const { events, telemetry, commands } = codec.channels;
|
|
57
67
|
const own = (address, channels) => channels.map((c) => (0, codec_1.topicOf)(codec, { siteId, lineId, address }, c));
|
|
@@ -70,7 +80,7 @@ function renderMosquittoAcl(line, codec) {
|
|
|
70
80
|
...commands.map((c) => `topic write ${(0, codec_1.topicOf)(codec, { siteId, lineId }, c)}`),
|
|
71
81
|
`topic read ${codec.root}/${siteId}/${lineId}/#`,
|
|
72
82
|
].join('\n');
|
|
73
|
-
return
|
|
83
|
+
return [...learned, ...shadows, ...machines, controller].join('\n\n');
|
|
74
84
|
}
|
|
75
85
|
/** Deny a declared station's channels to a certificate named for its address, which the patterns would grant. */
|
|
76
86
|
function shadowRules(line, address, topics) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The site's NATS server, rendered from
|
|
2
|
+
* The site's NATS server, rendered from its lines. It runs JetStream and an
|
|
3
3
|
* MQTT listener that only the machine broker's bridge logs in to (by client
|
|
4
4
|
* certificate; the CN is its user, and it may publish only under the line's
|
|
5
5
|
* topics). The gateway logs in by password and may only keep and read the
|
|
@@ -8,8 +8,11 @@
|
|
|
8
8
|
* site NATS stands alone; Long Tail's escalation events stay inside Long Tail.
|
|
9
9
|
*/
|
|
10
10
|
import { type LineDef } from '../line';
|
|
11
|
+
/** One topic root for every line, or a root per line (lines on different codecs). */
|
|
12
|
+
export type TopicRoot = string | ((line: LineDef) => string);
|
|
13
|
+
export declare function rootOf(root: TopicRoot, line: LineDef): string;
|
|
11
14
|
export interface SiteConfOptions {
|
|
12
|
-
root:
|
|
15
|
+
root: TopicRoot;
|
|
13
16
|
gatewayUser: string;
|
|
14
17
|
gatewayPassword: string;
|
|
15
18
|
certDir: string;
|
|
@@ -20,4 +23,11 @@ export interface SiteConfOptions {
|
|
|
20
23
|
export declare function bridgeId(line: LineDef): string;
|
|
21
24
|
/** What the gateway may publish: its streams' and its consumer's JetStream requests and acks, never a machine subject. */
|
|
22
25
|
export declare function gatewayPublish(line: LineDef): string[];
|
|
23
|
-
|
|
26
|
+
/** One line, or every line the site runs. */
|
|
27
|
+
export type Lines = LineDef | LineDef[];
|
|
28
|
+
export declare function linesOf(lines: Lines): LineDef[];
|
|
29
|
+
/**
|
|
30
|
+
* The site NATS for one line or several: one bridge user per line, one
|
|
31
|
+
* gateway user allowed every line's streams and subjects.
|
|
32
|
+
*/
|
|
33
|
+
export declare function renderSiteConf(lines: Lines, opts: SiteConfOptions): string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* The site's NATS server, rendered from
|
|
3
|
+
* The site's NATS server, rendered from its lines. It runs JetStream and an
|
|
4
4
|
* MQTT listener that only the machine broker's bridge logs in to (by client
|
|
5
5
|
* certificate; the CN is its user, and it may publish only under the line's
|
|
6
6
|
* topics). The gateway logs in by password and may only keep and read the
|
|
@@ -9,13 +9,18 @@
|
|
|
9
9
|
* site NATS stands alone; Long Tail's escalation events stay inside Long Tail.
|
|
10
10
|
*/
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.rootOf = rootOf;
|
|
12
13
|
exports.bridgeId = bridgeId;
|
|
13
14
|
exports.gatewayPublish = gatewayPublish;
|
|
15
|
+
exports.linesOf = linesOf;
|
|
14
16
|
exports.renderSiteConf = renderSiteConf;
|
|
15
17
|
const line_1 = require("../line");
|
|
16
18
|
const protocol_1 = require("../protocol");
|
|
17
19
|
const permissions_1 = require("../../messaging/nats/permissions");
|
|
18
20
|
const streams_1 = require("../transport/streams");
|
|
21
|
+
function rootOf(root, line) {
|
|
22
|
+
return typeof root === 'string' ? root : root(line);
|
|
23
|
+
}
|
|
19
24
|
const q = JSON.stringify;
|
|
20
25
|
/** The machine broker's bridge identity for a line. */
|
|
21
26
|
function bridgeId(line) {
|
|
@@ -25,18 +30,36 @@ function bridgeId(line) {
|
|
|
25
30
|
function gatewayPublish(line) {
|
|
26
31
|
return (0, permissions_1.jsPermissions)({ streams: Object.values(streams_1.LINE_STREAM), durable: `${(0, line_1.controllerId)(line)}-events` }).publish;
|
|
27
32
|
}
|
|
28
|
-
function
|
|
29
|
-
|
|
30
|
-
|
|
33
|
+
function linesOf(lines) {
|
|
34
|
+
return Array.isArray(lines) ? lines : [lines];
|
|
35
|
+
}
|
|
36
|
+
/** The server's name: the line for one line, the site when every line shares it, `site` otherwise. */
|
|
37
|
+
function serverName(lines) {
|
|
38
|
+
if (lines.length === 1)
|
|
39
|
+
return `${lines[0].siteId}-${lines[0].lineId}`;
|
|
40
|
+
const sites = new Set(lines.map((l) => l.siteId));
|
|
41
|
+
return sites.size === 1 ? lines[0].siteId : 'site';
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The site NATS for one line or several: one bridge user per line, one
|
|
45
|
+
* gateway user allowed every line's streams and subjects.
|
|
46
|
+
*/
|
|
47
|
+
function renderSiteConf(lines, opts) {
|
|
48
|
+
const list = linesOf(lines);
|
|
49
|
+
if (!list.length)
|
|
50
|
+
throw new Error('renderSiteConf needs at least one line');
|
|
51
|
+
const baseOf = (line) => (0, protocol_1.toSubject)(`${rootOf(opts.root, line)}/${line.siteId}/${line.lineId}`);
|
|
52
|
+
const bridge = list.map((line) => [
|
|
31
53
|
` { user: ${q(`CN=${bridgeId(line)}`)}, allowed_connection_types: ["MQTT"],`,
|
|
32
|
-
` permissions: { publish: [${q(`${
|
|
33
|
-
].join('\n');
|
|
54
|
+
` permissions: { publish: [${q(`${baseOf(line)}.>`)}], subscribe: { deny: [">"] } } }`,
|
|
55
|
+
].join('\n')).join('\n');
|
|
56
|
+
const publish = [...new Set(list.flatMap((line) => gatewayPublish(line)))];
|
|
34
57
|
const gateway = [
|
|
35
58
|
` { user: ${q(opts.gatewayUser)}, password: ${q(opts.gatewayPassword)}, allowed_connection_types: ["STANDARD"],`,
|
|
36
|
-
` permissions: { publish: ${q(
|
|
59
|
+
` permissions: { publish: ${q(publish)}, subscribe: ${q(['_INBOX.>', ...list.map((line) => `${baseOf(line)}.>`)])} } }`,
|
|
37
60
|
].join('\n');
|
|
38
61
|
return `# Rendered from the line definition by site/setup.ts. Do not edit by hand.
|
|
39
|
-
server_name: ${q(
|
|
62
|
+
server_name: ${q(serverName(list))}
|
|
40
63
|
port: 4222
|
|
41
64
|
http: 8222
|
|
42
65
|
jetstream { store_dir: ${q(opts.storeDir)} }
|
|
@@ -14,5 +14,6 @@ export declare class CallbackEscalationFeed implements EscalationFeed {
|
|
|
14
14
|
constructor(adapter: CallbackEventAdapter, nakDelayMs?: number);
|
|
15
15
|
connect(): Promise<void>;
|
|
16
16
|
consume(handler: (event: EscalationEvent) => Promise<MachineDisposition>): Promise<void>;
|
|
17
|
+
unsubscribe(): Promise<void>;
|
|
17
18
|
close(): Promise<void>;
|
|
18
19
|
}
|
|
@@ -23,9 +23,12 @@ class CallbackEscalationFeed {
|
|
|
23
23
|
void this.redelivery.deliver(() => handler(event));
|
|
24
24
|
});
|
|
25
25
|
}
|
|
26
|
-
async
|
|
26
|
+
async unsubscribe() {
|
|
27
27
|
this.off?.();
|
|
28
28
|
await this.redelivery.stop();
|
|
29
29
|
}
|
|
30
|
+
async close() {
|
|
31
|
+
await this.unsubscribe();
|
|
32
|
+
}
|
|
30
33
|
}
|
|
31
34
|
exports.CallbackEscalationFeed = CallbackEscalationFeed;
|
|
@@ -26,6 +26,7 @@ export declare class MemoryMachineBus implements MachineBus {
|
|
|
26
26
|
retain?: boolean;
|
|
27
27
|
}): Promise<void>;
|
|
28
28
|
retained(filter: string): Promise<InboundMessage[]>;
|
|
29
|
+
unsubscribe(): Promise<void>;
|
|
29
30
|
close(): Promise<void>;
|
|
30
31
|
}
|
|
31
32
|
export declare class MemoryEscalationFeed implements EscalationFeed {
|
|
@@ -36,5 +37,6 @@ export declare class MemoryEscalationFeed implements EscalationFeed {
|
|
|
36
37
|
emit(body: Record<string, any>): void;
|
|
37
38
|
connect(): Promise<void>;
|
|
38
39
|
consume(handler: (event: EscalationEvent) => Promise<Disposition>): Promise<void>;
|
|
40
|
+
unsubscribe(): Promise<void>;
|
|
39
41
|
close(): Promise<void>;
|
|
40
42
|
}
|
|
@@ -50,6 +50,9 @@ class MemoryMachineBus {
|
|
|
50
50
|
async retained(filter) {
|
|
51
51
|
return this.broker.retained(filter);
|
|
52
52
|
}
|
|
53
|
+
async unsubscribe() {
|
|
54
|
+
this.broker.detach(this.durableName);
|
|
55
|
+
}
|
|
53
56
|
async close() {
|
|
54
57
|
this.broker.detach(this.durableName);
|
|
55
58
|
}
|
|
@@ -72,6 +75,9 @@ class MemoryEscalationFeed {
|
|
|
72
75
|
return event ? handler(event) : delivery_1.DISPOSITION.TERM;
|
|
73
76
|
});
|
|
74
77
|
}
|
|
78
|
+
async unsubscribe() {
|
|
79
|
+
this.broker.detach(this.durableName);
|
|
80
|
+
}
|
|
75
81
|
async close() {
|
|
76
82
|
this.broker.detach(this.durableName);
|
|
77
83
|
}
|
|
@@ -19,6 +19,8 @@ export declare class MqttMachineBus implements MachineBus {
|
|
|
19
19
|
retain?: boolean;
|
|
20
20
|
}): Promise<void>;
|
|
21
21
|
retained(filter: string): Promise<InboundMessage[]>;
|
|
22
|
+
/** Stops delivery in this process; the persistent session keeps its subscription, so messages queue for the next gateway. */
|
|
23
|
+
unsubscribe(): Promise<void>;
|
|
22
24
|
close(): Promise<void>;
|
|
23
25
|
private connected;
|
|
24
26
|
}
|
|
@@ -30,6 +30,10 @@ class MqttMachineBus {
|
|
|
30
30
|
retained(filter) {
|
|
31
31
|
return this.connected().retained(filter);
|
|
32
32
|
}
|
|
33
|
+
/** Stops delivery in this process; the persistent session keeps its subscription, so messages queue for the next gateway. */
|
|
34
|
+
async unsubscribe() {
|
|
35
|
+
await this.redelivery.stop();
|
|
36
|
+
}
|
|
33
37
|
async close() {
|
|
34
38
|
await this.redelivery.stop();
|
|
35
39
|
await this.session?.close(true);
|
|
@@ -17,6 +17,8 @@ export interface NatsBusOptions {
|
|
|
17
17
|
lineId: string;
|
|
18
18
|
/** The codec's topics: which subjects are durable events and which are live telemetry. */
|
|
19
19
|
codec: StreamCodec;
|
|
20
|
+
/** The codecs of every line on this site, so the streams keep all their subjects. */
|
|
21
|
+
siteCodecs?: StreamCodec[];
|
|
20
22
|
nakDelayMs?: number;
|
|
21
23
|
}
|
|
22
24
|
export declare class NatsMachineBus implements MachineBus {
|
|
@@ -31,6 +33,7 @@ export declare class NatsMachineBus implements MachineBus {
|
|
|
31
33
|
retain?: boolean;
|
|
32
34
|
}): Promise<void>;
|
|
33
35
|
retained(filter: string): Promise<InboundMessage[]>;
|
|
36
|
+
unsubscribe(): Promise<void>;
|
|
34
37
|
close(): Promise<void>;
|
|
35
38
|
private stream;
|
|
36
39
|
}
|
|
@@ -13,5 +13,6 @@ export declare class PubSubEscalationFeed implements EscalationFeed {
|
|
|
13
13
|
constructor(pubsub: LTPubSub, nakDelayMs?: number);
|
|
14
14
|
connect(): Promise<void>;
|
|
15
15
|
consume(handler: (event: EscalationEvent) => Promise<Disposition>): Promise<void>;
|
|
16
|
+
unsubscribe(): Promise<void>;
|
|
16
17
|
close(): Promise<void>;
|
|
17
18
|
}
|
|
@@ -31,9 +31,12 @@ class PubSubEscalationFeed {
|
|
|
31
31
|
void this.redelivery.deliver(() => handler(event));
|
|
32
32
|
});
|
|
33
33
|
}
|
|
34
|
-
async
|
|
34
|
+
async unsubscribe() {
|
|
35
35
|
await this.sub?.close();
|
|
36
36
|
await this.redelivery.stop();
|
|
37
37
|
}
|
|
38
|
+
async close() {
|
|
39
|
+
await this.unsubscribe();
|
|
40
|
+
}
|
|
38
41
|
}
|
|
39
42
|
exports.PubSubEscalationFeed = PubSubEscalationFeed;
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
* line's durable consumer on LINE_EVENTS (replayed after a restart); telemetry
|
|
4
4
|
* is read live, since it only proves a machine is alive. Commands leave through
|
|
5
5
|
* an MQTT session at QoS 1 on the site broker, which queues them for a machine
|
|
6
|
-
* that is away; retained machine state is read there too.
|
|
6
|
+
* that is away; retained machine state is read there too. The streams are
|
|
7
|
+
* ensured with every codec on the site, so lines on different roots share
|
|
8
|
+
* them, and a consumer the stream would feed nothing refuses to start.
|
|
7
9
|
*/
|
|
8
10
|
import type { LTPubSub, LTStreams } from '../../../types/messaging';
|
|
9
11
|
import type { MqttEndpoint } from '../../../services/machines/config';
|
|
@@ -19,6 +21,8 @@ export interface StreamBusOptions {
|
|
|
19
21
|
lineId: string;
|
|
20
22
|
/** The codec's topics: which subjects are durable events and which are live telemetry. */
|
|
21
23
|
codec: StreamCodec;
|
|
24
|
+
/** The codecs of every line on this site; the streams keep all their subjects, whichever line starts last. */
|
|
25
|
+
siteCodecs?: StreamCodec[];
|
|
22
26
|
nakDelayMs?: number;
|
|
23
27
|
}
|
|
24
28
|
export declare class StreamMachineBus implements MachineBus {
|
|
@@ -35,6 +39,8 @@ export declare class StreamMachineBus implements MachineBus {
|
|
|
35
39
|
retain?: boolean;
|
|
36
40
|
}): Promise<void>;
|
|
37
41
|
retained(filter: string): Promise<InboundMessage[]>;
|
|
42
|
+
/** Stops the consumer and the live subscriptions; the MQTT session stays open for commands and receipts. */
|
|
43
|
+
unsubscribe(): Promise<void>;
|
|
38
44
|
close(): Promise<void>;
|
|
39
45
|
private mqtt;
|
|
40
46
|
}
|
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
* line's durable consumer on LINE_EVENTS (replayed after a restart); telemetry
|
|
5
5
|
* is read live, since it only proves a machine is alive. Commands leave through
|
|
6
6
|
* an MQTT session at QoS 1 on the site broker, which queues them for a machine
|
|
7
|
-
* that is away; retained machine state is read there too.
|
|
7
|
+
* that is away; retained machine state is read there too. The streams are
|
|
8
|
+
* ensured with every codec on the site, so lines on different roots share
|
|
9
|
+
* them, and a consumer the stream would feed nothing refuses to start.
|
|
8
10
|
*/
|
|
9
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
12
|
exports.StreamMachineBus = void 0;
|
|
@@ -23,10 +25,16 @@ class StreamMachineBus {
|
|
|
23
25
|
return `${this.opts.controllerId}-events`;
|
|
24
26
|
}
|
|
25
27
|
async connect() {
|
|
26
|
-
const { streams, codec, siteId, lineId, controllerId } = this.opts;
|
|
27
|
-
for (const spec of (0, streams_1.lineStreamSpecs)(codec))
|
|
28
|
+
const { streams, codec, siteId, lineId, controllerId, siteCodecs = [] } = this.opts;
|
|
29
|
+
for (const spec of (0, streams_1.lineStreamSpecs)([codec, ...siteCodecs]))
|
|
28
30
|
await streams.ensureStream(spec);
|
|
29
|
-
|
|
31
|
+
const consumer = (0, streams_1.lineEventConsumerSpec)(codec, siteId, lineId, this.durableName);
|
|
32
|
+
await streams.ensureConsumer(streams_1.LINE_STREAM.EVENTS, consumer);
|
|
33
|
+
const events = await streams.describeStream(streams_1.LINE_STREAM.EVENTS);
|
|
34
|
+
const missing = events ? (0, streams_1.uncoveredSubjects)(events, consumer.filterSubjects) : consumer.filterSubjects;
|
|
35
|
+
if (missing.length) {
|
|
36
|
+
throw new Error(`${streams_1.LINE_STREAM.EVENTS} keeps nothing of ${missing.join(', ')}; the stream holds ${events?.subjects.join(', ') ?? 'nothing'}`);
|
|
37
|
+
}
|
|
30
38
|
this.session = await mqtt_session_1.MqttSession.open(this.opts.mqtt, controllerId);
|
|
31
39
|
}
|
|
32
40
|
async consume(handler) {
|
|
@@ -42,10 +50,14 @@ class StreamMachineBus {
|
|
|
42
50
|
retained(filter) {
|
|
43
51
|
return this.mqtt().retained(filter);
|
|
44
52
|
}
|
|
45
|
-
|
|
53
|
+
/** Stops the consumer and the live subscriptions; the MQTT session stays open for commands and receipts. */
|
|
54
|
+
async unsubscribe() {
|
|
46
55
|
for (const sub of this.subs.splice(0))
|
|
47
56
|
await sub.close();
|
|
48
57
|
await this.queue.drained();
|
|
58
|
+
}
|
|
59
|
+
async close() {
|
|
60
|
+
await this.unsubscribe();
|
|
49
61
|
await this.session?.close(true);
|
|
50
62
|
}
|
|
51
63
|
mqtt() {
|
|
@@ -13,8 +13,16 @@ export declare const LINE_STREAM: {
|
|
|
13
13
|
export type StreamCodec = Pick<LineCodec, 'root' | 'channels' | 'topicFor'>;
|
|
14
14
|
/** An MQTT filter as a subject: levels become tokens, `+` becomes `*`, `#` becomes `>`. */
|
|
15
15
|
export declare function filterToSubject(filter: string): string;
|
|
16
|
-
/**
|
|
17
|
-
|
|
16
|
+
/**
|
|
17
|
+
* The site's streams: every line under each codec's root, since lines on
|
|
18
|
+
* different protocols share one site NATS. A root alone means the generic
|
|
19
|
+
* layout; several codecs give the union of their subjects, in order.
|
|
20
|
+
*/
|
|
21
|
+
export declare function lineStreamSpecs(codecs: StreamCodec | string | (StreamCodec | string)[]): StreamSpec[];
|
|
22
|
+
/** Whether a stream subject pattern keeps everything a consumer filter would read. */
|
|
23
|
+
export declare function subjectCovers(stream: string, filter: string): boolean;
|
|
24
|
+
/** The consumer's filter subjects the stream keeps nothing of. */
|
|
25
|
+
export declare function uncoveredSubjects(stream: Pick<StreamSpec, 'subjects'>, filters: string[]): string[];
|
|
18
26
|
/** The telemetry subjects for one line, read live rather than replayed. */
|
|
19
27
|
export declare function telemetrySubjects(codec: StreamCodec | string, siteId: string, lineId: string): string[];
|
|
20
28
|
/**
|
|
@@ -8,6 +8,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
8
8
|
exports.LINE_STREAM = void 0;
|
|
9
9
|
exports.filterToSubject = filterToSubject;
|
|
10
10
|
exports.lineStreamSpecs = lineStreamSpecs;
|
|
11
|
+
exports.subjectCovers = subjectCovers;
|
|
12
|
+
exports.uncoveredSubjects = uncoveredSubjects;
|
|
11
13
|
exports.telemetrySubjects = telemetrySubjects;
|
|
12
14
|
exports.lineEventConsumerSpec = lineEventConsumerSpec;
|
|
13
15
|
const codec_1 = require("../protocol/codec");
|
|
@@ -26,14 +28,39 @@ function filterToSubject(filter) {
|
|
|
26
28
|
function subjectsFor(codec, channels, siteId, lineId) {
|
|
27
29
|
return channels.map((c) => filterToSubject((0, codec_1.topicOf)(codec, { siteId, lineId }, c)));
|
|
28
30
|
}
|
|
29
|
-
/**
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
/**
|
|
32
|
+
* The site's streams: every line under each codec's root, since lines on
|
|
33
|
+
* different protocols share one site NATS. A root alone means the generic
|
|
34
|
+
* layout; several codecs give the union of their subjects, in order.
|
|
35
|
+
*/
|
|
36
|
+
function lineStreamSpecs(codecs) {
|
|
37
|
+
const list = (Array.isArray(codecs) ? codecs : [codecs]).map(codecOf);
|
|
38
|
+
const union = (channel) => [...new Set(list.flatMap((c) => subjectsFor(c, c.channels[channel])))];
|
|
32
39
|
return [
|
|
33
|
-
{ name: exports.LINE_STREAM.EVENTS, subjects:
|
|
34
|
-
{ name: exports.LINE_STREAM.TELEMETRY, subjects:
|
|
40
|
+
{ name: exports.LINE_STREAM.EVENTS, subjects: union('events'), maxAgeMs: 30 * DAY_MS },
|
|
41
|
+
{ name: exports.LINE_STREAM.TELEMETRY, subjects: union('telemetry'), maxAgeMs: 3 * DAY_MS },
|
|
35
42
|
];
|
|
36
43
|
}
|
|
44
|
+
/** Whether a stream subject pattern keeps everything a consumer filter would read. */
|
|
45
|
+
function subjectCovers(stream, filter) {
|
|
46
|
+
const s = stream.split('.');
|
|
47
|
+
const f = filter.split('.');
|
|
48
|
+
for (let i = 0; i < s.length; i++) {
|
|
49
|
+
if (s[i] === '>')
|
|
50
|
+
return f.length > i;
|
|
51
|
+
if (i >= f.length)
|
|
52
|
+
return false;
|
|
53
|
+
if (f[i] === '>')
|
|
54
|
+
return false;
|
|
55
|
+
if (s[i] !== '*' && s[i] !== f[i])
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
return s.length === f.length;
|
|
59
|
+
}
|
|
60
|
+
/** The consumer's filter subjects the stream keeps nothing of. */
|
|
61
|
+
function uncoveredSubjects(stream, filters) {
|
|
62
|
+
return filters.filter((f) => !stream.subjects.some((s) => subjectCovers(s, f)));
|
|
63
|
+
}
|
|
37
64
|
/** The telemetry subjects for one line, read live rather than replayed. */
|
|
38
65
|
function telemetrySubjects(codec, siteId, lineId) {
|
|
39
66
|
const c = codecOf(codec);
|
|
@@ -36,6 +36,9 @@ class MemoryStreams {
|
|
|
36
36
|
else
|
|
37
37
|
this.streams.set(spec.name, { spec, messages: [], seq: 0, consumers: new Map(), wake: new Set() });
|
|
38
38
|
}
|
|
39
|
+
async describeStream(name) {
|
|
40
|
+
return this.streams.get(name)?.spec ?? null;
|
|
41
|
+
}
|
|
39
42
|
async ensureConsumer(stream, spec) {
|
|
40
43
|
const s = this.stream(stream);
|
|
41
44
|
const existing = s.consumers.get(spec.name);
|
|
@@ -9,6 +9,8 @@ export declare function streamConfig(spec: StreamSpec): Partial<StreamConfig>;
|
|
|
9
9
|
export declare function consumerConfig(spec: ConsumerSpec): Partial<ConsumerConfig>;
|
|
10
10
|
/** Create the stream, or update an existing one to the spec. */
|
|
11
11
|
export declare function ensureStream(jsm: JetStreamManager, spec: StreamSpec): Promise<void>;
|
|
12
|
+
/** The stream as JetStream holds it, or null when there is none. */
|
|
13
|
+
export declare function describeStream(jsm: JetStreamManager, name: string): Promise<StreamSpec | null>;
|
|
12
14
|
/** Create the consumer, or move an existing one to the spec's subjects without losing its place. */
|
|
13
15
|
export declare function ensureConsumer(jsm: JetStreamManager, stream: string, spec: ConsumerSpec): Promise<void>;
|
|
14
16
|
export declare function payloadOf(m: {
|
|
@@ -20,6 +22,7 @@ export declare class NatsStreams implements LTStreams {
|
|
|
20
22
|
constructor(jsm: JetStreamManager, js: JetStreamClient);
|
|
21
23
|
ensureStream(spec: StreamSpec): Promise<void>;
|
|
22
24
|
ensureConsumer(stream: string, spec: ConsumerSpec): Promise<void>;
|
|
25
|
+
describeStream(name: string): Promise<StreamSpec | null>;
|
|
23
26
|
append(subject: Subject, payload: string): Promise<void>;
|
|
24
27
|
/** One message at a time: the next is not taken until the handler settles this one. */
|
|
25
28
|
consume(stream: string, consumer: string, handler: (m: LTStreamMessage) => Promise<Delivery>, opts?: LTConsumeOptions): Promise<LTSubscription>;
|