@hotmeshio/long-tail 0.27.0 → 0.28.0
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/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/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 +4 -1
- package/build/lib/machines/line.js +18 -1
- package/build/lib/machines/protocol/codec.d.ts +8 -0
- package/build/lib/machines/protocol/codec.js +9 -0
- 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.js +2 -2
- package/build/lib/machines/site/mosquitto-conf.d.ts +5 -4
- package/build/lib/machines/site/mosquitto-conf.js +31 -16
- package/build/lib/machines/site/site-conf.d.ts +9 -2
- package/build/lib/machines/site/site-conf.js +27 -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 +1 -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 +2 -0
- package/build/lib/machines/transport/stream-bus.js +5 -1
- package/build/modules/machines.d.ts +8 -0
- package/build/modules/machines.js +16 -0
- package/build/routes/index.js +2 -0
- package/build/routes/machines.d.ts +2 -0
- package/build/routes/machines.js +220 -0
- package/build/services/machines/commands.d.ts +5 -5
- package/build/services/machines/commands.js +3 -2
- package/build/services/machines/config.d.ts +2 -1
- package/build/services/machines/config.js +1 -1
- package/build/services/machines/contracts.d.ts +10 -0
- package/build/services/machines/gateway/actions.d.ts +1 -0
- package/build/services/machines/gateway/admission.d.ts +15 -3
- package/build/services/machines/gateway/admission.js +29 -14
- package/build/services/machines/gateway/dispatcher.d.ts +3 -0
- package/build/services/machines/gateway/dispatcher.js +12 -4
- package/build/services/machines/gateway/executor.d.ts +11 -2
- package/build/services/machines/gateway/executor.js +68 -29
- package/build/services/machines/gateway/gateway.d.ts +16 -1
- package/build/services/machines/gateway/gateway.js +55 -23
- 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 +8 -0
- package/build/services/machines/gateway/log.js +18 -0
- package/build/services/machines/gateway/pacing.js +1 -0
- package/build/services/machines/gateway/plan-escalation.js +8 -3
- package/build/services/machines/gateway/plan-machine.js +16 -6
- 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 +6 -3
- package/build/services/machines/gateway/reply-waiter.js +37 -16
- package/build/services/machines/gateway/state.d.ts +29 -3
- package/build/services/machines/gateway/state.js +61 -7
- package/build/services/machines/gateway/wire.d.ts +58 -0
- package/build/services/machines/gateway/wire.js +171 -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/rows.js +10 -1
- package/build/services/machines/surface.d.ts +45 -5
- package/build/services/machines/surface.js +95 -15
- 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/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/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/events.d.ts +6 -1
- package/build/types/index.d.ts +1 -0
- package/build/types/machines-view.d.ts +159 -0
- package/build/types/machines-view.js +7 -0
- package/build/types/machines.d.ts +4 -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 +1 -0
- package/docs/events.md +34 -1
- package/docs/machines.md +93 -16
- 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
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* reads escalation events (a new handoff row means "dispatch"), reads every
|
|
5
5
|
* machine message on the line (a receipt means "resolve"), and performs the
|
|
6
6
|
* verbs a person would, as the machine. Neither side knows about the other.
|
|
7
|
+
* Every message read or sent is recorded on the wire (wire.ts).
|
|
7
8
|
*/
|
|
8
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
10
|
exports.MachineGateway = void 0;
|
|
@@ -15,14 +16,18 @@ const address_book_1 = require("./address-book");
|
|
|
15
16
|
const admission_1 = require("./admission");
|
|
16
17
|
const protocol_1 = require("../../../lib/machines/protocol");
|
|
17
18
|
const transport_1 = require("../../../lib/machines/transport");
|
|
19
|
+
const publish_1 = require("../../../lib/events/publish");
|
|
18
20
|
const reply_waiter_1 = require("./reply-waiter");
|
|
19
21
|
const executor_1 = require("./executor");
|
|
22
|
+
const dispatcher_1 = require("./dispatcher");
|
|
23
|
+
const inspect_1 = require("./inspect");
|
|
20
24
|
const log_1 = require("./log");
|
|
21
25
|
const plan_escalation_1 = require("./plan-escalation");
|
|
22
26
|
const pacing_1 = require("./pacing");
|
|
23
27
|
const plan_machine_1 = require("./plan-machine");
|
|
24
28
|
const state_1 = require("./state");
|
|
25
29
|
const receipts_1 = require("./receipts");
|
|
30
|
+
const wire_1 = require("./wire");
|
|
26
31
|
class MachineGateway {
|
|
27
32
|
constructor(deps) {
|
|
28
33
|
this.deps = deps;
|
|
@@ -32,18 +37,20 @@ class MachineGateway {
|
|
|
32
37
|
this.codec = deps.codec ?? (0, protocol_1.genericCodec)({ root: deps.settings.topicRoot, line: deps.line });
|
|
33
38
|
this.state.unitsPerDispatch = this.codec.unitsPerDispatch;
|
|
34
39
|
this.state.dispatchOnArrival = this.codec.dispatchOn === protocol_1.DISPATCH_ON.ARRIVAL;
|
|
40
|
+
this.state.rowOps = (0, protocol_1.declaredRowOps)(this.codec);
|
|
35
41
|
this.state.lifecycle = deps.settings.lifecycle === true;
|
|
36
42
|
this.state.retainedAlarms = this.codec.retainedAlarms === true;
|
|
37
43
|
this.state.progressStep = deps.settings.progressStep ?? this.state.progressStep;
|
|
38
44
|
this.addresses = deps.addresses ?? new address_book_1.MemoryAddressBook();
|
|
45
|
+
this.wire = new wire_1.WireRecorder(deps.line, deps.wire ?? publish_1.publishMachineWireEvent, { telemetry: deps.settings.wireTelemetry === true });
|
|
39
46
|
this.executor = new executor_1.Executor({
|
|
40
|
-
addresses: this.addresses,
|
|
47
|
+
addresses: this.addresses, wire: this.wire,
|
|
41
48
|
bus: deps.bus, lt: deps.lt, replies: new reply_waiter_1.ReplyWaiter(), state: this.state, line: deps.line,
|
|
42
49
|
codec: this.codec, replyTimeoutMs: deps.settings.replyTimeoutMs,
|
|
43
50
|
dispatchAttempts: deps.settings.dispatchAttempts, offlineDebounceMs: deps.settings.offlineDebounceMs, log: this.log,
|
|
44
51
|
});
|
|
45
52
|
this.admission = { state: this.state, line: deps.line, executor: this.executor, log: this.log, pace: () => this.pace() };
|
|
46
|
-
this.receipts = new receipts_1.ReceiptBatcher({ bus: deps.bus, codec: this.codec, delayMs: deps.settings.receiptDelayMs ?? DEFAULT_RECEIPT_DELAY_MS, log: this.log });
|
|
53
|
+
this.receipts = new receipts_1.ReceiptBatcher({ bus: deps.bus, codec: this.codec, delayMs: deps.settings.receiptDelayMs ?? DEFAULT_RECEIPT_DELAY_MS, log: this.log, wire: this.wire });
|
|
47
54
|
}
|
|
48
55
|
async start() {
|
|
49
56
|
await this.deps.bus.connect();
|
|
@@ -61,10 +68,17 @@ class MachineGateway {
|
|
|
61
68
|
}
|
|
62
69
|
this.log.info(log_1.GATEWAY_LOG.STARTED, { site: this.deps.line.siteId, line: this.deps.line.lineId });
|
|
63
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* Hand the line over cleanly: nothing new is raised or sent, a message
|
|
73
|
+
* still being handled is nak'd for the next leader if it would make a row,
|
|
74
|
+
* receipts for what was applied go out, then the sessions close.
|
|
75
|
+
*/
|
|
64
76
|
async stop() {
|
|
65
77
|
if (this.quietTimer)
|
|
66
78
|
clearInterval(this.quietTimer);
|
|
67
79
|
this.executor.stop();
|
|
80
|
+
await this.deps.feed.unsubscribe();
|
|
81
|
+
await this.deps.bus.unsubscribe();
|
|
68
82
|
await this.executor.idle();
|
|
69
83
|
await this.receipts.flush();
|
|
70
84
|
await this.deps.feed.close();
|
|
@@ -81,6 +95,10 @@ class MachineGateway {
|
|
|
81
95
|
idle() {
|
|
82
96
|
return this.executor.idle();
|
|
83
97
|
}
|
|
98
|
+
/** A dry run of one message on a copy of the state: nothing is applied (inspect.ts). */
|
|
99
|
+
inspect(msg) {
|
|
100
|
+
return (0, inspect_1.dryRun)({ state: this.state, line: this.deps.line, codec: this.codec, dispatchTtlMs: this.deps.settings.dispatchTtlMs }, { ...msg, deliveries: 1 });
|
|
101
|
+
}
|
|
84
102
|
/**
|
|
85
103
|
* On taking the line: open handoff and command rows (a dispatch or command
|
|
86
104
|
* interrupted by a restart is sent again with the same cmdId), the gateway's
|
|
@@ -138,16 +156,21 @@ class MachineGateway {
|
|
|
138
156
|
const active = new Set();
|
|
139
157
|
this.state.readingRetained = true;
|
|
140
158
|
try {
|
|
141
|
-
for (const
|
|
142
|
-
|
|
159
|
+
for (const read of await this.deps.bus.retained((0, protocol_1.lineFilter)(this.codec.root, line.siteId, line.lineId))) {
|
|
160
|
+
const msg = { ...read, retained: true };
|
|
161
|
+
for (const raw of this.decode(msg)) {
|
|
143
162
|
if (!raw.parsed)
|
|
144
163
|
continue;
|
|
145
|
-
const
|
|
146
|
-
if (!('
|
|
164
|
+
const admitted = await (0, admission_1.admitSender)(this.admission, msg.topic, raw);
|
|
165
|
+
if (!('seen' in admitted)) {
|
|
166
|
+
this.wire.inbound(msg, raw, admitted, 1, admitted.sender);
|
|
147
167
|
continue;
|
|
168
|
+
}
|
|
169
|
+
const { seen } = admitted;
|
|
148
170
|
if (seen.parsed.kind === protocol_1.MESSAGE_KIND.ALARM && seen.body?.body?.active)
|
|
149
171
|
active.add(this.state.alarmKey(seen.parsed.ident.machineId, seen.parsed.key));
|
|
150
|
-
await this.applyMachine(msg.topic, seen.parsed, seen.body);
|
|
172
|
+
const applied = await this.applyMachine(msg.topic, seen.parsed, seen.body);
|
|
173
|
+
this.wire.inbound(msg, seen, { ...applied, actions: [...admitted.actions, ...applied.actions] }, 1);
|
|
151
174
|
}
|
|
152
175
|
}
|
|
153
176
|
}
|
|
@@ -170,7 +193,8 @@ class MachineGateway {
|
|
|
170
193
|
return transport_1.DISPOSITION.ACK;
|
|
171
194
|
}
|
|
172
195
|
catch (err) {
|
|
173
|
-
|
|
196
|
+
if (!(err instanceof dispatcher_1.GatewayStopped))
|
|
197
|
+
this.log.error(log_1.GATEWAY_LOG.VERB_FAILED, { event: event.type, error: err.message });
|
|
174
198
|
return transport_1.DISPOSITION.NAK;
|
|
175
199
|
}
|
|
176
200
|
}
|
|
@@ -188,19 +212,21 @@ class MachineGateway {
|
|
|
188
212
|
return { ...event, role: row.role, data: row };
|
|
189
213
|
}
|
|
190
214
|
async onMachine(msg) {
|
|
191
|
-
const decoded = this.decode(msg
|
|
215
|
+
const decoded = this.decode(msg);
|
|
192
216
|
const acted = [];
|
|
193
217
|
let outcome = transport_1.DISPOSITION.TERM;
|
|
194
218
|
let failed = false;
|
|
195
219
|
for (const raw of decoded) {
|
|
196
220
|
if (!raw.parsed)
|
|
197
221
|
continue;
|
|
198
|
-
const
|
|
199
|
-
if (!('
|
|
200
|
-
failed ||=
|
|
201
|
-
outcome = worse(outcome,
|
|
222
|
+
const admitted = await (0, admission_1.admitSender)(this.admission, msg.topic, raw);
|
|
223
|
+
if (!('seen' in admitted)) {
|
|
224
|
+
failed ||= admitted.failed;
|
|
225
|
+
outcome = worse(outcome, admitted.disposition);
|
|
226
|
+
this.wire.inbound(msg, raw, admitted, msg.deliveries, admitted.sender);
|
|
202
227
|
continue;
|
|
203
228
|
}
|
|
229
|
+
const { seen } = admitted;
|
|
204
230
|
acted.push(seen);
|
|
205
231
|
if (seen.violations.length && msg.deliveries === 1) {
|
|
206
232
|
this.log.warn(log_1.GATEWAY_LOG.CONTRACT_VIOLATION, { topic: msg.topic, violations: seen.violations });
|
|
@@ -210,9 +236,10 @@ class MachineGateway {
|
|
|
210
236
|
: await this.applyMachine(msg.topic, seen.parsed, seen.body);
|
|
211
237
|
failed ||= applied.failed;
|
|
212
238
|
outcome = worse(outcome, applied.disposition);
|
|
239
|
+
this.wire.inbound(msg, seen, { ...applied, actions: [...admitted.actions, ...applied.actions] }, msg.deliveries);
|
|
213
240
|
}
|
|
214
241
|
// No row has claimed it after this many tries, so it is not racing its row: stop. A failed verb always retries.
|
|
215
|
-
if (outcome === transport_1.DISPOSITION.NAK && !failed && msg.deliveries >= MAX_DELIVERIES) {
|
|
242
|
+
if (outcome === transport_1.DISPOSITION.NAK && !failed && msg.deliveries >= wire_1.MAX_DELIVERIES) {
|
|
216
243
|
this.log.warn(log_1.GATEWAY_LOG.UNMATCHED, { topic: msg.topic, deliveries: msg.deliveries });
|
|
217
244
|
outcome = transport_1.DISPOSITION.TERM;
|
|
218
245
|
}
|
|
@@ -221,14 +248,19 @@ class MachineGateway {
|
|
|
221
248
|
return outcome;
|
|
222
249
|
}
|
|
223
250
|
/** A message the codec cannot read is not retried: it is logged and has no effect. */
|
|
224
|
-
decode(
|
|
251
|
+
decode(msg) {
|
|
252
|
+
let decoded;
|
|
225
253
|
try {
|
|
226
|
-
|
|
254
|
+
decoded = this.codec.decode(msg.topic, msg.payload, msg.retained);
|
|
227
255
|
}
|
|
228
256
|
catch (err) {
|
|
229
|
-
this.log.warn(log_1.GATEWAY_LOG.UNREADABLE, { topic, error: err.message });
|
|
257
|
+
this.log.warn(log_1.GATEWAY_LOG.UNREADABLE, { topic: msg.topic, error: err.message });
|
|
258
|
+
this.wire.unreadable(msg, err.message);
|
|
230
259
|
return [];
|
|
231
260
|
}
|
|
261
|
+
if (!decoded.length)
|
|
262
|
+
this.wire.unreadable(msg, 'not a machine message', 'none');
|
|
263
|
+
return decoded;
|
|
232
264
|
}
|
|
233
265
|
/** Done with the message: confirm each id its codec asked to confirm. */
|
|
234
266
|
confirm(decoded) {
|
|
@@ -247,21 +279,21 @@ class MachineGateway {
|
|
|
247
279
|
}
|
|
248
280
|
catch (err) {
|
|
249
281
|
this.log.warn(log_1.GATEWAY_LOG.UNREADABLE, { topic, error: err.message });
|
|
250
|
-
return { disposition: transport_1.DISPOSITION.TERM, failed: false };
|
|
282
|
+
return { disposition: transport_1.DISPOSITION.TERM, failed: false, actions: [{ verb: 'unreadable', detail: err.message }] };
|
|
251
283
|
}
|
|
252
284
|
try {
|
|
253
|
-
await this.executor.apply(plan.actions);
|
|
285
|
+
const actions = await this.executor.apply(plan.actions);
|
|
254
286
|
await this.pace();
|
|
255
|
-
return { disposition: plan.disposition, failed: false };
|
|
287
|
+
return { disposition: plan.disposition, failed: false, actions };
|
|
256
288
|
}
|
|
257
289
|
catch (err) {
|
|
258
|
-
|
|
259
|
-
|
|
290
|
+
if (!(err instanceof dispatcher_1.GatewayStopped))
|
|
291
|
+
this.log.error(log_1.GATEWAY_LOG.VERB_FAILED, { topic, error: err.message });
|
|
292
|
+
return { disposition: transport_1.DISPOSITION.NAK, failed: true, actions: [] };
|
|
260
293
|
}
|
|
261
294
|
}
|
|
262
295
|
}
|
|
263
296
|
exports.MachineGateway = MachineGateway;
|
|
264
|
-
const MAX_DELIVERIES = 30;
|
|
265
297
|
const DEFAULT_RECEIPT_DELAY_MS = 250;
|
|
266
298
|
const RANK = { [transport_1.DISPOSITION.TERM]: 0, [transport_1.DISPOSITION.ACK]: 1, [transport_1.DISPOSITION.NAK]: 2 };
|
|
267
299
|
/** One wire message may decode to several; any that must be retried retries the message. */
|
|
@@ -24,3 +24,6 @@ __exportStar(require("./provision"), exports);
|
|
|
24
24
|
__exportStar(require("./state"), exports);
|
|
25
25
|
__exportStar(require("./address-book"), exports);
|
|
26
26
|
__exportStar(require("./registration"), exports);
|
|
27
|
+
__exportStar(require("./wire"), exports);
|
|
28
|
+
__exportStar(require("./project"), exports);
|
|
29
|
+
__exportStar(require("./inspect"), exports);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A dry run of one wire message: what the codec reads and what the gateway
|
|
3
|
+
* would do, planned on a copy of the state so the line is untouched and no
|
|
4
|
+
* row is created or changed.
|
|
5
|
+
*/
|
|
6
|
+
import type { LineDef } from '../../../lib/machines/line';
|
|
7
|
+
import type { LineCodec } from '../../../lib/machines/protocol';
|
|
8
|
+
import type { InboundMessage } from '../../../lib/machines/transport';
|
|
9
|
+
import type { InspectResult } from '../../../types/machines-view';
|
|
10
|
+
import type { GatewayState } from './state';
|
|
11
|
+
export interface DryRunContext {
|
|
12
|
+
state: GatewayState;
|
|
13
|
+
line: LineDef;
|
|
14
|
+
codec: LineCodec;
|
|
15
|
+
dispatchTtlMs: number;
|
|
16
|
+
}
|
|
17
|
+
export declare function dryRun(ctx: DryRunContext, msg: InboundMessage): InspectResult;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* A dry run of one wire message: what the codec reads and what the gateway
|
|
4
|
+
* would do, planned on a copy of the state so the line is untouched and no
|
|
5
|
+
* row is created or changed.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.dryRun = dryRun;
|
|
9
|
+
const plan_machine_1 = require("./plan-machine");
|
|
10
|
+
const registration_1 = require("./registration");
|
|
11
|
+
const wire_1 = require("./wire");
|
|
12
|
+
/** What admitting the sender would do, or null when the message would be acted on. */
|
|
13
|
+
function admission(state, line, raw) {
|
|
14
|
+
const sender = (0, registration_1.resolveSender)(state, line, raw);
|
|
15
|
+
if (sender.status === registration_1.SENDER.BOUND)
|
|
16
|
+
return { seen: sender.seen, actions: [{ verb: 'ack', detail: `bind ${sender.machineId} to ${sender.address}` }] };
|
|
17
|
+
if (sender.seen)
|
|
18
|
+
return { seen: sender.seen, actions: [] };
|
|
19
|
+
if (sender.status === registration_1.SENDER.UNKNOWN)
|
|
20
|
+
return { seen: null, actions: [{ verb: 'none', detail: `${sender.address} claims no station on this line` }] };
|
|
21
|
+
const raised = state.claimRaised(sender.address, sender.machineId);
|
|
22
|
+
return {
|
|
23
|
+
seen: null,
|
|
24
|
+
actions: [raised
|
|
25
|
+
? { verb: 'none', detail: `${sender.address} says it is ${sender.machineId}; waiting for a person` }
|
|
26
|
+
: { verb: 'create-row', detail: `${sender.address} says it is ${sender.machineId}; a person decides` }],
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function planOne(ctx, state, raw) {
|
|
30
|
+
const admitted = admission(state, ctx.line, raw);
|
|
31
|
+
if (!admitted.seen)
|
|
32
|
+
return admitted.actions;
|
|
33
|
+
if (raw.violations.length && ctx.codec.strict)
|
|
34
|
+
return [...admitted.actions, { verb: 'hold', detail: raw.violations.join('; ') }];
|
|
35
|
+
try {
|
|
36
|
+
const plan = (0, plan_machine_1.planMachineMessage)(state, admitted.seen.parsed, admitted.seen.body, ctx.dispatchTtlMs);
|
|
37
|
+
const actions = [...admitted.actions, ...plan.actions.map(wire_1.plannedAction)];
|
|
38
|
+
return (0, wire_1.appliedActions)({ disposition: plan.disposition, failed: false, actions }, 1);
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
return [...admitted.actions, { verb: 'unreadable', detail: err.message }];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function dryRun(ctx, msg) {
|
|
45
|
+
let decoded;
|
|
46
|
+
try {
|
|
47
|
+
decoded = ctx.codec.decode(msg.topic, msg.payload, msg.retained);
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
return { kind: null, event: null, summary: err.message, inspections: [], violations: [], actions: [{ verb: 'unreadable', detail: err.message }] };
|
|
51
|
+
}
|
|
52
|
+
if (!decoded.length) {
|
|
53
|
+
return { kind: null, event: null, summary: 'not a machine message', inspections: [], violations: [], actions: [{ verb: 'none', detail: 'not a machine message' }] };
|
|
54
|
+
}
|
|
55
|
+
const state = ctx.state.clone();
|
|
56
|
+
const actions = [];
|
|
57
|
+
const violations = [];
|
|
58
|
+
for (const raw of decoded) {
|
|
59
|
+
violations.push(...raw.violations);
|
|
60
|
+
if (raw.parsed)
|
|
61
|
+
actions.push(...planOne(ctx, state, raw));
|
|
62
|
+
}
|
|
63
|
+
const [first] = decoded;
|
|
64
|
+
return {
|
|
65
|
+
kind: first.parsed?.kind ?? null, event: (0, wire_1.eventOf)(first), summary: (0, wire_1.summarize)(first),
|
|
66
|
+
inspections: decoded, violations, actions: actions.length ? actions : [{ verb: 'unreadable', detail: 'unknown topic' }],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { publishMachineLogEvent } from '../../../lib/events/publish';
|
|
1
2
|
export declare const GATEWAY_LOG: {
|
|
2
3
|
readonly STARTED: "machine_gateway.started";
|
|
3
4
|
readonly RECONCILED: "machine_gateway.reconciled";
|
|
@@ -39,3 +40,10 @@ export interface GatewayLog {
|
|
|
39
40
|
}
|
|
40
41
|
export declare const consoleLog: GatewayLog;
|
|
41
42
|
export declare const silentLog: GatewayLog;
|
|
43
|
+
/** Each entry published as `machine.log.<site>.<line>.<event>` with its context, for the line's dashboard view. */
|
|
44
|
+
export declare function eventsLog(line: {
|
|
45
|
+
siteId: string;
|
|
46
|
+
lineId: string;
|
|
47
|
+
}, publish?: typeof publishMachineLogEvent): GatewayLog;
|
|
48
|
+
/** Every entry goes to each log in turn. */
|
|
49
|
+
export declare function composeLogs(...logs: GatewayLog[]): GatewayLog;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.silentLog = exports.consoleLog = exports.GATEWAY_LOG = void 0;
|
|
4
|
+
exports.eventsLog = eventsLog;
|
|
5
|
+
exports.composeLogs = composeLogs;
|
|
6
|
+
const publish_1 = require("../../../lib/events/publish");
|
|
4
7
|
exports.GATEWAY_LOG = {
|
|
5
8
|
STARTED: 'machine_gateway.started',
|
|
6
9
|
RECONCILED: 'machine_gateway.reconciled',
|
|
@@ -40,3 +43,18 @@ exports.consoleLog = {
|
|
|
40
43
|
error: (event, context) => console.error(JSON.stringify({ level: 'error', event, ...context })),
|
|
41
44
|
};
|
|
42
45
|
exports.silentLog = { info: () => undefined, warn: () => undefined, error: () => undefined };
|
|
46
|
+
/** Each entry published as `machine.log.<site>.<line>.<event>` with its context, for the line's dashboard view. */
|
|
47
|
+
function eventsLog(line, publish = publish_1.publishMachineLogEvent) {
|
|
48
|
+
const emit = (level) => (event, context) => {
|
|
49
|
+
publish({ siteId: line.siteId, lineId: line.lineId, level, event, context }).catch(() => undefined);
|
|
50
|
+
};
|
|
51
|
+
return { info: emit('info'), warn: emit('warn'), error: emit('error') };
|
|
52
|
+
}
|
|
53
|
+
/** Every entry goes to each log in turn. */
|
|
54
|
+
function composeLogs(...logs) {
|
|
55
|
+
const each = (level) => (event, context) => {
|
|
56
|
+
for (const log of logs)
|
|
57
|
+
log[level](event, context);
|
|
58
|
+
};
|
|
59
|
+
return { info: each('info'), warn: each('warn'), error: each('error') };
|
|
60
|
+
}
|
|
@@ -39,6 +39,7 @@ function dispatchArgs(row, expiresAt) {
|
|
|
39
39
|
expiresAt: (0, protocol_1.isoTs)(expiresAt),
|
|
40
40
|
...(row.artifactUrl ? { artifact: { url: row.artifactUrl, sha256: row.artifactSha256 } } : {}),
|
|
41
41
|
...(row.parameters ? { parameters: row.parameters } : {}),
|
|
42
|
+
...(row.refs ? { refs: row.refs } : {}),
|
|
42
43
|
};
|
|
43
44
|
}
|
|
44
45
|
/**
|
|
@@ -93,8 +93,9 @@ function commandRefusal(state, line, c, role) {
|
|
|
93
93
|
const own = (0, line_1.machineRole)((0, line_1.machineById)(line, c.machineId));
|
|
94
94
|
if (role !== own)
|
|
95
95
|
return `commands for ${c.machineId} are parked on ${own}, not ${role}`;
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
const allowed = rowOps(state);
|
|
97
|
+
if (!allowed.includes(c.op))
|
|
98
|
+
return `${c.op} is not a command a row may ask for; one of ${allowed.join(', ')}`;
|
|
98
99
|
if (c.op === protocol_1.OP.CANCEL && typeof c.args.jobId !== 'string')
|
|
99
100
|
return `${protocol_1.OP.CANCEL} needs args.jobId, the job to withdraw or stop`;
|
|
100
101
|
if (!(0, registration_1.reachable)(state, line, c.machineId))
|
|
@@ -110,7 +111,7 @@ function planCommandRow(state, line, event) {
|
|
|
110
111
|
if (event.verb !== VERB.CREATED && event.verb !== VERB.CLAIMED)
|
|
111
112
|
return [];
|
|
112
113
|
const c = (0, commands_1.readCommandFacets)(event.data?.metadata);
|
|
113
|
-
if (!c || !state.trackCommand(id))
|
|
114
|
+
if (!c || !state.trackCommand(id, c.machineId))
|
|
114
115
|
return [];
|
|
115
116
|
const refusal = commandRefusal(state, line, c, event.role);
|
|
116
117
|
if (refusal) {
|
|
@@ -119,6 +120,10 @@ function planCommandRow(state, line, event) {
|
|
|
119
120
|
const createdAt = event.data?.created_at ? new Date(event.data.created_at).getTime() : NaN;
|
|
120
121
|
return [{ kind: 'control', rowId: id, machineId: c.machineId, op: c.op, args: c.args, ...(Number.isFinite(createdAt) ? { createdAt } : {}) }];
|
|
121
122
|
}
|
|
123
|
+
/** The ops a machine-command row may ask for: the control ops, a snapshot, and the codec's own. */
|
|
124
|
+
function rowOps(state) {
|
|
125
|
+
return [...protocol_1.CONTROL_OPS, protocol_1.OP.SNAPSHOT, ...state.rowOps];
|
|
126
|
+
}
|
|
122
127
|
function onLine(line, machineId) {
|
|
123
128
|
return !!machineId && line.machines.some((m) => m.machineId === machineId);
|
|
124
129
|
}
|
|
@@ -36,7 +36,7 @@ function planMachineMessage(state, parsed, env, dispatchTtlMs) {
|
|
|
36
36
|
function planByKind(state, m, parsed, env, b, ttl) {
|
|
37
37
|
switch (parsed.kind) {
|
|
38
38
|
case protocol_1.MESSAGE_KIND.REPLY:
|
|
39
|
-
return ack([{ kind: 'settleReply', cmdId: b.cmdId, status: b.status, reason: b.reason }]);
|
|
39
|
+
return ack([{ kind: 'settleReply', cmdId: b.cmdId, status: b.status, reason: b.reason, ...(typeof b.code === 'string' ? { code: b.code } : {}) }]);
|
|
40
40
|
case protocol_1.MESSAGE_KIND.JOB:
|
|
41
41
|
return planJob(state, m, b, env?.at, ttl);
|
|
42
42
|
case protocol_1.MESSAGE_KIND.ALARM:
|
|
@@ -139,7 +139,8 @@ function planJob(state, m, b, at, ttl) {
|
|
|
139
139
|
if (b.result === protocol_1.JOB_RESULT.OK)
|
|
140
140
|
return ack([released]);
|
|
141
141
|
return ack([released, ...(0, plan_shared_1.failHandoff)(state, row, m, {
|
|
142
|
-
received: false, unitId, errorCode: contracts_1.HANDOFF_ERROR.SENDER_REJECTED,
|
|
142
|
+
received: false, unitId, errorCode: contracts_1.HANDOFF_ERROR.SENDER_REJECTED, result: b.result, reason: b.reason ?? null,
|
|
143
|
+
detail: `${m} finished ${unitId}: ${b.result}${b.reason ? ` (${b.reason})` : ''}`,
|
|
143
144
|
})]);
|
|
144
145
|
}
|
|
145
146
|
if (b.event === protocol_1.JOB_EVENT.TRANSFER_FAILED) {
|
|
@@ -198,7 +199,7 @@ function planAlarm(state, parsed, alarmId, env) {
|
|
|
198
199
|
const superseded = known?.rowId && known.open
|
|
199
200
|
? [{ kind: 'resolve', as: actions_1.CONTROLLER, rowId: known.rowId, payload: { decision: contracts_1.DECISION.CLEARED, note: `${m} raised ${alarmId} again; this one ended` } }]
|
|
200
201
|
: [];
|
|
201
|
-
const track = { machineId: m, alarmId, raisedAt: b.raisedAt, open: true };
|
|
202
|
+
const track = { machineId: m, alarmId, raisedAt: b.raisedAt, level: b.level, open: true };
|
|
202
203
|
state.alarms.set(key, track);
|
|
203
204
|
return ack([...superseded, ...(0, lifecycle_1.notePause)(state, track, b), {
|
|
204
205
|
kind: 'createAlarmRow', machineId: m, alarmId,
|
|
@@ -222,10 +223,12 @@ function catalogEnvelope(catalog) {
|
|
|
222
223
|
}
|
|
223
224
|
function planPresence(state, m, b) {
|
|
224
225
|
const link = state.link(m);
|
|
226
|
+
const session = typeof b.sessionId === 'string' ? b.sessionId : undefined;
|
|
225
227
|
if (b.online !== true) {
|
|
226
228
|
if (link.online)
|
|
227
229
|
link.since = Date.now();
|
|
228
230
|
link.online = false;
|
|
231
|
+
link.reason = typeof b.reason === 'string' ? b.reason : undefined;
|
|
229
232
|
if (link.rowId || link.watching)
|
|
230
233
|
return ack();
|
|
231
234
|
link.watching = true;
|
|
@@ -234,12 +237,17 @@ function planPresence(state, m, b) {
|
|
|
234
237
|
if (b.software)
|
|
235
238
|
link.software = b.software;
|
|
236
239
|
const wasOffline = !link.online;
|
|
240
|
+
// A new session while online: the machine reconnected before its offline presence was heard.
|
|
241
|
+
const reconnected = !!session && !!link.sessionId && session !== link.sessionId;
|
|
237
242
|
link.online = true;
|
|
238
243
|
link.watching = false;
|
|
244
|
+
link.reason = undefined;
|
|
245
|
+
if (session)
|
|
246
|
+
link.sessionId = session;
|
|
239
247
|
const actions = [];
|
|
240
248
|
// Back from a drop: ask for the full state rather than wait for the next heartbeat.
|
|
241
|
-
if (wasOffline)
|
|
242
|
-
actions.push({ kind: 'command', machineId: m, op: protocol_1.OP.SNAPSHOT, cmdId: `${m}:resync:${link.since}`, args: {} });
|
|
249
|
+
if (wasOffline || reconnected)
|
|
250
|
+
actions.push({ kind: 'command', machineId: m, op: protocol_1.OP.SNAPSHOT, cmdId: `${m}:resync:${session ?? link.since}`, args: {} });
|
|
243
251
|
if (link.rowId) {
|
|
244
252
|
actions.push({ kind: 'resolve', as: actions_1.CONTROLLER, rowId: link.rowId, payload: { decision: contracts_1.DECISION.RESTORED, note: `${m} back online` } });
|
|
245
253
|
link.rowId = undefined;
|
|
@@ -252,8 +260,10 @@ function planSnapshot(state, m, b, ttl) {
|
|
|
252
260
|
if (b.software)
|
|
253
261
|
link.software = b.software;
|
|
254
262
|
const jobIds = Array.isArray(b.jobs) ? b.jobs.map((j) => j?.jobId).filter((id) => typeof id === 'string') : [];
|
|
255
|
-
if (Array.isArray(b.jobs))
|
|
263
|
+
if (Array.isArray(b.jobs)) {
|
|
256
264
|
state.keepHeld(m, new Set(jobIds));
|
|
265
|
+
link.jobs = b.jobs;
|
|
266
|
+
}
|
|
257
267
|
const fresh = !state.retainedAlarms && !state.readingRetained && Array.isArray(b.alarms);
|
|
258
268
|
const cleared = fresh ? alarmsNoLongerListed(state, m, b.alarms) : [];
|
|
259
269
|
const answer = { kind: 'settleSnapshot', machineId: m, jobIds };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The line as its leader sees it, for the dashboard: each machine's link,
|
|
3
|
+
* held units, open rows and alarms from the gateway state, and the claims
|
|
4
|
+
* waiting for a person. Pure: reads the state and the line, changes nothing.
|
|
5
|
+
*/
|
|
6
|
+
import { type LineDef } from '../../../lib/machines/line';
|
|
7
|
+
import type { LineView } from '../../../types/machines-view';
|
|
8
|
+
import type { GatewayState } from './state';
|
|
9
|
+
export declare function projectLine(state: GatewayState, line: LineDef): LineView;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The line as its leader sees it, for the dashboard: each machine's link,
|
|
4
|
+
* held units, open rows and alarms from the gateway state, and the claims
|
|
5
|
+
* waiting for a person. Pure: reads the state and the line, changes nothing.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.projectLine = projectLine;
|
|
9
|
+
const line_1 = require("../../../lib/machines/line");
|
|
10
|
+
const protocol_1 = require("../../../lib/machines/protocol");
|
|
11
|
+
const at = (ms) => (ms ? (0, protocol_1.isoTs)(ms) : null);
|
|
12
|
+
function addressOf(state, line, def) {
|
|
13
|
+
if ((0, line_1.learnsAddress)(line, def.machineId))
|
|
14
|
+
return state.learnedAddress(def.machineId) ?? null;
|
|
15
|
+
return def.address ?? def.machineId;
|
|
16
|
+
}
|
|
17
|
+
function alarmsOf(state, machineId) {
|
|
18
|
+
return [...state.alarms.values()]
|
|
19
|
+
.filter((track) => track.machineId === machineId)
|
|
20
|
+
.map((track) => ({ alarmId: track.alarmId, level: track.level ?? '', raisedAt: track.raisedAt ?? '', rowId: track.rowId ?? null }));
|
|
21
|
+
}
|
|
22
|
+
/** The handoff that brought a unit into a machine: open first, then the recently closed one. */
|
|
23
|
+
function rowCarrying(state, machineId, unitId) {
|
|
24
|
+
const into = (r) => r.toMachine === machineId;
|
|
25
|
+
return state.openFor(unitId, into) ?? state.closedFor(unitId, into);
|
|
26
|
+
}
|
|
27
|
+
function machineView(state, line, def) {
|
|
28
|
+
const m = def.machineId;
|
|
29
|
+
const link = state.links.get(m);
|
|
30
|
+
const open = state.open();
|
|
31
|
+
return {
|
|
32
|
+
machineId: m, process: def.process, role: (0, line_1.machineRole)(def), address: addressOf(state, line, def),
|
|
33
|
+
online: link ? link.online : null, since: at(link?.since), lastSeen: at(link?.lastSeen),
|
|
34
|
+
software: link?.software ?? null, bootId: link?.bootId ?? null, sessionId: link?.sessionId ?? null,
|
|
35
|
+
heldUnits: state.heldUnitsAt(m).map(({ unitId }) => {
|
|
36
|
+
const row = rowCarrying(state, m, unitId);
|
|
37
|
+
return { unitId, carrierId: row?.units.find((u) => u.unitId === unitId)?.carrierId ?? null, rowId: row?.id ?? '' };
|
|
38
|
+
}),
|
|
39
|
+
rows: {
|
|
40
|
+
handoff: open.filter((r) => r.toMachine === m).length,
|
|
41
|
+
command: state.openCommandsFor(m),
|
|
42
|
+
alarm: [...state.alarms.values()].filter((t) => t.machineId === m && t.open && !!t.rowId).length,
|
|
43
|
+
offlineRowId: link?.rowId ?? null, quietRowId: link?.quietRowId ?? null,
|
|
44
|
+
},
|
|
45
|
+
alarms: alarmsOf(state, m),
|
|
46
|
+
jobs: link?.jobs ?? [],
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function projectLine(state, line) {
|
|
50
|
+
return {
|
|
51
|
+
siteId: line.siteId, lineId: line.lineId, leading: true, takenAt: at(state.takenAt),
|
|
52
|
+
machines: line.machines.map((def) => machineView(state, line, def)),
|
|
53
|
+
contested: state.contested(),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import { type LineCodec, type MachineIdent } from '../../../lib/machines/protocol';
|
|
10
10
|
import type { MachineBus } from '../../../lib/machines/transport';
|
|
11
11
|
import { type GatewayLog } from './log';
|
|
12
|
+
import type { WireRecorder } from './wire';
|
|
12
13
|
/** Most message ids one receipt carries. */
|
|
13
14
|
export declare const MAX_RECEIPT_IDS = 100;
|
|
14
15
|
export interface ReceiptDeps {
|
|
@@ -17,6 +18,8 @@ export interface ReceiptDeps {
|
|
|
17
18
|
/** How long ids gather before a receipt goes out. */
|
|
18
19
|
delayMs: number;
|
|
19
20
|
log: GatewayLog;
|
|
21
|
+
/** Records each receipt the gateway sends, for the line's wire view. */
|
|
22
|
+
wire?: Pick<WireRecorder, 'receipt'>;
|
|
20
23
|
}
|
|
21
24
|
export declare class ReceiptBatcher {
|
|
22
25
|
private readonly d;
|
|
@@ -58,8 +58,10 @@ class ReceiptBatcher {
|
|
|
58
58
|
this.sending.add(work);
|
|
59
59
|
}
|
|
60
60
|
async publish(ident, ids) {
|
|
61
|
-
for (const wire of this.d.codec.receipt(ident, ids))
|
|
61
|
+
for (const wire of this.d.codec.receipt(ident, ids)) {
|
|
62
62
|
await this.d.bus.publish(wire.topic, wire.payload);
|
|
63
|
+
this.d.wire?.receipt(ident, ids, wire);
|
|
64
|
+
}
|
|
63
65
|
}
|
|
64
66
|
}
|
|
65
67
|
exports.ReceiptBatcher = ReceiptBatcher;
|
|
@@ -22,8 +22,8 @@ async function restoreLineRows(state, lt, line) {
|
|
|
22
22
|
const [alarms, offline, quiet, registrations] = await Promise.all([contracts_1.ROW_TYPE.ALARM, contracts_1.ROW_TYPE.MACHINE_OFFLINE, contracts_1.ROW_TYPE.MACHINE_QUIET, contracts_1.ROW_TYPE.MACHINE_REGISTRATION]
|
|
23
23
|
.map(async (type) => (await lt.listOpen({ type, role })).filter(mine)));
|
|
24
24
|
for (const row of alarms) {
|
|
25
|
-
const { machineId, alarmId, raisedAt } = row.metadata;
|
|
26
|
-
state.alarms.set(state.alarmKey(machineId, alarmId), { machineId, alarmId, raisedAt, rowId: row.id, open: true });
|
|
25
|
+
const { machineId, alarmId, raisedAt, level } = row.metadata;
|
|
26
|
+
state.alarms.set(state.alarmKey(machineId, alarmId), { machineId, alarmId, raisedAt, level, rowId: row.id, open: true });
|
|
27
27
|
}
|
|
28
28
|
for (const row of offline) {
|
|
29
29
|
const link = state.link(row.metadata.machineId);
|
|
@@ -33,7 +33,7 @@ async function restoreLineRows(state, lt, line) {
|
|
|
33
33
|
for (const row of quiet)
|
|
34
34
|
state.link(row.metadata.machineId).quietRowId = row.id;
|
|
35
35
|
for (const row of registrations)
|
|
36
|
-
state.raiseClaim(row.metadata.address, row.metadata.machineId);
|
|
36
|
+
state.raiseClaim(row.metadata.address, row.metadata.machineId, row.id);
|
|
37
37
|
return { alarms: alarms.length, offline: offline.length, quiet: quiet.length, registrations: registrations.length };
|
|
38
38
|
}
|
|
39
39
|
/** The addresses the line learned before, for the stations that still learn theirs. */
|
|
@@ -106,7 +106,7 @@ function planRegistrationRow(state, line, event) {
|
|
|
106
106
|
if (typeof md.machineId !== 'string' || typeof md.address !== 'string')
|
|
107
107
|
return [];
|
|
108
108
|
if (event.verb === 'created') {
|
|
109
|
-
state.raiseClaim(md.address, md.machineId);
|
|
109
|
+
state.raiseClaim(md.address, md.machineId, event.escalationId);
|
|
110
110
|
return [];
|
|
111
111
|
}
|
|
112
112
|
state.settleClaim(md.address, md.machineId);
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Command replies by cmdId, and machine snapshots by machine. A wait registers
|
|
3
3
|
* before the command is published and resolves with the reply, or null at the
|
|
4
|
-
* deadline.
|
|
4
|
+
* deadline. Several waits on one key are all settled by the next answer, so
|
|
5
|
+
* two dispatches asking one machine what it holds share its next snapshot.
|
|
5
6
|
*/
|
|
6
7
|
export interface CommandReply {
|
|
7
8
|
cmdId: string;
|
|
8
9
|
status: string;
|
|
9
10
|
reason: string;
|
|
11
|
+
/** The machine's structured code for the outcome, when its reply carried one. */
|
|
12
|
+
code?: string;
|
|
10
13
|
}
|
|
11
14
|
/** The jobs a machine reports holding, queued or in work. */
|
|
12
15
|
export type HeldJobs = Set<string>;
|
|
@@ -16,9 +19,9 @@ export declare class ReplyWaiter {
|
|
|
16
19
|
wait(cmdId: string, timeoutMs: number): Promise<CommandReply | null>;
|
|
17
20
|
/** True when a waiter took the reply. */
|
|
18
21
|
settle(reply: CommandReply): boolean;
|
|
19
|
-
/** The next snapshot from `machineId`, or null at the deadline. */
|
|
22
|
+
/** The next snapshot from `machineId`, or null at the deadline; every wait in flight for the machine gets it. */
|
|
20
23
|
waitSnapshot(machineId: string, timeoutMs: number): Promise<HeldJobs | null>;
|
|
21
|
-
/** Answer
|
|
24
|
+
/** Answer the status queries in flight; null when there is nothing to wait for. */
|
|
22
25
|
settleSnapshot(machineId: string, jobs: HeldJobs | null): void;
|
|
23
26
|
cancelAll(): void;
|
|
24
27
|
}
|