@hotmeshio/long-tail 0.22.1 → 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.js +38 -19
- 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 +16 -10
- 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 +1 -21
- package/build/api/scan-codes/verbs.js +26 -115
- package/build/index.d.ts +1 -0
- package/build/index.js +8 -2
- package/build/lib/db/schemas/037_scan_gtin_and_subject_grants.sql +27 -0
- 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/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/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 +94 -18
- package/build/services/scan-code/write.d.ts +1 -0
- package/build/services/scan-code/write.js +9 -3
- 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/system/mcp-servers/admin/scan-codes.js +10 -4
- package/build/system/mcp-servers/admin/schemas.d.ts +754 -23
- package/build/system/mcp-servers/admin/schemas.js +57 -4
- package/build/system/mcp-servers/human-queue-schemas.d.ts +6 -6
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/escalation.d.ts +2 -0
- package/build/types/escalation.js +3 -1
- package/build/types/index.d.ts +2 -2
- 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} +72 -11
- 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-BbWve-Ax.js → AdminDashboard-DBW12qQt.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-BbWve-Ax.js.map → AdminDashboard-DBW12qQt.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-M-9eTKhP.js → AgentConfigPage-CmHv8U9M.js} +2 -2
- package/dashboard/dist/assets/{AgentConfigPage-M-9eTKhP.js.map → AgentConfigPage-CmHv8U9M.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-CsakSlx5.js → AgentDetailPage-D1scIbz-.js} +3 -3
- package/dashboard/dist/assets/{AgentDetailPage-CsakSlx5.js.map → AgentDetailPage-D1scIbz-.js.map} +1 -1
- package/dashboard/dist/assets/{AgentsPage-Cj_cRTT1.js → AgentsPage-BA_ai9HJ.js} +2 -2
- package/dashboard/dist/assets/{AgentsPage-Cj_cRTT1.js.map → AgentsPage-BA_ai9HJ.js.map} +1 -1
- package/dashboard/dist/assets/{AvailableEscalationsPage-BXJmMBM1.js → AvailableEscalationsPage-C2_5aEFW.js} +2 -2
- package/dashboard/dist/assets/{AvailableEscalationsPage-BXJmMBM1.js.map → AvailableEscalationsPage-C2_5aEFW.js.map} +1 -1
- package/dashboard/dist/assets/{BotPicker-CGB16rYU.js → BotPicker-BZo4Kp4a.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-CGB16rYU.js.map → BotPicker-BZo4Kp4a.js.map} +1 -1
- package/dashboard/dist/assets/{BulkAssignModal-MjxcU7N1.js → BulkAssignModal-BFhyxY2T.js} +2 -2
- package/dashboard/dist/assets/{BulkAssignModal-MjxcU7N1.js.map → BulkAssignModal-BFhyxY2T.js.map} +1 -1
- package/dashboard/dist/assets/CapabilitiesPage-CvOX6vAc.js +2 -0
- package/dashboard/dist/assets/{CapabilitiesPage-BxadotXn.js.map → CapabilitiesPage-CvOX6vAc.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-BBNpP-6h.js → CollapsibleSection-GCJsV9Oq.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-BBNpP-6h.js.map → CollapsibleSection-GCJsV9Oq.js.map} +1 -1
- package/dashboard/dist/assets/{ConfirmDeleteModal-D_kAbT_D.js → ConfirmDeleteModal-CAgYLcef.js} +2 -2
- package/dashboard/dist/assets/{ConfirmDeleteModal-D_kAbT_D.js.map → ConfirmDeleteModal-CAgYLcef.js.map} +1 -1
- package/dashboard/dist/assets/CountdownTimer-Dik2z0M_.js +2 -0
- package/dashboard/dist/assets/{CountdownTimer-CI_JOAvk.js.map → CountdownTimer-Dik2z0M_.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialsPage-C9OA1Q2J.js → CredentialsPage-twd2xCOW.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-C9OA1Q2J.js.map → CredentialsPage-twd2xCOW.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-sxLLBf2I.js → CronLabel-DdnIuudX.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-sxLLBf2I.js.map → CronLabel-DdnIuudX.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-jH9m8Dgl.js → ElapsedCell-DCctVv5R.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-jH9m8Dgl.js.map → ElapsedCell-DCctVv5R.js.map} +1 -1
- package/dashboard/dist/assets/{EntityTimelinePanel-Dl3Nr2kk.js → EntityTimelinePanel-CMnskyWv.js} +2 -2
- package/dashboard/dist/assets/{EntityTimelinePanel-Dl3Nr2kk.js.map → EntityTimelinePanel-CMnskyWv.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationListSchemaPage-DAK6It5J.js → EscalationListSchemaPage-VfCn6WDb.js} +3 -3
- package/dashboard/dist/assets/{EscalationListSchemaPage-DAK6It5J.js.map → EscalationListSchemaPage-VfCn6WDb.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationListView-CAHbdxKR.js → EscalationListView-CGQZxcC-.js} +2 -2
- package/dashboard/dist/assets/{EscalationListView-CAHbdxKR.js.map → EscalationListView-CGQZxcC-.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationSchemaPage-DotfAMCL.js → EscalationSchemaPage-BX0tx-PM.js} +3 -3
- package/dashboard/dist/assets/{EscalationSchemaPage-DotfAMCL.js.map → EscalationSchemaPage-BX0tx-PM.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationTimeline-DqmFydnU.js → EscalationTimeline-DKoSM56J.js} +2 -2
- package/dashboard/dist/assets/{EscalationTimeline-DqmFydnU.js.map → EscalationTimeline-DKoSM56J.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationTitleSelect-BpRquguO.js → EscalationTitleSelect-DWGLBOmS.js} +2 -2
- package/dashboard/dist/assets/{EscalationTitleSelect-BpRquguO.js.map → EscalationTitleSelect-DWGLBOmS.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-DtGOqnP4.js → EscalationsOverview-C2XoguaA.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-DtGOqnP4.js.map → EscalationsOverview-C2XoguaA.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-DSHqKyX2.js → EventTable-CBUWq7--.js} +2 -2
- package/dashboard/dist/assets/{EventTable-DSHqKyX2.js.map → EventTable-CBUWq7--.js.map} +1 -1
- package/dashboard/dist/assets/{FilterBar-Dxd0wNSW.js → FilterBar-8IdbleZ9.js} +2 -2
- package/dashboard/dist/assets/{FilterBar-Dxd0wNSW.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-ChqqGkro.js → GraphInvokePage-CUvoPzsW.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-ChqqGkro.js.map → GraphInvokePage-CUvoPzsW.js.map} +1 -1
- package/dashboard/dist/assets/{HomePage-ByKesG8w.js → HomePage-BP7v9GLJ.js} +2 -2
- package/dashboard/dist/assets/{HomePage-ByKesG8w.js.map → HomePage-BP7v9GLJ.js.map} +1 -1
- package/dashboard/dist/assets/{ListToolbar-Ddz_S2av.js → ListToolbar-Cnacuwoy.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-Ddz_S2av.js.map → ListToolbar-Cnacuwoy.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-CVe13tEv.js → McpOverview-C2JoNoDA.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-CVe13tEv.js.map → McpOverview-C2JoNoDA.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-BQYF2Mjq.js → McpQueryDetailPage-C_nih0w-.js} +2 -2
- package/dashboard/dist/assets/{McpQueryDetailPage-BQYF2Mjq.js.map → McpQueryDetailPage-C_nih0w-.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryPage-DZi5lm7s.js → McpQueryPage-U_wNXow2.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-DZi5lm7s.js.map → McpQueryPage-U_wNXow2.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunDetailPage-DreARTE1.js → McpRunDetailPage-DtKoJq6J.js} +2 -2
- package/dashboard/dist/assets/{McpRunDetailPage-DreARTE1.js.map → McpRunDetailPage-DtKoJq6J.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-DmO0YVhT.js → McpRunsPage-CnYtfGhf.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-DmO0YVhT.js.map → McpRunsPage-CnYtfGhf.js.map} +1 -1
- package/dashboard/dist/assets/{OperationsPage-DpjCO85T.js → OperationsPage-C7hupIer.js} +2 -2
- package/dashboard/dist/assets/{OperationsPage-DpjCO85T.js.map → OperationsPage-C7hupIer.js.map} +1 -1
- package/dashboard/dist/assets/{OperatorDashboard-Vv_MEBkv.js → OperatorDashboard-fVuLn2D5.js} +2 -2
- package/dashboard/dist/assets/{OperatorDashboard-Vv_MEBkv.js.map → OperatorDashboard-fVuLn2D5.js.map} +1 -1
- package/dashboard/dist/assets/{PersonaDetailPage-CW-2uBHY.js → PersonaDetailPage-C-4o8lPw.js} +2 -2
- package/dashboard/dist/assets/{PersonaDetailPage-CW-2uBHY.js.map → PersonaDetailPage-C-4o8lPw.js.map} +1 -1
- package/dashboard/dist/assets/{PersonasPage-CO6yYQdm.js → PersonasPage-BL1FwLmv.js} +2 -2
- package/dashboard/dist/assets/{PersonasPage-CO6yYQdm.js.map → PersonasPage-BL1FwLmv.js.map} +1 -1
- package/dashboard/dist/assets/{PortalPage-DcNqhBlg.js → PortalPage-tJG5sgb1.js} +2 -2
- package/dashboard/dist/assets/{PortalPage-DcNqhBlg.js.map → PortalPage-tJG5sgb1.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessDetailPage-BuipGZcC.js → ProcessDetailPage-Dz_jY4Yt.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-BuipGZcC.js.map → ProcessDetailPage-Dz_jY4Yt.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-D9DYntvl.js → ProcessesListPage-Cbn9cter.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-D9DYntvl.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/{RolesPage-0QJOBSzF.js → RolesPage-NwmMvZFa.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-0QJOBSzF.js.map → RolesPage-NwmMvZFa.js.map} +1 -1
- package/dashboard/dist/assets/{RunAsSelector-Dh4lyyRo.js → RunAsSelector-tgEooTyU.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-Dh4lyyRo.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/{StickyPagination-BSUyf5ja.js → StickyPagination-CsTI_gvJ.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-BSUyf5ja.js.map → StickyPagination-CsTI_gvJ.js.map} +1 -1
- package/dashboard/dist/assets/{StreamMessageDetail--tp7l2Sd.js → StreamMessageDetail-auRlvjTh.js} +2 -2
- package/dashboard/dist/assets/{StreamMessageDetail--tp7l2Sd.js.map → StreamMessageDetail-auRlvjTh.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-CxBZ2THh.js → SwimlaneTimeline-BLoVHYAd.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-CxBZ2THh.js.map → SwimlaneTimeline-BLoVHYAd.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-BJ1QrmPH.js → TaskDetailPage-BPsZ1bK_.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-BJ1QrmPH.js.map → TaskDetailPage-BPsZ1bK_.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-5BydGWmt.js → TasksListPage-BNGM74yT.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-5BydGWmt.js.map → TasksListPage-BNGM74yT.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-CCnz84Y4.js → TimeAgo-BnAHXGK7.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-CCnz84Y4.js.map → TimeAgo-BnAHXGK7.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-D0ru7Lya.js → TimestampCell-J4yae6mc.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-D0ru7Lya.js.map → TimestampCell-J4yae6mc.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-3Kpofmen.js → ToolTestPanel-BdzzgXDu.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-3Kpofmen.js.map → ToolTestPanel-BdzzgXDu.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-BaBXD_AK.js → TopicDetailPage-DJKg8lb7.js} +2 -2
- package/dashboard/dist/assets/{TopicDetailPage-BaBXD_AK.js.map → TopicDetailPage-DJKg8lb7.js.map} +1 -1
- package/dashboard/dist/assets/{TopicsPage-Cnm1AAjh.js → TopicsPage-DQV0WxG6.js} +2 -2
- package/dashboard/dist/assets/{TopicsPage-Cnm1AAjh.js.map → TopicsPage-DQV0WxG6.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-CXsdPiMZ.js → UserName-Ct09nGh5.js} +2 -2
- package/dashboard/dist/assets/{UserName-CXsdPiMZ.js.map → UserName-Ct09nGh5.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowExecutionPage-zx3AUJFd.js → WorkflowExecutionPage-B5WJOsee.js} +2 -2
- package/dashboard/dist/assets/{WorkflowExecutionPage-zx3AUJFd.js.map → WorkflowExecutionPage-B5WJOsee.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsDashboard-DfAGK1l7.js → WorkflowsDashboard-Hc87TRgD.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-DfAGK1l7.js.map → WorkflowsDashboard-Hc87TRgD.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-QIYvoa13.js → WorkflowsOverview-CJQbyOj-.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-QIYvoa13.js.map → WorkflowsOverview-CJQbyOj-.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-DGgO3hyB.js → YamlWorkflowDetailPage-BMeED677.js} +8 -8
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-DGgO3hyB.js.map → YamlWorkflowDetailPage-BMeED677.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-CEsHm0B9.js → YamlWorkflowsPage-BMMg0Id6.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-CEsHm0B9.js.map → YamlWorkflowsPage-BMMg0Id6.js.map} +1 -1
- package/dashboard/dist/assets/{agents-v_HH3Rji.js → agents-CdFkgFvg.js} +2 -2
- package/dashboard/dist/assets/{agents-v_HH3Rji.js.map → agents-CdFkgFvg.js.map} +1 -1
- package/dashboard/dist/assets/{bots-bwvWYrXz.js → bots-Mj3LHWWg.js} +2 -2
- package/dashboard/dist/assets/{bots-bwvWYrXz.js.map → bots-Mj3LHWWg.js.map} +1 -1
- package/dashboard/dist/assets/{capabilities-D4vaw_nQ.js → capabilities-Dw1ObK2-.js} +2 -2
- package/dashboard/dist/assets/{capabilities-D4vaw_nQ.js.map → capabilities-Dw1ObK2-.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-CiiZ6LJF.js → controlplane-DcNE1APv.js} +2 -2
- package/dashboard/dist/assets/{controlplane-CiiZ6LJF.js.map → controlplane-DcNE1APv.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-columns-Dv-MB3eC.js → escalation-columns-D364Trpy.js} +2 -2
- package/dashboard/dist/assets/{escalation-columns-Dv-MB3eC.js.map → escalation-columns-D364Trpy.js.map} +1 -1
- package/dashboard/dist/assets/{index-IJmtbuLh.js → index-B3veJ698.js} +2 -2
- package/dashboard/dist/assets/{index-IJmtbuLh.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-D2VKBMng.js → index-BRGTmoYY.js} +2 -2
- package/dashboard/dist/assets/{index-D2VKBMng.js.map → index-BRGTmoYY.js.map} +1 -1
- package/dashboard/dist/assets/{index-C4Lce2ET.js → index-Bd6-KmBE.js} +3 -3
- package/dashboard/dist/assets/{index-C4Lce2ET.js.map → index-Bd6-KmBE.js.map} +1 -1
- package/dashboard/dist/assets/{index-CcuvGdvf.js → index-BiVce3n0.js} +2 -2
- package/dashboard/dist/assets/{index-CcuvGdvf.js.map → index-BiVce3n0.js.map} +1 -1
- package/dashboard/dist/assets/{index-D6pBLZFu.js → index-BmNAVd4s.js} +2 -2
- package/dashboard/dist/assets/{index-D6pBLZFu.js.map → index-BmNAVd4s.js.map} +1 -1
- package/dashboard/dist/assets/{index-CjenRVX_.js → index-Bq5XNEzD.js} +2 -2
- package/dashboard/dist/assets/{index-CjenRVX_.js.map → index-Bq5XNEzD.js.map} +1 -1
- package/dashboard/dist/assets/{index-CzjUgFt_.js → index-DPStdq4T.js} +2 -2
- package/dashboard/dist/assets/{index-CzjUgFt_.js.map → index-DPStdq4T.js.map} +1 -1
- package/dashboard/dist/assets/index-DcppjzP5.css +1 -0
- package/dashboard/dist/assets/{index-C3WutFpT.js → index-DkcI4V_H.js} +2 -2
- package/dashboard/dist/assets/{index-C3WutFpT.js.map → index-DkcI4V_H.js.map} +1 -1
- package/dashboard/dist/assets/{index-2tzsxFat.js → index-Dyotfa_k.js} +2 -2
- package/dashboard/dist/assets/{index-2tzsxFat.js.map → index-Dyotfa_k.js.map} +1 -1
- package/dashboard/dist/assets/{index-C_ISDOWJ.js → index-MDD4JYtu.js} +2 -2
- package/dashboard/dist/assets/{index-C_ISDOWJ.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-BLB77tc8.js → index-eDm6cz0F.js} +2 -2
- package/dashboard/dist/assets/{index-BLB77tc8.js.map → index-eDm6cz0F.js.map} +1 -1
- package/dashboard/dist/assets/{knowledge-D1YP2NzS.js → knowledge-Bafewjxk.js} +2 -2
- package/dashboard/dist/assets/{knowledge-D1YP2NzS.js.map → knowledge-Bafewjxk.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-D5jUdZwN.js → mcp-query-BzTtIG90.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-D5jUdZwN.js.map → mcp-query-BzTtIG90.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-Bb5psC61.js → mcp-vLIutbnc.js} +2 -2
- package/dashboard/dist/assets/{mcp-Bb5psC61.js.map → mcp-vLIutbnc.js.map} +1 -1
- package/dashboard/dist/assets/{personas-CDndbkp4.js → personas-WD40EDS_.js} +2 -2
- package/dashboard/dist/assets/{personas-CDndbkp4.js.map → personas-WD40EDS_.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-Dq3kNhKu.js → pipelines-DFwULWs3.js} +2 -2
- package/dashboard/dist/assets/{pipelines-Dq3kNhKu.js.map → pipelines-DFwULWs3.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-BlpDsWCy.js → tasks-La_-WAUn.js} +2 -2
- package/dashboard/dist/assets/{tasks-BlpDsWCy.js.map → tasks-La_-WAUn.js.map} +1 -1
- package/dashboard/dist/assets/{topics-C0YaR9fu.js → topics-CzYMlvqm.js} +2 -2
- package/dashboard/dist/assets/{topics-C0YaR9fu.js.map → topics-CzYMlvqm.js.map} +1 -1
- package/dashboard/dist/assets/{useDebouncedValue-B-KC5ba3.js → useDebouncedValue-C0FQyANW.js} +2 -2
- package/dashboard/dist/assets/{useDebouncedValue-B-KC5ba3.js.map → useDebouncedValue-C0FQyANW.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-Dkr5g2Ac.js → useNamespace-WW_XjAb3.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-Dkr5g2Ac.js.map → useNamespace-WW_XjAb3.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-BANBOshA.js → useYamlActivityEvents-B3YxPeFt.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-BANBOshA.js.map → useYamlActivityEvents-B3YxPeFt.js.map} +1 -1
- package/dashboard/dist/assets/{yaml-workflows-BLYoJfmB.js → yaml-workflows-COHOjdhF.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-BLYoJfmB.js.map → yaml-workflows-COHOjdhF.js.map} +1 -1
- package/dashboard/dist/index.html +2 -2
- package/docs/dashboard.md +1 -1
- package/docs/hitl/x-lt-scan.md +51 -0
- package/docs/hitl-guide.md +2 -0
- package/docs/scan-codes.md +221 -21
- package/package.json +1 -1
- package/build/types/scan-code.d.ts +0 -317
- package/dashboard/dist/assets/CapabilitiesPage-BxadotXn.js +0 -2
- package/dashboard/dist/assets/CountdownTimer-CI_JOAvk.js +0 -2
- package/dashboard/dist/assets/ResolverForm-BVG8X0sS.js +0 -8
- package/dashboard/dist/assets/ResolverForm-BVG8X0sS.js.map +0 -1
- package/dashboard/dist/assets/RoleDetailPage-KCXDqoJz.js +0 -8
- package/dashboard/dist/assets/RoleDetailPage-KCXDqoJz.js.map +0 -1
- package/dashboard/dist/assets/ScanCodesPage-CUhCz-Yr.js +0 -2
- package/dashboard/dist/assets/ScanCodesPage-CUhCz-Yr.js.map +0 -1
- package/dashboard/dist/assets/ScanSchemeDetailPage-qzXKNqJK.js +0 -2
- package/dashboard/dist/assets/ScanSchemeDetailPage-qzXKNqJK.js.map +0 -1
- package/dashboard/dist/assets/ScanStationPage-D8e8cG3t.js +0 -2
- package/dashboard/dist/assets/ScanStationPage-D8e8cG3t.js.map +0 -1
- package/dashboard/dist/assets/index-CT-FN6CW.js +0 -3
- package/dashboard/dist/assets/index-CT-FN6CW.js.map +0 -1
- package/dashboard/dist/assets/index-Dh8MJl3L.css +0 -1
- package/dashboard/dist/assets/index-N71QQ3J5.js +0 -67
- package/dashboard/dist/assets/index-N71QQ3J5.js.map +0 -1
|
@@ -68,6 +68,15 @@ function isBatch(escalation) {
|
|
|
68
68
|
return Array.isArray(escalation.metadata?.[escalation_1.ESCALATION_BATCH_KEYS.PENDING]);
|
|
69
69
|
}
|
|
70
70
|
const NO_ACCUMULATOR_FOR_FACET = 'No pending accumulator found for this metadata';
|
|
71
|
+
/** The add's item-key error, or null when the key is usable. */
|
|
72
|
+
function itemKeyError(itemKey) {
|
|
73
|
+
if (!itemKey)
|
|
74
|
+
return { status: 400, error: 'itemKey is required' };
|
|
75
|
+
if (typeof itemKey !== 'string' || itemKey.length > escalation_1.ESCALATION_ITEM_KEY_MAX_LENGTH) {
|
|
76
|
+
return { status: 400, error: `itemKey must be a string of at most ${escalation_1.ESCALATION_ITEM_KEY_MAX_LENGTH} characters` };
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
71
80
|
/**
|
|
72
81
|
* The container a facet names: the highest priority pending row that carries
|
|
73
82
|
* the facet AND the accumulator declaration, within the given roles (null =
|
|
@@ -199,18 +208,22 @@ async function gatePayload(escalation, payload, userId) {
|
|
|
199
208
|
async function accumulateItem(input, auth) {
|
|
200
209
|
try {
|
|
201
210
|
const { id, itemKey, metadata } = input;
|
|
202
|
-
|
|
203
|
-
|
|
211
|
+
const keyError = itemKeyError(itemKey);
|
|
212
|
+
if (keyError)
|
|
213
|
+
return keyError;
|
|
204
214
|
const initiator = await resolveActor(input.initiatedBy, auth);
|
|
205
215
|
if ('error' in initiator)
|
|
206
216
|
return initiator.error;
|
|
207
217
|
const escalation = await escalationService.getEscalation(id);
|
|
208
218
|
if (!escalation)
|
|
209
219
|
return { status: 404, error: 'Escalation not found' };
|
|
210
|
-
if (escalation.status === 'cancelled')
|
|
211
|
-
return { status: 409, error: 'Escalation is cancelled' };
|
|
212
|
-
|
|
213
|
-
|
|
220
|
+
if (escalation.status === 'cancelled') {
|
|
221
|
+
return { status: 409, error: 'Escalation is cancelled', data: { error: 'Escalation is cancelled', outcome: 'already-cancelled' } };
|
|
222
|
+
}
|
|
223
|
+
if (escalation.status !== 'pending') {
|
|
224
|
+
const error = 'Escalation not available for accumulation';
|
|
225
|
+
return { status: 409, error, data: { error, outcome: `already-${escalation.status}` } };
|
|
226
|
+
}
|
|
214
227
|
if (!isAccumulator(escalation))
|
|
215
228
|
return { status: 400, error: 'Escalation is not an accumulator' };
|
|
216
229
|
if (await (0, helpers_1.assertReadAccess)(auth.userId, escalation)) {
|
|
@@ -250,8 +263,9 @@ async function accumulateItemBySignalKey(input, auth) {
|
|
|
250
263
|
const { signalKey, itemKey, metadata } = input;
|
|
251
264
|
if (!signalKey)
|
|
252
265
|
return { status: 400, error: 'signalKey is required' };
|
|
253
|
-
|
|
254
|
-
|
|
266
|
+
const keyError = itemKeyError(itemKey);
|
|
267
|
+
if (keyError)
|
|
268
|
+
return keyError;
|
|
255
269
|
const initiator = await resolveActor(input.initiatedBy, auth);
|
|
256
270
|
if ('error' in initiator)
|
|
257
271
|
return initiator.error;
|
|
@@ -301,8 +315,9 @@ async function accumulateItemByMetadata(input, auth) {
|
|
|
301
315
|
const { key, value, itemKey, metadata } = input;
|
|
302
316
|
if (!key || !value)
|
|
303
317
|
return { status: 400, error: 'key and value are required' };
|
|
304
|
-
|
|
305
|
-
|
|
318
|
+
const keyError = itemKeyError(itemKey);
|
|
319
|
+
if (keyError)
|
|
320
|
+
return keyError;
|
|
306
321
|
const initiator = await resolveActor(input.initiatedBy, auth);
|
|
307
322
|
if ('error' in initiator)
|
|
308
323
|
return initiator.error;
|
|
@@ -574,21 +589,21 @@ function accumulateOutcomeResult(result, itemKey, workflowId) {
|
|
|
574
589
|
},
|
|
575
590
|
};
|
|
576
591
|
case 'duplicate-item':
|
|
577
|
-
return { status: 409, error: 'Item already held', data: { error: 'Item already held', itemKey } };
|
|
592
|
+
return { status: 409, error: 'Item already held', data: { error: 'Item already held', itemKey, outcome: 'duplicate-item' } };
|
|
578
593
|
case 'full':
|
|
579
|
-
return { status: 409, error: 'Accumulator is full', data: { error: 'Accumulator is full', itemKey } };
|
|
594
|
+
return { status: 409, error: 'Accumulator is full', data: { error: 'Accumulator is full', itemKey, outcome: 'full' } };
|
|
580
595
|
case 'claimed-by-other':
|
|
581
|
-
return { status: 409, error: 'Escalation is claimed by another user' };
|
|
596
|
+
return { status: 409, error: 'Escalation is claimed by another user', data: { error: 'Escalation is claimed by another user', outcome: 'claimed-by-other' } };
|
|
582
597
|
case 'claim-expired':
|
|
583
|
-
return { status: 409, error: 'Your claim has expired; re-claim this escalation to add to it' };
|
|
598
|
+
return { status: 409, error: 'Your claim has expired; re-claim this escalation to add to it', data: { error: 'Your claim has expired; re-claim this escalation to add to it', outcome: 'claim-expired' } };
|
|
584
599
|
case 'not-found':
|
|
585
|
-
return { status: 404, error: 'Escalation not found' };
|
|
600
|
+
return { status: 404, error: 'Escalation not found', data: { error: 'Escalation not found', outcome: 'not-found' } };
|
|
586
601
|
case 'not-accumulator':
|
|
587
|
-
return { status: 400, error: 'Escalation is not an accumulator' };
|
|
602
|
+
return { status: 400, error: 'Escalation is not an accumulator', data: { error: 'Escalation is not an accumulator', outcome: 'not-accumulator' } };
|
|
588
603
|
case 'reciprocal-not-found':
|
|
589
|
-
return { status: 404, error: 'Reciprocal escalation not found' };
|
|
604
|
+
return { status: 404, error: 'Reciprocal escalation not found', data: { error: 'Reciprocal escalation not found', outcome: 'reciprocal-not-found' } };
|
|
590
605
|
case 'reciprocal-not-accumulator':
|
|
591
|
-
return { status: 400, error: 'Reciprocal escalation is not an accumulator' };
|
|
606
|
+
return { status: 400, error: 'Reciprocal escalation is not an accumulator', data: { error: 'Reciprocal escalation is not an accumulator', outcome: 'reciprocal-not-accumulator' } };
|
|
592
607
|
case 'reciprocal-duplicate':
|
|
593
608
|
return { status: 409, error: 'Reciprocal escalation already holds this container', data: { error: 'Reciprocal escalation already holds this container', outcome: result.outcome } };
|
|
594
609
|
case 'reciprocal-full':
|
|
@@ -596,7 +611,11 @@ function accumulateOutcomeResult(result, itemKey, workflowId) {
|
|
|
596
611
|
case 'reciprocal-terminal':
|
|
597
612
|
return { status: 409, error: 'Reciprocal escalation is no longer pending', data: { error: 'Reciprocal escalation is no longer pending', outcome: result.outcome } };
|
|
598
613
|
default:
|
|
599
|
-
return {
|
|
614
|
+
return {
|
|
615
|
+
status: 409,
|
|
616
|
+
error: 'Escalation not available for accumulation',
|
|
617
|
+
data: { error: 'Escalation not available for accumulation', outcome: result.outcome },
|
|
618
|
+
};
|
|
600
619
|
}
|
|
601
620
|
}
|
|
602
621
|
function removeOutcomeResult(result, itemKey) {
|
|
@@ -70,10 +70,13 @@ async function resolveBatchItem(input, auth) {
|
|
|
70
70
|
const escalation = await escalationService.getEscalation(id);
|
|
71
71
|
if (!escalation)
|
|
72
72
|
return { status: 404, error: 'Escalation not found' };
|
|
73
|
-
if (escalation.status === 'cancelled')
|
|
74
|
-
return { status: 409, error: 'Escalation is cancelled' };
|
|
75
|
-
|
|
76
|
-
|
|
73
|
+
if (escalation.status === 'cancelled') {
|
|
74
|
+
return { status: 409, error: 'Escalation is cancelled', data: { error: 'Escalation is cancelled', outcome: 'already-cancelled' } };
|
|
75
|
+
}
|
|
76
|
+
if (escalation.status !== 'pending') {
|
|
77
|
+
const error = 'Escalation not available for resolution';
|
|
78
|
+
return { status: 409, error, data: { error, outcome: `already-${escalation.status}` } };
|
|
79
|
+
}
|
|
77
80
|
// Advisory shape gate — cheap, readable rejection. The SDK's guarded
|
|
78
81
|
// statement re-checks and is the atomic arbiter (outcome 'not-batch').
|
|
79
82
|
const pending = escalation.metadata?.[escalation_1.ESCALATION_BATCH_KEYS.PENDING];
|
|
@@ -228,20 +231,24 @@ function batchOutcomeResult(result, itemKey, workflowId) {
|
|
|
228
231
|
return {
|
|
229
232
|
status: 409,
|
|
230
233
|
error: 'Batch item already submitted',
|
|
231
|
-
data: { error: 'Batch item already submitted', itemKey },
|
|
234
|
+
data: { error: 'Batch item already submitted', itemKey, outcome: 'duplicate-item' },
|
|
232
235
|
};
|
|
233
236
|
case 'claimed-by-other':
|
|
234
|
-
return { status: 409, error: 'Escalation is claimed by another user' };
|
|
237
|
+
return { status: 409, error: 'Escalation is claimed by another user', data: { error: 'Escalation is claimed by another user', outcome: 'claimed-by-other' } };
|
|
235
238
|
case 'claim-expired':
|
|
236
|
-
return { status: 409, error: 'Your claim has expired — re-claim this escalation to resolve it' };
|
|
239
|
+
return { status: 409, error: 'Your claim has expired — re-claim this escalation to resolve it', data: { error: 'Your claim has expired — re-claim this escalation to resolve it', outcome: 'claim-expired' } };
|
|
237
240
|
case 'not-found':
|
|
238
|
-
return { status: 404, error: 'Escalation not found' };
|
|
241
|
+
return { status: 404, error: 'Escalation not found', data: { error: 'Escalation not found', outcome: 'not-found' } };
|
|
239
242
|
case 'unknown-item':
|
|
240
|
-
return { status: 400, error: 'itemKey is not in the declared batch' };
|
|
243
|
+
return { status: 400, error: 'itemKey is not in the declared batch', data: { error: 'itemKey is not in the declared batch', outcome: 'unknown-item' } };
|
|
241
244
|
case 'not-batch':
|
|
242
|
-
return { status: 400, error: 'Escalation is not a batch' };
|
|
245
|
+
return { status: 400, error: 'Escalation is not a batch', data: { error: 'Escalation is not a batch', outcome: 'not-batch' } };
|
|
243
246
|
default:
|
|
244
247
|
// already-resolved / already-cancelled / already-expired
|
|
245
|
-
return {
|
|
248
|
+
return {
|
|
249
|
+
status: 409,
|
|
250
|
+
error: 'Escalation not available for resolution',
|
|
251
|
+
data: { error: 'Escalation not available for resolution', outcome: result.outcome },
|
|
252
|
+
};
|
|
246
253
|
}
|
|
247
254
|
}
|
package/build/api/roles.js
CHANGED
|
@@ -49,6 +49,7 @@ exports.listRoleListSchemaVersions = listRoleListSchemaVersions;
|
|
|
49
49
|
exports.deleteRole = deleteRole;
|
|
50
50
|
const roleService = __importStar(require("../services/role"));
|
|
51
51
|
const types_1 = require("../services/role/types");
|
|
52
|
+
const badge_grant_1 = require("../services/role/badge-grant");
|
|
52
53
|
const facet_sql_1 = require("../services/escalation/facet-sql");
|
|
53
54
|
/**
|
|
54
55
|
* List all distinct role names in the system.
|
|
@@ -291,6 +292,9 @@ async function updateRole(input) {
|
|
|
291
292
|
return { status: 400, error: 'default_pins must be [{ label, url, badge? }] with dashboard-relative urls' };
|
|
292
293
|
}
|
|
293
294
|
}
|
|
295
|
+
const grantError = (0, badge_grant_1.badgeGrantError)(input.properties?.[types_1.ROLE_PROPERTY_KEYS.BADGE_GRANT]);
|
|
296
|
+
if (grantError)
|
|
297
|
+
return { status: 400, error: grantError };
|
|
294
298
|
if (input.portals != null && !isPortalList(input.portals)) {
|
|
295
299
|
return {
|
|
296
300
|
status: 400,
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type ScanGrantScope, type ScanScheme } from '../../types';
|
|
2
|
+
export interface GrantPolicy {
|
|
3
|
+
ttlSeconds: number;
|
|
4
|
+
maxUses: number;
|
|
5
|
+
scope: ScanGrantScope;
|
|
6
|
+
/** The station role whose policy applied; absent when the scheme's did. */
|
|
7
|
+
role?: string;
|
|
8
|
+
}
|
|
9
|
+
/** The policy a badge scanned on this device mints under. */
|
|
10
|
+
export declare function stationGrantPolicy(scheme: ScanScheme, stationUserId: string, stationRole?: string): Promise<GrantPolicy>;
|
|
@@ -0,0 +1,72 @@
|
|
|
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.stationGrantPolicy = stationGrantPolicy;
|
|
37
|
+
const roleService = __importStar(require("../../services/role"));
|
|
38
|
+
const userService = __importStar(require("../../services/user"));
|
|
39
|
+
const badge_grant_1 = require("../../services/role/badge-grant");
|
|
40
|
+
const types_1 = require("../../types");
|
|
41
|
+
function schemePolicy(scheme) {
|
|
42
|
+
return {
|
|
43
|
+
ttlSeconds: scheme.grant_ttl_seconds ?? 0,
|
|
44
|
+
maxUses: scheme.grant_max_uses ?? 0,
|
|
45
|
+
scope: scheme.grant_scope ?? types_1.SCAN_GRANT_SCOPES.ACTION,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/** The policy a badge scanned on this device mints under. */
|
|
49
|
+
async function stationGrantPolicy(scheme, stationUserId, stationRole) {
|
|
50
|
+
const fallback = schemePolicy(scheme);
|
|
51
|
+
const user = await userService.getUser(stationUserId);
|
|
52
|
+
const memberRoles = (user?.roles ?? []).map((r) => r.role);
|
|
53
|
+
const candidates = stationRole
|
|
54
|
+
? memberRoles.filter((r) => r === stationRole)
|
|
55
|
+
: memberRoles;
|
|
56
|
+
const declared = [];
|
|
57
|
+
for (const role of candidates) {
|
|
58
|
+
const grant = (0, badge_grant_1.readBadgeGrant)(await roleService.getRoleProperties(role));
|
|
59
|
+
if (grant)
|
|
60
|
+
declared.push({ role, grant });
|
|
61
|
+
}
|
|
62
|
+
const distinct = new Set(declared.map((d) => JSON.stringify(d.grant)));
|
|
63
|
+
if (distinct.size !== 1)
|
|
64
|
+
return fallback;
|
|
65
|
+
const { role, grant } = declared[0];
|
|
66
|
+
return {
|
|
67
|
+
ttlSeconds: grant.ttl_seconds ?? fallback.ttlSeconds,
|
|
68
|
+
maxUses: grant.max_uses ?? fallback.maxUses,
|
|
69
|
+
scope: grant.scope ?? fallback.scope,
|
|
70
|
+
role,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
@@ -38,6 +38,7 @@ const scanCodeService = __importStar(require("../../services/scan-code"));
|
|
|
38
38
|
const escalationService = __importStar(require("../../services/escalation"));
|
|
39
39
|
const types_1 = require("../../types");
|
|
40
40
|
const identity_1 = require("./identity");
|
|
41
|
+
const grant_1 = require("./grant");
|
|
41
42
|
const context_1 = require("./context");
|
|
42
43
|
const locate_1 = require("./locate");
|
|
43
44
|
const verbs_1 = require("./verbs");
|
|
@@ -69,19 +70,19 @@ async function executeScanChoice(input, auth) {
|
|
|
69
70
|
data: { outcome: types_1.SCAN_OUTCOMES.UNCONFIGURED, error: 'the presented choice is no longer configured' },
|
|
70
71
|
};
|
|
71
72
|
}
|
|
72
|
-
// 2. The acting grant,
|
|
73
|
+
// 2. The acting grant, read (not spent) before anything reads or writes.
|
|
73
74
|
let effectiveAuth = auth;
|
|
74
|
-
let
|
|
75
|
+
let grant;
|
|
75
76
|
if (input.actingToken) {
|
|
76
|
-
const
|
|
77
|
-
if (!
|
|
77
|
+
const peeked = await (0, grant_1.peekGrant)(input.actingToken);
|
|
78
|
+
if (!peeked.ok) {
|
|
78
79
|
return {
|
|
79
80
|
status: 200,
|
|
80
|
-
data: { outcome: types_1.SCAN_OUTCOMES.NOT_PRIMED, notPrimed: rule.notPrimed, error:
|
|
81
|
+
data: { outcome: types_1.SCAN_OUTCOMES.NOT_PRIMED, notPrimed: rule.notPrimed, replayable: true, error: peeked.error },
|
|
81
82
|
};
|
|
82
83
|
}
|
|
83
|
-
effectiveAuth =
|
|
84
|
-
|
|
84
|
+
effectiveAuth = peeked.auth;
|
|
85
|
+
grant = peeked.grant;
|
|
85
86
|
}
|
|
86
87
|
// 3. The row anchors the target: the scheme's facet on the escalation the
|
|
87
88
|
// screen presented. A missing binding is loud misconfiguration.
|
|
@@ -100,7 +101,8 @@ async function executeScanChoice(input, auth) {
|
|
|
100
101
|
scannedAt: new Date().toISOString(),
|
|
101
102
|
auth: effectiveAuth,
|
|
102
103
|
stationAuth: auth,
|
|
103
|
-
acting,
|
|
104
|
+
acting: !!grant,
|
|
105
|
+
grant,
|
|
104
106
|
};
|
|
105
107
|
// 4. The identity gate, per the choice.
|
|
106
108
|
if (choice.requireActingIdentity && !(await (0, identity_1.actingIdentitySatisfied)(step, ctx))) {
|
|
@@ -116,8 +118,12 @@ async function executeScanChoice(input, auth) {
|
|
|
116
118
|
}
|
|
117
119
|
// 6. Dispatch through the same atomic executors a direct scan uses.
|
|
118
120
|
const synthesized = { query: step.query, verb: choice.verb, params: choice.params };
|
|
119
|
-
const result = await (0, verbs_1.dispatchChoiceVerb)(synthesized, ctx, presented);
|
|
120
|
-
|
|
121
|
+
const result = decorate(await (0, verbs_1.dispatchChoiceVerb)(synthesized, ctx, presented), ctx, input);
|
|
122
|
+
// 7. Settle the badge: refund a spend whose act did not land
|
|
123
|
+
const acting = await (0, grant_1.settleGrant)(ctx, result);
|
|
124
|
+
if (acting && result.data)
|
|
125
|
+
result.data = { ...result.data, acting };
|
|
126
|
+
return result;
|
|
121
127
|
}
|
|
122
128
|
catch (err) {
|
|
123
129
|
return { status: 500, error: err.message };
|
|
@@ -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
|
}
|