@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
|
@@ -4,87 +4,14 @@ exports.ScanTemplateError = void 0;
|
|
|
4
4
|
exports.parseScanCode = parseScanCode;
|
|
5
5
|
exports.mentionsClaimToken = mentionsClaimToken;
|
|
6
6
|
exports.interpolateScanTemplate = interpolateScanTemplate;
|
|
7
|
+
exports.renderScanCopy = renderScanCopy;
|
|
8
|
+
const scan_code_1 = require("../../shared/scan-code");
|
|
7
9
|
const types_1 = require("../../types");
|
|
8
|
-
/**
|
|
9
|
-
* Parse a raw scan string against the configured schemes. Pure — no I/O.
|
|
10
|
-
*
|
|
11
|
-
* The leading TWO digits pick the scheme (10-99, so a code never starts with a
|
|
12
|
-
* leading zero); the scheme then defines how the remainder splits into a
|
|
13
|
-
* single-digit category (0-9) and the target:
|
|
14
|
-
* - delimited: `10:1:ABC-123` (delimiter from the scheme row)
|
|
15
|
-
* - fixed: `1017554332` (one category digit, then target_length digits)
|
|
16
|
-
*/
|
|
10
|
+
/** Parse a raw scan string against the configured schemes. Pure; see shared/scan-code. */
|
|
17
11
|
function parseScanCode(raw, schemes) {
|
|
18
|
-
|
|
19
|
-
if (!code) {
|
|
20
|
-
return { ok: false, failure: { reason: 'empty', detail: 'empty scan code' } };
|
|
21
|
-
}
|
|
22
|
-
const versionToken = code.slice(0, 2);
|
|
23
|
-
const version = Number(versionToken);
|
|
24
|
-
if (!/^[0-9]{2}$/.test(versionToken) || version < 10 || version > 99) {
|
|
25
|
-
return {
|
|
26
|
-
ok: false,
|
|
27
|
-
failure: { reason: 'unknown_version', detail: `code must start with a two-digit scheme 10-99, got "${versionToken}"` },
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
const scheme = schemes.find((s) => s.version === version);
|
|
31
|
-
if (!scheme) {
|
|
32
|
-
return {
|
|
33
|
-
ok: false,
|
|
34
|
-
failure: { reason: 'unknown_version', detail: `no scan scheme configured for version ${version}` },
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
if (!scheme.enabled) {
|
|
38
|
-
return {
|
|
39
|
-
ok: false,
|
|
40
|
-
failure: { reason: 'scheme_disabled', detail: `scan scheme ${version} ("${scheme.name}") is disabled` },
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
if (scheme.encoding === types_1.SCAN_ENCODINGS.DELIMITED) {
|
|
44
|
-
return parseDelimited(code, version, scheme);
|
|
45
|
-
}
|
|
46
|
-
return parseFixed(code, version, scheme);
|
|
12
|
+
return (0, scan_code_1.parseScanCode)(raw, schemes);
|
|
47
13
|
}
|
|
48
|
-
|
|
49
|
-
const d = scheme.delimiter;
|
|
50
|
-
// version(2 digits) <d> category(1 digit) <d> target(rest, non-empty)
|
|
51
|
-
if (code[2] !== d) {
|
|
52
|
-
return malformed(scheme, `expected "${d}" after the two-digit scheme`);
|
|
53
|
-
}
|
|
54
|
-
const category = code.slice(3, 4);
|
|
55
|
-
if (!/^[0-9]$/.test(category)) {
|
|
56
|
-
return malformed(scheme, 'category must be a single digit');
|
|
57
|
-
}
|
|
58
|
-
if (code[4] !== d) {
|
|
59
|
-
return malformed(scheme, `expected "${d}" after the category`);
|
|
60
|
-
}
|
|
61
|
-
const target = code.slice(5);
|
|
62
|
-
if (!target) {
|
|
63
|
-
return malformed(scheme, 'target is empty');
|
|
64
|
-
}
|
|
65
|
-
return { ok: true, parsed: { version, category, target }, scheme };
|
|
66
|
-
}
|
|
67
|
-
function parseFixed(code, version, scheme) {
|
|
68
|
-
const targetLength = scheme.target_length ?? 0;
|
|
69
|
-
const expected = 2 + 1 + targetLength;
|
|
70
|
-
// UPC-A wedges deliver the trailing check digit too; accept it as slack.
|
|
71
|
-
if (!/^[0-9]+$/.test(code)) {
|
|
72
|
-
return malformed(scheme, 'fixed encoding accepts digits only');
|
|
73
|
-
}
|
|
74
|
-
if (code.length !== expected && code.length !== expected + 1) {
|
|
75
|
-
return malformed(scheme, `expected ${expected} digits (or ${expected + 1} with check digit), got ${code.length}`);
|
|
76
|
-
}
|
|
77
|
-
const category = code.slice(2, 3);
|
|
78
|
-
const target = code.slice(3, 3 + targetLength);
|
|
79
|
-
return { ok: true, parsed: { version, category, target }, scheme };
|
|
80
|
-
}
|
|
81
|
-
function malformed(scheme, detail) {
|
|
82
|
-
return {
|
|
83
|
-
ok: false,
|
|
84
|
-
failure: { reason: 'malformed', detail: `scheme ${scheme.version} ("${scheme.name}"): ${detail}` },
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
/** A `{claim.x}` or `{item.x}` token the context cannot resolve. */
|
|
14
|
+
/** A bag token the context cannot resolve. */
|
|
88
15
|
class ScanTemplateError extends Error {
|
|
89
16
|
constructor(token, reason) {
|
|
90
17
|
super(`scan template ${token}: ${reason}`);
|
|
@@ -94,37 +21,45 @@ class ScanTemplateError extends Error {
|
|
|
94
21
|
}
|
|
95
22
|
}
|
|
96
23
|
exports.ScanTemplateError = ScanTemplateError;
|
|
97
|
-
const BAG_TOKEN = /\{(claim|item)\.([a-zA-Z0-9_]+)\}/g;
|
|
24
|
+
const BAG_TOKEN = /\{(claim|item|subject|container|fill)\.([a-zA-Z0-9_]+)\}/g;
|
|
25
|
+
const MISSING_BAG = {
|
|
26
|
+
claim: 'the actor holds no single live claim',
|
|
27
|
+
item: 'no located item row on this step',
|
|
28
|
+
subject: 'no subject is held',
|
|
29
|
+
container: 'no container was located',
|
|
30
|
+
fill: 'no batch was read',
|
|
31
|
+
};
|
|
98
32
|
/** True when any string in the params mentions a `{claim.…}` token. */
|
|
99
33
|
function mentionsClaimToken(value) {
|
|
100
34
|
return JSON.stringify(value ?? null).includes(`{${types_1.SCAN_TEMPLATE_BAGS.CLAIM}.`);
|
|
101
35
|
}
|
|
102
36
|
function resolveBagToken(ctx, bag, facet, token) {
|
|
103
|
-
const source = bag
|
|
104
|
-
if (!source)
|
|
105
|
-
throw new ScanTemplateError(token, bag
|
|
106
|
-
? 'the actor holds no single live claim'
|
|
107
|
-
: 'no located item row on this step');
|
|
108
|
-
}
|
|
37
|
+
const source = ctx[bag];
|
|
38
|
+
if (!source)
|
|
39
|
+
throw new ScanTemplateError(token, MISSING_BAG[bag]);
|
|
109
40
|
const v = source[facet];
|
|
110
41
|
if (v === undefined || v === null || v === '') {
|
|
111
42
|
throw new ScanTemplateError(token, `facet ${facet} is absent`);
|
|
112
43
|
}
|
|
44
|
+
if (Array.isArray(v))
|
|
45
|
+
return v.join(', ');
|
|
113
46
|
return typeof v === 'object' ? JSON.stringify(v) : String(v);
|
|
114
47
|
}
|
|
115
48
|
/**
|
|
116
49
|
* Replace the template tokens inside string values of a params object.
|
|
117
|
-
* Deep, pure, non-mutating. The
|
|
118
|
-
*
|
|
119
|
-
* facet bags and throw
|
|
120
|
-
*
|
|
50
|
+
* Deep, pure, non-mutating. The scan tokens are plain text replacement; the
|
|
51
|
+
* bag tokens (`{claim.x}`, `{item.x}`, `{subject.x}`, `{container.x}`,
|
|
52
|
+
* `{fill.x}`) read the context's facet bags and throw
|
|
53
|
+
* {@link ScanTemplateError} when they cannot resolve, so a literal token
|
|
54
|
+
* never reaches a row. No expression language.
|
|
121
55
|
*/
|
|
122
56
|
function interpolateScanTemplate(value, ctx) {
|
|
123
57
|
if (typeof value === 'string') {
|
|
124
58
|
const scanned = value
|
|
125
59
|
.split(types_1.SCAN_TEMPLATE_TOKENS.TARGET).join(ctx.target)
|
|
126
60
|
.split(types_1.SCAN_TEMPLATE_TOKENS.CATEGORY).join(ctx.category)
|
|
127
|
-
.split(types_1.SCAN_TEMPLATE_TOKENS.SCANNED_AT).join(ctx.scannedAt)
|
|
61
|
+
.split(types_1.SCAN_TEMPLATE_TOKENS.SCANNED_AT).join(ctx.scannedAt)
|
|
62
|
+
.split(types_1.SCAN_TEMPLATE_TOKENS.CODE).join(ctx.code ?? ctx.target);
|
|
128
63
|
return scanned.replace(BAG_TOKEN, (token, bag, facet) => resolveBagToken(ctx, bag, facet, token));
|
|
129
64
|
}
|
|
130
65
|
if (Array.isArray(value)) {
|
|
@@ -139,3 +74,23 @@ function interpolateScanTemplate(value, ctx) {
|
|
|
139
74
|
}
|
|
140
75
|
return value;
|
|
141
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Render refusal copy, degrading instead of failing: a token with nothing to
|
|
79
|
+
* read becomes an empty string, so a refusal always has words to show.
|
|
80
|
+
*/
|
|
81
|
+
function renderScanCopy(markdown, ctx) {
|
|
82
|
+
try {
|
|
83
|
+
return interpolateScanTemplate(markdown, ctx);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
const safe = markdown.replace(BAG_TOKEN, (token, bag, facet) => {
|
|
87
|
+
try {
|
|
88
|
+
return resolveBagToken(ctx, bag, facet, token);
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return '';
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
return interpolateScanTemplate(safe, ctx);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -18,6 +18,7 @@ function mapScheme(row) {
|
|
|
18
18
|
kind: row.kind ?? 'action',
|
|
19
19
|
grant_ttl_seconds: row.grant_ttl_seconds ?? null,
|
|
20
20
|
grant_max_uses: row.grant_max_uses ?? 0,
|
|
21
|
+
grant_scope: row.grant_scope ?? 'action',
|
|
21
22
|
enabled: row.enabled,
|
|
22
23
|
created_at: row.created_at,
|
|
23
24
|
updated_at: row.updated_at,
|
|
@@ -2,16 +2,16 @@ export declare const LIST_SCHEMES = "SELECT * FROM lt_config_scan_schemes ORDER
|
|
|
2
2
|
export declare const GET_SCHEME = "SELECT * FROM lt_config_scan_schemes WHERE version = $1";
|
|
3
3
|
export declare const LIST_ACTIONS = "SELECT * FROM lt_config_scan_actions WHERE scheme_version = $1 ORDER BY category";
|
|
4
4
|
export declare const GET_ACTION = "SELECT * FROM lt_config_scan_actions WHERE scheme_version = $1 AND category = $2";
|
|
5
|
-
export declare const UPSERT_SCHEME = "INSERT INTO lt_config_scan_schemes\n (version, name, description, target_facet, encoding, delimiter, target_length,\n kind, grant_ttl_seconds, grant_max_uses, enabled)\nVALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)\nON CONFLICT (version) DO UPDATE SET\n name = EXCLUDED.name,\n description = EXCLUDED.description,\n target_facet = EXCLUDED.target_facet,\n encoding = EXCLUDED.encoding,\n delimiter = EXCLUDED.delimiter,\n target_length = EXCLUDED.target_length,\n kind = EXCLUDED.kind,\n grant_ttl_seconds = EXCLUDED.grant_ttl_seconds,\n grant_max_uses = EXCLUDED.grant_max_uses,\n enabled = EXCLUDED.enabled\nRETURNING *";
|
|
5
|
+
export declare const UPSERT_SCHEME = "INSERT INTO lt_config_scan_schemes\n (version, name, description, target_facet, encoding, delimiter, target_length,\n kind, grant_ttl_seconds, grant_max_uses, enabled, grant_scope)\nVALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)\nON CONFLICT (version) DO UPDATE SET\n name = EXCLUDED.name,\n description = EXCLUDED.description,\n target_facet = EXCLUDED.target_facet,\n encoding = EXCLUDED.encoding,\n delimiter = EXCLUDED.delimiter,\n target_length = EXCLUDED.target_length,\n kind = EXCLUDED.kind,\n grant_ttl_seconds = EXCLUDED.grant_ttl_seconds,\n grant_max_uses = EXCLUDED.grant_max_uses,\n grant_scope = EXCLUDED.grant_scope,\n enabled = EXCLUDED.enabled\nRETURNING *";
|
|
6
6
|
export declare const DELETE_SCHEME = "DELETE FROM lt_config_scan_schemes WHERE version = $1";
|
|
7
7
|
export declare const UPSERT_ACTION = "INSERT INTO lt_config_scan_actions\n (scheme_version, category, name, steps, fallback, not_primed, enabled)\nVALUES ($1, $2, $3, $4, $5, $6, $7)\nON CONFLICT (scheme_version, category) DO UPDATE SET\n name = EXCLUDED.name,\n steps = EXCLUDED.steps,\n fallback = EXCLUDED.fallback,\n not_primed = EXCLUDED.not_primed,\n enabled = EXCLUDED.enabled\nRETURNING *";
|
|
8
8
|
export declare const DELETE_ACTION = "DELETE FROM lt_config_scan_actions WHERE scheme_version = $1 AND category = $2";
|
|
9
|
-
export declare const SEED_SCHEME = "INSERT INTO lt_config_scan_schemes\n (version, name, description, target_facet, encoding, delimiter, target_length,\n kind, grant_ttl_seconds, grant_max_uses, enabled)\nVALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)\nON CONFLICT (version) DO NOTHING";
|
|
9
|
+
export declare const SEED_SCHEME = "INSERT INTO lt_config_scan_schemes\n (version, name, description, target_facet, encoding, delimiter, target_length,\n kind, grant_ttl_seconds, grant_max_uses, enabled, grant_scope)\nVALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)\nON CONFLICT (version) DO NOTHING";
|
|
10
10
|
export declare const SEED_ACTION = "INSERT INTO lt_config_scan_actions\n (scheme_version, category, name, steps, fallback, not_primed, enabled)\nVALUES ($1, $2, $3, $4, $5, $6, $7)\nON CONFLICT (scheme_version, category) DO NOTHING";
|
|
11
11
|
/**
|
|
12
12
|
* Apply — same column set as the upsert, guarded by IS DISTINCT FROM so an
|
|
13
13
|
* unchanged declaration is a zero-row no-op. `(xmax = 0)` distinguishes
|
|
14
14
|
* insert from update. jsonb columns compare content-wise in SQL.
|
|
15
15
|
*/
|
|
16
|
-
export declare const APPLY_SCHEME = "INSERT INTO lt_config_scan_schemes\n (version, name, description, target_facet, encoding, delimiter, target_length,\n kind, grant_ttl_seconds, grant_max_uses, enabled)\nVALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)\nON CONFLICT (version) DO UPDATE SET\n name = EXCLUDED.name,\n description = EXCLUDED.description,\n target_facet = EXCLUDED.target_facet,\n encoding = EXCLUDED.encoding,\n delimiter = EXCLUDED.delimiter,\n target_length = EXCLUDED.target_length,\n kind = EXCLUDED.kind,\n grant_ttl_seconds = EXCLUDED.grant_ttl_seconds,\n grant_max_uses = EXCLUDED.grant_max_uses,\n enabled = EXCLUDED.enabled,\n updated_at = NOW()\nWHERE (lt_config_scan_schemes.name, lt_config_scan_schemes.description,\n lt_config_scan_schemes.target_facet, lt_config_scan_schemes.encoding,\n lt_config_scan_schemes.delimiter, lt_config_scan_schemes.target_length,\n lt_config_scan_schemes.kind, lt_config_scan_schemes.grant_ttl_seconds,\n lt_config_scan_schemes.grant_max_uses, lt_config_scan_schemes.enabled)\n IS DISTINCT FROM\n (EXCLUDED.name, EXCLUDED.description, EXCLUDED.target_facet,\n EXCLUDED.encoding, EXCLUDED.delimiter, EXCLUDED.target_length,\n EXCLUDED.kind, EXCLUDED.grant_ttl_seconds, EXCLUDED.grant_max_uses,\n EXCLUDED.enabled)\nRETURNING (xmax = 0) AS inserted";
|
|
16
|
+
export declare const APPLY_SCHEME = "INSERT INTO lt_config_scan_schemes\n (version, name, description, target_facet, encoding, delimiter, target_length,\n kind, grant_ttl_seconds, grant_max_uses, enabled, grant_scope)\nVALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)\nON CONFLICT (version) DO UPDATE SET\n name = EXCLUDED.name,\n description = EXCLUDED.description,\n target_facet = EXCLUDED.target_facet,\n encoding = EXCLUDED.encoding,\n delimiter = EXCLUDED.delimiter,\n target_length = EXCLUDED.target_length,\n kind = EXCLUDED.kind,\n grant_ttl_seconds = EXCLUDED.grant_ttl_seconds,\n grant_max_uses = EXCLUDED.grant_max_uses,\n grant_scope = EXCLUDED.grant_scope,\n enabled = EXCLUDED.enabled,\n updated_at = NOW()\nWHERE (lt_config_scan_schemes.name, lt_config_scan_schemes.description,\n lt_config_scan_schemes.target_facet, lt_config_scan_schemes.encoding,\n lt_config_scan_schemes.delimiter, lt_config_scan_schemes.target_length,\n lt_config_scan_schemes.kind, lt_config_scan_schemes.grant_ttl_seconds,\n lt_config_scan_schemes.grant_max_uses, lt_config_scan_schemes.enabled,\n lt_config_scan_schemes.grant_scope)\n IS DISTINCT FROM\n (EXCLUDED.name, EXCLUDED.description, EXCLUDED.target_facet,\n EXCLUDED.encoding, EXCLUDED.delimiter, EXCLUDED.target_length,\n EXCLUDED.kind, EXCLUDED.grant_ttl_seconds, EXCLUDED.grant_max_uses,\n EXCLUDED.enabled, EXCLUDED.grant_scope)\nRETURNING (xmax = 0) AS inserted";
|
|
17
17
|
export declare const APPLY_ACTION = "INSERT INTO lt_config_scan_actions\n (scheme_version, category, name, steps, fallback, not_primed, enabled)\nVALUES ($1, $2, $3, $4, $5, $6, $7)\nON CONFLICT (scheme_version, category) DO UPDATE SET\n name = EXCLUDED.name,\n steps = EXCLUDED.steps,\n fallback = EXCLUDED.fallback,\n not_primed = EXCLUDED.not_primed,\n enabled = EXCLUDED.enabled,\n updated_at = NOW()\nWHERE (lt_config_scan_actions.name, lt_config_scan_actions.steps,\n lt_config_scan_actions.fallback, lt_config_scan_actions.not_primed,\n lt_config_scan_actions.enabled)\n IS DISTINCT FROM\n (EXCLUDED.name, EXCLUDED.steps, EXCLUDED.fallback,\n EXCLUDED.not_primed, EXCLUDED.enabled)\nRETURNING (xmax = 0) AS inserted";
|
|
@@ -18,8 +18,8 @@ SELECT * FROM lt_config_scan_actions WHERE scheme_version = $1 AND category = $2
|
|
|
18
18
|
exports.UPSERT_SCHEME = `\
|
|
19
19
|
INSERT INTO lt_config_scan_schemes
|
|
20
20
|
(version, name, description, target_facet, encoding, delimiter, target_length,
|
|
21
|
-
kind, grant_ttl_seconds, grant_max_uses, enabled)
|
|
22
|
-
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
|
|
21
|
+
kind, grant_ttl_seconds, grant_max_uses, enabled, grant_scope)
|
|
22
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
|
|
23
23
|
ON CONFLICT (version) DO UPDATE SET
|
|
24
24
|
name = EXCLUDED.name,
|
|
25
25
|
description = EXCLUDED.description,
|
|
@@ -30,6 +30,7 @@ ON CONFLICT (version) DO UPDATE SET
|
|
|
30
30
|
kind = EXCLUDED.kind,
|
|
31
31
|
grant_ttl_seconds = EXCLUDED.grant_ttl_seconds,
|
|
32
32
|
grant_max_uses = EXCLUDED.grant_max_uses,
|
|
33
|
+
grant_scope = EXCLUDED.grant_scope,
|
|
33
34
|
enabled = EXCLUDED.enabled
|
|
34
35
|
RETURNING *`;
|
|
35
36
|
exports.DELETE_SCHEME = `\
|
|
@@ -53,8 +54,8 @@ DELETE FROM lt_config_scan_actions WHERE scheme_version = $1 AND category = $2`;
|
|
|
53
54
|
exports.SEED_SCHEME = `\
|
|
54
55
|
INSERT INTO lt_config_scan_schemes
|
|
55
56
|
(version, name, description, target_facet, encoding, delimiter, target_length,
|
|
56
|
-
kind, grant_ttl_seconds, grant_max_uses, enabled)
|
|
57
|
-
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
|
|
57
|
+
kind, grant_ttl_seconds, grant_max_uses, enabled, grant_scope)
|
|
58
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
|
|
58
59
|
ON CONFLICT (version) DO NOTHING`;
|
|
59
60
|
exports.SEED_ACTION = `\
|
|
60
61
|
INSERT INTO lt_config_scan_actions
|
|
@@ -72,8 +73,8 @@ ON CONFLICT (scheme_version, category) DO NOTHING`;
|
|
|
72
73
|
exports.APPLY_SCHEME = `\
|
|
73
74
|
INSERT INTO lt_config_scan_schemes
|
|
74
75
|
(version, name, description, target_facet, encoding, delimiter, target_length,
|
|
75
|
-
kind, grant_ttl_seconds, grant_max_uses, enabled)
|
|
76
|
-
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
|
|
76
|
+
kind, grant_ttl_seconds, grant_max_uses, enabled, grant_scope)
|
|
77
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
|
|
77
78
|
ON CONFLICT (version) DO UPDATE SET
|
|
78
79
|
name = EXCLUDED.name,
|
|
79
80
|
description = EXCLUDED.description,
|
|
@@ -84,18 +85,20 @@ ON CONFLICT (version) DO UPDATE SET
|
|
|
84
85
|
kind = EXCLUDED.kind,
|
|
85
86
|
grant_ttl_seconds = EXCLUDED.grant_ttl_seconds,
|
|
86
87
|
grant_max_uses = EXCLUDED.grant_max_uses,
|
|
88
|
+
grant_scope = EXCLUDED.grant_scope,
|
|
87
89
|
enabled = EXCLUDED.enabled,
|
|
88
90
|
updated_at = NOW()
|
|
89
91
|
WHERE (lt_config_scan_schemes.name, lt_config_scan_schemes.description,
|
|
90
92
|
lt_config_scan_schemes.target_facet, lt_config_scan_schemes.encoding,
|
|
91
93
|
lt_config_scan_schemes.delimiter, lt_config_scan_schemes.target_length,
|
|
92
94
|
lt_config_scan_schemes.kind, lt_config_scan_schemes.grant_ttl_seconds,
|
|
93
|
-
lt_config_scan_schemes.grant_max_uses, lt_config_scan_schemes.enabled
|
|
95
|
+
lt_config_scan_schemes.grant_max_uses, lt_config_scan_schemes.enabled,
|
|
96
|
+
lt_config_scan_schemes.grant_scope)
|
|
94
97
|
IS DISTINCT FROM
|
|
95
98
|
(EXCLUDED.name, EXCLUDED.description, EXCLUDED.target_facet,
|
|
96
99
|
EXCLUDED.encoding, EXCLUDED.delimiter, EXCLUDED.target_length,
|
|
97
100
|
EXCLUDED.kind, EXCLUDED.grant_ttl_seconds, EXCLUDED.grant_max_uses,
|
|
98
|
-
EXCLUDED.enabled)
|
|
101
|
+
EXCLUDED.enabled, EXCLUDED.grant_scope)
|
|
99
102
|
RETURNING (xmax = 0) AS inserted`;
|
|
100
103
|
exports.APPLY_ACTION = `\
|
|
101
104
|
INSERT INTO lt_config_scan_actions
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type ScanStep } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Hold, fill, and the subject vocabulary (subject gate, match, refuse,
|
|
4
|
+
* accumulate from/into). A step that can never find its subject, or a
|
|
5
|
+
* guard that can never pass, fails the upsert rather than the bench.
|
|
6
|
+
*/
|
|
7
|
+
export declare function assertValidSubjectStep(step: ScanStep, at: string): void;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.assertValidSubjectStep = assertValidSubjectStep;
|
|
4
|
+
const types_1 = require("../../types");
|
|
5
|
+
const facet_sql_1 = require("../escalation/facet-sql");
|
|
6
|
+
function isSchemeList(value) {
|
|
7
|
+
return Array.isArray(value) && value.length > 0
|
|
8
|
+
&& value.every((v) => Number.isInteger(v) && v >= 10 && v <= 99);
|
|
9
|
+
}
|
|
10
|
+
function isStringList(value) {
|
|
11
|
+
return Array.isArray(value) && value.length > 0 && value.every((v) => typeof v === 'string' && v);
|
|
12
|
+
}
|
|
13
|
+
function isPlainObject(value) {
|
|
14
|
+
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Hold, fill, and the subject vocabulary (subject gate, match, refuse,
|
|
18
|
+
* accumulate from/into). A step that can never find its subject, or a
|
|
19
|
+
* guard that can never pass, fails the upsert rather than the bench.
|
|
20
|
+
*/
|
|
21
|
+
function assertValidSubjectStep(step, at) {
|
|
22
|
+
const accumulate = step.params?.accumulate;
|
|
23
|
+
const subjectMode = accumulate?.from === 'subject' || accumulate?.into === 'subject'
|
|
24
|
+
|| (step.verb === types_1.SCAN_VERBS.FILL && step.params?.fill?.into === 'subject');
|
|
25
|
+
if (step.subject !== undefined) {
|
|
26
|
+
if (!isPlainObject(step.subject) || !isSchemeList(step.subject.schemes)) {
|
|
27
|
+
throw new Error(`${at}: subject.schemes must be a non-empty array of scheme versions (10-99)`);
|
|
28
|
+
}
|
|
29
|
+
if (step.subject.claimedByOther !== undefined
|
|
30
|
+
&& step.subject.claimedByOther !== 'refuse' && step.subject.claimedByOther !== 'allow') {
|
|
31
|
+
throw new Error(`${at}: subject.claimedByOther must be 'refuse' or 'allow'`);
|
|
32
|
+
}
|
|
33
|
+
const facets = step.subject.facets;
|
|
34
|
+
if (facets !== undefined) {
|
|
35
|
+
if (!facets || typeof facets !== 'object' || Array.isArray(facets) || Object.keys(facets).length === 0) {
|
|
36
|
+
throw new Error(`${at}: subject.facets must be a non-empty object`);
|
|
37
|
+
}
|
|
38
|
+
for (const [key, value] of Object.entries(facets)) {
|
|
39
|
+
if (!facet_sql_1.FACET_KEY.test(key))
|
|
40
|
+
throw new Error(`${at}: subject.facets key "${key}" must be a facet key`);
|
|
41
|
+
if (!['string', 'number', 'boolean'].includes(typeof value)) {
|
|
42
|
+
throw new Error(`${at}: subject.facets.${key} must be a string, number, or boolean`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (step.verb !== types_1.SCAN_VERBS.ACCUMULATE && step.verb !== types_1.SCAN_VERBS.FILL) {
|
|
47
|
+
throw new Error(`${at}: a subject gate applies only to accumulate and fill steps`);
|
|
48
|
+
}
|
|
49
|
+
if (step.confirm)
|
|
50
|
+
throw new Error(`${at}: a subject step acts on the scan; it cannot carry confirm`);
|
|
51
|
+
if (!subjectMode) {
|
|
52
|
+
throw new Error(`${at}: a subject step must act on it (accumulate from/into 'subject', or fill into 'subject')`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else if (subjectMode) {
|
|
56
|
+
throw new Error(`${at}: acting on the held subject requires a subject gate`);
|
|
57
|
+
}
|
|
58
|
+
if (accumulate?.from !== undefined && accumulate.from !== 'subject') {
|
|
59
|
+
throw new Error(`${at}: params.accumulate.from must be 'subject'`);
|
|
60
|
+
}
|
|
61
|
+
if (accumulate?.into !== undefined && accumulate.into !== 'subject') {
|
|
62
|
+
throw new Error(`${at}: params.accumulate.into must be 'subject'`);
|
|
63
|
+
}
|
|
64
|
+
if (accumulate?.from && accumulate.into) {
|
|
65
|
+
throw new Error(`${at}: params.accumulate.from and into are exclusive`);
|
|
66
|
+
}
|
|
67
|
+
if ((accumulate?.from || accumulate?.into) && accumulate.containerFacet) {
|
|
68
|
+
throw new Error(`${at}: params.accumulate.containerFacet is item mode; drop it for from/into 'subject'`);
|
|
69
|
+
}
|
|
70
|
+
if (accumulate?.from && !step.params?.itemKey) {
|
|
71
|
+
throw new Error(`${at}: from-subject accumulate requires params.itemKey (e.g. '{subject.<facet>}')`);
|
|
72
|
+
}
|
|
73
|
+
if (step.match !== undefined) {
|
|
74
|
+
if (!step.subject)
|
|
75
|
+
throw new Error(`${at}: match applies only to steps with a subject gate`);
|
|
76
|
+
if (!isPlainObject(step.match))
|
|
77
|
+
throw new Error(`${at}: match must be an object`);
|
|
78
|
+
if (step.match.target === undefined && step.match.facets === undefined) {
|
|
79
|
+
throw new Error(`${at}: match needs target or facets`);
|
|
80
|
+
}
|
|
81
|
+
if (step.match.target !== undefined && !isStringList(step.match.target)) {
|
|
82
|
+
throw new Error(`${at}: match.target must be a non-empty array of templates`);
|
|
83
|
+
}
|
|
84
|
+
if (step.match.facets !== undefined) {
|
|
85
|
+
if (!isStringList(step.match.facets) || !step.match.facets.every((f) => facet_sql_1.FACET_KEY.test(f))) {
|
|
86
|
+
throw new Error(`${at}: match.facets must be a non-empty array of facet keys`);
|
|
87
|
+
}
|
|
88
|
+
if (accumulate?.from !== 'subject') {
|
|
89
|
+
throw new Error(`${at}: match.facets compares the located container, which only a from-subject accumulate has`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (step.refuse !== undefined) {
|
|
94
|
+
if (!isPlainObject(step.refuse) || typeof step.refuse.markdown !== 'string' || !step.refuse.markdown) {
|
|
95
|
+
throw new Error(`${at}: refuse.markdown is required`);
|
|
96
|
+
}
|
|
97
|
+
if (step.refuse.conflict !== undefined && typeof step.refuse.conflict !== 'string') {
|
|
98
|
+
throw new Error(`${at}: refuse.conflict must be markdown`);
|
|
99
|
+
}
|
|
100
|
+
if (step.refuse.missing !== undefined) {
|
|
101
|
+
if (typeof step.refuse.missing !== 'string' || !step.refuse.missing) {
|
|
102
|
+
throw new Error(`${at}: refuse.missing must be markdown`);
|
|
103
|
+
}
|
|
104
|
+
if (accumulate?.from !== 'subject') {
|
|
105
|
+
throw new Error(`${at}: refuse.missing applies only to a from-subject accumulate`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (step.verb === types_1.SCAN_VERBS.HOLD)
|
|
110
|
+
assertValidHold(step, at);
|
|
111
|
+
else if (step.params?.hold !== undefined)
|
|
112
|
+
throw new Error(`${at}: params.hold applies only to hold steps`);
|
|
113
|
+
if (step.verb === types_1.SCAN_VERBS.FILL)
|
|
114
|
+
assertValidFill(step, at);
|
|
115
|
+
else if (step.params?.fill !== undefined)
|
|
116
|
+
throw new Error(`${at}: params.fill applies only to fill steps`);
|
|
117
|
+
}
|
|
118
|
+
function assertValidHold(step, at) {
|
|
119
|
+
if (step.cardinality === 'many')
|
|
120
|
+
throw new Error(`${at}: hold locates a single row (cardinality first)`);
|
|
121
|
+
const hold = step.params?.hold;
|
|
122
|
+
if (hold === undefined)
|
|
123
|
+
return;
|
|
124
|
+
if (!isPlainObject(hold))
|
|
125
|
+
throw new Error(`${at}: params.hold must be an object`);
|
|
126
|
+
if (hold.ttlSeconds !== undefined && (!Number.isInteger(hold.ttlSeconds)
|
|
127
|
+
|| hold.ttlSeconds < types_1.SCAN_HOLD_TTL_MIN_SECONDS || hold.ttlSeconds > types_1.SCAN_HOLD_TTL_MAX_SECONDS)) {
|
|
128
|
+
throw new Error(`${at}: params.hold.ttlSeconds must be ${types_1.SCAN_HOLD_TTL_MIN_SECONDS}-${types_1.SCAN_HOLD_TTL_MAX_SECONDS}`);
|
|
129
|
+
}
|
|
130
|
+
if (hold.label !== undefined && typeof hold.label !== 'string') {
|
|
131
|
+
throw new Error(`${at}: params.hold.label must be a template string`);
|
|
132
|
+
}
|
|
133
|
+
if (hold.expect !== undefined) {
|
|
134
|
+
if (!isPlainObject(hold.expect) || !isSchemeList(hold.expect.schemes)) {
|
|
135
|
+
throw new Error(`${at}: params.hold.expect.schemes must be a non-empty array of scheme versions`);
|
|
136
|
+
}
|
|
137
|
+
if (hold.expect.prompt !== undefined && typeof hold.expect.prompt !== 'string') {
|
|
138
|
+
throw new Error(`${at}: params.hold.expect.prompt must be markdown`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function assertValidFill(step, at) {
|
|
143
|
+
const fill = step.params?.fill;
|
|
144
|
+
if (!fill || !isPlainObject(fill))
|
|
145
|
+
throw new Error(`${at}: fill requires params.fill`);
|
|
146
|
+
if (fill.into !== 'subject' && fill.into !== 'scanned') {
|
|
147
|
+
throw new Error(`${at}: params.fill.into must be 'subject' or 'scanned'`);
|
|
148
|
+
}
|
|
149
|
+
const separator = fill.separator ?? types_1.SCAN_FILL_SEPARATOR_DEFAULT;
|
|
150
|
+
if (typeof separator !== 'string' || separator.length !== 1) {
|
|
151
|
+
throw new Error(`${at}: params.fill.separator must be one character`);
|
|
152
|
+
}
|
|
153
|
+
if (fill.payload !== undefined && !isPlainObject(fill.payload)) {
|
|
154
|
+
throw new Error(`${at}: params.fill.payload must be an object`);
|
|
155
|
+
}
|
|
156
|
+
if (step.confirm)
|
|
157
|
+
throw new Error(`${at}: fill cannot carry confirm`);
|
|
158
|
+
}
|
|
@@ -5,6 +5,13 @@ import { type ScanScheme, type ScanStep } from '../../types';
|
|
|
5
5
|
* than a loud upsert failure.
|
|
6
6
|
*/
|
|
7
7
|
export declare function assertValidScheme(scheme: Partial<ScanScheme>): void;
|
|
8
|
+
/**
|
|
9
|
+
* A scheme must read codes no other scheme reads. Delimited and fixed
|
|
10
|
+
* schemes are told apart by their version prefix; a gtin scheme has none,
|
|
11
|
+
* so there is at most one, and no enabled fixed scheme may accept a GTIN
|
|
12
|
+
* length while it is enabled. Throws naming both schemes.
|
|
13
|
+
*/
|
|
14
|
+
export declare function assertSchemesCoexist(candidate: Partial<ScanScheme>, existing: ScanScheme[]): void;
|
|
8
15
|
/** Identity rules never walk steps — their fallback is the unknown-badge screen. */
|
|
9
16
|
export declare function assertValidIdentityRule(steps: ScanStep[]): void;
|
|
10
17
|
/**
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.assertValidScheme = assertValidScheme;
|
|
4
|
+
exports.assertSchemesCoexist = assertSchemesCoexist;
|
|
4
5
|
exports.assertValidIdentityRule = assertValidIdentityRule;
|
|
5
6
|
exports.assertValidSteps = assertValidSteps;
|
|
6
7
|
const types_1 = require("../../types");
|
|
8
|
+
const scan_code_1 = require("../../shared/scan-code");
|
|
7
9
|
const facet_sql_1 = require("../escalation/facet-sql");
|
|
10
|
+
const validate_subject_1 = require("./validate-subject");
|
|
8
11
|
const VALID_VERBS = new Set(Object.values(types_1.SCAN_VERBS));
|
|
9
12
|
/** Double-scan selection tokens — short, label-printable, never scheme-shaped. */
|
|
10
13
|
const CHOICE_CODE = /^[A-Za-z0-9_-]{1,32}$/;
|
|
@@ -22,6 +25,12 @@ function assertValidScheme(scheme) {
|
|
|
22
25
|
if (!scheme.target_facet)
|
|
23
26
|
throw new Error('scheme target_facet is required');
|
|
24
27
|
const encoding = scheme.encoding ?? types_1.SCAN_ENCODINGS.FIXED;
|
|
28
|
+
if (!Object.values(types_1.SCAN_ENCODINGS).includes(encoding)) {
|
|
29
|
+
throw new Error(`unknown scheme encoding "${encoding}"`);
|
|
30
|
+
}
|
|
31
|
+
if (encoding === types_1.SCAN_ENCODINGS.GTIN && (scheme.kind ?? types_1.SCAN_SCHEME_KINDS.ACTION) !== types_1.SCAN_SCHEME_KINDS.ACTION) {
|
|
32
|
+
throw new Error('gtin encoding applies only to action schemes');
|
|
33
|
+
}
|
|
25
34
|
if (encoding === types_1.SCAN_ENCODINGS.FIXED) {
|
|
26
35
|
if (!Number.isInteger(scheme.target_length) || scheme.target_length < 1) {
|
|
27
36
|
throw new Error('fixed encoding requires a positive integer target_length');
|
|
@@ -48,11 +57,50 @@ function assertValidScheme(scheme) {
|
|
|
48
57
|
if (!Number.isInteger(scheme.grant_max_uses ?? 0) || (scheme.grant_max_uses ?? 0) < 0) {
|
|
49
58
|
throw new Error('grant_max_uses must be a non-negative integer');
|
|
50
59
|
}
|
|
60
|
+
const scope = scheme.grant_scope ?? types_1.SCAN_GRANT_SCOPES.ACTION;
|
|
61
|
+
if (!Object.values(types_1.SCAN_GRANT_SCOPES).includes(scope)) {
|
|
62
|
+
throw new Error(`unknown grant_scope "${scope}"`);
|
|
63
|
+
}
|
|
51
64
|
}
|
|
52
|
-
else if (scheme.grant_ttl_seconds != null || (scheme.grant_max_uses ?? 0) !== 0
|
|
65
|
+
else if (scheme.grant_ttl_seconds != null || (scheme.grant_max_uses ?? 0) !== 0
|
|
66
|
+
|| (scheme.grant_scope ?? types_1.SCAN_GRANT_SCOPES.ACTION) !== types_1.SCAN_GRANT_SCOPES.ACTION) {
|
|
53
67
|
throw new Error('grant policy applies only to identity schemes');
|
|
54
68
|
}
|
|
55
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* A scheme must read codes no other scheme reads. Delimited and fixed
|
|
72
|
+
* schemes are told apart by their version prefix; a gtin scheme has none,
|
|
73
|
+
* so there is at most one, and no enabled fixed scheme may accept a GTIN
|
|
74
|
+
* length while it is enabled. Throws naming both schemes.
|
|
75
|
+
*/
|
|
76
|
+
function assertSchemesCoexist(candidate, existing) {
|
|
77
|
+
const others = existing.filter((s) => s.version !== candidate.version);
|
|
78
|
+
const encoding = candidate.encoding ?? types_1.SCAN_ENCODINGS.FIXED;
|
|
79
|
+
const enabled = candidate.enabled ?? true;
|
|
80
|
+
if (encoding === types_1.SCAN_ENCODINGS.GTIN) {
|
|
81
|
+
const gtin = others.find((s) => s.encoding === types_1.SCAN_ENCODINGS.GTIN);
|
|
82
|
+
if (gtin) {
|
|
83
|
+
throw new Error(`scheme ${gtin.version} ("${gtin.name}") already reads manufacturer barcodes; only one gtin scheme is allowed`);
|
|
84
|
+
}
|
|
85
|
+
if (!enabled)
|
|
86
|
+
return;
|
|
87
|
+
const clash = others.find((s) => s.enabled && s.encoding === types_1.SCAN_ENCODINGS.FIXED
|
|
88
|
+
&& (0, scan_code_1.fixedCodeLengths)(s).some((n) => types_1.GTIN_LENGTHS.includes(n)));
|
|
89
|
+
if (clash) {
|
|
90
|
+
throw new Error(`fixed scheme ${clash.version} ("${clash.name}") accepts ${(0, scan_code_1.fixedCodeLengths)(clash).join(' or ')}-digit codes, which a gtin scheme also reads; change its target_length or leave the gtin scheme disabled`);
|
|
91
|
+
}
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (encoding === types_1.SCAN_ENCODINGS.FIXED && enabled) {
|
|
95
|
+
const lengths = (0, scan_code_1.fixedCodeLengths)({ target_length: candidate.target_length ?? null });
|
|
96
|
+
if (!lengths.some((n) => types_1.GTIN_LENGTHS.includes(n)))
|
|
97
|
+
return;
|
|
98
|
+
const gtin = others.find((s) => s.enabled && s.encoding === types_1.SCAN_ENCODINGS.GTIN);
|
|
99
|
+
if (gtin) {
|
|
100
|
+
throw new Error(`a fixed scheme accepting ${lengths.join(' or ')}-digit codes collides with gtin scheme ${gtin.version} ("${gtin.name}"); change target_length or disable the gtin scheme`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
56
104
|
/** Identity rules never walk steps — their fallback is the unknown-badge screen. */
|
|
57
105
|
function assertValidIdentityRule(steps) {
|
|
58
106
|
if (Array.isArray(steps) && steps.length > 0) {
|
|
@@ -73,7 +121,8 @@ function assertValidChoices(choices, at) {
|
|
|
73
121
|
throw new Error(`${cat}: label is required`);
|
|
74
122
|
if (!VALID_VERBS.has(choice.verb))
|
|
75
123
|
throw new Error(`${cat}: unknown verb "${choice.verb}"`);
|
|
76
|
-
if (choice.verb === types_1.SCAN_VERBS.PRESENT || choice.verb === types_1.SCAN_VERBS.SHOW_LIST
|
|
124
|
+
if (choice.verb === types_1.SCAN_VERBS.PRESENT || choice.verb === types_1.SCAN_VERBS.SHOW_LIST
|
|
125
|
+
|| choice.verb === types_1.SCAN_VERBS.FILL) {
|
|
77
126
|
throw new Error(`${cat}: ${choice.verb} cannot be a choice verb`);
|
|
78
127
|
}
|
|
79
128
|
if (choice.confirm && !choice.confirm.prompt) {
|
|
@@ -157,10 +206,38 @@ function assertValidSteps(steps) {
|
|
|
157
206
|
if (options?.containerRoles !== undefined && !Array.isArray(options.containerRoles)) {
|
|
158
207
|
throw new Error(`${at}: params.accumulate.containerRoles must be an array`);
|
|
159
208
|
}
|
|
160
|
-
|
|
209
|
+
const container = options?.container;
|
|
210
|
+
if (container !== undefined) {
|
|
211
|
+
if (!container || typeof container !== 'object' || Array.isArray(container)) {
|
|
212
|
+
throw new Error(`${at}: params.accumulate.container must be an object`);
|
|
213
|
+
}
|
|
214
|
+
for (const list of ['roles', 'types', 'subtypes']) {
|
|
215
|
+
const value = container[list];
|
|
216
|
+
if (value !== undefined && (!Array.isArray(value) || !value.every((v) => typeof v === 'string' && v))) {
|
|
217
|
+
throw new Error(`${at}: params.accumulate.container.${list} must be an array of strings`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
if (container.facets !== undefined
|
|
221
|
+
&& (!container.facets || typeof container.facets !== 'object' || Array.isArray(container.facets))) {
|
|
222
|
+
throw new Error(`${at}: params.accumulate.container.facets must be an object`);
|
|
223
|
+
}
|
|
224
|
+
if (!options?.containerFacet && options?.from !== 'subject') {
|
|
225
|
+
throw new Error(`${at}: params.accumulate.container requires params.accumulate.containerFacet or from: 'subject'`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
if (!options?.containerFacet && !options?.into && !step.params?.itemKey) {
|
|
161
229
|
throw new Error(`${at}: accumulate requires params.itemKey or params.accumulate.containerFacet`);
|
|
162
230
|
}
|
|
163
231
|
}
|
|
232
|
+
(0, validate_subject_1.assertValidSubjectStep)(step, at);
|
|
233
|
+
if (step.done !== undefined) {
|
|
234
|
+
if (!step.done || typeof step.done !== 'object' || typeof step.done.markdown !== 'string' || !step.done.markdown) {
|
|
235
|
+
throw new Error(`${at}: done.markdown is required`);
|
|
236
|
+
}
|
|
237
|
+
if (!types_1.SCAN_MUTATING_VERBS.includes(step.verb)) {
|
|
238
|
+
throw new Error(`${at}: done applies only to steps that write`);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
164
241
|
assertValidTemplateTokens(step, at);
|
|
165
242
|
if (step.query && step.query.roles && !Array.isArray(step.query.roles)) {
|
|
166
243
|
throw new Error(`${at}: query.roles must be an array`);
|
|
@@ -179,21 +256,39 @@ function assertValidSteps(steps) {
|
|
|
179
256
|
}
|
|
180
257
|
});
|
|
181
258
|
}
|
|
182
|
-
const BAG_TOKEN = /\{(claim|item)\.([^}]*)\}/g;
|
|
259
|
+
const BAG_TOKEN = /\{(claim|item|subject|container|fill)\.([^}]*)\}/g;
|
|
183
260
|
/**
|
|
184
|
-
*
|
|
185
|
-
* the
|
|
261
|
+
* Bag tokens name facet keys and may only read what the step has:
|
|
262
|
+
* `{item.…}` the row an item-mode accumulate or a hold located,
|
|
263
|
+
* `{subject.…}` the held subject (steps with a subject gate), and
|
|
264
|
+
* `{container.…}` / `{fill.…}` only inside refusal and done copy, where a
|
|
265
|
+
* subject accumulate or a fill has read them.
|
|
186
266
|
*/
|
|
187
267
|
function assertValidTemplateTokens(step, at) {
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
268
|
+
const itemRow = (step.verb === types_1.SCAN_VERBS.ACCUMULATE && !!step.params?.accumulate?.containerFacet)
|
|
269
|
+
|| step.verb === types_1.SCAN_VERBS.HOLD;
|
|
270
|
+
const check = (value, inRefusal) => {
|
|
271
|
+
for (const match of JSON.stringify(value ?? {}).matchAll(BAG_TOKEN)) {
|
|
272
|
+
const [token, bag, facet] = match;
|
|
273
|
+
if (!facet_sql_1.FACET_KEY.test(facet)) {
|
|
274
|
+
throw new Error(`${at}: template token ${token} must name a facet key`);
|
|
275
|
+
}
|
|
276
|
+
if (bag === 'item' && !itemRow) {
|
|
277
|
+
throw new Error(`${at}: ${token} reads the located item row, which only an item-mode accumulate or a hold step has`);
|
|
278
|
+
}
|
|
279
|
+
if (bag === 'subject' && !step.subject) {
|
|
280
|
+
throw new Error(`${at}: ${token} reads the held subject, which only a step with a subject gate has`);
|
|
281
|
+
}
|
|
282
|
+
if (bag === 'container' && !(inRefusal && step.params?.accumulate?.from === 'subject')) {
|
|
283
|
+
throw new Error(`${at}: ${token} is readable only in the refusal or done copy of a from-subject accumulate step`);
|
|
284
|
+
}
|
|
285
|
+
if (bag === 'fill' && !(inRefusal && step.verb === types_1.SCAN_VERBS.FILL)) {
|
|
286
|
+
throw new Error(`${at}: ${token} is readable only in the refusal or done copy of a fill step`);
|
|
287
|
+
}
|
|
197
288
|
}
|
|
198
|
-
}
|
|
289
|
+
};
|
|
290
|
+
check(step.params, false);
|
|
291
|
+
check(step.match, false);
|
|
292
|
+
check(step.refuse, true);
|
|
293
|
+
check(step.done, true);
|
|
199
294
|
}
|