@hotmeshio/long-tail 0.10.11 → 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 +1 -0
- package/build/api/escalations/metadata.d.ts +11 -0
- package/build/api/escalations/metadata.js +27 -7
- 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/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 +8 -0
- package/build/modules/features.js +1 -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/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 +232 -14
- package/build/system/mcp-servers/admin/schemas.js +50 -0
- package/build/system/seed/tool-manifests-admin.d.ts +1380 -0
- package/build/system/seed/tool-manifests-admin.js +6 -0
- 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 +6 -0
- package/dashboard/dist/assets/{AdminDashboard-CkTbRfY9.js → AdminDashboard-Bv3pHBzn.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-CkTbRfY9.js.map → AdminDashboard-Bv3pHBzn.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-Cm8FRpXi.js → AgentConfigPage-Dk2zlvDb.js} +6 -6
- package/dashboard/dist/assets/{AgentConfigPage-Cm8FRpXi.js.map → AgentConfigPage-Dk2zlvDb.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-sQ1-UT46.js → AgentDetailPage-DUno6EGs.js} +2 -2
- package/dashboard/dist/assets/{AgentDetailPage-sQ1-UT46.js.map → AgentDetailPage-DUno6EGs.js.map} +1 -1
- package/dashboard/dist/assets/{AgentsPage-bSx_mdae.js → AgentsPage-CToVu1qj.js} +2 -2
- package/dashboard/dist/assets/{AgentsPage-bSx_mdae.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-8pMC7Xv6.js → AvailableEscalationsPage-DldboL4W.js} +2 -2
- package/dashboard/dist/assets/{AvailableEscalationsPage-8pMC7Xv6.js.map → AvailableEscalationsPage-DldboL4W.js.map} +1 -1
- package/dashboard/dist/assets/BotPicker-DQOpVB4M.js +2 -0
- package/dashboard/dist/assets/{BotPicker-C4uGH2x9.js.map → BotPicker-DQOpVB4M.js.map} +1 -1
- package/dashboard/dist/assets/{CapabilitiesPage-BRoOeKcc.js → CapabilitiesPage-Dmf46PUJ.js} +2 -2
- package/dashboard/dist/assets/{CapabilitiesPage-BRoOeKcc.js.map → CapabilitiesPage-Dmf46PUJ.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-CIj8Adc9.js → CollapsibleSection-CDADefUY.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-CIj8Adc9.js.map → CollapsibleSection-CDADefUY.js.map} +1 -1
- package/dashboard/dist/assets/{ConfirmDeleteModal-Ugi_9Ukq.js → ConfirmDeleteModal-CQsJUzEa.js} +2 -2
- package/dashboard/dist/assets/{ConfirmDeleteModal-Ugi_9Ukq.js.map → ConfirmDeleteModal-CQsJUzEa.js.map} +1 -1
- package/dashboard/dist/assets/{CopyableId-GUEdiiL5.js → CopyableId-4Lqlc5cU.js} +2 -2
- package/dashboard/dist/assets/{CopyableId-GUEdiiL5.js.map → CopyableId-4Lqlc5cU.js.map} +1 -1
- package/dashboard/dist/assets/{CountdownTimer-D3t0XMhE.js → CountdownTimer-DPjIkerB.js} +2 -2
- package/dashboard/dist/assets/{CountdownTimer-D3t0XMhE.js.map → CountdownTimer-DPjIkerB.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialsPage-B73Si6K1.js → CredentialsPage-8LIEvomi.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-B73Si6K1.js.map → CredentialsPage-8LIEvomi.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-Ca1aHolt.js → CronLabel-CK3WSsM5.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-Ca1aHolt.js.map → CronLabel-CK3WSsM5.js.map} +1 -1
- package/dashboard/dist/assets/{CustomDurationPicker-_9E9x1YN.js → CustomDurationPicker-FPmlA6cE.js} +2 -2
- package/dashboard/dist/assets/{CustomDurationPicker-_9E9x1YN.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-NYn6TWHz.js → DropZone-CL9gA7pu.js} +2 -2
- package/dashboard/dist/assets/{DropZone-NYn6TWHz.js.map → DropZone-CL9gA7pu.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-karxia93.js → ElapsedCell-BZVkVxE0.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-karxia93.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-CDaNmbUA.js → EscalationListSchemaPage-kYLdUtZX.js} +3 -3
- package/dashboard/dist/assets/{EscalationListSchemaPage-CDaNmbUA.js.map → EscalationListSchemaPage-kYLdUtZX.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationSchemaPage-k-2hFT2t.js → EscalationSchemaPage-kUmCDivo.js} +3 -3
- package/dashboard/dist/assets/{EscalationSchemaPage-k-2hFT2t.js.map → EscalationSchemaPage-kUmCDivo.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-C1e7IPn_.js → EscalationsOverview-D17auO-m.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-C1e7IPn_.js.map → EscalationsOverview-D17auO-m.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-CIrrtL7_.js → EventTable-CwPWl163.js} +2 -2
- package/dashboard/dist/assets/{EventTable-CIrrtL7_.js.map → EventTable-CwPWl163.js.map} +1 -1
- package/dashboard/dist/assets/{FilterBar-CzjtH74v.js → FilterBar-D7GghUsU.js} +2 -2
- package/dashboard/dist/assets/{FilterBar-CzjtH74v.js.map → FilterBar-D7GghUsU.js.map} +1 -1
- package/dashboard/dist/assets/{GraphInvokePage-LMpWw8z1.js → GraphInvokePage-D11uOnZi.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-LMpWw8z1.js.map → GraphInvokePage-D11uOnZi.js.map} +1 -1
- package/dashboard/dist/assets/{HomePage-Kl2DBG6l.js → HomePage-Bcq10Bxx.js} +2 -2
- package/dashboard/dist/assets/{HomePage-Kl2DBG6l.js.map → HomePage-Bcq10Bxx.js.map} +1 -1
- package/dashboard/dist/assets/ListToolbar-IPXsTb3Q.js +2 -0
- package/dashboard/dist/assets/{ListToolbar-B2fub0DY.js.map → ListToolbar-IPXsTb3Q.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-odYnCZCC.js → McpOverview-Dx2j0KkF.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-odYnCZCC.js.map → McpOverview-Dx2j0KkF.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-BtqwHUAg.js → McpQueryDetailPage-CzF_bna8.js} +3 -3
- package/dashboard/dist/assets/{McpQueryDetailPage-BtqwHUAg.js.map → McpQueryDetailPage-CzF_bna8.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryPage-CPkVwNIK.js → McpQueryPage-CNsuiw_q.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-CPkVwNIK.js.map → McpQueryPage-CNsuiw_q.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunDetailPage-D-Rz9MRw.js → McpRunDetailPage-BJguEMS0.js} +2 -2
- package/dashboard/dist/assets/{McpRunDetailPage-D-Rz9MRw.js.map → McpRunDetailPage-BJguEMS0.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-rdpZ2yMh.js → McpRunsPage-CK96s3Nt.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-rdpZ2yMh.js.map → McpRunsPage-CK96s3Nt.js.map} +1 -1
- package/dashboard/dist/assets/{Modal-Dr1Xy0j0.js → Modal-BU7No9NH.js} +2 -2
- package/dashboard/dist/assets/{Modal-Dr1Xy0j0.js.map → Modal-BU7No9NH.js.map} +1 -1
- package/dashboard/dist/assets/{NamespacePill-GwO-WfhX.js → NamespacePill-B9Vc_Pz2.js} +2 -2
- package/dashboard/dist/assets/{NamespacePill-GwO-WfhX.js.map → NamespacePill-B9Vc_Pz2.js.map} +1 -1
- package/dashboard/dist/assets/{OperationsPage-DlyGLPAs.js → OperationsPage-DvWrLuH6.js} +2 -2
- package/dashboard/dist/assets/{OperationsPage-DlyGLPAs.js.map → OperationsPage-DvWrLuH6.js.map} +1 -1
- package/dashboard/dist/assets/{OperatorDashboard-Csei5vj-.js → OperatorDashboard-C-jE0IRA.js} +2 -2
- package/dashboard/dist/assets/{OperatorDashboard-Csei5vj-.js.map → OperatorDashboard-C-jE0IRA.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeader-Bo9BU9pK.js → PageHeader-Ce4GcIYo.js} +2 -2
- package/dashboard/dist/assets/{PageHeader-Bo9BU9pK.js.map → PageHeader-Ce4GcIYo.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeaderWithStats-8_5cOSKL.js → PageHeaderWithStats-Ck0KZvXD.js} +2 -2
- package/dashboard/dist/assets/{PageHeaderWithStats-8_5cOSKL.js.map → PageHeaderWithStats-Ck0KZvXD.js.map} +1 -1
- package/dashboard/dist/assets/{PersonaDetailPage--ZL6Or6v.js → PersonaDetailPage-CJ6jqo7h.js} +2 -2
- package/dashboard/dist/assets/{PersonaDetailPage--ZL6Or6v.js.map → PersonaDetailPage-CJ6jqo7h.js.map} +1 -1
- package/dashboard/dist/assets/{PersonasPage-Bdcoay3P.js → PersonasPage-D8hL3kL5.js} +2 -2
- package/dashboard/dist/assets/{PersonasPage-Bdcoay3P.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-HrmVQq7S.js → ProcessDetailPage-Vnx8Z5_y.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-HrmVQq7S.js.map → ProcessDetailPage-Vnx8Z5_y.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-_xmj6Bo-.js → ProcessesListPage-DRYtvS3N.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-_xmj6Bo-.js.map → ProcessesListPage-DRYtvS3N.js.map} +1 -1
- package/dashboard/dist/assets/{RoleDetailPage-C0ju2-4K.js → RoleDetailPage-BKkUvTO-.js} +3 -3
- package/dashboard/dist/assets/{RoleDetailPage-C0ju2-4K.js.map → RoleDetailPage-BKkUvTO-.js.map} +1 -1
- package/dashboard/dist/assets/{RolePill-CQlnEWkK.js → RolePill-CnuBPhPw.js} +2 -2
- package/dashboard/dist/assets/{RolePill-CQlnEWkK.js.map → RolePill-CnuBPhPw.js.map} +1 -1
- package/dashboard/dist/assets/{RolesPage-CKluVSpB.js → RolesPage-BHzWK9n6.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-CKluVSpB.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-DdfecQ1U.js → RunAsSelector-CS3KQ-BF.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-DdfecQ1U.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-BBYkevuR.js → ScopeBadge-BUpYpS3x.js} +2 -2
- package/dashboard/dist/assets/{ScopeBadge-BBYkevuR.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-cLddIdtT.js → StickyPagination-hMrnLXde.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-cLddIdtT.js.map → StickyPagination-hMrnLXde.js.map} +1 -1
- package/dashboard/dist/assets/{StreamMessageDetail-CZXWDawC.js → StreamMessageDetail-DyJyZwBl.js} +2 -2
- package/dashboard/dist/assets/{StreamMessageDetail-CZXWDawC.js.map → StreamMessageDetail-DyJyZwBl.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-fWY0gaf3.js → SwimlaneTimeline-BlzV74V5.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-fWY0gaf3.js.map → SwimlaneTimeline-BlzV74V5.js.map} +1 -1
- package/dashboard/dist/assets/{TagInput-CDKbslLx.js → TagInput-BbZ25nNe.js} +2 -2
- package/dashboard/dist/assets/{TagInput-CDKbslLx.js.map → TagInput-BbZ25nNe.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-BjE4G2yn.js → TaskDetailPage-B0p_Z4J_.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-BjE4G2yn.js.map → TaskDetailPage-B0p_Z4J_.js.map} +1 -1
- package/dashboard/dist/assets/{TaskQueuePill-G3RuYRNZ.js → TaskQueuePill-D0QKBrN3.js} +2 -2
- package/dashboard/dist/assets/{TaskQueuePill-G3RuYRNZ.js.map → TaskQueuePill-D0QKBrN3.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-KAhmCWB2.js → TasksListPage-CiGR2QiQ.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-KAhmCWB2.js.map → TasksListPage-CiGR2QiQ.js.map} +1 -1
- package/dashboard/dist/assets/TimeAgo-D_DA9ucC.js +2 -0
- package/dashboard/dist/assets/{TimeAgo-C_H2TyZw.js.map → TimeAgo-D_DA9ucC.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-COG_4Flg.js → TimestampCell-C7rkC9nh.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-COG_4Flg.js.map → TimestampCell-C7rkC9nh.js.map} +1 -1
- package/dashboard/dist/assets/{ToolPill-ChSyRJZC.js → ToolPill-8xY9rkoc.js} +2 -2
- package/dashboard/dist/assets/{ToolPill-ChSyRJZC.js.map → ToolPill-8xY9rkoc.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-BPdJECW0.js → ToolTestPanel-E8efYGYs.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-BPdJECW0.js.map → ToolTestPanel-E8efYGYs.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-DAqx5JqA.js → TopicDetailPage-B455XrRc.js} +3 -3
- package/dashboard/dist/assets/{TopicDetailPage-DAqx5JqA.js.map → TopicDetailPage-B455XrRc.js.map} +1 -1
- package/dashboard/dist/assets/TopicsPage-1VAc29Qw.js +2 -0
- package/dashboard/dist/assets/{TopicsPage-DoGqAdPm.js.map → TopicsPage-1VAc29Qw.js.map} +1 -1
- package/dashboard/dist/assets/UserName-DikzjQHJ.js +2 -0
- package/dashboard/dist/assets/{UserName-CKO_rk1R.js.map → UserName-DikzjQHJ.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowExecutionPage-D3VQ9iQV.js → WorkflowExecutionPage-C15GSAoe.js} +2 -2
- package/dashboard/dist/assets/{WorkflowExecutionPage-D3VQ9iQV.js.map → WorkflowExecutionPage-C15GSAoe.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowPill-CNbwug5p.js → WorkflowPill-Da406nEj.js} +2 -2
- package/dashboard/dist/assets/{WorkflowPill-CNbwug5p.js.map → WorkflowPill-Da406nEj.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsDashboard-DdJ86We6.js → WorkflowsDashboard-BMQd_0tW.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-DdJ86We6.js.map → WorkflowsDashboard-BMQd_0tW.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-ZfFBzePp.js → WorkflowsOverview-CdxjVifp.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-ZfFBzePp.js.map → WorkflowsOverview-CdxjVifp.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-4bd5yXdA.js → YamlWorkflowDetailPage-DNVffIXa.js} +13 -13
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-4bd5yXdA.js.map → YamlWorkflowDetailPage-DNVffIXa.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-iHPNXjQj.js → YamlWorkflowsPage-BGP8wuos.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-iHPNXjQj.js.map → YamlWorkflowsPage-BGP8wuos.js.map} +1 -1
- package/dashboard/dist/assets/{agents-DjD5U3Wb.js → agents-BZJLIJ4h.js} +2 -2
- package/dashboard/dist/assets/{agents-DjD5U3Wb.js.map → agents-BZJLIJ4h.js.map} +1 -1
- package/dashboard/dist/assets/{bots-DiljVapH.js → bots-ClLcDGJb.js} +2 -2
- package/dashboard/dist/assets/{bots-DiljVapH.js.map → bots-ClLcDGJb.js.map} +1 -1
- package/dashboard/dist/assets/capabilities-IaCcS7ge.js +2 -0
- package/dashboard/dist/assets/{capabilities-DV_5ghHT.js.map → capabilities-IaCcS7ge.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-BKMvfWCB.js → controlplane-Zi4m_MSx.js} +2 -2
- package/dashboard/dist/assets/{controlplane-BKMvfWCB.js.map → controlplane-Zi4m_MSx.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-columns-BQpCaJId.js → escalation-columns-BY2mg9DY.js} +2 -2
- package/dashboard/dist/assets/{escalation-columns-BQpCaJId.js.map → escalation-columns-BY2mg9DY.js.map} +1 -1
- package/dashboard/dist/assets/{index-Tx_ETzcH.js → index-BqGnhkh0.js} +2 -2
- package/dashboard/dist/assets/{index-Tx_ETzcH.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-CI8rrKjx.js → index-C3o4OisO.js} +2 -2
- package/dashboard/dist/assets/{index-CI8rrKjx.js.map → index-C3o4OisO.js.map} +1 -1
- package/dashboard/dist/assets/{index-BO-7S9Xw.js → index-CJu2PBNx.js} +2 -2
- package/dashboard/dist/assets/{index-BO-7S9Xw.js.map → index-CJu2PBNx.js.map} +1 -1
- package/dashboard/dist/assets/{index-CItsikDw.js → index-CLmZaNTK.js} +2 -2
- package/dashboard/dist/assets/{index-CItsikDw.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-BaV3l0UE.js → index-CmnNqpWg.js} +2 -2
- package/dashboard/dist/assets/{index-BaV3l0UE.js.map → index-CmnNqpWg.js.map} +1 -1
- package/dashboard/dist/assets/{index-nIrYejxe.js → index-CvNBdkB1.js} +3 -3
- package/dashboard/dist/assets/{index-nIrYejxe.js.map → index-CvNBdkB1.js.map} +1 -1
- package/dashboard/dist/assets/{index-xZqQxqu2.js → index-D0zFReGL.js} +2 -2
- package/dashboard/dist/assets/{index-xZqQxqu2.js.map → index-D0zFReGL.js.map} +1 -1
- package/dashboard/dist/assets/{index-CStR4uIU.js → index-Dldi3Q3M.js} +2 -2
- package/dashboard/dist/assets/{index-CStR4uIU.js.map → index-Dldi3Q3M.js.map} +1 -1
- package/dashboard/dist/assets/{index-DhATO1cS.js → index-kiKZresb.js} +2 -2
- package/dashboard/dist/assets/{index-DhATO1cS.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-BsOxMMmb.js → index-yGNt29V9.js} +2 -2
- package/dashboard/dist/assets/{index-BsOxMMmb.js.map → index-yGNt29V9.js.map} +1 -1
- package/dashboard/dist/assets/index-zQiUPfxA.css +1 -0
- package/dashboard/dist/assets/{knowledge-BocTnSiA.js → knowledge-DWLxGTib.js} +2 -2
- package/dashboard/dist/assets/{knowledge-BocTnSiA.js.map → knowledge-DWLxGTib.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-C1KBjKQ_.js → mcp-B6AARZ2I.js} +2 -2
- package/dashboard/dist/assets/{mcp-C1KBjKQ_.js.map → mcp-B6AARZ2I.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-B3cjukkA.js → mcp-query-DrkvBU3a.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-B3cjukkA.js.map → mcp-query-DrkvBU3a.js.map} +1 -1
- package/dashboard/dist/assets/{personas-DiA2bJaX.js → personas-Cmz2SAEU.js} +2 -2
- package/dashboard/dist/assets/{personas-DiA2bJaX.js.map → personas-Cmz2SAEU.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-Dt2d2EFR.js → pipelines-CSgfVCMy.js} +2 -2
- package/dashboard/dist/assets/{pipelines-Dt2d2EFR.js.map → pipelines-CSgfVCMy.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-cDh2hNml.js → tasks-UOtUkDk-.js} +2 -2
- package/dashboard/dist/assets/{tasks-cDh2hNml.js.map → tasks-UOtUkDk-.js.map} +1 -1
- package/dashboard/dist/assets/{topics-yFlGF-u1.js → topics-Df5hGh6o.js} +2 -2
- package/dashboard/dist/assets/{topics-yFlGF-u1.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-D2R_ckS8.js → useEventHooks-PDbuSJ12.js} +2 -2
- package/dashboard/dist/assets/{useEventHooks-D2R_ckS8.js.map → useEventHooks-PDbuSJ12.js.map} +1 -1
- package/dashboard/dist/assets/{useFilterParams-B7suPsIK.js → useFilterParams-crmlBw_l.js} +2 -2
- package/dashboard/dist/assets/{useFilterParams-B7suPsIK.js.map → useFilterParams-crmlBw_l.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-u-V1GVUD.js → useNamespace-tZSOlge3.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-u-V1GVUD.js.map → useNamespace-tZSOlge3.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-BhOZeqgE.js → useYamlActivityEvents-CINLzE32.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-BhOZeqgE.js.map → useYamlActivityEvents-CINLzE32.js.map} +1 -1
- package/dashboard/dist/assets/{users-BoXPwdee.js → users-G8qwyZKS.js} +2 -2
- package/dashboard/dist/assets/{users-BoXPwdee.js.map → users-G8qwyZKS.js.map} +1 -1
- package/dashboard/dist/assets/{vendor-icons-D71XjkNy.js → vendor-icons-BpZiWH2f.js} +135 -130
- 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-C1YOyCSV.js → vendor-react-CdqEC2zv.js} +2 -2
- package/dashboard/dist/assets/{vendor-react-C1YOyCSV.js.map → vendor-react-CdqEC2zv.js.map} +1 -1
- package/dashboard/dist/assets/{workflows-mCoyKuLZ.js → workflows-DbPqi1TW.js} +2 -2
- package/dashboard/dist/assets/{workflows-mCoyKuLZ.js.map → workflows-DbPqi1TW.js.map} +1 -1
- package/dashboard/dist/assets/{yaml-workflows-CWxXGDpn.js → yaml-workflows-DozD8hpR.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-CWxXGDpn.js.map → yaml-workflows-DozD8hpR.js.map} +1 -1
- package/dashboard/dist/index.html +5 -5
- package/docs/hitl/x-lt-transition.md +105 -0
- package/docs/scan-codes.md +243 -0
- package/package.json +2 -2
- package/dashboard/dist/assets/BotPicker-C4uGH2x9.js +0 -2
- package/dashboard/dist/assets/ListToolbar-B2fub0DY.js +0 -2
- package/dashboard/dist/assets/TimeAgo-C_H2TyZw.js +0 -2
- package/dashboard/dist/assets/TopicsPage-DoGqAdPm.js +0 -2
- package/dashboard/dist/assets/UserName-CKO_rk1R.js +0 -2
- package/dashboard/dist/assets/capabilities-DV_5ghHT.js +0 -2
- package/dashboard/dist/assets/index-B-WkiNRN.js +0 -6
- package/dashboard/dist/assets/index-B-WkiNRN.js.map +0 -1
- package/dashboard/dist/assets/index-DbTD-dio.js +0 -63
- package/dashboard/dist/assets/index-DbTD-dio.js.map +0 -1
- package/dashboard/dist/assets/index-DnlsDaAw.css +0 -1
- package/dashboard/dist/assets/index-kzIIeVbx.js +0 -5
- package/dashboard/dist/assets/index-kzIIeVbx.js.map +0 -1
- package/dashboard/dist/assets/vendor-icons-D71XjkNy.js.map +0 -1
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { type ProvisionIfAbsent } from './helpers';
|
|
2
2
|
import type { LTApiAuth, LTApiResult } from '../../types/sdk';
|
|
3
|
+
/**
|
|
4
|
+
* Intersect the caller's scope roles with an optional caller-supplied
|
|
5
|
+
* restriction (e.g. a scan step's expected queues). Global scope with no
|
|
6
|
+
* restriction stays unfiltered (null); a restriction always applies. An
|
|
7
|
+
* empty intersection returns [] — which matches nothing in the SQL filter,
|
|
8
|
+
* the correct fail-closed outcome.
|
|
9
|
+
*/
|
|
10
|
+
export declare function restrictScopeRoles(scopeRoles: string[], global: boolean, restrictRoles?: string[]): string[] | null;
|
|
3
11
|
/**
|
|
4
12
|
* Find escalations by a metadata key-value pair.
|
|
5
13
|
*
|
|
@@ -27,6 +35,7 @@ export declare function claimByMetadata(input: {
|
|
|
27
35
|
assignee?: string;
|
|
28
36
|
metadata?: Record<string, any>;
|
|
29
37
|
provisionIfAbsent?: ProvisionIfAbsent;
|
|
38
|
+
restrictRoles?: string[];
|
|
30
39
|
}, auth: LTApiAuth): Promise<LTApiResult>;
|
|
31
40
|
/**
|
|
32
41
|
* Resolve an escalation by metadata key-value pair.
|
|
@@ -46,4 +55,6 @@ export declare function resolveByMetadata(input: {
|
|
|
46
55
|
resolverPayload: Record<string, any>;
|
|
47
56
|
assignee?: string;
|
|
48
57
|
metadata?: Record<string, any>;
|
|
58
|
+
restrictRoles?: string[];
|
|
59
|
+
extraFacets?: Record<string, any>;
|
|
49
60
|
}, auth: LTApiAuth): Promise<LTApiResult>;
|
|
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.restrictScopeRoles = restrictScopeRoles;
|
|
36
37
|
exports.findByMetadata = findByMetadata;
|
|
37
38
|
exports.claimByMetadata = claimByMetadata;
|
|
38
39
|
exports.resolveByMetadata = resolveByMetadata;
|
|
@@ -41,6 +42,20 @@ const helpers_1 = require("./helpers");
|
|
|
41
42
|
const resolver_validation_1 = require("../../services/escalation/resolver-validation");
|
|
42
43
|
const enforcement_cache_1 = require("../../services/role/enforcement-cache");
|
|
43
44
|
const resolve_1 = require("./resolve");
|
|
45
|
+
/**
|
|
46
|
+
* Intersect the caller's scope roles with an optional caller-supplied
|
|
47
|
+
* restriction (e.g. a scan step's expected queues). Global scope with no
|
|
48
|
+
* restriction stays unfiltered (null); a restriction always applies. An
|
|
49
|
+
* empty intersection returns [] — which matches nothing in the SQL filter,
|
|
50
|
+
* the correct fail-closed outcome.
|
|
51
|
+
*/
|
|
52
|
+
function restrictScopeRoles(scopeRoles, global, restrictRoles) {
|
|
53
|
+
if (!restrictRoles || restrictRoles.length === 0)
|
|
54
|
+
return global ? null : scopeRoles;
|
|
55
|
+
if (global)
|
|
56
|
+
return restrictRoles;
|
|
57
|
+
return scopeRoles.filter((r) => restrictRoles.includes(r));
|
|
58
|
+
}
|
|
44
59
|
/**
|
|
45
60
|
* Find escalations by a metadata key-value pair.
|
|
46
61
|
*
|
|
@@ -85,9 +100,10 @@ async function claimByMetadata(input, auth) {
|
|
|
85
100
|
// Write-scope: global → no filter; otherwise restrict to write_all roles. The
|
|
86
101
|
// SDK claim-by-metadata uses a flat role filter and cannot enforce write_self
|
|
87
102
|
// ownership, so self-scope members are excluded from this path (their items
|
|
88
|
-
// are pre-claimed and acted on by id).
|
|
103
|
+
// are pre-claimed and acted on by id). An optional caller restriction
|
|
104
|
+
// (expected queues) intersects with the scope inside the same SQL filter.
|
|
89
105
|
const writeScope = await (0, helpers_1.getEscalationWriteScope)(auth.userId);
|
|
90
|
-
const allowedRoles = writeScope.
|
|
106
|
+
const allowedRoles = restrictScopeRoles(writeScope.allRoles, writeScope.global, input.restrictRoles);
|
|
91
107
|
const result = await escalationService.claimByMetadata(input.key, input.value, claimUserId, input.durationMinutes, input.metadata, allowedRoles);
|
|
92
108
|
if (!result) {
|
|
93
109
|
// No rows matched. Check if candidates existed (role mismatch vs no match).
|
|
@@ -129,22 +145,26 @@ async function resolveByMetadata(input, auth) {
|
|
|
129
145
|
// Write-scope folds into the atomic resolve SQL: global → no filter; otherwise
|
|
130
146
|
// write_all roles match any item, write_self roles match only items assigned
|
|
131
147
|
// to the resolver. A non-global caller cannot pass a foreign assignee, so the
|
|
132
|
-
// self-branch (assigned_to = resolveUserId) is the caller's own items.
|
|
148
|
+
// self-branch (assigned_to = resolveUserId) is the caller's own items. An
|
|
149
|
+
// optional caller restriction (expected queues) intersects with both arrays
|
|
150
|
+
// inside the same SQL filter.
|
|
133
151
|
const writeScope = await (0, helpers_1.getEscalationWriteScope)(auth.userId);
|
|
134
|
-
const writeAllRoles = writeScope.
|
|
135
|
-
const writeSelfRoles = writeScope.global
|
|
152
|
+
const writeAllRoles = restrictScopeRoles(writeScope.allRoles, writeScope.global, input.restrictRoles);
|
|
153
|
+
const writeSelfRoles = writeScope.global
|
|
154
|
+
? (input.restrictRoles?.length ? [] : null)
|
|
155
|
+
: restrictScopeRoles(writeScope.selfRoles, false, input.restrictRoles);
|
|
136
156
|
// Schema enforcement rides the atomic statement: with the cached enforcing
|
|
137
157
|
// set empty (the common case) the single-call behavior is unchanged. When
|
|
138
158
|
// the picked row's role enforces, the statement returns the row WITHOUT
|
|
139
159
|
// writing; the payload validates here, then a second asserted pass claims
|
|
140
160
|
// + resolves the same row with pending re-checked inside the statement.
|
|
141
161
|
const enforcing = await (0, enforcement_cache_1.getEnforcingRoles)();
|
|
142
|
-
let result = await escalationService.resolveByMetadataAtomic(input.key, input.value, resolveUserId, input.resolverPayload, input.metadata, writeAllRoles, writeSelfRoles, enforcing.size > 0 ? [...enforcing] : null);
|
|
162
|
+
let result = await escalationService.resolveByMetadataAtomic(input.key, input.value, resolveUserId, input.resolverPayload, input.metadata, writeAllRoles, writeSelfRoles, enforcing.size > 0 ? [...enforcing] : null, null, input.extraFacets);
|
|
143
163
|
if (result.outcome === 'validation_required' && result.row) {
|
|
144
164
|
const report = await (0, resolver_validation_1.checkResolverPayload)(result.row, input.resolverPayload);
|
|
145
165
|
if (report)
|
|
146
166
|
return (0, resolve_1.validationFailure)(report);
|
|
147
|
-
result = await escalationService.resolveByMetadataAtomic(input.key, input.value, resolveUserId, input.resolverPayload, input.metadata, writeAllRoles, writeSelfRoles, null, result.row.id);
|
|
167
|
+
result = await escalationService.resolveByMetadataAtomic(input.key, input.value, resolveUserId, input.resolverPayload, input.metadata, writeAllRoles, writeSelfRoles, null, result.row.id, input.extraFacets);
|
|
148
168
|
// The asserted row left pending between the two passes — a concurrent
|
|
149
169
|
// resolution won the row; surface it as the conflict it is.
|
|
150
170
|
if (result.outcome === 'not_found') {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as scanCodeService from '../../services/scan-code';
|
|
2
|
+
import type { LTApiResult } from '../../types/sdk';
|
|
3
|
+
export declare function listScanSchemes(): Promise<LTApiResult>;
|
|
4
|
+
export declare function getScanScheme(input: {
|
|
5
|
+
version: number;
|
|
6
|
+
}): Promise<LTApiResult>;
|
|
7
|
+
export declare function upsertScanScheme(input: scanCodeService.ScanSchemeInput): Promise<LTApiResult>;
|
|
8
|
+
export declare function deleteScanScheme(input: {
|
|
9
|
+
version: number;
|
|
10
|
+
}): Promise<LTApiResult>;
|
|
11
|
+
export declare function listScanRules(input: {
|
|
12
|
+
version: number;
|
|
13
|
+
}): Promise<LTApiResult>;
|
|
14
|
+
export declare function getScanRule(input: {
|
|
15
|
+
version: number;
|
|
16
|
+
category: string;
|
|
17
|
+
}): Promise<LTApiResult>;
|
|
18
|
+
export declare function upsertScanRule(input: scanCodeService.ScanRuleInput): Promise<LTApiResult>;
|
|
19
|
+
export declare function deleteScanRule(input: {
|
|
20
|
+
version: number;
|
|
21
|
+
category: string;
|
|
22
|
+
}): Promise<LTApiResult>;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.listScanSchemes = listScanSchemes;
|
|
37
|
+
exports.getScanScheme = getScanScheme;
|
|
38
|
+
exports.upsertScanScheme = upsertScanScheme;
|
|
39
|
+
exports.deleteScanScheme = deleteScanScheme;
|
|
40
|
+
exports.listScanRules = listScanRules;
|
|
41
|
+
exports.getScanRule = getScanRule;
|
|
42
|
+
exports.upsertScanRule = upsertScanRule;
|
|
43
|
+
exports.deleteScanRule = deleteScanRule;
|
|
44
|
+
const scanCodeService = __importStar(require("../../services/scan-code"));
|
|
45
|
+
// ── Scheme CRUD ────────────────────────────────────────────────────────────
|
|
46
|
+
// Admin gating happens at the transport layer (requireAdmin on routes, admin
|
|
47
|
+
// MCP registration) — same convention as workflow config.
|
|
48
|
+
async function listScanSchemes() {
|
|
49
|
+
try {
|
|
50
|
+
const schemes = await scanCodeService.listScanSchemes();
|
|
51
|
+
return { status: 200, data: { schemes } };
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
return { status: 500, error: err.message };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async function getScanScheme(input) {
|
|
58
|
+
try {
|
|
59
|
+
const scheme = await scanCodeService.getScanScheme(input.version);
|
|
60
|
+
if (!scheme)
|
|
61
|
+
return { status: 404, error: `No scan scheme for version ${input.version}` };
|
|
62
|
+
const rules = await scanCodeService.listScanRules(input.version);
|
|
63
|
+
return { status: 200, data: { scheme, rules } };
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
return { status: 500, error: err.message };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async function upsertScanScheme(input) {
|
|
70
|
+
try {
|
|
71
|
+
const scheme = await scanCodeService.upsertScanScheme(input);
|
|
72
|
+
return { status: 200, data: { scheme } };
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
// Write-time invariant violations are caller errors, not server faults.
|
|
76
|
+
return { status: 400, error: err.message };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async function deleteScanScheme(input) {
|
|
80
|
+
try {
|
|
81
|
+
const deleted = await scanCodeService.deleteScanScheme(input.version);
|
|
82
|
+
if (!deleted)
|
|
83
|
+
return { status: 404, error: `No scan scheme for version ${input.version}` };
|
|
84
|
+
return { status: 200, data: { deleted: true } };
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
return { status: 500, error: err.message };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// ── Rule CRUD ──────────────────────────────────────────────────────────────
|
|
91
|
+
async function listScanRules(input) {
|
|
92
|
+
try {
|
|
93
|
+
const rules = await scanCodeService.listScanRules(input.version);
|
|
94
|
+
return { status: 200, data: { rules } };
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
return { status: 500, error: err.message };
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
async function getScanRule(input) {
|
|
101
|
+
try {
|
|
102
|
+
const rule = await scanCodeService.getScanRule(input.version, input.category);
|
|
103
|
+
if (!rule) {
|
|
104
|
+
return { status: 404, error: `No scan rule for ${input.version}:${input.category}` };
|
|
105
|
+
}
|
|
106
|
+
return { status: 200, data: { rule } };
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
return { status: 500, error: err.message };
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
async function upsertScanRule(input) {
|
|
113
|
+
try {
|
|
114
|
+
const scheme = await scanCodeService.getScanScheme(input.scheme_version);
|
|
115
|
+
if (!scheme) {
|
|
116
|
+
return { status: 404, error: `No scan scheme for version ${input.scheme_version} — create the scheme first` };
|
|
117
|
+
}
|
|
118
|
+
const rule = await scanCodeService.upsertScanRule(input);
|
|
119
|
+
return { status: 200, data: { rule } };
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
return { status: 400, error: err.message };
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
async function deleteScanRule(input) {
|
|
126
|
+
try {
|
|
127
|
+
const deleted = await scanCodeService.deleteScanRule(input.version, input.category);
|
|
128
|
+
if (!deleted) {
|
|
129
|
+
return { status: 404, error: `No scan rule for ${input.version}:${input.category}` };
|
|
130
|
+
}
|
|
131
|
+
return { status: 200, data: { deleted: true } };
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
return { status: 500, error: err.message };
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type ScanExecuteRequest, type ScanExecuteResponse } from '../../types';
|
|
2
|
+
import type { LTApiAuth, LTApiResult } from '../../types/sdk';
|
|
3
|
+
/**
|
|
4
|
+
* Execute a raw scan code: parse → load the rule → walk its steps in order.
|
|
5
|
+
* The first step whose condition matches performs its verb and answers; a
|
|
6
|
+
* step that matches nothing falls through to the next. Every terminal state
|
|
7
|
+
* is a structured 200 outcome — the scan surface reports, it doesn't throw.
|
|
8
|
+
*/
|
|
9
|
+
export declare function executeScanCode(input: ScanExecuteRequest, auth: LTApiAuth): Promise<LTApiResult<ScanExecuteResponse>>;
|
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.executeScanCode = executeScanCode;
|
|
37
|
+
const scanCodeService = __importStar(require("../../services/scan-code"));
|
|
38
|
+
const escalationService = __importStar(require("../../services/escalation"));
|
|
39
|
+
const metadata_1 = require("../escalations/metadata");
|
|
40
|
+
const create_1 = require("../escalations/create");
|
|
41
|
+
const claim_1 = require("../escalations/claim");
|
|
42
|
+
const helpers_1 = require("../escalations/helpers");
|
|
43
|
+
const types_1 = require("../../types");
|
|
44
|
+
/**
|
|
45
|
+
* Execute a raw scan code: parse → load the rule → walk its steps in order.
|
|
46
|
+
* The first step whose condition matches performs its verb and answers; a
|
|
47
|
+
* step that matches nothing falls through to the next. Every terminal state
|
|
48
|
+
* is a structured 200 outcome — the scan surface reports, it doesn't throw.
|
|
49
|
+
*/
|
|
50
|
+
async function executeScanCode(input, auth) {
|
|
51
|
+
try {
|
|
52
|
+
if (!input.code || typeof input.code !== 'string') {
|
|
53
|
+
return { status: 400, error: 'code is required' };
|
|
54
|
+
}
|
|
55
|
+
// 1. Parse against the configured schemes
|
|
56
|
+
const schemes = await scanCodeService.listScanSchemes();
|
|
57
|
+
const parseResult = scanCodeService.parseScanCode(input.code, schemes);
|
|
58
|
+
if (!parseResult.ok) {
|
|
59
|
+
const { reason, detail } = parseResult.failure;
|
|
60
|
+
const outcome = reason === 'unknown_version' || reason === 'scheme_disabled'
|
|
61
|
+
? types_1.SCAN_OUTCOMES.UNCONFIGURED
|
|
62
|
+
: types_1.SCAN_OUTCOMES.INVALID_CODE;
|
|
63
|
+
return { status: 200, data: { outcome, error: detail } };
|
|
64
|
+
}
|
|
65
|
+
const { parsed, scheme } = parseResult;
|
|
66
|
+
// 2. Load the rule for this category
|
|
67
|
+
const rule = await scanCodeService.getScanRule(parsed.version, parsed.category);
|
|
68
|
+
if (!rule || !rule.enabled) {
|
|
69
|
+
return {
|
|
70
|
+
status: 200,
|
|
71
|
+
data: {
|
|
72
|
+
outcome: types_1.SCAN_OUTCOMES.UNCONFIGURED,
|
|
73
|
+
parsed,
|
|
74
|
+
error: `no scan rule configured for ${parsed.version}:${parsed.category}`,
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
// 3. Walk the steps — first condition match wins
|
|
79
|
+
const ctx = {
|
|
80
|
+
scheme, rule, parsed, scannedAt: new Date().toISOString(), auth,
|
|
81
|
+
};
|
|
82
|
+
for (let i = 0; i < rule.steps.length; i++) {
|
|
83
|
+
const result = await executeStep(rule.steps[i], i, ctx);
|
|
84
|
+
if (result)
|
|
85
|
+
return decorate(result, ctx, i);
|
|
86
|
+
}
|
|
87
|
+
// 4. Nothing matched — the fallback screen is the answer
|
|
88
|
+
return {
|
|
89
|
+
status: 200,
|
|
90
|
+
data: decorateData({ outcome: types_1.SCAN_OUTCOMES.NO_MATCH_FALLBACK, fallback: rule.fallback }, ctx),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
return { status: 500, error: err.message };
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/** Stamp rule identity + parsed code onto a step result. */
|
|
98
|
+
function decorate(result, ctx, stepIndex) {
|
|
99
|
+
if (result.data && typeof result.data === 'object' && 'outcome' in result.data) {
|
|
100
|
+
result.data = { ...decorateData(result.data, ctx), stepIndex };
|
|
101
|
+
}
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
function decorateData(data, ctx) {
|
|
105
|
+
return {
|
|
106
|
+
...data,
|
|
107
|
+
parsed: ctx.parsed,
|
|
108
|
+
rule: {
|
|
109
|
+
schemeVersion: ctx.rule.scheme_version,
|
|
110
|
+
category: ctx.rule.category,
|
|
111
|
+
name: ctx.rule.name,
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Execute one step. Returns null when the step's condition matched nothing
|
|
117
|
+
* (fall through) and an LTApiResult for every terminal outcome.
|
|
118
|
+
*/
|
|
119
|
+
async function executeStep(step, index, ctx) {
|
|
120
|
+
// Confirm steps and read verbs only locate — mutation happens after the
|
|
121
|
+
// user confirms, through the standard per-id endpoints.
|
|
122
|
+
if (step.confirm || step.verb === types_1.SCAN_VERBS.SHOW_DETAIL || step.verb === types_1.SCAN_VERBS.SHOW_LIST) {
|
|
123
|
+
return locateStep(step, ctx);
|
|
124
|
+
}
|
|
125
|
+
switch (step.verb) {
|
|
126
|
+
case types_1.SCAN_VERBS.CLAIM:
|
|
127
|
+
case types_1.SCAN_VERBS.CLAIM_SHOW_DETAIL:
|
|
128
|
+
return claimStep(step, ctx);
|
|
129
|
+
case types_1.SCAN_VERBS.RESOLVE:
|
|
130
|
+
return resolveStep(step, ctx);
|
|
131
|
+
case types_1.SCAN_VERBS.ESCALATE:
|
|
132
|
+
return escalateStep(step, ctx);
|
|
133
|
+
case types_1.SCAN_VERBS.RELEASE:
|
|
134
|
+
return releaseStep(step, ctx);
|
|
135
|
+
case types_1.SCAN_VERBS.CANCEL:
|
|
136
|
+
return cancelStep(step, ctx);
|
|
137
|
+
default:
|
|
138
|
+
throw new Error(`unknown scan verb "${step.verb}"`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// ── Shared pieces ──────────────────────────────────────────────────────────
|
|
142
|
+
function targetFilter(step, ctx) {
|
|
143
|
+
return { [ctx.scheme.target_facet]: ctx.parsed.target, ...(step.query?.facets ?? {}) };
|
|
144
|
+
}
|
|
145
|
+
function templateContext(ctx) {
|
|
146
|
+
return { target: ctx.parsed.target, category: ctx.parsed.category, scannedAt: ctx.scannedAt };
|
|
147
|
+
}
|
|
148
|
+
function provenance(ctx) {
|
|
149
|
+
return {
|
|
150
|
+
[types_1.SCAN_PROVENANCE_KEYS.SCHEME]: ctx.scheme.version,
|
|
151
|
+
[types_1.SCAN_PROVENANCE_KEYS.CATEGORY]: ctx.parsed.category,
|
|
152
|
+
[types_1.SCAN_PROVENANCE_KEYS.ACTION_NAME]: ctx.rule.name,
|
|
153
|
+
[types_1.SCAN_PROVENANCE_KEYS.SCANNED_AT]: ctx.scannedAt,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function executed(escalation, step) {
|
|
157
|
+
return { status: 200, data: { outcome: types_1.SCAN_OUTCOMES.EXECUTED, verb: step.verb, escalation } };
|
|
158
|
+
}
|
|
159
|
+
// ── Locate (show-detail, show-list, confirm phase 1) ───────────────────────
|
|
160
|
+
async function locateStep(step, ctx) {
|
|
161
|
+
const scope = await (0, helpers_1.getEscalationReadScope)(ctx.auth.userId);
|
|
162
|
+
const availability = step.query?.availability ?? types_1.SCAN_AVAILABILITY.ANY;
|
|
163
|
+
const status = step.query?.status ?? 'pending';
|
|
164
|
+
const wantMany = step.verb === types_1.SCAN_VERBS.SHOW_LIST
|
|
165
|
+
|| step.cardinality === types_1.SCAN_CARDINALITY.MANY;
|
|
166
|
+
const limit = wantMany ? 50 : 2;
|
|
167
|
+
const facets = targetFilter(step, ctx);
|
|
168
|
+
let escalations;
|
|
169
|
+
let total;
|
|
170
|
+
if (availability === types_1.SCAN_AVAILABILITY.MINE) {
|
|
171
|
+
// "mine" = assigned to the caller; self-scope roles qualify because the
|
|
172
|
+
// assigned_to predicate satisfies their visibility branch.
|
|
173
|
+
const readable = [...scope.allRoles, ...scope.selfRoles];
|
|
174
|
+
const roles = (0, metadata_1.restrictScopeRoles)(readable, scope.global, step.query?.roles);
|
|
175
|
+
if (roles !== null && roles.length === 0)
|
|
176
|
+
return null;
|
|
177
|
+
const result = await escalationService.listEscalations({
|
|
178
|
+
metadata: facets,
|
|
179
|
+
status,
|
|
180
|
+
assigned_to: ctx.auth.userId,
|
|
181
|
+
visibleRoles: roles ?? undefined,
|
|
182
|
+
limit,
|
|
183
|
+
});
|
|
184
|
+
escalations = result.escalations;
|
|
185
|
+
total = result.total;
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
const roles = (0, metadata_1.restrictScopeRoles)(scope.allRoles, scope.global, step.query?.roles);
|
|
189
|
+
if (roles !== null && roles.length === 0)
|
|
190
|
+
return null;
|
|
191
|
+
const result = await escalationService.searchByFacets({
|
|
192
|
+
roles: roles ?? undefined,
|
|
193
|
+
facets,
|
|
194
|
+
status,
|
|
195
|
+
available: availability === types_1.SCAN_AVAILABILITY.AVAILABLE
|
|
196
|
+
? true
|
|
197
|
+
: availability === types_1.SCAN_AVAILABILITY.CLAIMED ? false : undefined,
|
|
198
|
+
limit,
|
|
199
|
+
});
|
|
200
|
+
escalations = result.escalations;
|
|
201
|
+
total = result.total;
|
|
202
|
+
}
|
|
203
|
+
if (escalations.length === 0)
|
|
204
|
+
return null;
|
|
205
|
+
if (step.confirm) {
|
|
206
|
+
const target = escalations[0];
|
|
207
|
+
const interpolated = step.params
|
|
208
|
+
? scanCodeService.interpolateScanTemplate(step.params, templateContext(ctx))
|
|
209
|
+
: undefined;
|
|
210
|
+
return {
|
|
211
|
+
status: 200,
|
|
212
|
+
data: {
|
|
213
|
+
outcome: types_1.SCAN_OUTCOMES.CONFIRM_REQUIRED,
|
|
214
|
+
verb: step.verb,
|
|
215
|
+
escalation: target,
|
|
216
|
+
pendingAction: {
|
|
217
|
+
escalationId: target.id,
|
|
218
|
+
verb: step.verb,
|
|
219
|
+
prompt: step.confirm.prompt,
|
|
220
|
+
params: interpolated,
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
if (wantMany) {
|
|
226
|
+
return {
|
|
227
|
+
status: 200,
|
|
228
|
+
data: {
|
|
229
|
+
outcome: types_1.SCAN_OUTCOMES.MATCHED_LIST,
|
|
230
|
+
verb: step.verb,
|
|
231
|
+
escalations,
|
|
232
|
+
total,
|
|
233
|
+
listQuery: {
|
|
234
|
+
...step.query,
|
|
235
|
+
targetFacet: ctx.scheme.target_facet,
|
|
236
|
+
target: ctx.parsed.target,
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
return executed(escalations[0], step);
|
|
242
|
+
}
|
|
243
|
+
// ── Mutating verbs — each a single atomic operation under the caller's RBAC ─
|
|
244
|
+
async function claimStep(step, ctx) {
|
|
245
|
+
const result = await (0, metadata_1.claimByMetadata)({
|
|
246
|
+
key: ctx.scheme.target_facet,
|
|
247
|
+
value: ctx.parsed.target,
|
|
248
|
+
durationMinutes: step.params?.durationMinutes,
|
|
249
|
+
metadata: { ...interpolatedMetadata(step, ctx), ...provenance(ctx) },
|
|
250
|
+
restrictRoles: step.query?.roles,
|
|
251
|
+
}, ctx.auth);
|
|
252
|
+
if (result.status === 404)
|
|
253
|
+
return null;
|
|
254
|
+
if (result.status === 403)
|
|
255
|
+
return forbidden(result.error);
|
|
256
|
+
if (result.status !== 200)
|
|
257
|
+
return result;
|
|
258
|
+
return executed(result.data.escalation, step);
|
|
259
|
+
}
|
|
260
|
+
async function resolveStep(step, ctx) {
|
|
261
|
+
const result = await (0, metadata_1.resolveByMetadata)({
|
|
262
|
+
key: ctx.scheme.target_facet,
|
|
263
|
+
value: ctx.parsed.target,
|
|
264
|
+
resolverPayload: scanCodeService.interpolateScanTemplate(step.params?.resolverPayload ?? {}, templateContext(ctx)),
|
|
265
|
+
metadata: { ...interpolatedMetadata(step, ctx), ...provenance(ctx) },
|
|
266
|
+
restrictRoles: step.query?.roles,
|
|
267
|
+
extraFacets: step.query?.facets,
|
|
268
|
+
}, ctx.auth);
|
|
269
|
+
if (result.status === 404)
|
|
270
|
+
return null;
|
|
271
|
+
if (result.status === 403)
|
|
272
|
+
return forbidden(result.error);
|
|
273
|
+
if (result.status === 409)
|
|
274
|
+
return conflict(result.error);
|
|
275
|
+
if (result.status !== 200)
|
|
276
|
+
return result;
|
|
277
|
+
const escalation = result.data.escalation
|
|
278
|
+
?? (result.data.escalationId ? { id: result.data.escalationId } : undefined);
|
|
279
|
+
return executed(escalation, step);
|
|
280
|
+
}
|
|
281
|
+
async function escalateStep(step, ctx) {
|
|
282
|
+
// Close the located escalation first when configured — the close doubles as
|
|
283
|
+
// the condition check AND the double-scan guard (second scan finds nothing
|
|
284
|
+
// to close and falls through).
|
|
285
|
+
if (step.params?.closeCurrent === 'resolve') {
|
|
286
|
+
const closed = await resolveStep({ ...step, params: { ...step.params, resolverPayload: step.params?.resolverPayload ?? {} } }, ctx);
|
|
287
|
+
if (closed === null)
|
|
288
|
+
return null;
|
|
289
|
+
if (closed.data?.outcome !== types_1.SCAN_OUTCOMES.EXECUTED)
|
|
290
|
+
return closed;
|
|
291
|
+
}
|
|
292
|
+
else if (step.params?.closeCurrent === 'cancel') {
|
|
293
|
+
const cancelled = await cancelStep(step, ctx);
|
|
294
|
+
if (cancelled === null)
|
|
295
|
+
return null;
|
|
296
|
+
if (cancelled.data?.outcome !== types_1.SCAN_OUTCOMES.EXECUTED)
|
|
297
|
+
return cancelled;
|
|
298
|
+
}
|
|
299
|
+
const created = await (0, create_1.createEscalation)({
|
|
300
|
+
type: step.params?.escalationType ?? 'scan',
|
|
301
|
+
role: step.params.targetRole,
|
|
302
|
+
description: step.params?.description ?? ctx.rule.name,
|
|
303
|
+
metadata: {
|
|
304
|
+
[ctx.scheme.target_facet]: ctx.parsed.target,
|
|
305
|
+
...interpolatedMetadata(step, ctx),
|
|
306
|
+
...provenance(ctx),
|
|
307
|
+
},
|
|
308
|
+
}, ctx.auth);
|
|
309
|
+
if (created.status === 403)
|
|
310
|
+
return forbidden(created.error);
|
|
311
|
+
if (created.status !== 201)
|
|
312
|
+
return created;
|
|
313
|
+
return executed(created.data, step);
|
|
314
|
+
}
|
|
315
|
+
async function releaseStep(step, ctx) {
|
|
316
|
+
// Locate the caller's own claim; release-by-id re-asserts the assignee
|
|
317
|
+
// inside the SDK, so a lost race resolves to 409, never a foreign release.
|
|
318
|
+
const scope = await (0, helpers_1.getEscalationReadScope)(ctx.auth.userId);
|
|
319
|
+
const readable = [...scope.allRoles, ...scope.selfRoles];
|
|
320
|
+
const roles = (0, metadata_1.restrictScopeRoles)(readable, scope.global, step.query?.roles);
|
|
321
|
+
if (roles !== null && roles.length === 0)
|
|
322
|
+
return null;
|
|
323
|
+
const { escalations } = await escalationService.listEscalations({
|
|
324
|
+
metadata: targetFilter(step, ctx),
|
|
325
|
+
status: 'pending',
|
|
326
|
+
assigned_to: ctx.auth.userId,
|
|
327
|
+
visibleRoles: roles ?? undefined,
|
|
328
|
+
limit: 1,
|
|
329
|
+
});
|
|
330
|
+
if (escalations.length === 0)
|
|
331
|
+
return null;
|
|
332
|
+
const result = await (0, claim_1.releaseEscalation)({ id: escalations[0].id }, ctx.auth);
|
|
333
|
+
if (result.status === 403)
|
|
334
|
+
return forbidden(result.error);
|
|
335
|
+
if (result.status === 409)
|
|
336
|
+
return conflict(result.error);
|
|
337
|
+
if (result.status !== 200)
|
|
338
|
+
return result;
|
|
339
|
+
return executed(result.data.escalation, step);
|
|
340
|
+
}
|
|
341
|
+
async function cancelStep(step, ctx) {
|
|
342
|
+
// Claim-as-lock: the atomic claim pins the row to this caller (or extends
|
|
343
|
+
// their claim), serializing concurrent double-scans before the cancel.
|
|
344
|
+
const claimed = await (0, metadata_1.claimByMetadata)({
|
|
345
|
+
key: ctx.scheme.target_facet,
|
|
346
|
+
value: ctx.parsed.target,
|
|
347
|
+
metadata: provenance(ctx),
|
|
348
|
+
restrictRoles: step.query?.roles,
|
|
349
|
+
}, ctx.auth);
|
|
350
|
+
if (claimed.status === 404)
|
|
351
|
+
return null;
|
|
352
|
+
if (claimed.status === 403)
|
|
353
|
+
return forbidden(claimed.error);
|
|
354
|
+
if (claimed.status !== 200)
|
|
355
|
+
return claimed;
|
|
356
|
+
const cancelled = await escalationService.cancelEscalation(claimed.data.escalation.id);
|
|
357
|
+
if (!cancelled)
|
|
358
|
+
return conflict('Escalation is not cancellable (already terminal)');
|
|
359
|
+
return executed(cancelled, step);
|
|
360
|
+
}
|
|
361
|
+
// ── Small result helpers ───────────────────────────────────────────────────
|
|
362
|
+
function interpolatedMetadata(step, ctx) {
|
|
363
|
+
return step.params?.metadata
|
|
364
|
+
? scanCodeService.interpolateScanTemplate(step.params.metadata, templateContext(ctx))
|
|
365
|
+
: {};
|
|
366
|
+
}
|
|
367
|
+
function forbidden(error) {
|
|
368
|
+
return { status: 200, data: { outcome: types_1.SCAN_OUTCOMES.FORBIDDEN, error } };
|
|
369
|
+
}
|
|
370
|
+
function conflict(error) {
|
|
371
|
+
return { status: 200, data: { outcome: types_1.SCAN_OUTCOMES.CONFLICT, error } };
|
|
372
|
+
}
|