@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
|
@@ -9,6 +9,7 @@ exports.NatsStreams = void 0;
|
|
|
9
9
|
exports.streamConfig = streamConfig;
|
|
10
10
|
exports.consumerConfig = consumerConfig;
|
|
11
11
|
exports.ensureStream = ensureStream;
|
|
12
|
+
exports.describeStream = describeStream;
|
|
12
13
|
exports.ensureConsumer = ensureConsumer;
|
|
13
14
|
exports.payloadOf = payloadOf;
|
|
14
15
|
const nats_1 = require("nats");
|
|
@@ -41,6 +42,18 @@ async function ensureStream(jsm, spec) {
|
|
|
41
42
|
}
|
|
42
43
|
await jsm.streams.update(spec.name, config);
|
|
43
44
|
}
|
|
45
|
+
/** The stream as JetStream holds it, or null when there is none. */
|
|
46
|
+
async function describeStream(jsm, name) {
|
|
47
|
+
try {
|
|
48
|
+
const info = await jsm.streams.info(name);
|
|
49
|
+
return { name, subjects: info.config.subjects ?? [], maxAgeMs: Math.round((info.config.max_age ?? 0) / 1_000_000) };
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
if (/stream not found/i.test(err?.message ?? ''))
|
|
53
|
+
return null;
|
|
54
|
+
throw err;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
44
57
|
/** Create the consumer, or move an existing one to the spec's subjects without losing its place. */
|
|
45
58
|
async function ensureConsumer(jsm, stream, spec) {
|
|
46
59
|
let existing;
|
|
@@ -72,6 +85,9 @@ class NatsStreams {
|
|
|
72
85
|
ensureConsumer(stream, spec) {
|
|
73
86
|
return ensureConsumer(this.jsm, stream, spec);
|
|
74
87
|
}
|
|
88
|
+
describeStream(name) {
|
|
89
|
+
return describeStream(this.jsm, name);
|
|
90
|
+
}
|
|
75
91
|
async append(subject, payload) {
|
|
76
92
|
await this.js.publish(subject, payload);
|
|
77
93
|
}
|
|
@@ -32,10 +32,12 @@ export declare class LocalStorageBackend implements StorageBackend {
|
|
|
32
32
|
directories: string[];
|
|
33
33
|
nextToken?: string;
|
|
34
34
|
}>;
|
|
35
|
+
/** The digest is read from the file itself, so it is always the stored bytes' own. */
|
|
35
36
|
getMetadata(key: string): Promise<{
|
|
36
37
|
size: number;
|
|
37
38
|
modified_at: string;
|
|
38
39
|
content_type: string;
|
|
40
|
+
sha256: string;
|
|
39
41
|
}>;
|
|
40
42
|
getSignedUrl(key: string, expiresInSeconds: number): Promise<string>;
|
|
41
43
|
}
|
|
@@ -37,6 +37,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.LocalStorageBackend = void 0;
|
|
40
|
+
const crypto_1 = require("crypto");
|
|
40
41
|
const fs = __importStar(require("fs"));
|
|
41
42
|
const path = __importStar(require("path"));
|
|
42
43
|
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
@@ -168,6 +169,7 @@ class LocalStorageBackend {
|
|
|
168
169
|
nextToken: hasMore ? String(offset + limit) : undefined,
|
|
169
170
|
};
|
|
170
171
|
}
|
|
172
|
+
/** The digest is read from the file itself, so it is always the stored bytes' own. */
|
|
171
173
|
async getMetadata(key) {
|
|
172
174
|
const resolved = resolveAndValidate(key);
|
|
173
175
|
if (!fs.existsSync(resolved)) {
|
|
@@ -178,6 +180,7 @@ class LocalStorageBackend {
|
|
|
178
180
|
size: stat.size,
|
|
179
181
|
modified_at: stat.mtime.toISOString(),
|
|
180
182
|
content_type: (0, mime_1.mimeFromPath)(key),
|
|
183
|
+
sha256: (0, crypto_1.createHash)('sha256').update(fs.readFileSync(resolved)).digest('hex'),
|
|
181
184
|
};
|
|
182
185
|
}
|
|
183
186
|
async getSignedUrl(key, expiresInSeconds) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { StorageBackend } from './types';
|
|
1
|
+
import type { StorageBackend, WriteOptions } from './types';
|
|
2
2
|
export declare class S3StorageBackend implements StorageBackend {
|
|
3
3
|
private client;
|
|
4
4
|
private signingClient;
|
|
@@ -6,7 +6,7 @@ export declare class S3StorageBackend implements StorageBackend {
|
|
|
6
6
|
private bucketReady;
|
|
7
7
|
constructor();
|
|
8
8
|
private ensureBucket;
|
|
9
|
-
write(key: string, data: Buffer): Promise<{
|
|
9
|
+
write(key: string, data: Buffer, options?: WriteOptions): Promise<{
|
|
10
10
|
ref: string;
|
|
11
11
|
size: number;
|
|
12
12
|
}>;
|
|
@@ -42,6 +42,7 @@ export declare class S3StorageBackend implements StorageBackend {
|
|
|
42
42
|
size: number;
|
|
43
43
|
modified_at: string;
|
|
44
44
|
content_type: string;
|
|
45
|
+
sha256?: string;
|
|
45
46
|
}>;
|
|
46
47
|
getSignedUrl(key: string, expiresInSeconds: number): Promise<string>;
|
|
47
48
|
}
|
package/build/lib/storage/s3.js
CHANGED
|
@@ -39,6 +39,8 @@ const os = __importStar(require("os"));
|
|
|
39
39
|
const path = __importStar(require("path"));
|
|
40
40
|
const client_s3_1 = require("@aws-sdk/client-s3");
|
|
41
41
|
const s3_request_presigner_1 = require("@aws-sdk/s3-request-presigner");
|
|
42
|
+
/** The object metadata key the digest is kept under. */
|
|
43
|
+
const SHA256_METADATA = 'sha256';
|
|
42
44
|
const mime_1 = require("./mime");
|
|
43
45
|
const STAGING_DIR = path.join(os.tmpdir(), 'lt-staging');
|
|
44
46
|
class S3StorageBackend {
|
|
@@ -91,12 +93,13 @@ class S3StorageBackend {
|
|
|
91
93
|
}
|
|
92
94
|
}
|
|
93
95
|
}
|
|
94
|
-
async write(key, data) {
|
|
96
|
+
async write(key, data, options) {
|
|
95
97
|
await this.bucketReady;
|
|
96
98
|
await this.client.send(new client_s3_1.PutObjectCommand({
|
|
97
99
|
Bucket: this.bucket,
|
|
98
100
|
Key: normalizeKey(key),
|
|
99
101
|
Body: data,
|
|
102
|
+
...(options?.sha256 ? { Metadata: { [SHA256_METADATA]: options.sha256 } } : {}),
|
|
100
103
|
}));
|
|
101
104
|
return { ref: key, size: data.length };
|
|
102
105
|
}
|
|
@@ -222,10 +225,12 @@ class S3StorageBackend {
|
|
|
222
225
|
Bucket: this.bucket,
|
|
223
226
|
Key: normalizeKey(key),
|
|
224
227
|
}));
|
|
228
|
+
const sha256 = resp.Metadata?.[SHA256_METADATA];
|
|
225
229
|
return {
|
|
226
230
|
size: resp.ContentLength || 0,
|
|
227
231
|
modified_at: resp.LastModified?.toISOString() || new Date().toISOString(),
|
|
228
232
|
content_type: resp.ContentType || (0, mime_1.mimeFromPath)(key),
|
|
233
|
+
...(sha256 ? { sha256 } : {}),
|
|
229
234
|
};
|
|
230
235
|
}
|
|
231
236
|
async getSignedUrl(key, expiresInSeconds) {
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
export interface WriteOptions {
|
|
2
|
+
/** The SHA-256 of `data`, hex, kept with the object. */
|
|
3
|
+
sha256?: string;
|
|
4
|
+
}
|
|
1
5
|
export interface StorageBackend {
|
|
2
6
|
/** Write data to storage. Returns the key and size. */
|
|
3
|
-
write(key: string, data: Buffer): Promise<{
|
|
7
|
+
write(key: string, data: Buffer, options?: WriteOptions): Promise<{
|
|
4
8
|
ref: string;
|
|
5
9
|
size: number;
|
|
6
10
|
}>;
|
|
@@ -53,6 +57,8 @@ export interface StorageBackend {
|
|
|
53
57
|
size: number;
|
|
54
58
|
modified_at: string;
|
|
55
59
|
content_type: string;
|
|
60
|
+
/** The object's SHA-256, hex, when the backend knows it. */
|
|
61
|
+
sha256?: string;
|
|
56
62
|
}>;
|
|
57
63
|
/** Generate a time-limited signed URL for unauthenticated file access. */
|
|
58
64
|
getSignedUrl(key: string, expiresInSeconds: number): Promise<string>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The running machine surface, for settings and the machines API. Set by
|
|
3
|
+
* start() when the config declares lines; absent otherwise, so a deployment
|
|
4
|
+
* without machines serves no lines and no Lines view.
|
|
5
|
+
*/
|
|
6
|
+
import type { LineSurface } from '../services/machines/surface';
|
|
7
|
+
export declare function registerMachineSurface(next: LineSurface | null): void;
|
|
8
|
+
export declare function getMachineSurface(): LineSurface | null;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The running machine surface, for settings and the machines API. Set by
|
|
4
|
+
* start() when the config declares lines; absent otherwise, so a deployment
|
|
5
|
+
* without machines serves no lines and no Lines view.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.registerMachineSurface = registerMachineSurface;
|
|
9
|
+
exports.getMachineSurface = getMachineSurface;
|
|
10
|
+
let surface = null;
|
|
11
|
+
function registerMachineSurface(next) {
|
|
12
|
+
surface = next;
|
|
13
|
+
}
|
|
14
|
+
function getMachineSurface() {
|
|
15
|
+
return surface;
|
|
16
|
+
}
|
|
@@ -128,6 +128,7 @@ router.get('/download/{*filePath}', auth_1.requireBuilder, async (req, res) => {
|
|
|
128
128
|
* POST /api/file-browser/upload
|
|
129
129
|
* Upload a file to storage.
|
|
130
130
|
* Query: ?path=images/photo.png (target path including filename)
|
|
131
|
+
* &sha256=<hex> (optional; the upload is refused with 422 when the bytes differ)
|
|
131
132
|
* Body: raw file bytes (Content-Type should match the file type)
|
|
132
133
|
*/
|
|
133
134
|
router.post('/upload', auth_1.requireBuilder, async (req, res) => {
|
|
@@ -146,7 +147,8 @@ router.post('/upload', auth_1.requireBuilder, async (req, res) => {
|
|
|
146
147
|
res.status(400).json({ error: 'Empty file body' });
|
|
147
148
|
return;
|
|
148
149
|
}
|
|
149
|
-
const
|
|
150
|
+
const sha256 = typeof req.query.sha256 === 'string' ? req.query.sha256 : undefined;
|
|
151
|
+
const result = await api.uploadFile({ path: targetPath, buffer, sha256 });
|
|
150
152
|
res.status(result.status).json(result.data ?? { error: result.error });
|
|
151
153
|
}
|
|
152
154
|
catch (err) {
|
package/build/routes/index.js
CHANGED
|
@@ -40,6 +40,7 @@ const nats_credentials_1 = __importDefault(require("./nats-credentials"));
|
|
|
40
40
|
const scan_codes_1 = __importDefault(require("./scan-codes"));
|
|
41
41
|
const domain_1 = __importDefault(require("./domain"));
|
|
42
42
|
const announcements_1 = __importDefault(require("./announcements"));
|
|
43
|
+
const machines_1 = __importDefault(require("./machines"));
|
|
43
44
|
const router = (0, http_1.Router)();
|
|
44
45
|
// Public routes (no auth required — they handle their own auth)
|
|
45
46
|
router.use('/auth', auth_2.default);
|
|
@@ -80,6 +81,7 @@ router.use('/topics', topics_1.default);
|
|
|
80
81
|
router.use('/scan-codes', scan_codes_1.default);
|
|
81
82
|
router.use('/domain', domain_1.default);
|
|
82
83
|
router.use('/announcements', announcements_1.default);
|
|
84
|
+
router.use('/machines', machines_1.default);
|
|
83
85
|
const overview_1 = __importDefault(require("./overview"));
|
|
84
86
|
router.use('/overview', overview_1.default);
|
|
85
87
|
const diagnostics_1 = __importDefault(require("./diagnostics"));
|
|
@@ -74,8 +74,8 @@ router.get('/entries', async (req, res) => {
|
|
|
74
74
|
/**
|
|
75
75
|
* GET /api/knowledge/entry
|
|
76
76
|
* Get a single knowledge entry — the live edition, or an immutable snapshot
|
|
77
|
-
* when ?version=N is present.
|
|
78
|
-
* Query: ?domain=...&key=...&version=N
|
|
77
|
+
* when ?version=N (or ?version=<label>) is present.
|
|
78
|
+
* Query: ?domain=...&key=...&version=N|label
|
|
79
79
|
*/
|
|
80
80
|
router.get('/entry', async (req, res) => {
|
|
81
81
|
const domain = req.query.domain;
|
|
@@ -85,9 +85,10 @@ router.get('/entry', async (req, res) => {
|
|
|
85
85
|
return;
|
|
86
86
|
}
|
|
87
87
|
if (req.query.version !== undefined) {
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
const raw = String(req.query.version);
|
|
89
|
+
const version = /^[1-9][0-9]*$/.test(raw) ? Number(raw) : raw;
|
|
90
|
+
if (version === '' || version === 'current') {
|
|
91
|
+
res.status(400).json({ error: 'version must be a positive integer or an edition label' });
|
|
91
92
|
return;
|
|
92
93
|
}
|
|
93
94
|
const result = await api.getEntryVersion({ domain, key, version });
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const http_1 = require("../lib/http");
|
|
37
|
+
const escalationsApi = __importStar(require("../api/escalations"));
|
|
38
|
+
const auth_1 = require("../modules/auth");
|
|
39
|
+
const machines_1 = require("../modules/machines");
|
|
40
|
+
const commands_1 = require("../services/machines/commands");
|
|
41
|
+
const registry_1 = require("../services/machines/registry");
|
|
42
|
+
const registry_sync_1 = require("../services/machines/registry-sync");
|
|
43
|
+
const line_index_1 = require("../services/machines/line-index");
|
|
44
|
+
const topics_1 = require("../lib/machines/protocol/topics");
|
|
45
|
+
const browser_view_1 = require("../lib/events/browser-view");
|
|
46
|
+
const wire_window_1 = require("../services/machines/gateway/wire-window");
|
|
47
|
+
const router = (0, http_1.Router)();
|
|
48
|
+
/**
|
|
49
|
+
* The machine surface for the dashboard's Lines view. Reads and the dry run
|
|
50
|
+
* take the ops tier (superadmin, admin type, or engineer); declaring and
|
|
51
|
+
* retiring a line takes an administrator. A command is a row parked on the
|
|
52
|
+
* machine's role as the caller, so that role's write access decides, exactly
|
|
53
|
+
* as it does for any row created through the API.
|
|
54
|
+
*/
|
|
55
|
+
const NO_LINES = 'no machine lines are declared';
|
|
56
|
+
const NOT_LEADING = 'this replica is not leading the line';
|
|
57
|
+
function lineOf(req) {
|
|
58
|
+
const surface = (0, machines_1.getMachineSurface)();
|
|
59
|
+
const siteId = String(req.params.siteId);
|
|
60
|
+
const lineId = String(req.params.lineId);
|
|
61
|
+
const line = surface?.findLine(siteId, lineId);
|
|
62
|
+
return { surface, siteId, lineId, line };
|
|
63
|
+
}
|
|
64
|
+
const SORTS = new Set(['attention', 'site', 'updated']);
|
|
65
|
+
/** The longest search a person types; anything past it is cut, never an error. */
|
|
66
|
+
const QUERY_MAX_CHARS = 200;
|
|
67
|
+
function queryString(v) {
|
|
68
|
+
return typeof v === 'string' && v.trim() ? v.trim().slice(0, QUERY_MAX_CHARS) : undefined;
|
|
69
|
+
}
|
|
70
|
+
/** The line a path names, when both tokens could name a line at all. */
|
|
71
|
+
function pathLine(req) {
|
|
72
|
+
const siteId = req.params.siteId;
|
|
73
|
+
const lineId = req.params.lineId;
|
|
74
|
+
return (0, topics_1.isTopicLevel)(siteId) && (0, topics_1.isTopicLevel)(lineId) ? { siteId, lineId } : null;
|
|
75
|
+
}
|
|
76
|
+
function queryBoolean(v) {
|
|
77
|
+
return v === 'true' ? true : v === 'false' ? false : undefined;
|
|
78
|
+
}
|
|
79
|
+
function queryInt(v) {
|
|
80
|
+
const n = typeof v === 'string' ? Number(v) : NaN;
|
|
81
|
+
return Number.isFinite(n) ? n : undefined;
|
|
82
|
+
}
|
|
83
|
+
router.get('/lines', auth_1.requireRoleManager, async (req, res) => {
|
|
84
|
+
const surface = (0, machines_1.getMachineSurface)();
|
|
85
|
+
if (!surface) {
|
|
86
|
+
res.status(404).json({ error: NO_LINES });
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const sort = queryString(req.query.sort);
|
|
90
|
+
if (sort && !SORTS.has(sort)) {
|
|
91
|
+
res.status(400).json({ error: `sort must be one of ${[...SORTS].join(', ')}` });
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const query = {
|
|
95
|
+
q: queryString(req.query.q), site: queryString(req.query.site), attention: queryBoolean(req.query.attention),
|
|
96
|
+
sort: sort, limit: queryInt(req.query.limit), offset: queryInt(req.query.offset),
|
|
97
|
+
};
|
|
98
|
+
const [page, sites] = await Promise.all([(0, registry_1.listLines)(query), (0, registry_1.listSites)()]);
|
|
99
|
+
const body = {
|
|
100
|
+
lines: page.lines.map((record) => (0, line_index_1.toLineIndexRow)(surface, record)),
|
|
101
|
+
total: page.total, sites, limit: page.limit, offset: page.offset,
|
|
102
|
+
};
|
|
103
|
+
res.status(200).json(body);
|
|
104
|
+
});
|
|
105
|
+
router.put('/lines/:siteId/:lineId', auth_1.requireAdmin, async (req, res) => {
|
|
106
|
+
const surface = (0, machines_1.getMachineSurface)();
|
|
107
|
+
if (!surface) {
|
|
108
|
+
res.status(404).json({ error: NO_LINES });
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const named = pathLine(req);
|
|
112
|
+
if (!named) {
|
|
113
|
+
res.status(400).json({ error: 'siteId and lineId must be topic levels' });
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const { siteId, lineId } = named;
|
|
117
|
+
const definition = req.body?.definition;
|
|
118
|
+
if (!definition || typeof definition !== 'object' || Array.isArray(definition)) {
|
|
119
|
+
res.status(400).json({ error: 'definition is required' });
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (definition.siteId !== siteId || definition.lineId !== lineId) {
|
|
123
|
+
res.status(400).json({ error: `definition must be for ${siteId}/${lineId}` });
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const version = req.body?.version;
|
|
127
|
+
if (version !== undefined && !(Number.isInteger(version) && version >= 1)) {
|
|
128
|
+
res.status(400).json({ error: 'version must be a whole number of at least 1' });
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
try {
|
|
132
|
+
const record = await (0, registry_sync_1.declareLine)(surface, definition, version);
|
|
133
|
+
const stored = (await (0, registry_1.getLineWithHealth)(siteId, lineId)) ?? { ...record, health: (0, line_index_1.emptyLineHealth)(record.definition.machines.length) };
|
|
134
|
+
res.status(200).json({ line: (0, line_index_1.toLineIndexRow)(surface, stored) });
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
if (err instanceof registry_1.LineVersionConflict) {
|
|
138
|
+
res.status(409).json({ error: err.message });
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
res.status(400).json({ error: err instanceof Error ? err.message : String(err) });
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
router.delete('/lines/:siteId/:lineId', auth_1.requireAdmin, async (req, res) => {
|
|
145
|
+
const surface = (0, machines_1.getMachineSurface)();
|
|
146
|
+
if (!surface) {
|
|
147
|
+
res.status(404).json({ error: NO_LINES });
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const named = pathLine(req);
|
|
151
|
+
if (!named) {
|
|
152
|
+
res.status(404).json({ error: 'no such line' });
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const { siteId, lineId } = named;
|
|
156
|
+
const record = await (0, registry_sync_1.retireLine)(surface, siteId, lineId);
|
|
157
|
+
if (!record) {
|
|
158
|
+
res.status(404).json({ error: `no line ${siteId}/${lineId}` });
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
res.status(204).end();
|
|
162
|
+
});
|
|
163
|
+
router.get('/lines/:siteId/:lineId', auth_1.requireRoleManager, (req, res) => {
|
|
164
|
+
const { surface, siteId, lineId, line } = lineOf(req);
|
|
165
|
+
if (!surface || !line) {
|
|
166
|
+
res.status(404).json({ error: surface ? `no line ${siteId}/${lineId}` : NO_LINES });
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const body = {
|
|
170
|
+
...(surface.describeLine(siteId, lineId) ?? { siteId, lineId, leading: false }),
|
|
171
|
+
summary: (0, line_index_1.lineSummaryOf)(surface, siteId, lineId, line),
|
|
172
|
+
};
|
|
173
|
+
res.status(200).json(body);
|
|
174
|
+
});
|
|
175
|
+
/** The event as this viewer reads it: builders see the payload, everyone else the record without it. */
|
|
176
|
+
function wireForViewer(event, builder) {
|
|
177
|
+
if (builder)
|
|
178
|
+
return event;
|
|
179
|
+
const { payload: _payload, ...rest } = event;
|
|
180
|
+
return rest;
|
|
181
|
+
}
|
|
182
|
+
router.get('/lines/:siteId/:lineId/wire', auth_1.requireRoleManager, async (req, res) => {
|
|
183
|
+
const { surface, siteId, lineId, line } = lineOf(req);
|
|
184
|
+
if (!surface || !line) {
|
|
185
|
+
res.status(404).json({ error: surface ? `no line ${siteId}/${lineId}` : NO_LINES });
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const { direction, kind } = req.query;
|
|
189
|
+
if (direction !== undefined && !(0, wire_window_1.isWireDirection)(direction)) {
|
|
190
|
+
res.status(400).json({ error: 'direction must be in or out' });
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
if (kind !== undefined && !(0, wire_window_1.isWireKind)(kind)) {
|
|
194
|
+
res.status(400).json({ error: 'kind is not a wire kind' });
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
const query = {
|
|
198
|
+
limit: queryInt(req.query.limit), machine: queryString(req.query.machine), since: queryString(req.query.since),
|
|
199
|
+
...(direction !== undefined ? { direction } : {}), ...(kind !== undefined ? { kind } : {}),
|
|
200
|
+
};
|
|
201
|
+
const events = surface.wire(siteId, lineId, query);
|
|
202
|
+
const viewer = await (0, browser_view_1.viewerFor)(req.auth?.userId);
|
|
203
|
+
const body = { siteId, lineId, leading: events !== null, events: (events ?? []).map((e) => wireForViewer(e, viewer.builder)) };
|
|
204
|
+
res.status(200).json(body);
|
|
205
|
+
});
|
|
206
|
+
router.post('/lines/:siteId/:lineId/inspect', auth_1.requireRoleManager, (req, res) => {
|
|
207
|
+
const { surface, siteId, lineId, line } = lineOf(req);
|
|
208
|
+
if (!surface || !line) {
|
|
209
|
+
res.status(404).json({ error: surface ? `no line ${siteId}/${lineId}` : NO_LINES });
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
const topic = req.body?.topic;
|
|
213
|
+
if (typeof topic !== 'string' || !topic) {
|
|
214
|
+
res.status(400).json({ error: 'topic is required' });
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
const result = surface.inspect(siteId, lineId, { topic, payload: (0, line_index_1.wirePayloadOf)(req.body?.payload), retained: req.body?.retained === true });
|
|
218
|
+
if (!result) {
|
|
219
|
+
res.status(409).json({ error: NOT_LEADING });
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
res.status(200).json(result);
|
|
223
|
+
});
|
|
224
|
+
router.post('/lines/:siteId/:lineId/machines/:machineId/commands', async (req, res) => {
|
|
225
|
+
const { surface, siteId, lineId, line } = lineOf(req);
|
|
226
|
+
if (!surface || !line) {
|
|
227
|
+
res.status(404).json({ error: surface ? `no line ${siteId}/${lineId}` : NO_LINES });
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
const machineId = String(req.params.machineId);
|
|
231
|
+
if (!line.machines.some((m) => m.machineId === machineId)) {
|
|
232
|
+
res.status(404).json({ error: `no machine ${machineId} on ${siteId}/${lineId}` });
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
const op = req.body?.op;
|
|
236
|
+
const ops = surface.commandOps(siteId, lineId);
|
|
237
|
+
if (typeof op !== 'string' || !ops.includes(op)) {
|
|
238
|
+
res.status(400).json({ error: `op must be one of ${ops.join(', ')}` });
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
const args = req.body?.args;
|
|
242
|
+
if (args !== undefined && (!args || typeof args !== 'object' || Array.isArray(args))) {
|
|
243
|
+
res.status(400).json({ error: 'args must be an object' });
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
const result = await escalationsApi.createEscalation((0, commands_1.commandRow)((0, commands_1.commandTarget)(line, machineId), op, args ?? {}), req.auth);
|
|
247
|
+
if (result.status !== 201) {
|
|
248
|
+
res.status(result.status).json({ error: result.error });
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
res.status(201).json({ rowId: result.data.id });
|
|
252
|
+
});
|
|
253
|
+
exports.default = router;
|
|
@@ -2,15 +2,17 @@ export * from './lookup-cache';
|
|
|
2
2
|
export * from './lookup-refs';
|
|
3
3
|
export interface KnowledgeVersionMeta {
|
|
4
4
|
version: number;
|
|
5
|
+
label: string | null;
|
|
5
6
|
change_summary: string | null;
|
|
6
7
|
created_at: string;
|
|
7
8
|
is_current: boolean;
|
|
8
9
|
}
|
|
9
|
-
/** The immutable snapshot at (domain, key, version), uncached full shape. */
|
|
10
|
-
export declare function getKnowledgeVersion(domain: string, key: string, version: number): Promise<{
|
|
10
|
+
/** The immutable snapshot at (domain, key, version), by number or by the edition's label; uncached full shape. */
|
|
11
|
+
export declare function getKnowledgeVersion(domain: string, key: string, version: number | string): Promise<{
|
|
11
12
|
domain: string;
|
|
12
13
|
key: string;
|
|
13
14
|
version: number;
|
|
15
|
+
label: string | null;
|
|
14
16
|
data: Record<string, unknown>;
|
|
15
17
|
tags: string[];
|
|
16
18
|
created_at: string;
|
|
@@ -22,19 +22,24 @@ exports.listKnowledgeVersions = listKnowledgeVersions;
|
|
|
22
22
|
* writes produce, and resolves escalation lookup refs against them.
|
|
23
23
|
*/
|
|
24
24
|
const db_1 = require("../../lib/db");
|
|
25
|
+
const lookup_cache_1 = require("./lookup-cache");
|
|
25
26
|
const sql_1 = require("./sql");
|
|
26
27
|
__exportStar(require("./lookup-cache"), exports);
|
|
27
28
|
__exportStar(require("./lookup-refs"), exports);
|
|
28
|
-
/** The immutable snapshot at (domain, key, version), uncached full shape. */
|
|
29
|
+
/** The immutable snapshot at (domain, key, version), by number or by the edition's label; uncached full shape. */
|
|
29
30
|
async function getKnowledgeVersion(domain, key, version) {
|
|
30
31
|
const pool = (0, db_1.getPool)();
|
|
31
|
-
const
|
|
32
|
+
const number = typeof version === 'string' ? await (0, lookup_cache_1.editionOfLabel)(domain, key, version) : version;
|
|
33
|
+
if (number === null)
|
|
34
|
+
return null;
|
|
35
|
+
const { rows } = await pool.query(sql_1.GET_KNOWLEDGE_VERSION, [domain, key, number]);
|
|
32
36
|
if (!rows[0])
|
|
33
37
|
return null;
|
|
34
38
|
return {
|
|
35
39
|
domain: rows[0].domain,
|
|
36
40
|
key: rows[0].key,
|
|
37
41
|
version: rows[0].version,
|
|
42
|
+
label: rows[0].label ?? null,
|
|
38
43
|
data: rows[0].data ?? {},
|
|
39
44
|
tags: rows[0].tags ?? [],
|
|
40
45
|
created_at: rows[0].created_at.toISOString(),
|
|
@@ -46,6 +51,7 @@ async function listKnowledgeVersions(domain, key) {
|
|
|
46
51
|
const { rows } = await pool.query(sql_1.LIST_KNOWLEDGE_VERSIONS, [domain, key]);
|
|
47
52
|
return rows.map((r) => ({
|
|
48
53
|
version: r.version,
|
|
54
|
+
label: r.label ?? null,
|
|
49
55
|
change_summary: r.change_summary ?? null,
|
|
50
56
|
created_at: r.created_at.toISOString(),
|
|
51
57
|
is_current: r.is_current === true,
|
|
@@ -10,6 +10,8 @@ export interface ResolvedLookup {
|
|
|
10
10
|
version: number | null;
|
|
11
11
|
/** The ref follows the newest edition rather than pinning one. */
|
|
12
12
|
current?: true;
|
|
13
|
+
/** The ref pins an edition by this label. */
|
|
14
|
+
label?: string;
|
|
13
15
|
as?: string;
|
|
14
16
|
data: Record<string, unknown> | null;
|
|
15
17
|
missing?: boolean;
|
|
@@ -25,6 +27,12 @@ export declare function resolveRefEdition(ref: EscalationLookupRef, asOf?: strin
|
|
|
25
27
|
version: number;
|
|
26
28
|
snapshot: KnowledgeSnapshot;
|
|
27
29
|
} | null>;
|
|
30
|
+
/**
|
|
31
|
+
* The edition a label names, or, for a label that is a whole number no edition
|
|
32
|
+
* carries, that edition's number. Null when the label names nothing; that is
|
|
33
|
+
* never cached, so a label given later becomes visible.
|
|
34
|
+
*/
|
|
35
|
+
export declare function editionOfLabel(domain: string, key: string, label: string): Promise<number | null>;
|
|
28
36
|
/**
|
|
29
37
|
* Resolve a metadata `lookups` array into the form-context `lookup` domain:
|
|
30
38
|
* { [as ?? key]: data }. Returns null when there is nothing to resolve, so
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getKnowledgeSnapshot = getKnowledgeSnapshot;
|
|
4
4
|
exports.resolveRefEdition = resolveRefEdition;
|
|
5
|
+
exports.editionOfLabel = editionOfLabel;
|
|
5
6
|
exports.resolveLookupContext = resolveLookupContext;
|
|
6
7
|
exports.resolveLookupRefs = resolveLookupRefs;
|
|
7
8
|
/**
|
|
@@ -18,6 +19,8 @@ const sql_1 = require("./sql");
|
|
|
18
19
|
const SNAPSHOT_CACHE_MAX_ENTRIES = 256;
|
|
19
20
|
// Map preserves insertion order — delete+set on read keeps it LRU.
|
|
20
21
|
const snapshotCache = new Map();
|
|
22
|
+
// A label names one edition for good, so the number it resolves to is kept too.
|
|
23
|
+
const labelCache = new Map();
|
|
21
24
|
function remember(cacheKey, snapshot) {
|
|
22
25
|
snapshotCache.set(cacheKey, snapshot);
|
|
23
26
|
while (snapshotCache.size > SNAPSHOT_CACHE_MAX_ENTRIES) {
|
|
@@ -52,7 +55,9 @@ async function getKnowledgeSnapshot(domain, key, version) {
|
|
|
52
55
|
*/
|
|
53
56
|
async function resolveRefEdition(ref, asOf) {
|
|
54
57
|
if (!(0, escalation_1.isCurrentLookupRef)(ref)) {
|
|
55
|
-
const version = ref.version;
|
|
58
|
+
const version = (0, escalation_1.isLabelLookupRef)(ref) ? await editionOfLabel(ref.domain, ref.key, ref.version) : ref.version;
|
|
59
|
+
if (version === null)
|
|
60
|
+
return null;
|
|
56
61
|
const snapshot = await getKnowledgeSnapshot(ref.domain, ref.key, version);
|
|
57
62
|
return snapshot ? { version, snapshot } : null;
|
|
58
63
|
}
|
|
@@ -71,6 +76,26 @@ async function resolveRefEdition(ref, asOf) {
|
|
|
71
76
|
remember(cacheKey, snapshot);
|
|
72
77
|
return { version, snapshot };
|
|
73
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* The edition a label names, or, for a label that is a whole number no edition
|
|
81
|
+
* carries, that edition's number. Null when the label names nothing; that is
|
|
82
|
+
* never cached, so a label given later becomes visible.
|
|
83
|
+
*/
|
|
84
|
+
async function editionOfLabel(domain, key, label) {
|
|
85
|
+
const cacheKey = `${domain} ${key} #${label}`;
|
|
86
|
+
const hit = labelCache.get(cacheKey);
|
|
87
|
+
if (hit !== undefined)
|
|
88
|
+
return hit;
|
|
89
|
+
const { rows } = await (0, db_1.getPool)().query(sql_1.GET_KNOWLEDGE_VERSION_BY_LABEL, [domain, key, label]);
|
|
90
|
+
if (rows[0]) {
|
|
91
|
+
const version = Number(rows[0].version);
|
|
92
|
+
labelCache.set(cacheKey, version);
|
|
93
|
+
while (labelCache.size > SNAPSHOT_CACHE_MAX_ENTRIES)
|
|
94
|
+
labelCache.delete(labelCache.keys().next().value);
|
|
95
|
+
return version;
|
|
96
|
+
}
|
|
97
|
+
return /^[1-9][0-9]*$/.test(label) ? Number(label) : null;
|
|
98
|
+
}
|
|
74
99
|
/** Structural check for one ref — malformed entries in stored metadata are skipped, not fatal. */
|
|
75
100
|
function isLookupRef(ref) {
|
|
76
101
|
if (!ref || typeof ref !== 'object')
|
|
@@ -78,7 +103,7 @@ function isLookupRef(ref) {
|
|
|
78
103
|
const r = ref;
|
|
79
104
|
return typeof r.domain === 'string' && r.domain.length > 0
|
|
80
105
|
&& typeof r.key === 'string' && r.key.length > 0
|
|
81
|
-
&& ((0, escalation_1.isCurrentLookupRef)(r) || (typeof r.version === 'number' && Number.isInteger(r.version) && r.version >= 1))
|
|
106
|
+
&& ((0, escalation_1.isCurrentLookupRef)(r) || (0, escalation_1.isLabelLookupRef)(r) || (typeof r.version === 'number' && Number.isInteger(r.version) && r.version >= 1))
|
|
82
107
|
&& (r.as === undefined || (typeof r.as === 'string' && r.as.length > 0));
|
|
83
108
|
}
|
|
84
109
|
/**
|
|
@@ -112,12 +137,14 @@ async function resolveLookupRefs(refs, asOf) {
|
|
|
112
137
|
if (!isLookupRef(ref))
|
|
113
138
|
continue;
|
|
114
139
|
const current = (0, escalation_1.isCurrentLookupRef)(ref);
|
|
140
|
+
const label = (0, escalation_1.isLabelLookupRef)(ref) ? ref.version : undefined;
|
|
115
141
|
const edition = await resolveRefEdition(ref, asOf);
|
|
116
142
|
resolved.push({
|
|
117
143
|
domain: ref.domain,
|
|
118
144
|
key: ref.key,
|
|
119
|
-
version: edition?.version ?? (current ? null : ref.version),
|
|
145
|
+
version: edition?.version ?? (current || label !== undefined ? null : ref.version),
|
|
120
146
|
...(current ? { current: true } : {}),
|
|
147
|
+
...(label !== undefined ? { label } : {}),
|
|
121
148
|
...(ref.as ? { as: ref.as } : {}),
|
|
122
149
|
data: edition ? edition.snapshot.data : null,
|
|
123
150
|
...(edition ? {} : { missing: true }),
|