@hotmeshio/long-tail 0.22.0 → 0.22.2
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/build/api/escalations/accumulate.d.ts +10 -1
- package/build/api/escalations/accumulate.js +121 -34
- package/build/api/escalations/metadata.d.ts +5 -0
- package/build/api/escalations/metadata.js +6 -2
- package/build/api/escalations/resolve-batch.js +18 -11
- package/build/api/roles.js +4 -0
- package/build/api/scan-codes/badge-policy.d.ts +10 -0
- package/build/api/scan-codes/badge-policy.js +72 -0
- package/build/api/scan-codes/choice.js +18 -11
- package/build/api/scan-codes/context.d.ts +45 -1
- package/build/api/scan-codes/context.js +51 -3
- package/build/api/scan-codes/execute.js +73 -35
- package/build/api/scan-codes/grant.d.ts +27 -0
- package/build/api/scan-codes/grant.js +67 -0
- package/build/api/scan-codes/hold.d.ts +10 -0
- package/build/api/scan-codes/hold.js +98 -0
- package/build/api/scan-codes/identity.d.ts +5 -2
- package/build/api/scan-codes/identity.js +26 -8
- package/build/api/scan-codes/subject.d.ts +15 -0
- package/build/api/scan-codes/subject.js +68 -0
- package/build/api/scan-codes/verb-accumulate.d.ts +24 -0
- package/build/api/scan-codes/verb-accumulate.js +147 -0
- package/build/api/scan-codes/verb-fill.d.ts +6 -0
- package/build/api/scan-codes/verb-fill.js +152 -0
- package/build/api/scan-codes/verbs-subject.d.ts +14 -0
- package/build/api/scan-codes/verbs-subject.js +270 -0
- package/build/api/scan-codes/verbs.d.ts +7 -22
- package/build/api/scan-codes/verbs.js +35 -114
- package/build/api/workflows/invocation.d.ts +8 -4
- package/build/api/workflows/invocation.js +26 -9
- package/build/index.d.ts +1 -0
- package/build/index.js +8 -2
- package/build/lib/cli/commands/workflows.js +9 -4
- package/build/lib/db/schemas/037_scan_gtin_and_subject_grants.sql +27 -0
- package/build/routes/escalations/accumulate.js +13 -6
- package/build/routes/escalations/acting.d.ts +5 -0
- package/build/routes/escalations/acting.js +8 -1
- package/build/routes/scan-codes.js +3 -0
- package/build/sdk/index.d.ts +3 -0
- package/build/services/escalation/crud.d.ts +2 -2
- package/build/services/escalation/crud.js +4 -2
- package/build/services/escalation/facet-sql.js +8 -0
- package/build/services/escalation/sql.d.ts +4 -2
- package/build/services/escalation/sql.js +10 -2
- package/build/services/export/index.d.ts +8 -3
- package/build/services/export/index.js +15 -21
- package/build/services/iam/acting-identity.d.ts +29 -4
- package/build/services/iam/acting-identity.js +60 -17
- package/build/services/iam/ephemeral.d.ts +21 -0
- package/build/services/iam/ephemeral.js +32 -1
- package/build/services/iam/sql.d.ts +10 -0
- package/build/services/iam/sql.js +32 -3
- package/build/services/pipelines/events.js +2 -1
- package/build/services/pipelines/execution-builder.js +2 -1
- package/build/services/pipelines/queries.js +2 -1
- package/build/services/role/badge-grant.d.ts +5 -0
- package/build/services/role/badge-grant.js +36 -0
- package/build/services/role/seed.js +5 -0
- package/build/services/role/types.d.ts +14 -0
- package/build/services/role/types.js +5 -0
- package/build/services/scan-code/index.d.ts +3 -2
- package/build/services/scan-code/index.js +7 -1
- package/build/services/scan-code/parse.d.ts +23 -20
- package/build/services/scan-code/parse.js +45 -90
- package/build/services/scan-code/read.js +1 -0
- package/build/services/scan-code/sql.d.ts +3 -3
- package/build/services/scan-code/sql.js +11 -8
- package/build/services/scan-code/validate-subject.d.ts +7 -0
- package/build/services/scan-code/validate-subject.js +158 -0
- package/build/services/scan-code/validate.d.ts +7 -0
- package/build/services/scan-code/validate.js +111 -16
- package/build/services/scan-code/write.d.ts +1 -0
- package/build/services/scan-code/write.js +9 -3
- package/build/services/workflow-state.d.ts +21 -0
- package/build/services/workflow-state.js +39 -0
- package/build/shared/form-validation/field-validator.js +4 -0
- package/build/shared/form-validation/index.d.ts +1 -0
- package/build/shared/form-validation/index.js +1 -0
- package/build/shared/form-validation/x-lt-scan.d.ts +52 -0
- package/build/shared/form-validation/x-lt-scan.js +166 -0
- package/build/shared/scan-code/gtin.d.ts +5 -0
- package/build/shared/scan-code/gtin.js +25 -0
- package/build/shared/scan-code/index.d.ts +2 -0
- package/build/shared/scan-code/index.js +10 -0
- package/build/shared/scan-code/parse.d.ts +46 -0
- package/build/shared/scan-code/parse.js +133 -0
- package/build/shared/workflow-state.d.ts +17 -0
- package/build/shared/workflow-state.js +29 -0
- package/build/system/mcp-servers/admin/escalations.js +8 -4
- package/build/system/mcp-servers/admin/scan-codes.js +10 -4
- package/build/system/mcp-servers/admin/schemas.d.ts +792 -23
- package/build/system/mcp-servers/admin/schemas.js +61 -4
- package/build/system/mcp-servers/admin/workflows.js +20 -31
- package/build/system/mcp-servers/human-queue-schemas.d.ts +6 -6
- package/build/system/seed/tool-manifests-admin.d.ts +94 -0
- package/build/system/seed/tool-manifests-admin.js +3 -3
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/escalation.d.ts +2 -0
- package/build/types/escalation.js +3 -1
- package/build/types/facets.d.ts +14 -0
- package/build/types/index.d.ts +3 -3
- package/build/types/index.js +8 -1
- package/build/types/scan-code/constants.d.ts +182 -0
- package/build/types/{scan-code.js → scan-code/constants.js} +62 -12
- package/build/types/scan-code/index.d.ts +3 -0
- package/build/types/scan-code/index.js +17 -0
- package/build/types/scan-code/response.d.ts +140 -0
- package/build/types/scan-code/response.js +2 -0
- package/build/types/scan-code/rule.d.ts +199 -0
- package/build/types/scan-code/rule.js +2 -0
- package/build/types/startup.d.ts +3 -1
- package/dashboard/dist/assets/{AdminDashboard-Covdam48.js → AdminDashboard-DBW12qQt.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-Covdam48.js.map → AdminDashboard-DBW12qQt.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-CE1k6J5r.js → AgentConfigPage-CmHv8U9M.js} +2 -2
- package/dashboard/dist/assets/{AgentConfigPage-CE1k6J5r.js.map → AgentConfigPage-CmHv8U9M.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-CWJZIZP1.js → AgentDetailPage-D1scIbz-.js} +3 -3
- package/dashboard/dist/assets/{AgentDetailPage-CWJZIZP1.js.map → AgentDetailPage-D1scIbz-.js.map} +1 -1
- package/dashboard/dist/assets/{AgentsPage---Dg5ufF.js → AgentsPage-BA_ai9HJ.js} +2 -2
- package/dashboard/dist/assets/{AgentsPage---Dg5ufF.js.map → AgentsPage-BA_ai9HJ.js.map} +1 -1
- package/dashboard/dist/assets/AvailableEscalationsPage-C2_5aEFW.js +2 -0
- package/dashboard/dist/assets/AvailableEscalationsPage-C2_5aEFW.js.map +1 -0
- package/dashboard/dist/assets/{BotPicker-D3drO3-T.js → BotPicker-BZo4Kp4a.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-D3drO3-T.js.map → BotPicker-BZo4Kp4a.js.map} +1 -1
- package/dashboard/dist/assets/{BulkAssignModal-BOAWsViq.js → BulkAssignModal-BFhyxY2T.js} +2 -2
- package/dashboard/dist/assets/{BulkAssignModal-BOAWsViq.js.map → BulkAssignModal-BFhyxY2T.js.map} +1 -1
- package/dashboard/dist/assets/CapabilitiesPage-CvOX6vAc.js +2 -0
- package/dashboard/dist/assets/{CapabilitiesPage-RGgD3YZO.js.map → CapabilitiesPage-CvOX6vAc.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-DNkZn87n.js → CollapsibleSection-GCJsV9Oq.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-DNkZn87n.js.map → CollapsibleSection-GCJsV9Oq.js.map} +1 -1
- package/dashboard/dist/assets/{ConfirmDeleteModal-BqzOwhPr.js → ConfirmDeleteModal-CAgYLcef.js} +2 -2
- package/dashboard/dist/assets/{ConfirmDeleteModal-BqzOwhPr.js.map → ConfirmDeleteModal-CAgYLcef.js.map} +1 -1
- package/dashboard/dist/assets/CountdownTimer-Dik2z0M_.js +2 -0
- package/dashboard/dist/assets/{CountdownTimer-BaexQMK6.js.map → CountdownTimer-Dik2z0M_.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialsPage-D7abp0aS.js → CredentialsPage-twd2xCOW.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-D7abp0aS.js.map → CredentialsPage-twd2xCOW.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-DZiWmTwJ.js → CronLabel-DdnIuudX.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-DZiWmTwJ.js.map → CronLabel-DdnIuudX.js.map} +1 -1
- package/dashboard/dist/assets/{DropZone-f1o-GLM8.js → DropZone-B1Tdfddc.js} +2 -2
- package/dashboard/dist/assets/{DropZone-f1o-GLM8.js.map → DropZone-B1Tdfddc.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-BdGO_w4v.js → ElapsedCell-DCctVv5R.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-BdGO_w4v.js.map → ElapsedCell-DCctVv5R.js.map} +1 -1
- package/dashboard/dist/assets/{EntityTimelinePanel-DIDcF5Yu.js → EntityTimelinePanel-CMnskyWv.js} +2 -2
- package/dashboard/dist/assets/{EntityTimelinePanel-DIDcF5Yu.js.map → EntityTimelinePanel-CMnskyWv.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationListSchemaPage-C28rn9XC.js → EscalationListSchemaPage-VfCn6WDb.js} +3 -3
- package/dashboard/dist/assets/{EscalationListSchemaPage-C28rn9XC.js.map → EscalationListSchemaPage-VfCn6WDb.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationListView-CkBnkpDJ.js → EscalationListView-CGQZxcC-.js} +2 -2
- package/dashboard/dist/assets/{EscalationListView-CkBnkpDJ.js.map → EscalationListView-CGQZxcC-.js.map} +1 -1
- package/dashboard/dist/assets/EscalationSchemaPage-BX0tx-PM.js +9 -0
- package/dashboard/dist/assets/EscalationSchemaPage-BX0tx-PM.js.map +1 -0
- package/dashboard/dist/assets/EscalationTimeline-DKoSM56J.js +2 -0
- package/dashboard/dist/assets/EscalationTimeline-DKoSM56J.js.map +1 -0
- package/dashboard/dist/assets/{EscalationTitleSelect-CzKfavri.js → EscalationTitleSelect-DWGLBOmS.js} +2 -2
- package/dashboard/dist/assets/{EscalationTitleSelect-CzKfavri.js.map → EscalationTitleSelect-DWGLBOmS.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-Tdu3Yx2c.js → EscalationsOverview-C2XoguaA.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-Tdu3Yx2c.js.map → EscalationsOverview-C2XoguaA.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-DiIxOJwO.js → EventTable-CBUWq7--.js} +2 -2
- package/dashboard/dist/assets/{EventTable-DiIxOJwO.js.map → EventTable-CBUWq7--.js.map} +1 -1
- package/dashboard/dist/assets/{FilterBar-CvMBCVIo.js → FilterBar-8IdbleZ9.js} +2 -2
- package/dashboard/dist/assets/{FilterBar-CvMBCVIo.js.map → FilterBar-8IdbleZ9.js.map} +1 -1
- package/dashboard/dist/assets/GrantScopeField-BzWGzBfA.js +2 -0
- package/dashboard/dist/assets/GrantScopeField-BzWGzBfA.js.map +1 -0
- package/dashboard/dist/assets/{GraphInvokePage-DO-yyhi6.js → GraphInvokePage-CUvoPzsW.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-DO-yyhi6.js.map → GraphInvokePage-CUvoPzsW.js.map} +1 -1
- package/dashboard/dist/assets/{HomePage-DSS3eHR2.js → HomePage-BP7v9GLJ.js} +2 -2
- package/dashboard/dist/assets/{HomePage-DSS3eHR2.js.map → HomePage-BP7v9GLJ.js.map} +1 -1
- package/dashboard/dist/assets/{ListToolbar-C3-Tqqub.js → ListToolbar-Cnacuwoy.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-C3-Tqqub.js.map → ListToolbar-Cnacuwoy.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-DEJmsdVi.js → McpOverview-C2JoNoDA.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-DEJmsdVi.js.map → McpOverview-C2JoNoDA.js.map} +1 -1
- package/dashboard/dist/assets/McpQueryDetailPage-C_nih0w-.js +5 -0
- package/dashboard/dist/assets/McpQueryDetailPage-C_nih0w-.js.map +1 -0
- package/dashboard/dist/assets/{McpQueryPage-BBcG_UuU.js → McpQueryPage-U_wNXow2.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-BBcG_UuU.js.map → McpQueryPage-U_wNXow2.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunDetailPage-C6xw0kBg.js → McpRunDetailPage-DtKoJq6J.js} +2 -2
- package/dashboard/dist/assets/{McpRunDetailPage-C6xw0kBg.js.map → McpRunDetailPage-DtKoJq6J.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-CRQqrF4Q.js → McpRunsPage-CnYtfGhf.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-CRQqrF4Q.js.map → McpRunsPage-CnYtfGhf.js.map} +1 -1
- package/dashboard/dist/assets/{NamespacePill-DADRJOUl.js → NamespacePill-DwM5pNA4.js} +2 -2
- package/dashboard/dist/assets/{NamespacePill-DADRJOUl.js.map → NamespacePill-DwM5pNA4.js.map} +1 -1
- package/dashboard/dist/assets/{OperationsPage-Dlfwzf-0.js → OperationsPage-C7hupIer.js} +2 -2
- package/dashboard/dist/assets/{OperationsPage-Dlfwzf-0.js.map → OperationsPage-C7hupIer.js.map} +1 -1
- package/dashboard/dist/assets/{OperatorDashboard-DoiDGZ9R.js → OperatorDashboard-fVuLn2D5.js} +2 -2
- package/dashboard/dist/assets/{OperatorDashboard-DoiDGZ9R.js.map → OperatorDashboard-fVuLn2D5.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeader-Csq434-v.js → PageHeader-CMd3f4bz.js} +2 -2
- package/dashboard/dist/assets/{PageHeader-Csq434-v.js.map → PageHeader-CMd3f4bz.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeaderWithStats-CSnk1p5A.js → PageHeaderWithStats-DHj8Mqox.js} +2 -2
- package/dashboard/dist/assets/{PageHeaderWithStats-CSnk1p5A.js.map → PageHeaderWithStats-DHj8Mqox.js.map} +1 -1
- package/dashboard/dist/assets/{PersonaDetailPage-BzbA4Prr.js → PersonaDetailPage-C-4o8lPw.js} +2 -2
- package/dashboard/dist/assets/{PersonaDetailPage-BzbA4Prr.js.map → PersonaDetailPage-C-4o8lPw.js.map} +1 -1
- package/dashboard/dist/assets/{PersonasPage-B36yn4hU.js → PersonasPage-BL1FwLmv.js} +2 -2
- package/dashboard/dist/assets/{PersonasPage-B36yn4hU.js.map → PersonasPage-BL1FwLmv.js.map} +1 -1
- package/dashboard/dist/assets/{PortalPage-BkD4YfDf.js → PortalPage-tJG5sgb1.js} +2 -2
- package/dashboard/dist/assets/{PortalPage-BkD4YfDf.js.map → PortalPage-tJG5sgb1.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessDetailPage-BT0eiBWY.js → ProcessDetailPage-Dz_jY4Yt.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-BT0eiBWY.js.map → ProcessDetailPage-Dz_jY4Yt.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-BEqeeNae.js → ProcessesListPage-Cbn9cter.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-BEqeeNae.js.map → ProcessesListPage-Cbn9cter.js.map} +1 -1
- package/dashboard/dist/assets/ResolverForm-Bk8iXQ6-.js +8 -0
- package/dashboard/dist/assets/ResolverForm-Bk8iXQ6-.js.map +1 -0
- package/dashboard/dist/assets/RoleDetailPage-owPi6gI9.js +8 -0
- package/dashboard/dist/assets/RoleDetailPage-owPi6gI9.js.map +1 -0
- package/dashboard/dist/assets/{RolePill-BafrASDX.js → RolePill-Di2CAHuD.js} +2 -2
- package/dashboard/dist/assets/{RolePill-BafrASDX.js.map → RolePill-Di2CAHuD.js.map} +1 -1
- package/dashboard/dist/assets/{RolesPage-80quJU5-.js → RolesPage-NwmMvZFa.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-80quJU5-.js.map → RolesPage-NwmMvZFa.js.map} +1 -1
- package/dashboard/dist/assets/{RunAsSelector-BoePhWVD.js → RunAsSelector-tgEooTyU.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-BoePhWVD.js.map → RunAsSelector-tgEooTyU.js.map} +1 -1
- package/dashboard/dist/assets/ScanCodesPage-CUv_8ic6.js +2 -0
- package/dashboard/dist/assets/ScanCodesPage-CUv_8ic6.js.map +1 -0
- package/dashboard/dist/assets/ScanSchemeDetailPage-YHqbu7oK.js +2 -0
- package/dashboard/dist/assets/ScanSchemeDetailPage-YHqbu7oK.js.map +1 -0
- package/dashboard/dist/assets/ScanStationPage-B275l6r_.js +2 -0
- package/dashboard/dist/assets/ScanStationPage-B275l6r_.js.map +1 -0
- package/dashboard/dist/assets/{ScopeBadge-b6MIBiYD.js → ScopeBadge-CSItPVOH.js} +2 -2
- package/dashboard/dist/assets/{ScopeBadge-b6MIBiYD.js.map → ScopeBadge-CSItPVOH.js.map} +1 -1
- package/dashboard/dist/assets/{StickyPagination-9ITrei_d.js → StickyPagination-CsTI_gvJ.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-9ITrei_d.js.map → StickyPagination-CsTI_gvJ.js.map} +1 -1
- package/dashboard/dist/assets/{StreamMessageDetail-BkYvEHFY.js → StreamMessageDetail-auRlvjTh.js} +2 -2
- package/dashboard/dist/assets/{StreamMessageDetail-BkYvEHFY.js.map → StreamMessageDetail-auRlvjTh.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-B1rotFix.js → SwimlaneTimeline-BLoVHYAd.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-B1rotFix.js.map → SwimlaneTimeline-BLoVHYAd.js.map} +1 -1
- package/dashboard/dist/assets/{TagInput-ZrIIrEUP.js → TagInput-CAgdLN_b.js} +2 -2
- package/dashboard/dist/assets/{TagInput-ZrIIrEUP.js.map → TagInput-CAgdLN_b.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-zhn_U_eC.js → TaskDetailPage-BPsZ1bK_.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-zhn_U_eC.js.map → TaskDetailPage-BPsZ1bK_.js.map} +1 -1
- package/dashboard/dist/assets/{TaskQueuePill-DkQ1uc6y.js → TaskQueuePill-h0oorVMe.js} +2 -2
- package/dashboard/dist/assets/{TaskQueuePill-DkQ1uc6y.js.map → TaskQueuePill-h0oorVMe.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-CNbNeagx.js → TasksListPage-BNGM74yT.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-CNbNeagx.js.map → TasksListPage-BNGM74yT.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-0YVMBwls.js → TimeAgo-BnAHXGK7.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-0YVMBwls.js.map → TimeAgo-BnAHXGK7.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-DB7r3np8.js → TimestampCell-J4yae6mc.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-DB7r3np8.js.map → TimestampCell-J4yae6mc.js.map} +1 -1
- package/dashboard/dist/assets/{ToolPill-Baxm02L6.js → ToolPill-CQCsVdzD.js} +2 -2
- package/dashboard/dist/assets/{ToolPill-Baxm02L6.js.map → ToolPill-CQCsVdzD.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-BLfA02wv.js → ToolTestPanel-BdzzgXDu.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-BLfA02wv.js.map → ToolTestPanel-BdzzgXDu.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-eAqPKShq.js → TopicDetailPage-DJKg8lb7.js} +4 -4
- package/dashboard/dist/assets/{TopicDetailPage-eAqPKShq.js.map → TopicDetailPage-DJKg8lb7.js.map} +1 -1
- package/dashboard/dist/assets/{TopicsPage-BNNWD-zl.js → TopicsPage-DQV0WxG6.js} +2 -2
- package/dashboard/dist/assets/{TopicsPage-BNNWD-zl.js.map → TopicsPage-DQV0WxG6.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-Pw46tO_k.js → UserName-Ct09nGh5.js} +2 -2
- package/dashboard/dist/assets/{UserName-Pw46tO_k.js.map → UserName-Ct09nGh5.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowExecutionPage-DvA51lT3.js → WorkflowExecutionPage-B5WJOsee.js} +2 -2
- package/dashboard/dist/assets/{WorkflowExecutionPage-DvA51lT3.js.map → WorkflowExecutionPage-B5WJOsee.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowPill-ZepbO_ny.js → WorkflowPill-Dg7BDTyM.js} +2 -2
- package/dashboard/dist/assets/{WorkflowPill-ZepbO_ny.js.map → WorkflowPill-Dg7BDTyM.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsDashboard-DFDTwnhn.js → WorkflowsDashboard-Hc87TRgD.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-DFDTwnhn.js.map → WorkflowsDashboard-Hc87TRgD.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-5i2Tcy-p.js → WorkflowsOverview-CJQbyOj-.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-5i2Tcy-p.js.map → WorkflowsOverview-CJQbyOj-.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-p4VEYZS0.js → YamlWorkflowDetailPage-BMeED677.js} +8 -8
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-p4VEYZS0.js.map → YamlWorkflowDetailPage-BMeED677.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-Cq-hMVxl.js → YamlWorkflowsPage-BMMg0Id6.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-Cq-hMVxl.js.map → YamlWorkflowsPage-BMMg0Id6.js.map} +1 -1
- package/dashboard/dist/assets/{agents-EyBPJMYa.js → agents-CdFkgFvg.js} +2 -2
- package/dashboard/dist/assets/{agents-EyBPJMYa.js.map → agents-CdFkgFvg.js.map} +1 -1
- package/dashboard/dist/assets/{bots-DX6jjqtF.js → bots-Mj3LHWWg.js} +2 -2
- package/dashboard/dist/assets/{bots-DX6jjqtF.js.map → bots-Mj3LHWWg.js.map} +1 -1
- package/dashboard/dist/assets/{capabilities-ZdLv9xBQ.js → capabilities-Dw1ObK2-.js} +2 -2
- package/dashboard/dist/assets/{capabilities-ZdLv9xBQ.js.map → capabilities-Dw1ObK2-.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-CpvZaJuw.js → controlplane-DcNE1APv.js} +2 -2
- package/dashboard/dist/assets/{controlplane-CpvZaJuw.js.map → controlplane-DcNE1APv.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-columns-Mvsze5eV.js → escalation-columns-D364Trpy.js} +2 -2
- package/dashboard/dist/assets/{escalation-columns-Mvsze5eV.js.map → escalation-columns-D364Trpy.js.map} +1 -1
- package/dashboard/dist/assets/{index-Cn8uJsd7.js → index-B3veJ698.js} +2 -2
- package/dashboard/dist/assets/{index-Cn8uJsd7.js.map → index-B3veJ698.js.map} +1 -1
- package/dashboard/dist/assets/index-BQeHJHYN.js +67 -0
- package/dashboard/dist/assets/index-BQeHJHYN.js.map +1 -0
- package/dashboard/dist/assets/{index-D-Xs4rAW.js → index-BRGTmoYY.js} +2 -2
- package/dashboard/dist/assets/{index-D-Xs4rAW.js.map → index-BRGTmoYY.js.map} +1 -1
- package/dashboard/dist/assets/{index-DkrBFFSO.js → index-Bd6-KmBE.js} +3 -3
- package/dashboard/dist/assets/{index-DkrBFFSO.js.map → index-Bd6-KmBE.js.map} +1 -1
- package/dashboard/dist/assets/{index-Bhb89oHH.js → index-BiVce3n0.js} +2 -2
- package/dashboard/dist/assets/{index-Bhb89oHH.js.map → index-BiVce3n0.js.map} +1 -1
- package/dashboard/dist/assets/{index-z5Hpeidu.js → index-BmNAVd4s.js} +2 -2
- package/dashboard/dist/assets/{index-z5Hpeidu.js.map → index-BmNAVd4s.js.map} +1 -1
- package/dashboard/dist/assets/{index-BbCjGO3M.js → index-Bq5XNEzD.js} +2 -2
- package/dashboard/dist/assets/{index-BbCjGO3M.js.map → index-Bq5XNEzD.js.map} +1 -1
- package/dashboard/dist/assets/{index-DGmzBY9D.js → index-DPStdq4T.js} +2 -2
- package/dashboard/dist/assets/{index-DGmzBY9D.js.map → index-DPStdq4T.js.map} +1 -1
- package/dashboard/dist/assets/index-DcppjzP5.css +1 -0
- package/dashboard/dist/assets/{index-PfSRKerc.js → index-DkcI4V_H.js} +2 -2
- package/dashboard/dist/assets/{index-PfSRKerc.js.map → index-DkcI4V_H.js.map} +1 -1
- package/dashboard/dist/assets/{index-oFKUFGQL.js → index-Dyotfa_k.js} +2 -2
- package/dashboard/dist/assets/{index-oFKUFGQL.js.map → index-Dyotfa_k.js.map} +1 -1
- package/dashboard/dist/assets/{index-Eo-l3Lqo.js → index-MDD4JYtu.js} +2 -2
- package/dashboard/dist/assets/{index-Eo-l3Lqo.js.map → index-MDD4JYtu.js.map} +1 -1
- package/dashboard/dist/assets/index-WSm8bgE7.js +3 -0
- package/dashboard/dist/assets/index-WSm8bgE7.js.map +1 -0
- package/dashboard/dist/assets/{index-DZhtP2Ok.js → index-eDm6cz0F.js} +2 -2
- package/dashboard/dist/assets/{index-DZhtP2Ok.js.map → index-eDm6cz0F.js.map} +1 -1
- package/dashboard/dist/assets/{knowledge-CgloEkaf.js → knowledge-Bafewjxk.js} +2 -2
- package/dashboard/dist/assets/{knowledge-CgloEkaf.js.map → knowledge-Bafewjxk.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-o-sGX2ST.js → mcp-query-BzTtIG90.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-o-sGX2ST.js.map → mcp-query-BzTtIG90.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-Bix7QYO7.js → mcp-vLIutbnc.js} +2 -2
- package/dashboard/dist/assets/{mcp-Bix7QYO7.js.map → mcp-vLIutbnc.js.map} +1 -1
- package/dashboard/dist/assets/{personas-30azkJ_s.js → personas-WD40EDS_.js} +2 -2
- package/dashboard/dist/assets/{personas-30azkJ_s.js.map → personas-WD40EDS_.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-Bfk2GFK7.js → pipelines-DFwULWs3.js} +2 -2
- package/dashboard/dist/assets/{pipelines-Bfk2GFK7.js.map → pipelines-DFwULWs3.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-CpdopewW.js → tasks-La_-WAUn.js} +2 -2
- package/dashboard/dist/assets/{tasks-CpdopewW.js.map → tasks-La_-WAUn.js.map} +1 -1
- package/dashboard/dist/assets/{topics--bvCV9Yp.js → topics-CzYMlvqm.js} +2 -2
- package/dashboard/dist/assets/{topics--bvCV9Yp.js.map → topics-CzYMlvqm.js.map} +1 -1
- package/dashboard/dist/assets/{useDebouncedValue-Da0lPmj3.js → useDebouncedValue-C0FQyANW.js} +2 -2
- package/dashboard/dist/assets/{useDebouncedValue-Da0lPmj3.js.map → useDebouncedValue-C0FQyANW.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-DD_Esl6n.js → useNamespace-WW_XjAb3.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-DD_Esl6n.js.map → useNamespace-WW_XjAb3.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-AeAhZJJk.js → useYamlActivityEvents-B3YxPeFt.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-AeAhZJJk.js.map → useYamlActivityEvents-B3YxPeFt.js.map} +1 -1
- package/dashboard/dist/assets/{vendor-icons-B7OcUM6b.js → vendor-icons-CeVtUKyP.js} +2 -2
- package/dashboard/dist/assets/{vendor-icons-B7OcUM6b.js.map → vendor-icons-CeVtUKyP.js.map} +1 -1
- package/dashboard/dist/assets/{yaml-workflows-BHAOOGvn.js → yaml-workflows-COHOjdhF.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-BHAOOGvn.js.map → yaml-workflows-COHOjdhF.js.map} +1 -1
- package/dashboard/dist/index.html +3 -3
- package/docs/accumulator.md +37 -1
- package/docs/api/mcp/admin.md +3 -2
- package/docs/api/sdk/escalations.md +6 -0
- package/docs/api/sdk/exports.md +1 -1
- package/docs/api/sdk/workflows.md +23 -4
- package/docs/cli.md +1 -1
- package/docs/dashboard.md +2 -2
- package/docs/faceted-routing.md +2 -0
- package/docs/hitl/x-lt-scan.md +51 -0
- package/docs/hitl/x-lt-widget.md +5 -0
- package/docs/hitl-guide.md +2 -0
- package/docs/scan-codes.md +252 -19
- package/package.json +1 -1
- package/build/types/scan-code.d.ts +0 -308
- package/dashboard/dist/assets/AvailableEscalationsPage-CpbC8oTN.js +0 -2
- package/dashboard/dist/assets/AvailableEscalationsPage-CpbC8oTN.js.map +0 -1
- package/dashboard/dist/assets/CapabilitiesPage-RGgD3YZO.js +0 -2
- package/dashboard/dist/assets/CountdownTimer-BaexQMK6.js +0 -2
- package/dashboard/dist/assets/EscalationSchemaPage-W5r0A1kj.js +0 -9
- package/dashboard/dist/assets/EscalationSchemaPage-W5r0A1kj.js.map +0 -1
- package/dashboard/dist/assets/EscalationTimeline-DKyTz6sM.js +0 -2
- package/dashboard/dist/assets/EscalationTimeline-DKyTz6sM.js.map +0 -1
- package/dashboard/dist/assets/McpQueryDetailPage-DYJr16l7.js +0 -5
- package/dashboard/dist/assets/McpQueryDetailPage-DYJr16l7.js.map +0 -1
- package/dashboard/dist/assets/ResolverForm-BwgjIX97.js +0 -7
- package/dashboard/dist/assets/ResolverForm-BwgjIX97.js.map +0 -1
- package/dashboard/dist/assets/RoleDetailPage-BFuLNJXa.js +0 -8
- package/dashboard/dist/assets/RoleDetailPage-BFuLNJXa.js.map +0 -1
- package/dashboard/dist/assets/ScanCodesPage-Cu1bKEix.js +0 -2
- package/dashboard/dist/assets/ScanCodesPage-Cu1bKEix.js.map +0 -1
- package/dashboard/dist/assets/ScanSchemeDetailPage-D9AbS6UY.js +0 -2
- package/dashboard/dist/assets/ScanSchemeDetailPage-D9AbS6UY.js.map +0 -1
- package/dashboard/dist/assets/ScanStationPage-gcZGefvT.js +0 -2
- package/dashboard/dist/assets/ScanStationPage-gcZGefvT.js.map +0 -1
- package/dashboard/dist/assets/index-B_GT23TE.js +0 -3
- package/dashboard/dist/assets/index-B_GT23TE.js.map +0 -1
- package/dashboard/dist/assets/index-CgUcYveM.js +0 -67
- package/dashboard/dist/assets/index-CgUcYveM.js.map +0 -1
- package/dashboard/dist/assets/index-Dh8MJl3L.css +0 -1
|
@@ -1,11 +1,34 @@
|
|
|
1
1
|
import * as scanCodeService from '../../services/scan-code';
|
|
2
2
|
import { type LTEscalationRecord, type ParsedScanCode, type ScanExecuteResponse, type ScanRule, type ScanScheme, type ScanStep } from '../../types';
|
|
3
3
|
import type { LTApiAuth, LTApiResult } from '../../types/sdk';
|
|
4
|
+
/** The held subject, re-derived from the client's pointer on this request. */
|
|
5
|
+
export interface HeldSubject {
|
|
6
|
+
row: LTEscalationRecord;
|
|
7
|
+
parsed: ParsedScanCode;
|
|
8
|
+
scheme: ScanScheme;
|
|
9
|
+
code: string;
|
|
10
|
+
}
|
|
11
|
+
/** The acting grant riding the request, and whether this request spent it. */
|
|
12
|
+
export interface GrantLedger {
|
|
13
|
+
token: string;
|
|
14
|
+
/** Before this request touched it. */
|
|
15
|
+
peeked: {
|
|
16
|
+
remaining: number | null;
|
|
17
|
+
bound: boolean;
|
|
18
|
+
};
|
|
19
|
+
/** Set once this request spends a use; null until then. */
|
|
20
|
+
spent: {
|
|
21
|
+
remaining: number | null;
|
|
22
|
+
bound: boolean;
|
|
23
|
+
} | null;
|
|
24
|
+
}
|
|
4
25
|
/** Everything a step executor needs about the scan that reached it. */
|
|
5
26
|
export interface StepContext {
|
|
6
27
|
scheme: ScanScheme;
|
|
7
28
|
rule: ScanRule;
|
|
8
29
|
parsed: ParsedScanCode;
|
|
30
|
+
/** The code as the station scanned it; absent when a choice re-derived the target. */
|
|
31
|
+
rawCode?: string;
|
|
9
32
|
scannedAt: string;
|
|
10
33
|
/** The effective actor — the acting (badged) user when a grant rode the request. */
|
|
11
34
|
auth: LTApiAuth;
|
|
@@ -13,9 +36,17 @@ export interface StepContext {
|
|
|
13
36
|
stationAuth: LTApiAuth;
|
|
14
37
|
/** True when `auth` came from an acting-identity grant. */
|
|
15
38
|
acting: boolean;
|
|
39
|
+
/** The grant behind `acting`; spent only when an act lands. */
|
|
40
|
+
grant?: GrantLedger;
|
|
41
|
+
/** The subject the station holds, when its pointer still checks out. */
|
|
42
|
+
subject?: HeldSubject;
|
|
43
|
+
/** The station sent a subject pointer that no longer checks out. */
|
|
44
|
+
subjectStale?: boolean;
|
|
16
45
|
}
|
|
17
46
|
export declare function targetFilter(step: ScanStep, ctx: StepContext): Record<string, any>;
|
|
18
47
|
export declare function templateContext(ctx: StepContext): scanCodeService.ScanTemplateContext;
|
|
48
|
+
/** The `{subject.x}` bag: the held row's metadata plus its id. */
|
|
49
|
+
export declare function subjectBag(row: LTEscalationRecord): Record<string, unknown>;
|
|
19
50
|
/**
|
|
20
51
|
* The metadata of the acting user's single live claim, or undefined when
|
|
21
52
|
* they hold none or more than one. One scoped list query, read before the
|
|
@@ -34,4 +65,17 @@ export declare function interpolatedMetadata(step: ScanStep, ctx: StepContext, t
|
|
|
34
65
|
export declare function executed(escalation: LTEscalationRecord | Record<string, any> | undefined, step: Pick<ScanStep, 'verb'>): LTApiResult<ScanExecuteResponse>;
|
|
35
66
|
export declare function forbidden(error?: string): LTApiResult<ScanExecuteResponse>;
|
|
36
67
|
export declare function conflict(error?: string): LTApiResult<ScanExecuteResponse>;
|
|
37
|
-
export declare function notPrimed(ctx: StepContext): LTApiResult<ScanExecuteResponse>;
|
|
68
|
+
export declare function notPrimed(ctx: StepContext, error?: string): LTApiResult<ScanExecuteResponse>;
|
|
69
|
+
/** Nothing was written; say why, and name what the step expected. */
|
|
70
|
+
export declare function refused(markdown: string, extra?: Partial<ScanExecuteResponse>): LTApiResult<ScanExecuteResponse>;
|
|
71
|
+
/**
|
|
72
|
+
* Interpolates a step's params, or falls through when a `{claim.…}` or
|
|
73
|
+
* `{item.…}` token has nothing to read: a literal token never reaches a row.
|
|
74
|
+
*/
|
|
75
|
+
export declare function templated<T>(step: ScanStep, ctx: StepContext, render: (tpl: scanCodeService.ScanTemplateContext) => T, item?: LTEscalationRecord): Promise<T | null>;
|
|
76
|
+
/**
|
|
77
|
+
* Attach the step's `done` copy to a write that landed. `tpl` carries the
|
|
78
|
+
* bags the copy may read (the container a subject step located, a fill's
|
|
79
|
+
* batch); an unreadable token renders empty rather than failing the act.
|
|
80
|
+
*/
|
|
81
|
+
export declare function withDone(result: LTApiResult<ScanExecuteResponse>, step: ScanStep, tpl: scanCodeService.ScanTemplateContext): LTApiResult<ScanExecuteResponse>;
|
|
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.targetFilter = targetFilter;
|
|
37
37
|
exports.templateContext = templateContext;
|
|
38
|
+
exports.subjectBag = subjectBag;
|
|
38
39
|
exports.liveClaimMetadata = liveClaimMetadata;
|
|
39
40
|
exports.stepTemplate = stepTemplate;
|
|
40
41
|
exports.provenance = provenance;
|
|
@@ -43,6 +44,9 @@ exports.executed = executed;
|
|
|
43
44
|
exports.forbidden = forbidden;
|
|
44
45
|
exports.conflict = conflict;
|
|
45
46
|
exports.notPrimed = notPrimed;
|
|
47
|
+
exports.refused = refused;
|
|
48
|
+
exports.templated = templated;
|
|
49
|
+
exports.withDone = withDone;
|
|
46
50
|
const scanCodeService = __importStar(require("../../services/scan-code"));
|
|
47
51
|
const escalationService = __importStar(require("../../services/escalation"));
|
|
48
52
|
const types_1 = require("../../types");
|
|
@@ -50,7 +54,17 @@ function targetFilter(step, ctx) {
|
|
|
50
54
|
return { [ctx.scheme.target_facet]: ctx.parsed.target, ...(step.query?.facets ?? {}) };
|
|
51
55
|
}
|
|
52
56
|
function templateContext(ctx) {
|
|
53
|
-
return {
|
|
57
|
+
return {
|
|
58
|
+
target: ctx.parsed.target,
|
|
59
|
+
category: ctx.parsed.category,
|
|
60
|
+
scannedAt: ctx.scannedAt,
|
|
61
|
+
code: ctx.parsed.raw ?? ctx.parsed.target,
|
|
62
|
+
...(ctx.subject ? { subject: subjectBag(ctx.subject.row) } : {}),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/** The `{subject.x}` bag: the held row's metadata plus its id. */
|
|
66
|
+
function subjectBag(row) {
|
|
67
|
+
return { ...(row.metadata ?? {}), id: row.id };
|
|
54
68
|
}
|
|
55
69
|
/**
|
|
56
70
|
* The metadata of the acting user's single live claim, or undefined when
|
|
@@ -102,13 +116,47 @@ function forbidden(error) {
|
|
|
102
116
|
function conflict(error) {
|
|
103
117
|
return { status: 200, data: { outcome: types_1.SCAN_OUTCOMES.CONFLICT, error } };
|
|
104
118
|
}
|
|
105
|
-
function notPrimed(ctx) {
|
|
119
|
+
function notPrimed(ctx, error) {
|
|
106
120
|
return {
|
|
107
121
|
status: 200,
|
|
108
122
|
data: {
|
|
109
123
|
outcome: types_1.SCAN_OUTCOMES.NOT_PRIMED,
|
|
110
124
|
notPrimed: ctx.rule.notPrimed,
|
|
111
|
-
|
|
125
|
+
replayable: true,
|
|
126
|
+
error: error ?? 'an acting identity is required — scan your badge',
|
|
112
127
|
},
|
|
113
128
|
};
|
|
114
129
|
}
|
|
130
|
+
/** Nothing was written; say why, and name what the step expected. */
|
|
131
|
+
function refused(markdown, extra = {}) {
|
|
132
|
+
return {
|
|
133
|
+
status: 200,
|
|
134
|
+
data: { outcome: types_1.SCAN_OUTCOMES.REFUSED, refusal: { markdown }, error: markdown, ...extra },
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Interpolates a step's params, or falls through when a `{claim.…}` or
|
|
139
|
+
* `{item.…}` token has nothing to read: a literal token never reaches a row.
|
|
140
|
+
*/
|
|
141
|
+
async function templated(step, ctx, render, item) {
|
|
142
|
+
const tpl = await stepTemplate(step, ctx, item);
|
|
143
|
+
try {
|
|
144
|
+
return render(tpl);
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
if (err instanceof scanCodeService.ScanTemplateError)
|
|
148
|
+
return null;
|
|
149
|
+
throw err;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Attach the step's `done` copy to a write that landed. `tpl` carries the
|
|
154
|
+
* bags the copy may read (the container a subject step located, a fill's
|
|
155
|
+
* batch); an unreadable token renders empty rather than failing the act.
|
|
156
|
+
*/
|
|
157
|
+
function withDone(result, step, tpl) {
|
|
158
|
+
const data = result.data;
|
|
159
|
+
if (!step.done || !data || data.outcome !== types_1.SCAN_OUTCOMES.EXECUTED || data.already || data.done)
|
|
160
|
+
return result;
|
|
161
|
+
return { ...result, data: { ...data, done: { markdown: scanCodeService.renderScanCopy(step.done.markdown, tpl) } } };
|
|
162
|
+
}
|
|
@@ -37,10 +37,15 @@ exports.executeScanCode = executeScanCode;
|
|
|
37
37
|
const scanCodeService = __importStar(require("../../services/scan-code"));
|
|
38
38
|
const identity_1 = require("./identity");
|
|
39
39
|
const context_1 = require("./context");
|
|
40
|
+
const grant_1 = require("./grant");
|
|
41
|
+
const hold_1 = require("./hold");
|
|
40
42
|
const locate_1 = require("./locate");
|
|
41
43
|
const present_1 = require("./present");
|
|
44
|
+
const subject_1 = require("./subject");
|
|
45
|
+
const verb_fill_1 = require("./verb-fill");
|
|
42
46
|
const verbs_1 = require("./verbs");
|
|
43
47
|
const types_1 = require("../../types");
|
|
48
|
+
const SUBJECT_STALE_MESSAGE = 'That one moved on. Scan it again.';
|
|
44
49
|
/**
|
|
45
50
|
* Execute a raw scan code: parse → load the rule → walk its steps in order.
|
|
46
51
|
* The first step whose condition matches performs its verb and answers; a
|
|
@@ -77,45 +82,57 @@ async function executeScanCode(input, auth) {
|
|
|
77
82
|
}
|
|
78
83
|
// 2a. Identity schemes are the badge layer — they mint, never walk steps.
|
|
79
84
|
if (scheme.kind === types_1.SCAN_SCHEME_KINDS.IDENTITY) {
|
|
80
|
-
return (0, identity_1.executeIdentityScan)(parsed, scheme, rule, input.previousActingToken
|
|
85
|
+
return (0, identity_1.executeIdentityScan)(parsed, scheme, rule, input.previousActingToken, {
|
|
86
|
+
userId: auth.userId,
|
|
87
|
+
stationRole: typeof input.stationRole === 'string' ? input.stationRole : undefined,
|
|
88
|
+
});
|
|
81
89
|
}
|
|
82
|
-
// 2b. A supplied acting grant is
|
|
83
|
-
// user's read scope
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
|
|
90
|
+
// 2b. A supplied acting grant is read up front (not spent): the acting
|
|
91
|
+
// user's read scope governs the locate as much as the mutation. A dead
|
|
92
|
+
// grant terminates loudly; silently degrading to the station identity
|
|
93
|
+
// would misattribute whatever follows.
|
|
94
|
+
const ctx = {
|
|
95
|
+
scheme, rule, parsed, rawCode: input.code.trim(), scannedAt: new Date().toISOString(),
|
|
96
|
+
auth, stationAuth: auth, acting: false,
|
|
97
|
+
};
|
|
88
98
|
if (input.actingToken) {
|
|
89
|
-
const
|
|
90
|
-
if (!
|
|
91
|
-
return {
|
|
92
|
-
status: 200,
|
|
93
|
-
data: {
|
|
94
|
-
outcome: types_1.SCAN_OUTCOMES.NOT_PRIMED,
|
|
95
|
-
parsed,
|
|
96
|
-
notPrimed: rule.notPrimed,
|
|
97
|
-
error: resolved.error,
|
|
98
|
-
},
|
|
99
|
-
};
|
|
99
|
+
const peeked = await (0, grant_1.peekGrant)(input.actingToken);
|
|
100
|
+
if (!peeked.ok) {
|
|
101
|
+
return { status: 200, data: { ...(0, context_1.notPrimed)(ctx, peeked.error).data, parsed } };
|
|
100
102
|
}
|
|
101
|
-
|
|
102
|
-
acting = true;
|
|
103
|
+
ctx.auth = peeked.auth;
|
|
104
|
+
ctx.acting = true;
|
|
105
|
+
ctx.grant = peeked.grant;
|
|
103
106
|
}
|
|
107
|
+
// 2c. The held subject, re-derived from the station's pointer
|
|
108
|
+
const held = await (0, subject_1.resolveSubject)(input.subject, schemes, auth);
|
|
109
|
+
if (held?.ok)
|
|
110
|
+
ctx.subject = held.subject;
|
|
111
|
+
else if (held)
|
|
112
|
+
ctx.subjectStale = true;
|
|
104
113
|
// 3. Walk the steps — first condition match wins
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const result = await executeStep(rule.steps[i], i, ctx);
|
|
111
|
-
if (result)
|
|
112
|
-
return decorate(result, ctx, i);
|
|
114
|
+
let result = null;
|
|
115
|
+
for (let i = 0; i < rule.steps.length && !result; i++) {
|
|
116
|
+
const stepResult = await executeStep(rule.steps[i], ctx);
|
|
117
|
+
if (stepResult)
|
|
118
|
+
result = decorate((0, context_1.withDone)(stepResult, rule.steps[i], (0, context_1.templateContext)(ctx)), ctx, i);
|
|
113
119
|
}
|
|
114
|
-
// 4. Nothing matched
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
120
|
+
// 4. Nothing matched: a stale subject, or the fallback screen
|
|
121
|
+
if (!result) {
|
|
122
|
+
result = ctx.subjectStale
|
|
123
|
+
? { status: 200, data: decorateData({ outcome: types_1.SCAN_OUTCOMES.SUBJECT_STALE, clearSubject: true, error: SUBJECT_STALE_MESSAGE }, ctx) }
|
|
124
|
+
: { status: 200, data: decorateData({ outcome: types_1.SCAN_OUTCOMES.NO_MATCH_FALLBACK, fallback: rule.fallback }, ctx) };
|
|
125
|
+
}
|
|
126
|
+
// 5. Settle the badge: refund a spend whose act did not land
|
|
127
|
+
const acting = await (0, grant_1.settleGrant)(ctx, result);
|
|
128
|
+
if (result.data && typeof result.data === 'object' && 'outcome' in result.data) {
|
|
129
|
+
result.data = {
|
|
130
|
+
...result.data,
|
|
131
|
+
...(acting ? { acting } : {}),
|
|
132
|
+
...(ctx.subjectStale ? { clearSubject: true } : {}),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
return result;
|
|
119
136
|
}
|
|
120
137
|
catch (err) {
|
|
121
138
|
return { status: 500, error: err.message };
|
|
@@ -139,17 +156,34 @@ function decorateData(data, ctx) {
|
|
|
139
156
|
},
|
|
140
157
|
};
|
|
141
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* A subject step runs only while a subject from one of its schemes is held,
|
|
161
|
+
* and, when it declares facets, only while the held row carries them.
|
|
162
|
+
*/
|
|
163
|
+
function subjectGateOpen(step, ctx) {
|
|
164
|
+
if (!step.subject)
|
|
165
|
+
return true;
|
|
166
|
+
if (!ctx.subject || !step.subject.schemes.includes(ctx.subject.scheme.version))
|
|
167
|
+
return false;
|
|
168
|
+
const meta = (ctx.subject.row.metadata ?? {});
|
|
169
|
+
return Object.entries(step.subject.facets ?? {}).every(([key, value]) => meta[key] === value);
|
|
170
|
+
}
|
|
142
171
|
/**
|
|
143
172
|
* Execute one step. Returns null when the step's condition matched nothing
|
|
144
173
|
* (fall through) and an LTApiResult for every terminal outcome.
|
|
145
174
|
*/
|
|
146
|
-
async function executeStep(step,
|
|
175
|
+
async function executeStep(step, ctx) {
|
|
176
|
+
if (!subjectGateOpen(step, ctx))
|
|
177
|
+
return null;
|
|
147
178
|
// The identity pre-condition: the effective actor must be a real acting
|
|
148
179
|
// identity — a badge grant, or an authenticated user whose own write scope
|
|
149
180
|
// covers the step. A write-incapable shared account can never self-satisfy,
|
|
150
181
|
// so the outcome is the rule's "scan your badge" screen, never a silent or
|
|
151
182
|
// misattributed action.
|
|
152
|
-
|
|
183
|
+
// A subject step checks the pairing first and asks for the badge only when
|
|
184
|
+
// the pairing is right (see identityGate), so a wrong container is named
|
|
185
|
+
// at once.
|
|
186
|
+
if (step.requireActingIdentity && !step.subject && !(await (0, identity_1.actingIdentitySatisfied)(step, ctx))) {
|
|
153
187
|
return (0, context_1.notPrimed)(ctx);
|
|
154
188
|
}
|
|
155
189
|
// Confirm steps and read verbs only locate — mutation happens after the
|
|
@@ -160,6 +194,8 @@ async function executeStep(step, index, ctx) {
|
|
|
160
194
|
switch (step.verb) {
|
|
161
195
|
case types_1.SCAN_VERBS.PRESENT:
|
|
162
196
|
return (0, present_1.presentStep)(step, ctx);
|
|
197
|
+
case types_1.SCAN_VERBS.HOLD:
|
|
198
|
+
return (0, hold_1.holdStep)(step, ctx);
|
|
163
199
|
case types_1.SCAN_VERBS.CLAIM:
|
|
164
200
|
case types_1.SCAN_VERBS.CLAIM_SHOW_DETAIL:
|
|
165
201
|
return (0, verbs_1.claimStep)(step, ctx);
|
|
@@ -173,6 +209,8 @@ async function executeStep(step, index, ctx) {
|
|
|
173
209
|
return (0, verbs_1.cancelStep)(step, ctx);
|
|
174
210
|
case types_1.SCAN_VERBS.ACCUMULATE:
|
|
175
211
|
return (0, verbs_1.accumulateStep)(step, ctx);
|
|
212
|
+
case types_1.SCAN_VERBS.FILL:
|
|
213
|
+
return (0, verb_fill_1.fillStep)(step, ctx);
|
|
176
214
|
default:
|
|
177
215
|
throw new Error(`unknown scan verb "${step.verb}"`);
|
|
178
216
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type ScanExecuteResponse, type ScanStep } from '../../types';
|
|
2
|
+
import type { LTApiAuth, LTApiResult } from '../../types/sdk';
|
|
3
|
+
import { type GrantLedger, type StepContext } from './context';
|
|
4
|
+
export type PeekResult = {
|
|
5
|
+
ok: true;
|
|
6
|
+
auth: LTApiAuth;
|
|
7
|
+
grant: GrantLedger;
|
|
8
|
+
} | {
|
|
9
|
+
ok: false;
|
|
10
|
+
error: string;
|
|
11
|
+
};
|
|
12
|
+
/** Read the grant without spending it. */
|
|
13
|
+
export declare function peekGrant(token: string): Promise<PeekResult>;
|
|
14
|
+
/**
|
|
15
|
+
* Spend the request's grant before a write. Returns null when the act may
|
|
16
|
+
* proceed (spent now, spent earlier in this request, or no grant rides it),
|
|
17
|
+
* and the not-primed result when the grant cannot cover this act. `ref` is
|
|
18
|
+
* the held subject the act lands on.
|
|
19
|
+
*/
|
|
20
|
+
export declare function spendGrant(ctx: StepContext, ref?: string | null): Promise<LTApiResult<ScanExecuteResponse> | null>;
|
|
21
|
+
/** The step's identity requirement, checked at the moment it is about to act. */
|
|
22
|
+
export declare function identityGate(step: ScanStep, ctx: StepContext): Promise<LTApiResult<ScanExecuteResponse> | null>;
|
|
23
|
+
/**
|
|
24
|
+
* Close the request's books on the grant: refund a spend whose act did not
|
|
25
|
+
* land, and report the grant's state for the client to keep or retire.
|
|
26
|
+
*/
|
|
27
|
+
export declare function settleGrant(ctx: StepContext, result: LTApiResult<ScanExecuteResponse> | null): Promise<ScanExecuteResponse['acting'] | undefined>;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.peekGrant = peekGrant;
|
|
4
|
+
exports.spendGrant = spendGrant;
|
|
5
|
+
exports.identityGate = identityGate;
|
|
6
|
+
exports.settleGrant = settleGrant;
|
|
7
|
+
const acting_identity_1 = require("../../services/iam/acting-identity");
|
|
8
|
+
const types_1 = require("../../types");
|
|
9
|
+
const context_1 = require("./context");
|
|
10
|
+
const identity_1 = require("./identity");
|
|
11
|
+
/** Read the grant without spending it. */
|
|
12
|
+
async function peekGrant(token) {
|
|
13
|
+
const peeked = await (0, acting_identity_1.peekActingAuth)(token);
|
|
14
|
+
if (!peeked.ok)
|
|
15
|
+
return peeked;
|
|
16
|
+
return {
|
|
17
|
+
ok: true,
|
|
18
|
+
auth: peeked.auth,
|
|
19
|
+
grant: { token, peeked: { remaining: peeked.grant.remaining, bound: peeked.grant.bound }, spent: null },
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Spend the request's grant before a write. Returns null when the act may
|
|
24
|
+
* proceed (spent now, spent earlier in this request, or no grant rides it),
|
|
25
|
+
* and the not-primed result when the grant cannot cover this act. `ref` is
|
|
26
|
+
* the held subject the act lands on.
|
|
27
|
+
*/
|
|
28
|
+
async function spendGrant(ctx, ref = ctx.subject?.row.id ?? null) {
|
|
29
|
+
const grant = ctx.grant;
|
|
30
|
+
if (!grant || grant.spent)
|
|
31
|
+
return null;
|
|
32
|
+
const consumed = await (0, acting_identity_1.consumeActingGrant)(grant.token, ref);
|
|
33
|
+
if (!consumed.ok)
|
|
34
|
+
return (0, context_1.notPrimed)(ctx, consumed.error);
|
|
35
|
+
grant.spent = { remaining: consumed.grant.remaining, bound: consumed.grant.bound };
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
/** The step's identity requirement, checked at the moment it is about to act. */
|
|
39
|
+
async function identityGate(step, ctx) {
|
|
40
|
+
if (!step.requireActingIdentity || (await (0, identity_1.actingIdentitySatisfied)(step, ctx)))
|
|
41
|
+
return null;
|
|
42
|
+
return (0, context_1.notPrimed)(ctx);
|
|
43
|
+
}
|
|
44
|
+
/** True when the result is a write that landed. */
|
|
45
|
+
function landed(result) {
|
|
46
|
+
const data = result?.data;
|
|
47
|
+
return !!data && data.outcome === types_1.SCAN_OUTCOMES.EXECUTED
|
|
48
|
+
&& !!data.verb && types_1.SCAN_MUTATING_VERBS.includes(data.verb) && !data.already;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Close the request's books on the grant: refund a spend whose act did not
|
|
52
|
+
* land, and report the grant's state for the client to keep or retire.
|
|
53
|
+
*/
|
|
54
|
+
async function settleGrant(ctx, result) {
|
|
55
|
+
const grant = ctx.grant;
|
|
56
|
+
if (!grant)
|
|
57
|
+
return undefined;
|
|
58
|
+
if (grant.spent && !landed(result)) {
|
|
59
|
+
// Spending a bound grant cost nothing; spending an unbound one counted
|
|
60
|
+
// a use and may have bound it, so both come back.
|
|
61
|
+
if (!grant.peeked.bound)
|
|
62
|
+
await (0, acting_identity_1.refundActingGrant)(grant.token, grant.spent.bound);
|
|
63
|
+
grant.spent = null;
|
|
64
|
+
}
|
|
65
|
+
const state = grant.spent ?? grant.peeked;
|
|
66
|
+
return { consumed: !!grant.spent, remaining: state.remaining, bound: state.bound };
|
|
67
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type LTEscalationRecord, type ScanExecuteResponse, type ScanStep } from '../../types';
|
|
2
|
+
import type { LTApiResult } from '../../types/sdk';
|
|
3
|
+
import { type StepContext } from './context';
|
|
4
|
+
/**
|
|
5
|
+
* HOLD: locate the row and hand the station a subject to hold. The next
|
|
6
|
+
* scans (the badge, then the container) act on it. Writes nothing and spends
|
|
7
|
+
* no badge use. A live claim by someone else is reported, not refused: the
|
|
8
|
+
* bench says whose it is, and the act decides.
|
|
9
|
+
*/
|
|
10
|
+
export declare function holdStep(step: ScanStep, ctx: StepContext, located?: LTEscalationRecord): Promise<LTApiResult<ScanExecuteResponse> | null>;
|
|
@@ -0,0 +1,98 @@
|
|
|
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
|
+
exports.holdStep = holdStep;
|
|
37
|
+
const scanCodeService = __importStar(require("../../services/scan-code"));
|
|
38
|
+
const types_1 = require("../../types");
|
|
39
|
+
const context_1 = require("./context");
|
|
40
|
+
const locate_1 = require("./locate");
|
|
41
|
+
const subject_1 = require("./subject");
|
|
42
|
+
/**
|
|
43
|
+
* HOLD: locate the row and hand the station a subject to hold. The next
|
|
44
|
+
* scans (the badge, then the container) act on it. Writes nothing and spends
|
|
45
|
+
* no badge use. A live claim by someone else is reported, not refused: the
|
|
46
|
+
* bench says whose it is, and the act decides.
|
|
47
|
+
*/
|
|
48
|
+
async function holdStep(step, ctx, located) {
|
|
49
|
+
const row = located ?? (await (0, locate_1.locateForStep)(step, ctx, 1))?.escalations[0];
|
|
50
|
+
if (!row)
|
|
51
|
+
return null;
|
|
52
|
+
return {
|
|
53
|
+
status: 200,
|
|
54
|
+
data: {
|
|
55
|
+
outcome: types_1.SCAN_OUTCOMES.HELD,
|
|
56
|
+
verb: step.verb,
|
|
57
|
+
escalation: row,
|
|
58
|
+
subject: await heldSubject(step, ctx, row),
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
async function heldSubject(step, ctx, row) {
|
|
63
|
+
const hold = step.params?.hold ?? {};
|
|
64
|
+
const tpl = { ...(0, context_1.templateContext)(ctx), item: row.metadata ?? {} };
|
|
65
|
+
const ttl = hold.ttlSeconds ?? types_1.SCAN_HOLD_TTL_DEFAULT_SECONDS;
|
|
66
|
+
const claimant = await (0, subject_1.claimedByOther)(row, ctx.acting ? ctx.auth.userId : null);
|
|
67
|
+
return {
|
|
68
|
+
code: ctx.rawCode ?? holdCode(ctx),
|
|
69
|
+
escalationId: row.id,
|
|
70
|
+
label: scanCodeService.renderScanCopy(hold.label ?? types_1.SCAN_TEMPLATE_TOKENS.TARGET, tpl),
|
|
71
|
+
...optionalCopy('headline', hold.headline, tpl),
|
|
72
|
+
...optionalCopy('subline', hold.subline, tpl),
|
|
73
|
+
expiresAt: new Date(Date.now() + ttl * 1000).toISOString(),
|
|
74
|
+
...(hold.expect ? {
|
|
75
|
+
expect: {
|
|
76
|
+
schemes: hold.expect.schemes,
|
|
77
|
+
...(hold.expect.prompt ? { prompt: scanCodeService.renderScanCopy(hold.expect.prompt, tpl) } : {}),
|
|
78
|
+
},
|
|
79
|
+
} : {}),
|
|
80
|
+
...(claimant ? { claimedBy: claimant } : {}),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/** The canonical code for the held row, as the station would scan it. */
|
|
84
|
+
function holdCode(ctx) {
|
|
85
|
+
const { scheme, parsed } = ctx;
|
|
86
|
+
if (scheme.encoding === 'delimited') {
|
|
87
|
+
const d = scheme.delimiter;
|
|
88
|
+
return `${parsed.version}${d}${parsed.category}${d}${parsed.target}`;
|
|
89
|
+
}
|
|
90
|
+
return `${parsed.version}${parsed.category}${parsed.target}`;
|
|
91
|
+
}
|
|
92
|
+
/** A rendered line, or nothing when the template is absent or renders empty. */
|
|
93
|
+
function optionalCopy(key, template, tpl) {
|
|
94
|
+
if (!template)
|
|
95
|
+
return {};
|
|
96
|
+
const text = scanCodeService.renderScanCopy(template, tpl).trim();
|
|
97
|
+
return text ? { [key]: text } : {};
|
|
98
|
+
}
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { type ParsedScanCode, type ScanExecuteResponse, type ScanRule, type ScanScheme, type ScanStep } from '../../types';
|
|
2
2
|
import type { LTApiResult } from '../../types/sdk';
|
|
3
3
|
import type { StepContext } from './context';
|
|
4
|
-
export { resolveActingAuth, type ActingAuthResult } from '../../services/iam/acting-identity';
|
|
4
|
+
export { resolveActingAuth, peekActingAuth, type ActingAuthResult } from '../../services/iam/acting-identity';
|
|
5
5
|
/**
|
|
6
6
|
* Resolve an identity scan: badge → user → minted acting grant.
|
|
7
7
|
* Identity schemes never walk steps; the rule's fallback is the
|
|
8
8
|
* unknown-badge screen.
|
|
9
9
|
*/
|
|
10
|
-
export declare function executeIdentityScan(parsed: ParsedScanCode, scheme: ScanScheme, rule: ScanRule, previousActingToken?: string
|
|
10
|
+
export declare function executeIdentityScan(parsed: ParsedScanCode, scheme: ScanScheme, rule: ScanRule, previousActingToken?: string, station?: {
|
|
11
|
+
userId: string;
|
|
12
|
+
stationRole?: string;
|
|
13
|
+
}): Promise<LTApiResult<ScanExecuteResponse>>;
|
|
11
14
|
/**
|
|
12
15
|
* The identity pre-condition's satisfaction test. A primed grant always
|
|
13
16
|
* satisfies; without one, the authenticated user satisfies only when their
|
|
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.resolveActingAuth = void 0;
|
|
36
|
+
exports.peekActingAuth = exports.resolveActingAuth = void 0;
|
|
37
37
|
exports.executeIdentityScan = executeIdentityScan;
|
|
38
38
|
exports.actingIdentitySatisfied = actingIdentitySatisfied;
|
|
39
39
|
const userService = __importStar(require("../../services/user"));
|
|
@@ -41,8 +41,10 @@ const ephemeral_1 = require("../../services/iam/ephemeral");
|
|
|
41
41
|
const metadata_1 = require("../escalations/metadata");
|
|
42
42
|
const helpers_1 = require("../escalations/helpers");
|
|
43
43
|
const types_1 = require("../../types");
|
|
44
|
+
const badge_policy_1 = require("./badge-policy");
|
|
44
45
|
var acting_identity_1 = require("../../services/iam/acting-identity");
|
|
45
46
|
Object.defineProperty(exports, "resolveActingAuth", { enumerable: true, get: function () { return acting_identity_1.resolveActingAuth; } });
|
|
47
|
+
Object.defineProperty(exports, "peekActingAuth", { enumerable: true, get: function () { return acting_identity_1.peekActingAuth; } });
|
|
46
48
|
// ── Acting identity — the badge layer over the scan surface ────────────────
|
|
47
49
|
//
|
|
48
50
|
// A shared station device signs in as an ordinary read-capable account; the
|
|
@@ -58,8 +60,18 @@ Object.defineProperty(exports, "resolveActingAuth", { enumerable: true, get: fun
|
|
|
58
60
|
* Identity schemes never walk steps; the rule's fallback is the
|
|
59
61
|
* unknown-badge screen.
|
|
60
62
|
*/
|
|
61
|
-
async function executeIdentityScan(parsed, scheme, rule, previousActingToken) {
|
|
62
|
-
|
|
63
|
+
async function executeIdentityScan(parsed, scheme, rule, previousActingToken, station) {
|
|
64
|
+
// Two users bound to one badge is a configuration fault: refuse the badge
|
|
65
|
+
// and name the fault, never pick one of them.
|
|
66
|
+
let user;
|
|
67
|
+
let unknownReason = 'badge not recognized';
|
|
68
|
+
try {
|
|
69
|
+
user = await userService.getUserByMetadataValue(scheme.target_facet, parsed.target);
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
user = null;
|
|
73
|
+
unknownReason = `badge is bound to more than one person: ${err.message}`;
|
|
74
|
+
}
|
|
63
75
|
if (!user) {
|
|
64
76
|
return {
|
|
65
77
|
status: 200,
|
|
@@ -68,7 +80,7 @@ async function executeIdentityScan(parsed, scheme, rule, previousActingToken) {
|
|
|
68
80
|
parsed,
|
|
69
81
|
rule: { schemeVersion: rule.scheme_version, category: rule.category, name: rule.name },
|
|
70
82
|
fallback: rule.fallback,
|
|
71
|
-
error:
|
|
83
|
+
error: unknownReason,
|
|
72
84
|
},
|
|
73
85
|
};
|
|
74
86
|
}
|
|
@@ -79,12 +91,17 @@ async function executeIdentityScan(parsed, scheme, rule, previousActingToken) {
|
|
|
79
91
|
await (0, ephemeral_1.revokeEphemeral)(prev.uuid).catch(() => { });
|
|
80
92
|
}
|
|
81
93
|
}
|
|
94
|
+
// The station decides the policy: its role's badge_grant, else the scheme's.
|
|
95
|
+
const policy = station
|
|
96
|
+
? await (0, badge_policy_1.stationGrantPolicy)(scheme, station.userId, station.stationRole)
|
|
97
|
+
: { ttlSeconds: scheme.grant_ttl_seconds ?? 0, maxUses: scheme.grant_max_uses ?? 0, scope: scheme.grant_scope ?? types_1.SCAN_GRANT_SCOPES.ACTION };
|
|
82
98
|
const uuid = await (0, ephemeral_1.storeEphemeral)(user.id, {
|
|
83
|
-
ttlSeconds:
|
|
84
|
-
maxUses:
|
|
99
|
+
ttlSeconds: policy.ttlSeconds || undefined,
|
|
100
|
+
maxUses: policy.maxUses,
|
|
85
101
|
label: types_1.ACTING_IDENTITY_LABEL,
|
|
102
|
+
bindOnUse: policy.scope === types_1.SCAN_GRANT_SCOPES.SUBJECT,
|
|
86
103
|
});
|
|
87
|
-
const expiresAt = new Date(Date.now() +
|
|
104
|
+
const expiresAt = new Date(Date.now() + policy.ttlSeconds * 1000).toISOString();
|
|
88
105
|
return {
|
|
89
106
|
status: 200,
|
|
90
107
|
data: {
|
|
@@ -94,7 +111,8 @@ async function executeIdentityScan(parsed, scheme, rule, previousActingToken) {
|
|
|
94
111
|
actor: { id: user.id, displayName: user.display_name || user.external_id },
|
|
95
112
|
actingToken: (0, ephemeral_1.formatEphemeralToken)(uuid, types_1.ACTING_IDENTITY_LABEL),
|
|
96
113
|
expiresAt,
|
|
97
|
-
maxUses:
|
|
114
|
+
maxUses: policy.maxUses,
|
|
115
|
+
grantScope: policy.scope,
|
|
98
116
|
},
|
|
99
117
|
};
|
|
100
118
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type LTEscalationRecord, type ScanScheme, type ScanSubjectRef } from '../../types';
|
|
2
|
+
import type { LTApiAuth } from '../../types/sdk';
|
|
3
|
+
import type { HeldSubject } from './context';
|
|
4
|
+
export type SubjectResult = {
|
|
5
|
+
ok: true;
|
|
6
|
+
subject: HeldSubject;
|
|
7
|
+
} | {
|
|
8
|
+
ok: false;
|
|
9
|
+
};
|
|
10
|
+
export declare function resolveSubject(ref: ScanSubjectRef | undefined, schemes: ScanScheme[], stationAuth: LTApiAuth): Promise<SubjectResult | null>;
|
|
11
|
+
/** Who holds a live claim on the row, when that is someone other than `actorId`. */
|
|
12
|
+
export declare function claimedByOther(row: LTEscalationRecord, actorId: string | null): Promise<{
|
|
13
|
+
id: string;
|
|
14
|
+
displayName: string;
|
|
15
|
+
} | null>;
|