@hotmeshio/long-tail 0.10.10 → 0.10.13
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/list.d.ts +1 -0
- package/build/api/escalations/list.js +12 -4
- package/build/api/escalations/metadata.d.ts +11 -0
- package/build/api/escalations/metadata.js +27 -7
- package/build/api/roles.d.ts +2 -0
- package/build/api/roles.js +4 -0
- package/build/api/scan-codes/config.d.ts +22 -0
- package/build/api/scan-codes/config.js +136 -0
- package/build/api/scan-codes/execute.d.ts +9 -0
- package/build/api/scan-codes/execute.js +372 -0
- package/build/api/scan-codes/index.d.ts +2 -0
- package/build/api/scan-codes/index.js +14 -0
- package/build/lib/db/schemas/025_ops_home_default.sql +11 -0
- package/build/lib/db/schemas/026_scan_codes.sql +51 -0
- package/build/lib/db/schemas/027_scan_codes_reindex.sql +23 -0
- package/build/lib/events/system-events.js +4 -0
- package/build/modules/features.d.ts +17 -0
- package/build/modules/features.js +2 -0
- package/build/routes/escalations/list.js +1 -0
- package/build/routes/index.js +2 -0
- package/build/routes/scan-codes.d.ts +2 -0
- package/build/routes/scan-codes.js +138 -0
- package/build/sdk/index.d.ts +4 -0
- package/build/services/escalation/crud.d.ts +1 -1
- package/build/services/escalation/crud.js +4 -2
- package/build/services/escalation/queries.d.ts +1 -0
- package/build/services/escalation/queries.js +2 -0
- package/build/services/escalation/sql.d.ts +11 -6
- package/build/services/escalation/sql.js +20 -20
- package/build/services/role/index.js +1 -0
- package/build/services/role/sql.d.ts +6 -2
- package/build/services/role/sql.js +11 -2
- package/build/services/role/types.d.ts +9 -0
- package/build/services/scan-code/index.d.ts +4 -0
- package/build/services/scan-code/index.js +21 -0
- package/build/services/scan-code/parse.d.ts +35 -0
- package/build/services/scan-code/parse.js +108 -0
- package/build/services/scan-code/read.d.ts +5 -0
- package/build/services/scan-code/read.js +50 -0
- package/build/services/scan-code/sql.d.ts +10 -0
- package/build/services/scan-code/sql.js +57 -0
- package/build/services/scan-code/validate.d.ts +12 -0
- package/build/services/scan-code/validate.js +78 -0
- package/build/services/scan-code/write.d.ts +26 -0
- package/build/services/scan-code/write.js +71 -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-transition.d.ts +47 -0
- package/build/shared/form-validation/x-lt-transition.js +65 -0
- package/build/system/mcp-servers/admin/index.d.ts +1 -0
- package/build/system/mcp-servers/admin/index.js +5 -2
- package/build/system/mcp-servers/admin/scan-codes.d.ts +10 -0
- package/build/system/mcp-servers/admin/scan-codes.js +111 -0
- package/build/system/mcp-servers/admin/schemas.d.ts +235 -14
- package/build/system/mcp-servers/admin/schemas.js +51 -0
- package/build/system/mcp-servers/admin/users.js +1 -0
- package/build/system/seed/tool-manifests-admin.d.ts +1462 -0
- package/build/system/seed/tool-manifests-admin.js +7 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/events.d.ts +9 -0
- package/build/types/index.d.ts +2 -0
- package/build/types/index.js +10 -1
- package/build/types/scan-code.d.ts +183 -0
- package/build/types/scan-code.js +80 -0
- package/build/types/startup.d.ts +14 -0
- package/dashboard/dist/assets/{AdminDashboard-cGYuppUP.js → AdminDashboard-Bv3pHBzn.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-cGYuppUP.js.map → AdminDashboard-Bv3pHBzn.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-DwaUyoCy.js → AgentConfigPage-Dk2zlvDb.js} +6 -6
- package/dashboard/dist/assets/{AgentConfigPage-DwaUyoCy.js.map → AgentConfigPage-Dk2zlvDb.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-DxpFaltM.js → AgentDetailPage-DUno6EGs.js} +2 -2
- package/dashboard/dist/assets/{AgentDetailPage-DxpFaltM.js.map → AgentDetailPage-DUno6EGs.js.map} +1 -1
- package/dashboard/dist/assets/{AgentsPage-ByOoA8oT.js → AgentsPage-CToVu1qj.js} +2 -2
- package/dashboard/dist/assets/{AgentsPage-ByOoA8oT.js.map → AgentsPage-CToVu1qj.js.map} +1 -1
- package/dashboard/dist/assets/{AutoGrowTextarea-y-oNY51_.js → AutoGrowTextarea-DgEQeRQw.js} +2 -2
- package/dashboard/dist/assets/{AutoGrowTextarea-y-oNY51_.js.map → AutoGrowTextarea-DgEQeRQw.js.map} +1 -1
- package/dashboard/dist/assets/AvailableEscalationsPage-DldboL4W.js +2 -0
- package/dashboard/dist/assets/AvailableEscalationsPage-DldboL4W.js.map +1 -0
- package/dashboard/dist/assets/BotPicker-DQOpVB4M.js +2 -0
- package/dashboard/dist/assets/{BotPicker-Dohv8dhR.js.map → BotPicker-DQOpVB4M.js.map} +1 -1
- package/dashboard/dist/assets/{CapabilitiesPage-DeijFG3J.js → CapabilitiesPage-Dmf46PUJ.js} +2 -2
- package/dashboard/dist/assets/{CapabilitiesPage-DeijFG3J.js.map → CapabilitiesPage-Dmf46PUJ.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-BPNwS4eO.js → CollapsibleSection-CDADefUY.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-BPNwS4eO.js.map → CollapsibleSection-CDADefUY.js.map} +1 -1
- package/dashboard/dist/assets/{ConfirmDeleteModal-DD7SEMeX.js → ConfirmDeleteModal-CQsJUzEa.js} +2 -2
- package/dashboard/dist/assets/{ConfirmDeleteModal-DD7SEMeX.js.map → ConfirmDeleteModal-CQsJUzEa.js.map} +1 -1
- package/dashboard/dist/assets/{CopyableId-BpB-NvDh.js → CopyableId-4Lqlc5cU.js} +2 -2
- package/dashboard/dist/assets/{CopyableId-BpB-NvDh.js.map → CopyableId-4Lqlc5cU.js.map} +1 -1
- package/dashboard/dist/assets/CountdownTimer-DPjIkerB.js +2 -0
- package/dashboard/dist/assets/{CountdownTimer-BF71ldGF.js.map → CountdownTimer-DPjIkerB.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialsPage-oeNmMzTM.js → CredentialsPage-8LIEvomi.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-oeNmMzTM.js.map → CredentialsPage-8LIEvomi.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-CebR1m2k.js → CronLabel-CK3WSsM5.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-CebR1m2k.js.map → CronLabel-CK3WSsM5.js.map} +1 -1
- package/dashboard/dist/assets/{CustomDurationPicker-Bh9QdBVw.js → CustomDurationPicker-FPmlA6cE.js} +2 -2
- package/dashboard/dist/assets/{CustomDurationPicker-Bh9QdBVw.js.map → CustomDurationPicker-FPmlA6cE.js.map} +1 -1
- package/dashboard/dist/assets/{DataTable-BTu2AaEl.js → DataTable-Bir0Xs1p.js} +2 -2
- package/dashboard/dist/assets/{DataTable-BTu2AaEl.js.map → DataTable-Bir0Xs1p.js.map} +1 -1
- package/dashboard/dist/assets/{DropZone-Bavzt2QR.js → DropZone-CL9gA7pu.js} +2 -2
- package/dashboard/dist/assets/{DropZone-Bavzt2QR.js.map → DropZone-CL9gA7pu.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-Caa6CU_y.js → ElapsedCell-BZVkVxE0.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-Caa6CU_y.js.map → ElapsedCell-BZVkVxE0.js.map} +1 -1
- package/dashboard/dist/assets/{EmptyState-BcsfPq9T.js → EmptyState-lpUFYfun.js} +2 -2
- package/dashboard/dist/assets/{EmptyState-BcsfPq9T.js.map → EmptyState-lpUFYfun.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationListSchemaPage-CAGfq0eK.js → EscalationListSchemaPage-kYLdUtZX.js} +3 -3
- package/dashboard/dist/assets/{EscalationListSchemaPage-CAGfq0eK.js.map → EscalationListSchemaPage-kYLdUtZX.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationSchemaPage-qDD4ur6P.js → EscalationSchemaPage-kUmCDivo.js} +3 -3
- package/dashboard/dist/assets/{EscalationSchemaPage-qDD4ur6P.js.map → EscalationSchemaPage-kUmCDivo.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-CC1wRTzy.js → EscalationsOverview-D17auO-m.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-CC1wRTzy.js.map → EscalationsOverview-D17auO-m.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-4JeTcXr_.js → EventTable-CwPWl163.js} +2 -2
- package/dashboard/dist/assets/{EventTable-4JeTcXr_.js.map → EventTable-CwPWl163.js.map} +1 -1
- package/dashboard/dist/assets/{FilterBar-BOV8DWIO.js → FilterBar-D7GghUsU.js} +2 -2
- package/dashboard/dist/assets/{FilterBar-BOV8DWIO.js.map → FilterBar-D7GghUsU.js.map} +1 -1
- package/dashboard/dist/assets/{GraphInvokePage-C0i1speW.js → GraphInvokePage-D11uOnZi.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-C0i1speW.js.map → GraphInvokePage-D11uOnZi.js.map} +1 -1
- package/dashboard/dist/assets/HomePage-Bcq10Bxx.js +2 -0
- package/dashboard/dist/assets/HomePage-Bcq10Bxx.js.map +1 -0
- package/dashboard/dist/assets/ListToolbar-IPXsTb3Q.js +2 -0
- package/dashboard/dist/assets/ListToolbar-IPXsTb3Q.js.map +1 -0
- package/dashboard/dist/assets/{McpOverview-Chn2zIXr.js → McpOverview-Dx2j0KkF.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-Chn2zIXr.js.map → McpOverview-Dx2j0KkF.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-Cv1FKrvw.js → McpQueryDetailPage-CzF_bna8.js} +3 -3
- package/dashboard/dist/assets/{McpQueryDetailPage-Cv1FKrvw.js.map → McpQueryDetailPage-CzF_bna8.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryPage-Dzn8JE4E.js → McpQueryPage-CNsuiw_q.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-Dzn8JE4E.js.map → McpQueryPage-CNsuiw_q.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunDetailPage-CuNtR4Ed.js → McpRunDetailPage-BJguEMS0.js} +2 -2
- package/dashboard/dist/assets/{McpRunDetailPage-CuNtR4Ed.js.map → McpRunDetailPage-BJguEMS0.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-C8iifeKN.js → McpRunsPage-CK96s3Nt.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-C8iifeKN.js.map → McpRunsPage-CK96s3Nt.js.map} +1 -1
- package/dashboard/dist/assets/{Modal-CA2Iv02H.js → Modal-BU7No9NH.js} +2 -2
- package/dashboard/dist/assets/{Modal-CA2Iv02H.js.map → Modal-BU7No9NH.js.map} +1 -1
- package/dashboard/dist/assets/{NamespacePill-ep9Zmokr.js → NamespacePill-B9Vc_Pz2.js} +2 -2
- package/dashboard/dist/assets/{NamespacePill-ep9Zmokr.js.map → NamespacePill-B9Vc_Pz2.js.map} +1 -1
- package/dashboard/dist/assets/OperationsPage-DvWrLuH6.js +2 -0
- package/dashboard/dist/assets/OperationsPage-DvWrLuH6.js.map +1 -0
- package/dashboard/dist/assets/OperatorDashboard-C-jE0IRA.js +2 -0
- package/dashboard/dist/assets/OperatorDashboard-C-jE0IRA.js.map +1 -0
- package/dashboard/dist/assets/{PageHeader-Bw8RNkqR.js → PageHeader-Ce4GcIYo.js} +2 -2
- package/dashboard/dist/assets/{PageHeader-Bw8RNkqR.js.map → PageHeader-Ce4GcIYo.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeaderWithStats-NR_4idn6.js → PageHeaderWithStats-Ck0KZvXD.js} +2 -2
- package/dashboard/dist/assets/{PageHeaderWithStats-NR_4idn6.js.map → PageHeaderWithStats-Ck0KZvXD.js.map} +1 -1
- package/dashboard/dist/assets/{PersonaDetailPage-DKILoUqL.js → PersonaDetailPage-CJ6jqo7h.js} +2 -2
- package/dashboard/dist/assets/{PersonaDetailPage-DKILoUqL.js.map → PersonaDetailPage-CJ6jqo7h.js.map} +1 -1
- package/dashboard/dist/assets/{PersonasPage-qvzHTrFw.js → PersonasPage-D8hL3kL5.js} +2 -2
- package/dashboard/dist/assets/{PersonasPage-qvzHTrFw.js.map → PersonasPage-D8hL3kL5.js.map} +1 -1
- package/dashboard/dist/assets/{PriorityBadge-CCERr9vQ.js → PriorityBadge-BETdj4M-.js} +2 -2
- package/dashboard/dist/assets/{PriorityBadge-CCERr9vQ.js.map → PriorityBadge-BETdj4M-.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessDetailPage-C3LfeKvi.js → ProcessDetailPage-Vnx8Z5_y.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-C3LfeKvi.js.map → ProcessDetailPage-Vnx8Z5_y.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-OoZ_u4ty.js → ProcessesListPage-DRYtvS3N.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-OoZ_u4ty.js.map → ProcessesListPage-DRYtvS3N.js.map} +1 -1
- package/dashboard/dist/assets/RoleDetailPage-BKkUvTO-.js +8 -0
- package/dashboard/dist/assets/RoleDetailPage-BKkUvTO-.js.map +1 -0
- package/dashboard/dist/assets/{RolePill-TySZq7dB.js → RolePill-CnuBPhPw.js} +2 -2
- package/dashboard/dist/assets/{RolePill-TySZq7dB.js.map → RolePill-CnuBPhPw.js.map} +1 -1
- package/dashboard/dist/assets/RolesPage-BHzWK9n6.js +2 -0
- package/dashboard/dist/assets/{RolesPage-CNueMVuJ.js.map → RolesPage-BHzWK9n6.js.map} +1 -1
- package/dashboard/dist/assets/{RowActions-BA9L9djf.js → RowActions-eYrzgQSj.js} +2 -2
- package/dashboard/dist/assets/{RowActions-BA9L9djf.js.map → RowActions-eYrzgQSj.js.map} +1 -1
- package/dashboard/dist/assets/{RunAsSelector-CwWEpiSF.js → RunAsSelector-CS3KQ-BF.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-CwWEpiSF.js.map → RunAsSelector-CS3KQ-BF.js.map} +1 -1
- package/dashboard/dist/assets/ScanCodesPage-BW4P4zWf.js +2 -0
- package/dashboard/dist/assets/ScanCodesPage-BW4P4zWf.js.map +1 -0
- package/dashboard/dist/assets/ScanSchemeDetailPage-BLykA4j-.js +2 -0
- package/dashboard/dist/assets/ScanSchemeDetailPage-BLykA4j-.js.map +1 -0
- package/dashboard/dist/assets/{ScopeBadge-C7Uixtmk.js → ScopeBadge-BUpYpS3x.js} +2 -2
- package/dashboard/dist/assets/{ScopeBadge-C7Uixtmk.js.map → ScopeBadge-BUpYpS3x.js.map} +1 -1
- package/dashboard/dist/assets/{StatCard-Ca-ngCaD.js → StatCard-BXQ8dD9Y.js} +2 -2
- package/dashboard/dist/assets/{StatCard-Ca-ngCaD.js.map → StatCard-BXQ8dD9Y.js.map} +1 -1
- package/dashboard/dist/assets/{StatusBadge-BwUvykDo.js → StatusBadge-DkgllZHv.js} +2 -2
- package/dashboard/dist/assets/{StatusBadge-BwUvykDo.js.map → StatusBadge-DkgllZHv.js.map} +1 -1
- package/dashboard/dist/assets/{StickyPagination-DvIF3kQK.js → StickyPagination-hMrnLXde.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-DvIF3kQK.js.map → StickyPagination-hMrnLXde.js.map} +1 -1
- package/dashboard/dist/assets/{StreamMessageDetail-DkFK_XGD.js → StreamMessageDetail-DyJyZwBl.js} +2 -2
- package/dashboard/dist/assets/{StreamMessageDetail-DkFK_XGD.js.map → StreamMessageDetail-DyJyZwBl.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-CMw-Et6h.js → SwimlaneTimeline-BlzV74V5.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-CMw-Et6h.js.map → SwimlaneTimeline-BlzV74V5.js.map} +1 -1
- package/dashboard/dist/assets/{TagInput-D8gSp48D.js → TagInput-BbZ25nNe.js} +2 -2
- package/dashboard/dist/assets/{TagInput-D8gSp48D.js.map → TagInput-BbZ25nNe.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-BhXuChOf.js → TaskDetailPage-B0p_Z4J_.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-BhXuChOf.js.map → TaskDetailPage-B0p_Z4J_.js.map} +1 -1
- package/dashboard/dist/assets/{TaskQueuePill-CHqolBmU.js → TaskQueuePill-D0QKBrN3.js} +2 -2
- package/dashboard/dist/assets/{TaskQueuePill-CHqolBmU.js.map → TaskQueuePill-D0QKBrN3.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-6JHQQ5QZ.js → TasksListPage-CiGR2QiQ.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-6JHQQ5QZ.js.map → TasksListPage-CiGR2QiQ.js.map} +1 -1
- package/dashboard/dist/assets/TimeAgo-D_DA9ucC.js +2 -0
- package/dashboard/dist/assets/{TimeAgo-CInx-vzY.js.map → TimeAgo-D_DA9ucC.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-Fq17Zrsu.js → TimestampCell-C7rkC9nh.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-Fq17Zrsu.js.map → TimestampCell-C7rkC9nh.js.map} +1 -1
- package/dashboard/dist/assets/{ToolPill-BbgMDhaE.js → ToolPill-8xY9rkoc.js} +2 -2
- package/dashboard/dist/assets/{ToolPill-BbgMDhaE.js.map → ToolPill-8xY9rkoc.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-DhjEe59s.js → ToolTestPanel-E8efYGYs.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-DhjEe59s.js.map → ToolTestPanel-E8efYGYs.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-DbIdmQpQ.js → TopicDetailPage-B455XrRc.js} +3 -3
- package/dashboard/dist/assets/{TopicDetailPage-DbIdmQpQ.js.map → TopicDetailPage-B455XrRc.js.map} +1 -1
- package/dashboard/dist/assets/{TopicsPage-CAP-GUbr.js → TopicsPage-1VAc29Qw.js} +2 -2
- package/dashboard/dist/assets/{TopicsPage-CAP-GUbr.js.map → TopicsPage-1VAc29Qw.js.map} +1 -1
- package/dashboard/dist/assets/UserName-DikzjQHJ.js +2 -0
- package/dashboard/dist/assets/{UserName-DggcLkSc.js.map → UserName-DikzjQHJ.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowExecutionPage-Bmra5fVt.js → WorkflowExecutionPage-C15GSAoe.js} +2 -2
- package/dashboard/dist/assets/{WorkflowExecutionPage-Bmra5fVt.js.map → WorkflowExecutionPage-C15GSAoe.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowPill-CcUUVugA.js → WorkflowPill-Da406nEj.js} +2 -2
- package/dashboard/dist/assets/{WorkflowPill-CcUUVugA.js.map → WorkflowPill-Da406nEj.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsDashboard-BQsZAGYU.js → WorkflowsDashboard-BMQd_0tW.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-BQsZAGYU.js.map → WorkflowsDashboard-BMQd_0tW.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-CeliraHZ.js → WorkflowsOverview-CdxjVifp.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-CeliraHZ.js.map → WorkflowsOverview-CdxjVifp.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-DGxlonrV.js → YamlWorkflowDetailPage-DNVffIXa.js} +13 -13
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-DGxlonrV.js.map → YamlWorkflowDetailPage-DNVffIXa.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-DnT8UiyQ.js → YamlWorkflowsPage-BGP8wuos.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-DnT8UiyQ.js.map → YamlWorkflowsPage-BGP8wuos.js.map} +1 -1
- package/dashboard/dist/assets/{agents-mRV7m4sh.js → agents-BZJLIJ4h.js} +2 -2
- package/dashboard/dist/assets/{agents-mRV7m4sh.js.map → agents-BZJLIJ4h.js.map} +1 -1
- package/dashboard/dist/assets/{bots-SONCZlCM.js → bots-ClLcDGJb.js} +2 -2
- package/dashboard/dist/assets/{bots-SONCZlCM.js.map → bots-ClLcDGJb.js.map} +1 -1
- package/dashboard/dist/assets/capabilities-IaCcS7ge.js +2 -0
- package/dashboard/dist/assets/{capabilities-DZjCMN32.js.map → capabilities-IaCcS7ge.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-RQNXjna2.js → controlplane-Zi4m_MSx.js} +2 -2
- package/dashboard/dist/assets/{controlplane-RQNXjna2.js.map → controlplane-Zi4m_MSx.js.map} +1 -1
- package/dashboard/dist/assets/escalation-columns-BY2mg9DY.js +2 -0
- package/dashboard/dist/assets/escalation-columns-BY2mg9DY.js.map +1 -0
- package/dashboard/dist/assets/{index-ymm58cTW.js → index-BqGnhkh0.js} +2 -2
- package/dashboard/dist/assets/{index-ymm58cTW.js.map → index-BqGnhkh0.js.map} +1 -1
- package/dashboard/dist/assets/index-BzkE48xJ.js +6 -0
- package/dashboard/dist/assets/index-BzkE48xJ.js.map +1 -0
- package/dashboard/dist/assets/{index-CkeSxuZ0.js → index-C3o4OisO.js} +2 -2
- package/dashboard/dist/assets/{index-CkeSxuZ0.js.map → index-C3o4OisO.js.map} +1 -1
- package/dashboard/dist/assets/{index-DY_hlZCQ.js → index-CJu2PBNx.js} +2 -2
- package/dashboard/dist/assets/{index-DY_hlZCQ.js.map → index-CJu2PBNx.js.map} +1 -1
- package/dashboard/dist/assets/{index-DYKRtstT.js → index-CLmZaNTK.js} +2 -2
- package/dashboard/dist/assets/{index-DYKRtstT.js.map → index-CLmZaNTK.js.map} +1 -1
- package/dashboard/dist/assets/index-CfAi1OsI.js +65 -0
- package/dashboard/dist/assets/index-CfAi1OsI.js.map +1 -0
- package/dashboard/dist/assets/{index-CK-6m8e_.js → index-CmnNqpWg.js} +2 -2
- package/dashboard/dist/assets/{index-CK-6m8e_.js.map → index-CmnNqpWg.js.map} +1 -1
- package/dashboard/dist/assets/{index-DFJF8aWz.js → index-CvNBdkB1.js} +3 -3
- package/dashboard/dist/assets/{index-DFJF8aWz.js.map → index-CvNBdkB1.js.map} +1 -1
- package/dashboard/dist/assets/{index-DbZpL10z.js → index-D0zFReGL.js} +2 -2
- package/dashboard/dist/assets/{index-DbZpL10z.js.map → index-D0zFReGL.js.map} +1 -1
- package/dashboard/dist/assets/{index-C6GsrvX1.js → index-Dldi3Q3M.js} +2 -2
- package/dashboard/dist/assets/{index-C6GsrvX1.js.map → index-Dldi3Q3M.js.map} +1 -1
- package/dashboard/dist/assets/{index-DqsLfO-0.js → index-kiKZresb.js} +2 -2
- package/dashboard/dist/assets/{index-DqsLfO-0.js.map → index-kiKZresb.js.map} +1 -1
- package/dashboard/dist/assets/index-mKcQGi2B.js +3 -0
- package/dashboard/dist/assets/index-mKcQGi2B.js.map +1 -0
- package/dashboard/dist/assets/{index-CxVGlkK6.js → index-yGNt29V9.js} +2 -2
- package/dashboard/dist/assets/{index-CxVGlkK6.js.map → index-yGNt29V9.js.map} +1 -1
- package/dashboard/dist/assets/index-zQiUPfxA.css +1 -0
- package/dashboard/dist/assets/{knowledge-Bawo8u7l.js → knowledge-DWLxGTib.js} +2 -2
- package/dashboard/dist/assets/{knowledge-Bawo8u7l.js.map → knowledge-DWLxGTib.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-CKIpbpRZ.js → mcp-B6AARZ2I.js} +2 -2
- package/dashboard/dist/assets/{mcp-CKIpbpRZ.js.map → mcp-B6AARZ2I.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-vld4hYxQ.js → mcp-query-DrkvBU3a.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-vld4hYxQ.js.map → mcp-query-DrkvBU3a.js.map} +1 -1
- package/dashboard/dist/assets/{personas-BsARc3df.js → personas-Cmz2SAEU.js} +2 -2
- package/dashboard/dist/assets/{personas-BsARc3df.js.map → personas-Cmz2SAEU.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-BTSL-5ko.js → pipelines-CSgfVCMy.js} +2 -2
- package/dashboard/dist/assets/{pipelines-BTSL-5ko.js.map → pipelines-CSgfVCMy.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-DggQdNbj.js → tasks-UOtUkDk-.js} +2 -2
- package/dashboard/dist/assets/{tasks-DggQdNbj.js.map → tasks-UOtUkDk-.js.map} +1 -1
- package/dashboard/dist/assets/{topics-DzAKa34X.js → topics-Df5hGh6o.js} +2 -2
- package/dashboard/dist/assets/{topics-DzAKa34X.js.map → topics-Df5hGh6o.js.map} +1 -1
- package/dashboard/dist/assets/{useDebouncedValue-BA5S7V54.js → useDebouncedValue-C4P2jQuh.js} +2 -2
- package/dashboard/dist/assets/{useDebouncedValue-BA5S7V54.js.map → useDebouncedValue-C4P2jQuh.js.map} +1 -1
- package/dashboard/dist/assets/{useEventHooks-5uI9oI5W.js → useEventHooks-PDbuSJ12.js} +2 -2
- package/dashboard/dist/assets/{useEventHooks-5uI9oI5W.js.map → useEventHooks-PDbuSJ12.js.map} +1 -1
- package/dashboard/dist/assets/{useFilterParams-CvRyYHJN.js → useFilterParams-crmlBw_l.js} +2 -2
- package/dashboard/dist/assets/{useFilterParams-CvRyYHJN.js.map → useFilterParams-crmlBw_l.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-CEKzFIqe.js → useNamespace-tZSOlge3.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-CEKzFIqe.js.map → useNamespace-tZSOlge3.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-hHgX1Z50.js → useYamlActivityEvents-CINLzE32.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-hHgX1Z50.js.map → useYamlActivityEvents-CINLzE32.js.map} +1 -1
- package/dashboard/dist/assets/{users-AO8lUyNr.js → users-G8qwyZKS.js} +2 -2
- package/dashboard/dist/assets/{users-AO8lUyNr.js.map → users-G8qwyZKS.js.map} +1 -1
- package/dashboard/dist/assets/{vendor-icons-DN9yGSuM.js → vendor-icons-BpZiWH2f.js} +40 -40
- package/dashboard/dist/assets/vendor-icons-BpZiWH2f.js.map +1 -0
- package/dashboard/dist/assets/{vendor-query-B2UbickB.js → vendor-query-RUZdMvN6.js} +2 -2
- package/dashboard/dist/assets/{vendor-query-B2UbickB.js.map → vendor-query-RUZdMvN6.js.map} +1 -1
- package/dashboard/dist/assets/{vendor-react-BpdAFEQc.js → vendor-react-CdqEC2zv.js} +3 -3
- package/dashboard/dist/assets/{vendor-react-BpdAFEQc.js.map → vendor-react-CdqEC2zv.js.map} +1 -1
- package/dashboard/dist/assets/{workflows-PtnlRK09.js → workflows-DbPqi1TW.js} +2 -2
- package/dashboard/dist/assets/{workflows-PtnlRK09.js.map → workflows-DbPqi1TW.js.map} +1 -1
- package/dashboard/dist/assets/{yaml-workflows-DPu3Y8vG.js → yaml-workflows-DozD8hpR.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-DPu3Y8vG.js.map → yaml-workflows-DozD8hpR.js.map} +1 -1
- package/dashboard/dist/index.html +5 -5
- package/docs/dashboard.md +9 -2
- package/docs/design-principles.md +4 -0
- package/docs/hitl/pinned-views.md +3 -3
- package/docs/hitl/x-lt-transition.md +105 -0
- package/docs/operations.md +1 -1
- package/docs/scan-codes.md +243 -0
- package/package.json +2 -2
- package/dashboard/dist/assets/AvailableEscalationsPage-C1vtTvqP.js +0 -2
- package/dashboard/dist/assets/AvailableEscalationsPage-C1vtTvqP.js.map +0 -1
- package/dashboard/dist/assets/BotPicker-Dohv8dhR.js +0 -2
- package/dashboard/dist/assets/CountdownTimer-BF71ldGF.js +0 -2
- package/dashboard/dist/assets/HomePage-HPCd8SjF.js +0 -2
- package/dashboard/dist/assets/HomePage-HPCd8SjF.js.map +0 -1
- package/dashboard/dist/assets/ListToolbar-BFHVOba6.js +0 -2
- package/dashboard/dist/assets/ListToolbar-BFHVOba6.js.map +0 -1
- package/dashboard/dist/assets/OperationsPage-flrZ-EJ9.js +0 -2
- package/dashboard/dist/assets/OperationsPage-flrZ-EJ9.js.map +0 -1
- package/dashboard/dist/assets/OperatorDashboard-Dhs2eo8p.js +0 -2
- package/dashboard/dist/assets/OperatorDashboard-Dhs2eo8p.js.map +0 -1
- package/dashboard/dist/assets/RoleDetailPage-D70jTLZm.js +0 -8
- package/dashboard/dist/assets/RoleDetailPage-D70jTLZm.js.map +0 -1
- package/dashboard/dist/assets/RolesPage-CNueMVuJ.js +0 -2
- package/dashboard/dist/assets/TimeAgo-CInx-vzY.js +0 -2
- package/dashboard/dist/assets/UserName-DggcLkSc.js +0 -2
- package/dashboard/dist/assets/capabilities-DZjCMN32.js +0 -2
- package/dashboard/dist/assets/escalation-columns-XLEcZRCg.js +0 -2
- package/dashboard/dist/assets/escalation-columns-XLEcZRCg.js.map +0 -1
- package/dashboard/dist/assets/index-2BwHxjCw.css +0 -1
- package/dashboard/dist/assets/index-D2CfSx_x.js +0 -5
- package/dashboard/dist/assets/index-D2CfSx_x.js.map +0 -1
- package/dashboard/dist/assets/index-Dh3CVChT.js +0 -63
- package/dashboard/dist/assets/index-Dh3CVChT.js.map +0 -1
- package/dashboard/dist/assets/index-iHV3d7o3.js +0 -6
- package/dashboard/dist/assets/index-iHV3d7o3.js.map +0 -1
- package/dashboard/dist/assets/role-display-Dvo2lDpU.js +0 -2
- package/dashboard/dist/assets/role-display-Dvo2lDpU.js.map +0 -1
- package/dashboard/dist/assets/vendor-icons-DN9yGSuM.js.map +0 -1
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const express_1 = require("express");
|
|
37
|
+
const api = __importStar(require("../api/scan-codes"));
|
|
38
|
+
const auth_1 = require("../modules/auth");
|
|
39
|
+
const router = (0, express_1.Router)();
|
|
40
|
+
// ── Execute ───────────────────────────────────────────────────────────────
|
|
41
|
+
/**
|
|
42
|
+
* POST /api/scan-codes/execute
|
|
43
|
+
* Execute a raw scan code (from any input source) as the calling user.
|
|
44
|
+
* Every terminal state is a structured 200 outcome.
|
|
45
|
+
*/
|
|
46
|
+
router.post('/execute', async (req, res) => {
|
|
47
|
+
const result = await api.executeScanCode({ code: req.body.code }, req.auth);
|
|
48
|
+
res.status(result.status).json(result.data ?? { error: result.error });
|
|
49
|
+
});
|
|
50
|
+
// ── Scheme CRUD (admin, engineer, superadmin) ─────────────────────────────
|
|
51
|
+
/**
|
|
52
|
+
* GET /api/scan-codes/schemes
|
|
53
|
+
* List all scan schemes.
|
|
54
|
+
*/
|
|
55
|
+
router.get('/schemes', async (_req, res) => {
|
|
56
|
+
const result = await api.listScanSchemes();
|
|
57
|
+
res.status(result.status).json(result.data ?? { error: result.error });
|
|
58
|
+
});
|
|
59
|
+
/**
|
|
60
|
+
* GET /api/scan-codes/schemes/:version
|
|
61
|
+
* Get one scheme with its rules.
|
|
62
|
+
*/
|
|
63
|
+
router.get('/schemes/:version', async (req, res) => {
|
|
64
|
+
const result = await api.getScanScheme({ version: Number(req.params.version) });
|
|
65
|
+
res.status(result.status).json(result.data ?? { error: result.error });
|
|
66
|
+
});
|
|
67
|
+
/**
|
|
68
|
+
* PUT /api/scan-codes/schemes/:version
|
|
69
|
+
* Create or replace a scan scheme. Admin, engineer, or superadmin.
|
|
70
|
+
*/
|
|
71
|
+
router.put('/schemes/:version', auth_1.requireRoleManager, async (req, res) => {
|
|
72
|
+
const result = await api.upsertScanScheme({
|
|
73
|
+
version: Number(req.params.version),
|
|
74
|
+
name: req.body.name,
|
|
75
|
+
description: req.body.description,
|
|
76
|
+
target_facet: req.body.target_facet,
|
|
77
|
+
encoding: req.body.encoding,
|
|
78
|
+
delimiter: req.body.delimiter,
|
|
79
|
+
target_length: req.body.target_length,
|
|
80
|
+
enabled: req.body.enabled,
|
|
81
|
+
});
|
|
82
|
+
res.status(result.status).json(result.data ?? { error: result.error });
|
|
83
|
+
});
|
|
84
|
+
/**
|
|
85
|
+
* DELETE /api/scan-codes/schemes/:version
|
|
86
|
+
* Delete a scheme and its rules (cascade). Admin, engineer, or superadmin.
|
|
87
|
+
*/
|
|
88
|
+
router.delete('/schemes/:version', auth_1.requireRoleManager, async (req, res) => {
|
|
89
|
+
const result = await api.deleteScanScheme({ version: Number(req.params.version) });
|
|
90
|
+
res.status(result.status).json(result.data ?? { error: result.error });
|
|
91
|
+
});
|
|
92
|
+
// ── Rule CRUD (admin, engineer, superadmin) ───────────────────────────────
|
|
93
|
+
/**
|
|
94
|
+
* GET /api/scan-codes/schemes/:version/actions
|
|
95
|
+
* List a scheme's rules.
|
|
96
|
+
*/
|
|
97
|
+
router.get('/schemes/:version/actions', async (req, res) => {
|
|
98
|
+
const result = await api.listScanRules({ version: Number(req.params.version) });
|
|
99
|
+
res.status(result.status).json(result.data ?? { error: result.error });
|
|
100
|
+
});
|
|
101
|
+
/**
|
|
102
|
+
* GET /api/scan-codes/schemes/:version/actions/:category
|
|
103
|
+
* Get one rule.
|
|
104
|
+
*/
|
|
105
|
+
router.get('/schemes/:version/actions/:category', async (req, res) => {
|
|
106
|
+
const result = await api.getScanRule({
|
|
107
|
+
version: Number(req.params.version),
|
|
108
|
+
category: req.params.category,
|
|
109
|
+
});
|
|
110
|
+
res.status(result.status).json(result.data ?? { error: result.error });
|
|
111
|
+
});
|
|
112
|
+
/**
|
|
113
|
+
* PUT /api/scan-codes/schemes/:version/actions/:category
|
|
114
|
+
* Create or replace a rule. Admin, engineer, or superadmin.
|
|
115
|
+
*/
|
|
116
|
+
router.put('/schemes/:version/actions/:category', auth_1.requireRoleManager, async (req, res) => {
|
|
117
|
+
const result = await api.upsertScanRule({
|
|
118
|
+
scheme_version: Number(req.params.version),
|
|
119
|
+
category: req.params.category,
|
|
120
|
+
name: req.body.name,
|
|
121
|
+
steps: req.body.steps,
|
|
122
|
+
fallback: req.body.fallback,
|
|
123
|
+
enabled: req.body.enabled,
|
|
124
|
+
});
|
|
125
|
+
res.status(result.status).json(result.data ?? { error: result.error });
|
|
126
|
+
});
|
|
127
|
+
/**
|
|
128
|
+
* DELETE /api/scan-codes/schemes/:version/actions/:category
|
|
129
|
+
* Delete a rule. Admin, engineer, or superadmin.
|
|
130
|
+
*/
|
|
131
|
+
router.delete('/schemes/:version/actions/:category', auth_1.requireRoleManager, async (req, res) => {
|
|
132
|
+
const result = await api.deleteScanRule({
|
|
133
|
+
version: Number(req.params.version),
|
|
134
|
+
category: req.params.category,
|
|
135
|
+
});
|
|
136
|
+
res.status(result.status).json(result.data ?? { error: result.error });
|
|
137
|
+
});
|
|
138
|
+
exports.default = router;
|
package/build/sdk/index.d.ts
CHANGED
|
@@ -96,6 +96,7 @@ export declare function createClient(options?: LTClientOptions): {
|
|
|
96
96
|
type?: string;
|
|
97
97
|
subtype?: string;
|
|
98
98
|
assigned_to?: string;
|
|
99
|
+
parent_id?: string;
|
|
99
100
|
claimed?: boolean;
|
|
100
101
|
priority?: number;
|
|
101
102
|
limit?: number;
|
|
@@ -202,6 +203,7 @@ export declare function createClient(options?: LTClientOptions): {
|
|
|
202
203
|
assignee?: string;
|
|
203
204
|
metadata?: Record<string, any>;
|
|
204
205
|
provisionIfAbsent?: import("../api/escalations/helpers").ProvisionIfAbsent;
|
|
206
|
+
restrictRoles?: string[];
|
|
205
207
|
}, auth?: LTApiAuth) => Promise<LTApiResult<any>>;
|
|
206
208
|
resolveByMetadata: (input: {
|
|
207
209
|
key: string;
|
|
@@ -209,6 +211,8 @@ export declare function createClient(options?: LTClientOptions): {
|
|
|
209
211
|
resolverPayload: Record<string, any>;
|
|
210
212
|
assignee?: string;
|
|
211
213
|
metadata?: Record<string, any>;
|
|
214
|
+
restrictRoles?: string[];
|
|
215
|
+
extraFacets?: Record<string, any>;
|
|
212
216
|
}, auth?: LTApiAuth) => Promise<LTApiResult<any>>;
|
|
213
217
|
searchByFacets: (input: import("..").FacetQuery, auth?: LTApiAuth) => Promise<LTApiResult<any>>;
|
|
214
218
|
claimGroups: (input: {
|
|
@@ -241,4 +241,4 @@ export interface ResolveByMetadataResult {
|
|
|
241
241
|
* business logic over the shared table, so it runs as one atomic statement on
|
|
242
242
|
* `hmsh_escalations` rather than through the generic SDK resolve.
|
|
243
243
|
*/
|
|
244
|
-
export declare function resolveByMetadataAtomic(key: string, value: string, userId: string, resolverPayload: Record<string, any>, metadata?: Record<string, any>, writeAllRoles?: string[] | null, writeSelfRoles?: string[] | null, enforcingRoles?: string[] | null, assertId?: string | null): Promise<ResolveByMetadataResult>;
|
|
244
|
+
export declare function resolveByMetadataAtomic(key: string, value: string, userId: string, resolverPayload: Record<string, any>, metadata?: Record<string, any>, writeAllRoles?: string[] | null, writeSelfRoles?: string[] | null, enforcingRoles?: string[] | null, assertId?: string | null, extraFacets?: Record<string, any> | null): Promise<ResolveByMetadataResult>;
|
|
@@ -554,10 +554,12 @@ async function claimByMetadata(key, value, userId, durationMinutes = 30, metadat
|
|
|
554
554
|
* business logic over the shared table, so it runs as one atomic statement on
|
|
555
555
|
* `hmsh_escalations` rather than through the generic SDK resolve.
|
|
556
556
|
*/
|
|
557
|
-
async function resolveByMetadataAtomic(key, value, userId, resolverPayload, metadata, writeAllRoles, writeSelfRoles, enforcingRoles, assertId) {
|
|
557
|
+
async function resolveByMetadataAtomic(key, value, userId, resolverPayload, metadata, writeAllRoles, writeSelfRoles, enforcingRoles, assertId, extraFacets) {
|
|
558
558
|
await (0, client_1.ensureEscalationCompatView)();
|
|
559
559
|
const pool = (0, db_1.getPool)();
|
|
560
|
-
|
|
560
|
+
// The statement's filter is jsonb containment — extra facet guards simply
|
|
561
|
+
// widen the containment object and ride the same atomic WHERE.
|
|
562
|
+
const filter = JSON.stringify({ [key]: value, ...(extraFacets ?? {}) });
|
|
561
563
|
const payloadJson = JSON.stringify(resolverPayload);
|
|
562
564
|
const metaPatch = metadata ? JSON.stringify(metadata) : null;
|
|
563
565
|
// null write_all roles = global (no filter). A scoped caller passes its arrays
|
|
@@ -298,6 +298,8 @@ async function listEscalations(filters) {
|
|
|
298
298
|
};
|
|
299
299
|
if (filters.assigned_to)
|
|
300
300
|
where.assignedTo = filters.assigned_to;
|
|
301
|
+
if (filters.parent_id)
|
|
302
|
+
where.parentId = filters.parent_id;
|
|
301
303
|
if (heldNow)
|
|
302
304
|
where.available = false;
|
|
303
305
|
if (filters.metadata)
|
|
@@ -26,13 +26,18 @@ export declare function searchEscalationsQuery(orderBy: string): string;
|
|
|
26
26
|
* 3. `metadata.signal_id` present, row already claimed and claim not expired →
|
|
27
27
|
* a concurrent caller is handling the signal. `signal_already_claimed = true`;
|
|
28
28
|
* caller returns 409 without re-signaling.
|
|
29
|
-
* 4. `signal_key` present (atomic conditionLT) →
|
|
29
|
+
* 4. `signal_key` present (atomic conditionLT) → the write skips entirely.
|
|
30
30
|
* Caller invokes SDK resolve to atomically mark resolved + deliver the signal.
|
|
31
31
|
*
|
|
32
|
-
* Signal_id hardening: the
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
32
|
+
* Signal_id hardening: the write runs for signal_id rows too, stamping
|
|
33
|
+
* `assigned_to` inside the FOR UPDATE transaction so a concurrent second caller
|
|
34
|
+
* sees `signal_already_claimed = true` and aborts. The resolve columns skip
|
|
35
|
+
* signal_id rows (CASE branches) — the workflow resolves durably.
|
|
36
|
+
*
|
|
37
|
+
* ONE UPDATE does both claim and resolve: Postgres does not support a second
|
|
38
|
+
* same-statement UPDATE of a row already updated by an earlier CTE (the second
|
|
39
|
+
* silently no-ops), so a chained claim→resolve pair leaves the row claimed but
|
|
40
|
+
* pending. The resolve columns ride the claim UPDATE as CASE branches instead.
|
|
36
41
|
*
|
|
37
42
|
* $1 = metadata filter (jsonb), $2 = userId, $3 = resolver_payload (jsonb),
|
|
38
43
|
* $4 = metadata patch (jsonb, nullable), $5 = write_all roles (text[], null = global /
|
|
@@ -53,7 +58,7 @@ export declare function searchEscalationsQuery(orderBy: string): string;
|
|
|
53
58
|
* resolution surfaces as zero rows → the caller's conflict handling). This is
|
|
54
59
|
* the same pick-then-guarded-finish shape the signal outcomes already use.
|
|
55
60
|
*/
|
|
56
|
-
export declare const RESOLVE_BY_METADATA_ATOMIC = "WITH target AS MATERIALIZED (\n SELECT *\n FROM public.hmsh_escalations\n WHERE metadata @> $1::jsonb\n AND status = 'pending'\n AND (\n $5::text[] IS NULL\n OR role = ANY($5)\n OR (role = ANY($6::text[]) AND assigned_to = $2)\n )\n AND ($8::uuid IS NULL OR id = $8::uuid)\n ORDER BY priority ASC, created_at ASC\n LIMIT 1\n FOR UPDATE\n),\
|
|
61
|
+
export declare const RESOLVE_BY_METADATA_ATOMIC = "WITH target AS MATERIALIZED (\n SELECT *\n FROM public.hmsh_escalations\n WHERE metadata @> $1::jsonb\n AND status = 'pending'\n AND (\n $5::text[] IS NULL\n OR role = ANY($5)\n OR (role = ANY($6::text[]) AND assigned_to = $2)\n )\n AND ($8::uuid IS NULL OR id = $8::uuid)\n ORDER BY priority ASC, created_at ASC\n LIMIT 1\n FOR UPDATE\n),\nwritten AS (\n UPDATE public.hmsh_escalations e\n SET assigned_to = COALESCE(e.assigned_to, $2),\n claimed_at = COALESCE(e.claimed_at, NOW()),\n assigned_until = CASE\n WHEN e.assigned_to IS NOT NULL AND e.assigned_until > NOW() THEN e.assigned_until\n ELSE NOW() + INTERVAL '5 minutes' END,\n claim_expires_at = CASE\n WHEN e.assigned_to IS NOT NULL AND e.assigned_until > NOW() THEN e.claim_expires_at\n ELSE NOW() + INTERVAL '5 minutes' END,\n metadata = CASE WHEN $4::jsonb IS NOT NULL\n THEN COALESCE(e.metadata, '{}'::jsonb) || $4::jsonb\n ELSE e.metadata END,\n status = CASE WHEN (target.metadata->>'signal_id') IS NULL\n THEN 'resolved' ELSE e.status END,\n resolved_at = CASE WHEN (target.metadata->>'signal_id') IS NULL\n THEN NOW() ELSE e.resolved_at END,\n resolver_payload = CASE WHEN (target.metadata->>'signal_id') IS NULL\n THEN $3 ELSE e.resolver_payload END,\n updated_at = NOW()\n FROM target\n WHERE e.id = target.id\n AND target.signal_key IS NULL\n AND ($7::text[] IS NULL OR NOT (target.role = ANY($7)))\n RETURNING e.*\n)\nSELECT\n written.*,\n target.id AS target_id,\n target.role AS target_role,\n target.metadata AS target_metadata,\n target.envelope AS target_envelope,\n target.escalation_payload AS target_escalation_payload,\n target.metadata->>'signal_id' AS signal_id,\n target.signal_key AS signal_key,\n target.workflow_id AS target_workflow_id,\n target.workflow_type AS target_workflow_type,\n target.task_queue AS target_task_queue,\n (target.assigned_to IS NOT NULL\n AND target.assigned_until IS NOT NULL\n AND target.assigned_until > NOW()) AS signal_already_claimed,\n CASE\n WHEN written.status = 'resolved' THEN 'resolved'\n WHEN $7::text[] IS NOT NULL AND target.role = ANY($7) THEN 'validation_required'\n ELSE 'signal_required'\n END AS outcome\nFROM target\nLEFT JOIN written ON written.id = target.id";
|
|
57
62
|
/**
|
|
58
63
|
* Live counts — pending, active claims, and priority (past-threshold) per role.
|
|
59
64
|
*
|
|
@@ -108,13 +108,18 @@ function searchEscalationsQuery(orderBy) {
|
|
|
108
108
|
* 3. `metadata.signal_id` present, row already claimed and claim not expired →
|
|
109
109
|
* a concurrent caller is handling the signal. `signal_already_claimed = true`;
|
|
110
110
|
* caller returns 409 without re-signaling.
|
|
111
|
-
* 4. `signal_key` present (atomic conditionLT) →
|
|
111
|
+
* 4. `signal_key` present (atomic conditionLT) → the write skips entirely.
|
|
112
112
|
* Caller invokes SDK resolve to atomically mark resolved + deliver the signal.
|
|
113
113
|
*
|
|
114
|
-
* Signal_id hardening: the
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
114
|
+
* Signal_id hardening: the write runs for signal_id rows too, stamping
|
|
115
|
+
* `assigned_to` inside the FOR UPDATE transaction so a concurrent second caller
|
|
116
|
+
* sees `signal_already_claimed = true` and aborts. The resolve columns skip
|
|
117
|
+
* signal_id rows (CASE branches) — the workflow resolves durably.
|
|
118
|
+
*
|
|
119
|
+
* ONE UPDATE does both claim and resolve: Postgres does not support a second
|
|
120
|
+
* same-statement UPDATE of a row already updated by an earlier CTE (the second
|
|
121
|
+
* silently no-ops), so a chained claim→resolve pair leaves the row claimed but
|
|
122
|
+
* pending. The resolve columns ride the claim UPDATE as CASE branches instead.
|
|
118
123
|
*
|
|
119
124
|
* $1 = metadata filter (jsonb), $2 = userId, $3 = resolver_payload (jsonb),
|
|
120
125
|
* $4 = metadata patch (jsonb, nullable), $5 = write_all roles (text[], null = global /
|
|
@@ -151,7 +156,7 @@ WITH target AS MATERIALIZED (
|
|
|
151
156
|
LIMIT 1
|
|
152
157
|
FOR UPDATE
|
|
153
158
|
),
|
|
154
|
-
|
|
159
|
+
written AS (
|
|
155
160
|
UPDATE public.hmsh_escalations e
|
|
156
161
|
SET assigned_to = COALESCE(e.assigned_to, $2),
|
|
157
162
|
claimed_at = COALESCE(e.claimed_at, NOW()),
|
|
@@ -164,26 +169,21 @@ claimed AS (
|
|
|
164
169
|
metadata = CASE WHEN $4::jsonb IS NOT NULL
|
|
165
170
|
THEN COALESCE(e.metadata, '{}'::jsonb) || $4::jsonb
|
|
166
171
|
ELSE e.metadata END,
|
|
172
|
+
status = CASE WHEN (target.metadata->>'signal_id') IS NULL
|
|
173
|
+
THEN 'resolved' ELSE e.status END,
|
|
174
|
+
resolved_at = CASE WHEN (target.metadata->>'signal_id') IS NULL
|
|
175
|
+
THEN NOW() ELSE e.resolved_at END,
|
|
176
|
+
resolver_payload = CASE WHEN (target.metadata->>'signal_id') IS NULL
|
|
177
|
+
THEN $3 ELSE e.resolver_payload END,
|
|
167
178
|
updated_at = NOW()
|
|
168
179
|
FROM target
|
|
169
180
|
WHERE e.id = target.id
|
|
170
181
|
AND target.signal_key IS NULL
|
|
171
182
|
AND ($7::text[] IS NULL OR NOT (target.role = ANY($7)))
|
|
172
183
|
RETURNING e.*
|
|
173
|
-
),
|
|
174
|
-
resolved AS (
|
|
175
|
-
UPDATE public.hmsh_escalations e
|
|
176
|
-
SET status = 'resolved',
|
|
177
|
-
resolved_at = NOW(),
|
|
178
|
-
resolver_payload = $3,
|
|
179
|
-
updated_at = NOW()
|
|
180
|
-
FROM claimed
|
|
181
|
-
WHERE e.id = claimed.id
|
|
182
|
-
AND (claimed.metadata->>'signal_id') IS NULL
|
|
183
|
-
RETURNING e.*
|
|
184
184
|
)
|
|
185
185
|
SELECT
|
|
186
|
-
|
|
186
|
+
written.*,
|
|
187
187
|
target.id AS target_id,
|
|
188
188
|
target.role AS target_role,
|
|
189
189
|
target.metadata AS target_metadata,
|
|
@@ -198,12 +198,12 @@ SELECT
|
|
|
198
198
|
AND target.assigned_until IS NOT NULL
|
|
199
199
|
AND target.assigned_until > NOW()) AS signal_already_claimed,
|
|
200
200
|
CASE
|
|
201
|
-
WHEN
|
|
201
|
+
WHEN written.status = 'resolved' THEN 'resolved'
|
|
202
202
|
WHEN $7::text[] IS NOT NULL AND target.role = ANY($7) THEN 'validation_required'
|
|
203
203
|
ELSE 'signal_required'
|
|
204
204
|
END AS outcome
|
|
205
205
|
FROM target
|
|
206
|
-
LEFT JOIN
|
|
206
|
+
LEFT JOIN written ON written.id = target.id`;
|
|
207
207
|
// ---------------------------------------------------------------------------
|
|
208
208
|
// Station metrics — split into two queries with very different cost profiles.
|
|
209
209
|
//
|
|
@@ -149,6 +149,7 @@ async function updateRoleMetadata(role, input) {
|
|
|
149
149
|
provided('list_schema'), input.list_schema != null ? JSON.stringify(input.list_schema) : null,
|
|
150
150
|
provided('default_pins'), input.default_pins != null ? JSON.stringify(input.default_pins) : null,
|
|
151
151
|
provided('enforce_schema'), input.enforce_schema ?? null,
|
|
152
|
+
provided('ops_home_default'), input.ops_home_default ?? null,
|
|
152
153
|
]);
|
|
153
154
|
if (!rows[0])
|
|
154
155
|
return null;
|
|
@@ -46,8 +46,12 @@ export declare const DELETE_ROLE = "\n DELETE FROM lt_roles WHERE role = $1";
|
|
|
46
46
|
* enforce_schema ($33 = provided sentinel, $34 = value) is unversioned config:
|
|
47
47
|
* the server-side resolver-validation opt-in. The service layer invalidates
|
|
48
48
|
* the enforcement cache after this statement commits.
|
|
49
|
+
*
|
|
50
|
+
* ops_home_default ($35 = provided sentinel, $36 = value) is single-holder:
|
|
51
|
+
* setting it true clears the flag on every other role in the same statement
|
|
52
|
+
* (the home_clear CTE touches only OTHER rows, so the two UPDATEs never meet).
|
|
49
53
|
*/
|
|
50
|
-
export declare const UPDATE_ROLE_METADATA = "\n WITH updated AS (\n UPDATE lt_roles SET\n title = CASE WHEN $2::boolean THEN $3 ELSE title END,\n description = CASE WHEN $4::boolean THEN $5 ELSE description END,\n form_schema = CASE WHEN $6::boolean THEN $7::jsonb ELSE form_schema END,\n metadata_schema = CASE WHEN $8::boolean THEN $9::jsonb ELSE metadata_schema END,\n properties = CASE WHEN $10::boolean THEN COALESCE($11::jsonb, '{}'::jsonb) ELSE properties END,\n ops_visible = CASE WHEN $12::boolean THEN $13::boolean ELSE ops_visible END,\n parent_role = CASE WHEN $14::boolean THEN $15 ELSE parent_role END,\n sla_minutes = CASE WHEN $16::boolean THEN $17::numeric ELSE sla_minutes END,\n target_per_hour = CASE WHEN $18::boolean THEN $19::numeric ELSE target_per_hour END,\n worker_count = CASE WHEN $20::boolean THEN $21::int ELSE worker_count END,\n priority_threshold_minutes\n = CASE WHEN $22::boolean THEN $23::numeric ELSE priority_threshold_minutes END,\n priority_facet = CASE WHEN $24::boolean THEN $25 ELSE priority_facet END,\n list_schema = CASE WHEN $29::boolean THEN $30::jsonb ELSE list_schema END,\n default_pins = CASE WHEN $31::boolean THEN $32::jsonb ELSE default_pins END,\n enforce_schema = CASE WHEN $33::boolean THEN COALESCE($34::boolean, false) ELSE enforce_schema END,\n current_schema_version = CASE\n WHEN ($6::boolean AND $7::jsonb IS DISTINCT FROM form_schema)\n OR ($8::boolean AND $9::jsonb IS DISTINCT FROM metadata_schema)\n THEN COALESCE(current_schema_version, 0) + 1\n ELSE current_schema_version END,\n current_list_schema_version = CASE\n WHEN $29::boolean AND $30::jsonb IS DISTINCT FROM list_schema\n THEN COALESCE(current_list_schema_version, 0) + 1\n ELSE current_list_schema_version END\n WHERE role = $1\n RETURNING\n role, title, description, form_schema, metadata_schema, properties,\n ops_visible, parent_role, sla_minutes, target_per_hour, worker_count,\n priority_threshold_minutes, priority_facet,\n current_schema_version, list_schema, current_list_schema_version,\n default_pins, enforce_schema\n ), snapshot AS (\n INSERT INTO lt_role_schemas (role, version, form_schema, metadata_schema, change_summary)\n SELECT role, current_schema_version, form_schema, metadata_schema, $26\n FROM updated\n WHERE ($6::boolean OR $8::boolean) AND current_schema_version IS NOT NULL\n ON CONFLICT (role, version) DO NOTHING\n ), list_snapshot AS (\n INSERT INTO lt_role_list_schemas (role, version, list_schema, change_summary)\n SELECT role, current_list_schema_version, list_schema, $26\n FROM updated\n WHERE $29::boolean AND current_list_schema_version IS NOT NULL\n ON CONFLICT (role, version) DO NOTHING\n ), upstream_prune AS (\n DELETE FROM lt_role_upstreams\n WHERE $27::boolean AND role = $1 AND upstream_role <> ALL($28::text[])\n ), upstream_add AS (\n INSERT INTO lt_role_upstreams (role, upstream_role)\n SELECT $1, u FROM unnest($28::text[]) AS u\n WHERE $27::boolean\n ON CONFLICT DO NOTHING\n )\n SELECT * FROM updated";
|
|
54
|
+
export declare const UPDATE_ROLE_METADATA = "\n WITH home_clear AS (\n UPDATE lt_roles SET ops_home_default = false\n WHERE $35::boolean AND COALESCE($36::boolean, false) AND role <> $1 AND ops_home_default\n ), updated AS (\n UPDATE lt_roles SET\n title = CASE WHEN $2::boolean THEN $3 ELSE title END,\n description = CASE WHEN $4::boolean THEN $5 ELSE description END,\n form_schema = CASE WHEN $6::boolean THEN $7::jsonb ELSE form_schema END,\n metadata_schema = CASE WHEN $8::boolean THEN $9::jsonb ELSE metadata_schema END,\n properties = CASE WHEN $10::boolean THEN COALESCE($11::jsonb, '{}'::jsonb) ELSE properties END,\n ops_visible = CASE WHEN $12::boolean THEN $13::boolean ELSE ops_visible END,\n parent_role = CASE WHEN $14::boolean THEN $15 ELSE parent_role END,\n sla_minutes = CASE WHEN $16::boolean THEN $17::numeric ELSE sla_minutes END,\n target_per_hour = CASE WHEN $18::boolean THEN $19::numeric ELSE target_per_hour END,\n worker_count = CASE WHEN $20::boolean THEN $21::int ELSE worker_count END,\n priority_threshold_minutes\n = CASE WHEN $22::boolean THEN $23::numeric ELSE priority_threshold_minutes END,\n priority_facet = CASE WHEN $24::boolean THEN $25 ELSE priority_facet END,\n list_schema = CASE WHEN $29::boolean THEN $30::jsonb ELSE list_schema END,\n default_pins = CASE WHEN $31::boolean THEN $32::jsonb ELSE default_pins END,\n enforce_schema = CASE WHEN $33::boolean THEN COALESCE($34::boolean, false) ELSE enforce_schema END,\n ops_home_default = CASE WHEN $35::boolean THEN COALESCE($36::boolean, false) ELSE ops_home_default END,\n current_schema_version = CASE\n WHEN ($6::boolean AND $7::jsonb IS DISTINCT FROM form_schema)\n OR ($8::boolean AND $9::jsonb IS DISTINCT FROM metadata_schema)\n THEN COALESCE(current_schema_version, 0) + 1\n ELSE current_schema_version END,\n current_list_schema_version = CASE\n WHEN $29::boolean AND $30::jsonb IS DISTINCT FROM list_schema\n THEN COALESCE(current_list_schema_version, 0) + 1\n ELSE current_list_schema_version END\n WHERE role = $1\n RETURNING\n role, title, description, form_schema, metadata_schema, properties,\n ops_visible, ops_home_default, parent_role, sla_minutes, target_per_hour, worker_count,\n priority_threshold_minutes, priority_facet,\n current_schema_version, list_schema, current_list_schema_version,\n default_pins, enforce_schema\n ), snapshot AS (\n INSERT INTO lt_role_schemas (role, version, form_schema, metadata_schema, change_summary)\n SELECT role, current_schema_version, form_schema, metadata_schema, $26\n FROM updated\n WHERE ($6::boolean OR $8::boolean) AND current_schema_version IS NOT NULL\n ON CONFLICT (role, version) DO NOTHING\n ), list_snapshot AS (\n INSERT INTO lt_role_list_schemas (role, version, list_schema, change_summary)\n SELECT role, current_list_schema_version, list_schema, $26\n FROM updated\n WHERE $29::boolean AND current_list_schema_version IS NOT NULL\n ON CONFLICT (role, version) DO NOTHING\n ), upstream_prune AS (\n DELETE FROM lt_role_upstreams\n WHERE $27::boolean AND role = $1 AND upstream_role <> ALL($28::text[])\n ), upstream_add AS (\n INSERT INTO lt_role_upstreams (role, upstream_role)\n SELECT $1, u FROM unnest($28::text[]) AS u\n WHERE $27::boolean\n ON CONFLICT DO NOTHING\n )\n SELECT * FROM updated";
|
|
51
55
|
export declare const GET_ROLE_FORM_SCHEMA = "\n SELECT form_schema FROM lt_roles WHERE role = $1";
|
|
52
56
|
/**
|
|
53
57
|
* The set of roles with server-side resolver validation turned on. Small and
|
|
@@ -71,7 +75,7 @@ export declare const GET_ROLE_LIST_SCHEMA_VERSION = "\n SELECT s.role, s.versio
|
|
|
71
75
|
* never versioned its list schema still answers, with version NULL).
|
|
72
76
|
*/
|
|
73
77
|
export declare const GET_ROLE_LIST_SCHEMA_CURRENT = "\n SELECT r.role, r.current_list_schema_version AS version, r.list_schema,\n s.change_summary, s.created_at,\n r.current_list_schema_version AS latest_version\n FROM lt_roles r\n LEFT JOIN lt_role_list_schemas s\n ON s.role = r.role AND s.version = r.current_list_schema_version\n WHERE r.role = $1";
|
|
74
|
-
export declare const LIST_ROLES_WITH_DETAILS = "\n WITH\n user_counts AS (\n SELECT role, COUNT(DISTINCT user_id)::int AS cnt\n FROM lt_user_roles\n GROUP BY role\n ),\n chain_counts AS (\n SELECT role, COUNT(*)::int AS cnt\n FROM (\n SELECT source_role AS role FROM lt_config_role_escalations\n UNION ALL\n SELECT target_role AS role FROM lt_config_role_escalations\n ) c\n GROUP BY role\n ),\n workflow_counts AS (\n SELECT role, COUNT(*)::int AS cnt\n FROM lt_config_roles\n GROUP BY role\n ),\n upstreams AS (\n SELECT role, array_agg(upstream_role ORDER BY upstream_role) AS ups\n FROM lt_role_upstreams\n GROUP BY role\n )\n SELECT\n r.role,\n r.title,\n r.description,\n r.form_schema,\n r.metadata_schema,\n r.properties,\n r.ops_visible,\n r.parent_role,\n r.sla_minutes,\n r.target_per_hour,\n r.worker_count,\n r.priority_threshold_minutes,\n r.priority_facet,\n r.current_schema_version,\n r.list_schema,\n r.current_list_schema_version,\n r.default_pins,\n r.enforce_schema,\n COALESCE(up.ups, '{}') AS upstream_roles,\n COALESCE(uc.cnt, 0) AS user_count,\n COALESCE(cc.cnt, 0) AS chain_count,\n COALESCE(wc.cnt, 0) AS workflow_count\n FROM lt_roles r\n LEFT JOIN user_counts uc ON uc.role = r.role\n LEFT JOIN chain_counts cc ON cc.role = r.role\n LEFT JOIN workflow_counts wc ON wc.role = r.role\n LEFT JOIN upstreams up ON up.role = r.role\n ORDER BY r.role";
|
|
78
|
+
export declare const LIST_ROLES_WITH_DETAILS = "\n WITH\n user_counts AS (\n SELECT role, COUNT(DISTINCT user_id)::int AS cnt\n FROM lt_user_roles\n GROUP BY role\n ),\n chain_counts AS (\n SELECT role, COUNT(*)::int AS cnt\n FROM (\n SELECT source_role AS role FROM lt_config_role_escalations\n UNION ALL\n SELECT target_role AS role FROM lt_config_role_escalations\n ) c\n GROUP BY role\n ),\n workflow_counts AS (\n SELECT role, COUNT(*)::int AS cnt\n FROM lt_config_roles\n GROUP BY role\n ),\n upstreams AS (\n SELECT role, array_agg(upstream_role ORDER BY upstream_role) AS ups\n FROM lt_role_upstreams\n GROUP BY role\n )\n SELECT\n r.role,\n r.title,\n r.description,\n r.form_schema,\n r.metadata_schema,\n r.properties,\n r.ops_visible,\n r.ops_home_default,\n r.parent_role,\n r.sla_minutes,\n r.target_per_hour,\n r.worker_count,\n r.priority_threshold_minutes,\n r.priority_facet,\n r.current_schema_version,\n r.list_schema,\n r.current_list_schema_version,\n r.default_pins,\n r.enforce_schema,\n COALESCE(up.ups, '{}') AS upstream_roles,\n COALESCE(uc.cnt, 0) AS user_count,\n COALESCE(cc.cnt, 0) AS chain_count,\n COALESCE(wc.cnt, 0) AS workflow_count\n FROM lt_roles r\n LEFT JOIN user_counts uc ON uc.role = r.role\n LEFT JOIN chain_counts cc ON cc.role = r.role\n LEFT JOIN workflow_counts wc ON wc.role = r.role\n LEFT JOIN upstreams up ON up.role = r.role\n ORDER BY r.role";
|
|
75
79
|
export declare const COUNT_USER_ROLE_REFS = "\n SELECT COUNT(*)::int AS cnt FROM lt_user_roles WHERE role = $1";
|
|
76
80
|
export declare const COUNT_CHAIN_REFS = "\n SELECT COUNT(*)::int AS cnt\n FROM lt_config_role_escalations\n WHERE source_role = $1 OR target_role = $1";
|
|
77
81
|
export declare const COUNT_WORKFLOW_REFS = "\n SELECT COUNT(*)::int AS cnt FROM lt_config_roles WHERE role = $1";
|
|
@@ -80,9 +80,16 @@ exports.DELETE_ROLE = `
|
|
|
80
80
|
* enforce_schema ($33 = provided sentinel, $34 = value) is unversioned config:
|
|
81
81
|
* the server-side resolver-validation opt-in. The service layer invalidates
|
|
82
82
|
* the enforcement cache after this statement commits.
|
|
83
|
+
*
|
|
84
|
+
* ops_home_default ($35 = provided sentinel, $36 = value) is single-holder:
|
|
85
|
+
* setting it true clears the flag on every other role in the same statement
|
|
86
|
+
* (the home_clear CTE touches only OTHER rows, so the two UPDATEs never meet).
|
|
83
87
|
*/
|
|
84
88
|
exports.UPDATE_ROLE_METADATA = `
|
|
85
|
-
WITH
|
|
89
|
+
WITH home_clear AS (
|
|
90
|
+
UPDATE lt_roles SET ops_home_default = false
|
|
91
|
+
WHERE $35::boolean AND COALESCE($36::boolean, false) AND role <> $1 AND ops_home_default
|
|
92
|
+
), updated AS (
|
|
86
93
|
UPDATE lt_roles SET
|
|
87
94
|
title = CASE WHEN $2::boolean THEN $3 ELSE title END,
|
|
88
95
|
description = CASE WHEN $4::boolean THEN $5 ELSE description END,
|
|
@@ -100,6 +107,7 @@ exports.UPDATE_ROLE_METADATA = `
|
|
|
100
107
|
list_schema = CASE WHEN $29::boolean THEN $30::jsonb ELSE list_schema END,
|
|
101
108
|
default_pins = CASE WHEN $31::boolean THEN $32::jsonb ELSE default_pins END,
|
|
102
109
|
enforce_schema = CASE WHEN $33::boolean THEN COALESCE($34::boolean, false) ELSE enforce_schema END,
|
|
110
|
+
ops_home_default = CASE WHEN $35::boolean THEN COALESCE($36::boolean, false) ELSE ops_home_default END,
|
|
103
111
|
current_schema_version = CASE
|
|
104
112
|
WHEN ($6::boolean AND $7::jsonb IS DISTINCT FROM form_schema)
|
|
105
113
|
OR ($8::boolean AND $9::jsonb IS DISTINCT FROM metadata_schema)
|
|
@@ -112,7 +120,7 @@ exports.UPDATE_ROLE_METADATA = `
|
|
|
112
120
|
WHERE role = $1
|
|
113
121
|
RETURNING
|
|
114
122
|
role, title, description, form_schema, metadata_schema, properties,
|
|
115
|
-
ops_visible, parent_role, sla_minutes, target_per_hour, worker_count,
|
|
123
|
+
ops_visible, ops_home_default, parent_role, sla_minutes, target_per_hour, worker_count,
|
|
116
124
|
priority_threshold_minutes, priority_facet,
|
|
117
125
|
current_schema_version, list_schema, current_list_schema_version,
|
|
118
126
|
default_pins, enforce_schema
|
|
@@ -247,6 +255,7 @@ exports.LIST_ROLES_WITH_DETAILS = `
|
|
|
247
255
|
r.metadata_schema,
|
|
248
256
|
r.properties,
|
|
249
257
|
r.ops_visible,
|
|
258
|
+
r.ops_home_default,
|
|
250
259
|
r.parent_role,
|
|
251
260
|
r.sla_minutes,
|
|
252
261
|
r.target_per_hour,
|
|
@@ -20,6 +20,13 @@ export interface RoleDetail {
|
|
|
20
20
|
/** Free-form user-owned bag. No reserved keys — use for icons, colors, tags, etc. */
|
|
21
21
|
properties: Record<string, any>;
|
|
22
22
|
ops_visible: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Marks this role's sequence as the HOME page's default Pace Board segment.
|
|
25
|
+
* Single-holder: setting it on one role clears it everywhere else. Only
|
|
26
|
+
* meaningful while ops_visible is on; unset anywhere → the home board shows
|
|
27
|
+
* the primary (first) segment.
|
|
28
|
+
*/
|
|
29
|
+
ops_home_default: boolean;
|
|
23
30
|
parent_role: string | null;
|
|
24
31
|
/** Target resolution time (minutes). Part of the ops triangle. */
|
|
25
32
|
sla_minutes: number | null;
|
|
@@ -134,6 +141,8 @@ export interface UpdateRoleInput {
|
|
|
134
141
|
}[] | null;
|
|
135
142
|
properties?: Record<string, any> | null;
|
|
136
143
|
ops_visible?: boolean;
|
|
144
|
+
/** Make this role's sequence the home Pace Board's default segment (single-holder). */
|
|
145
|
+
ops_home_default?: boolean;
|
|
137
146
|
parent_role?: string | null;
|
|
138
147
|
sla_minutes?: number | null;
|
|
139
148
|
target_per_hour?: number | null;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { listScanSchemes, getScanScheme, listScanRules, getScanRule, } from './read';
|
|
2
|
+
export { upsertScanScheme, deleteScanScheme, upsertScanRule, deleteScanRule, seedScanScheme, seedScanRule, type ScanSchemeInput, type ScanRuleInput, } from './write';
|
|
3
|
+
export { parseScanCode, interpolateScanTemplate, type ScanParseResult, type ScanParseFailure, type ScanTemplateContext, } from './parse';
|
|
4
|
+
export { assertValidScheme, assertValidSteps } from './validate';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.assertValidSteps = exports.assertValidScheme = exports.interpolateScanTemplate = exports.parseScanCode = exports.seedScanRule = exports.seedScanScheme = exports.deleteScanRule = exports.upsertScanRule = exports.deleteScanScheme = exports.upsertScanScheme = exports.getScanRule = exports.listScanRules = exports.getScanScheme = exports.listScanSchemes = void 0;
|
|
4
|
+
var read_1 = require("./read");
|
|
5
|
+
Object.defineProperty(exports, "listScanSchemes", { enumerable: true, get: function () { return read_1.listScanSchemes; } });
|
|
6
|
+
Object.defineProperty(exports, "getScanScheme", { enumerable: true, get: function () { return read_1.getScanScheme; } });
|
|
7
|
+
Object.defineProperty(exports, "listScanRules", { enumerable: true, get: function () { return read_1.listScanRules; } });
|
|
8
|
+
Object.defineProperty(exports, "getScanRule", { enumerable: true, get: function () { return read_1.getScanRule; } });
|
|
9
|
+
var write_1 = require("./write");
|
|
10
|
+
Object.defineProperty(exports, "upsertScanScheme", { enumerable: true, get: function () { return write_1.upsertScanScheme; } });
|
|
11
|
+
Object.defineProperty(exports, "deleteScanScheme", { enumerable: true, get: function () { return write_1.deleteScanScheme; } });
|
|
12
|
+
Object.defineProperty(exports, "upsertScanRule", { enumerable: true, get: function () { return write_1.upsertScanRule; } });
|
|
13
|
+
Object.defineProperty(exports, "deleteScanRule", { enumerable: true, get: function () { return write_1.deleteScanRule; } });
|
|
14
|
+
Object.defineProperty(exports, "seedScanScheme", { enumerable: true, get: function () { return write_1.seedScanScheme; } });
|
|
15
|
+
Object.defineProperty(exports, "seedScanRule", { enumerable: true, get: function () { return write_1.seedScanRule; } });
|
|
16
|
+
var parse_1 = require("./parse");
|
|
17
|
+
Object.defineProperty(exports, "parseScanCode", { enumerable: true, get: function () { return parse_1.parseScanCode; } });
|
|
18
|
+
Object.defineProperty(exports, "interpolateScanTemplate", { enumerable: true, get: function () { return parse_1.interpolateScanTemplate; } });
|
|
19
|
+
var validate_1 = require("./validate");
|
|
20
|
+
Object.defineProperty(exports, "assertValidScheme", { enumerable: true, get: function () { return validate_1.assertValidScheme; } });
|
|
21
|
+
Object.defineProperty(exports, "assertValidSteps", { enumerable: true, get: function () { return validate_1.assertValidSteps; } });
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type ParsedScanCode, type ScanScheme } from '../../types';
|
|
2
|
+
export interface ScanParseFailure {
|
|
3
|
+
/** Why the code did not parse. */
|
|
4
|
+
reason: 'empty' | 'unknown_version' | 'scheme_disabled' | 'malformed';
|
|
5
|
+
detail: string;
|
|
6
|
+
}
|
|
7
|
+
export type ScanParseResult = {
|
|
8
|
+
ok: true;
|
|
9
|
+
parsed: ParsedScanCode;
|
|
10
|
+
scheme: ScanScheme;
|
|
11
|
+
} | {
|
|
12
|
+
ok: false;
|
|
13
|
+
failure: ScanParseFailure;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Parse a raw scan string against the configured schemes. Pure — no I/O.
|
|
17
|
+
*
|
|
18
|
+
* The leading TWO digits pick the scheme (10-99, so a code never starts with a
|
|
19
|
+
* leading zero); the scheme then defines how the remainder splits into a
|
|
20
|
+
* single-digit category (0-9) and the target:
|
|
21
|
+
* - delimited: `10:1:ABC-123` (delimiter from the scheme row)
|
|
22
|
+
* - fixed: `1017554332` (one category digit, then target_length digits)
|
|
23
|
+
*/
|
|
24
|
+
export declare function parseScanCode(raw: string, schemes: ScanScheme[]): ScanParseResult;
|
|
25
|
+
export interface ScanTemplateContext {
|
|
26
|
+
target: string;
|
|
27
|
+
category: string;
|
|
28
|
+
scannedAt: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Replace SCAN_TEMPLATE_TOKENS inside string values of a params object.
|
|
32
|
+
* Deep, pure, non-mutating. Only exact-token and in-string replacement of
|
|
33
|
+
* the three known tokens — no expression language.
|
|
34
|
+
*/
|
|
35
|
+
export declare function interpolateScanTemplate<T>(value: T, ctx: ScanTemplateContext): T;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseScanCode = parseScanCode;
|
|
4
|
+
exports.interpolateScanTemplate = interpolateScanTemplate;
|
|
5
|
+
const types_1 = require("../../types");
|
|
6
|
+
/**
|
|
7
|
+
* Parse a raw scan string against the configured schemes. Pure — no I/O.
|
|
8
|
+
*
|
|
9
|
+
* The leading TWO digits pick the scheme (10-99, so a code never starts with a
|
|
10
|
+
* leading zero); the scheme then defines how the remainder splits into a
|
|
11
|
+
* single-digit category (0-9) and the target:
|
|
12
|
+
* - delimited: `10:1:ABC-123` (delimiter from the scheme row)
|
|
13
|
+
* - fixed: `1017554332` (one category digit, then target_length digits)
|
|
14
|
+
*/
|
|
15
|
+
function parseScanCode(raw, schemes) {
|
|
16
|
+
const code = raw.trim();
|
|
17
|
+
if (!code) {
|
|
18
|
+
return { ok: false, failure: { reason: 'empty', detail: 'empty scan code' } };
|
|
19
|
+
}
|
|
20
|
+
const versionToken = code.slice(0, 2);
|
|
21
|
+
const version = Number(versionToken);
|
|
22
|
+
if (!/^[0-9]{2}$/.test(versionToken) || version < 10 || version > 99) {
|
|
23
|
+
return {
|
|
24
|
+
ok: false,
|
|
25
|
+
failure: { reason: 'unknown_version', detail: `code must start with a two-digit scheme 10-99, got "${versionToken}"` },
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const scheme = schemes.find((s) => s.version === version);
|
|
29
|
+
if (!scheme) {
|
|
30
|
+
return {
|
|
31
|
+
ok: false,
|
|
32
|
+
failure: { reason: 'unknown_version', detail: `no scan scheme configured for version ${version}` },
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
if (!scheme.enabled) {
|
|
36
|
+
return {
|
|
37
|
+
ok: false,
|
|
38
|
+
failure: { reason: 'scheme_disabled', detail: `scan scheme ${version} ("${scheme.name}") is disabled` },
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (scheme.encoding === types_1.SCAN_ENCODINGS.DELIMITED) {
|
|
42
|
+
return parseDelimited(code, version, scheme);
|
|
43
|
+
}
|
|
44
|
+
return parseFixed(code, version, scheme);
|
|
45
|
+
}
|
|
46
|
+
function parseDelimited(code, version, scheme) {
|
|
47
|
+
const d = scheme.delimiter;
|
|
48
|
+
// version(2 digits) <d> category(1 digit) <d> target(rest, non-empty)
|
|
49
|
+
if (code[2] !== d) {
|
|
50
|
+
return malformed(scheme, `expected "${d}" after the two-digit scheme`);
|
|
51
|
+
}
|
|
52
|
+
const category = code.slice(3, 4);
|
|
53
|
+
if (!/^[0-9]$/.test(category)) {
|
|
54
|
+
return malformed(scheme, 'category must be a single digit');
|
|
55
|
+
}
|
|
56
|
+
if (code[4] !== d) {
|
|
57
|
+
return malformed(scheme, `expected "${d}" after the category`);
|
|
58
|
+
}
|
|
59
|
+
const target = code.slice(5);
|
|
60
|
+
if (!target) {
|
|
61
|
+
return malformed(scheme, 'target is empty');
|
|
62
|
+
}
|
|
63
|
+
return { ok: true, parsed: { version, category, target }, scheme };
|
|
64
|
+
}
|
|
65
|
+
function parseFixed(code, version, scheme) {
|
|
66
|
+
const targetLength = scheme.target_length ?? 0;
|
|
67
|
+
const expected = 2 + 1 + targetLength;
|
|
68
|
+
// UPC-A wedges deliver the trailing check digit too; accept it as slack.
|
|
69
|
+
if (!/^[0-9]+$/.test(code)) {
|
|
70
|
+
return malformed(scheme, 'fixed encoding accepts digits only');
|
|
71
|
+
}
|
|
72
|
+
if (code.length !== expected && code.length !== expected + 1) {
|
|
73
|
+
return malformed(scheme, `expected ${expected} digits (or ${expected + 1} with check digit), got ${code.length}`);
|
|
74
|
+
}
|
|
75
|
+
const category = code.slice(2, 3);
|
|
76
|
+
const target = code.slice(3, 3 + targetLength);
|
|
77
|
+
return { ok: true, parsed: { version, category, target }, scheme };
|
|
78
|
+
}
|
|
79
|
+
function malformed(scheme, detail) {
|
|
80
|
+
return {
|
|
81
|
+
ok: false,
|
|
82
|
+
failure: { reason: 'malformed', detail: `scheme ${scheme.version} ("${scheme.name}"): ${detail}` },
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Replace SCAN_TEMPLATE_TOKENS inside string values of a params object.
|
|
87
|
+
* Deep, pure, non-mutating. Only exact-token and in-string replacement of
|
|
88
|
+
* the three known tokens — no expression language.
|
|
89
|
+
*/
|
|
90
|
+
function interpolateScanTemplate(value, ctx) {
|
|
91
|
+
if (typeof value === 'string') {
|
|
92
|
+
return value
|
|
93
|
+
.split(types_1.SCAN_TEMPLATE_TOKENS.TARGET).join(ctx.target)
|
|
94
|
+
.split(types_1.SCAN_TEMPLATE_TOKENS.CATEGORY).join(ctx.category)
|
|
95
|
+
.split(types_1.SCAN_TEMPLATE_TOKENS.SCANNED_AT).join(ctx.scannedAt);
|
|
96
|
+
}
|
|
97
|
+
if (Array.isArray(value)) {
|
|
98
|
+
return value.map((v) => interpolateScanTemplate(v, ctx));
|
|
99
|
+
}
|
|
100
|
+
if (value && typeof value === 'object') {
|
|
101
|
+
const out = {};
|
|
102
|
+
for (const [k, v] of Object.entries(value)) {
|
|
103
|
+
out[k] = interpolateScanTemplate(v, ctx);
|
|
104
|
+
}
|
|
105
|
+
return out;
|
|
106
|
+
}
|
|
107
|
+
return value;
|
|
108
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ScanScheme, ScanRule } from '../../types';
|
|
2
|
+
export declare function listScanSchemes(): Promise<ScanScheme[]>;
|
|
3
|
+
export declare function getScanScheme(version: number): Promise<ScanScheme | null>;
|
|
4
|
+
export declare function listScanRules(schemeVersion: number): Promise<ScanRule[]>;
|
|
5
|
+
export declare function getScanRule(schemeVersion: number, category: string): Promise<ScanRule | null>;
|