@hotmeshio/long-tail 0.5.12 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/build/api/escalations/bulk.js +9 -1
- package/build/api/escalations/cancel.js +5 -7
- package/build/api/escalations/claim.js +18 -15
- package/build/api/escalations/create.d.ts +6 -0
- package/build/api/escalations/create.js +11 -8
- package/build/api/escalations/facets.d.ts +18 -0
- package/build/api/escalations/facets.js +115 -0
- package/build/api/escalations/helpers.d.ts +70 -1
- package/build/api/escalations/helpers.js +101 -7
- package/build/api/escalations/index.d.ts +3 -2
- package/build/api/escalations/index.js +7 -1
- package/build/api/escalations/list.d.ts +21 -2
- package/build/api/escalations/list.js +109 -10
- package/build/api/escalations/metadata.js +22 -27
- package/build/api/escalations/resolve.d.ts +19 -1
- package/build/api/escalations/resolve.js +111 -26
- package/build/api/escalations/single.js +8 -8
- package/build/api/users.d.ts +6 -0
- package/build/api/users.js +29 -1
- package/build/bin/ltc.js +40 -0
- package/build/lib/cli/commands/escalations.d.ts +36 -0
- package/build/lib/cli/commands/escalations.js +98 -0
- package/build/lib/db/schemas/001_schema.sql +10 -5
- package/build/lib/db/schemas/012_lt_tasks_workflow_id_unique.sql +20 -0
- package/build/lib/db/schemas/013_role_scope.sql +37 -0
- package/build/modules/version.d.ts +10 -5
- package/build/modules/version.js +27 -11
- package/build/routes/escalations/facets.d.ts +7 -0
- package/build/routes/escalations/facets.js +81 -0
- package/build/routes/escalations/index.js +3 -0
- package/build/routes/escalations/list.js +46 -0
- package/build/routes/escalations/resolve.js +22 -4
- package/build/routes/users.js +9 -5
- package/build/sdk/index.d.ts +33 -2
- package/build/sdk/index.js +7 -0
- package/build/services/escalation/crud.d.ts +56 -6
- package/build/services/escalation/crud.js +102 -31
- package/build/services/escalation/facet-sql.d.ts +18 -0
- package/build/services/escalation/facet-sql.js +118 -0
- package/build/services/escalation/facets.d.ts +45 -0
- package/build/services/escalation/facets.js +218 -0
- package/build/services/escalation/index.d.ts +1 -0
- package/build/services/escalation/index.js +8 -1
- package/build/services/escalation/queries.d.ts +45 -0
- package/build/services/escalation/queries.js +107 -6
- package/build/services/escalation/sql.d.ts +10 -4
- package/build/services/escalation/sql.js +36 -8
- package/build/services/interceptor/activities/escalation.d.ts +2 -0
- package/build/services/interceptor/activities/escalation.js +1 -1
- package/build/services/interceptor/lifecycle.js +4 -0
- package/build/services/mcp/server-tools.js +10 -4
- package/build/services/orchestrator/condition.js +6 -2
- package/build/services/role/index.js +2 -3
- package/build/services/role/sql.d.ts +8 -0
- package/build/services/role/sql.js +17 -1
- package/build/services/task/crud.js +22 -14
- package/build/services/task/process.js +3 -21
- package/build/services/task/sql.d.ts +24 -1
- package/build/services/task/sql.js +65 -1
- package/build/services/user/crud.d.ts +1 -0
- package/build/services/user/crud.js +29 -11
- package/build/services/user/index.d.ts +2 -1
- package/build/services/user/index.js +12 -1
- package/build/services/user/rbac.d.ts +18 -0
- package/build/services/user/rbac.js +27 -0
- package/build/services/user/roles.d.ts +7 -2
- package/build/services/user/roles.js +21 -5
- package/build/services/user/scope.d.ts +22 -0
- package/build/services/user/scope.js +50 -0
- package/build/services/user/seed-admin.js +34 -17
- package/build/services/user/sql.d.ts +18 -7
- package/build/services/user/sql.js +38 -13
- package/build/services/user/sso-provision.js +41 -24
- package/build/services/user/types.d.ts +9 -5
- package/build/system/mcp-servers/admin/escalations.js +65 -0
- package/build/system/mcp-servers/admin/schemas.d.ts +325 -0
- package/build/system/mcp-servers/admin/schemas.js +63 -2
- package/build/system/mcp-servers/admin/users.js +28 -2
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/envelope.d.ts +7 -0
- package/build/types/facets.d.ts +60 -0
- package/build/types/facets.js +10 -0
- package/build/types/index.d.ts +2 -1
- package/build/types/user.d.ts +11 -0
- package/dashboard/dist/assets/AdminDashboard-C5gfVEeL.js +2 -0
- package/dashboard/dist/assets/{AdminDashboard-LTiYLuzq.js.map → AdminDashboard-C5gfVEeL.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-nlOudfpZ.js → AgentConfigPage-CWEnuiGN.js} +6 -6
- package/dashboard/dist/assets/{AgentConfigPage-nlOudfpZ.js.map → AgentConfigPage-CWEnuiGN.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-BSUnDvGp.js → AgentDetailPage-B6IE27iK.js} +3 -3
- package/dashboard/dist/assets/AgentDetailPage-B6IE27iK.js.map +1 -0
- package/dashboard/dist/assets/AgentsPage-Blhh2RsK.js +2 -0
- package/dashboard/dist/assets/{AgentsPage-DpS0cCYe.js.map → AgentsPage-Blhh2RsK.js.map} +1 -1
- package/dashboard/dist/assets/AvailableEscalationsPage-ClwAle76.js +2 -0
- package/dashboard/dist/assets/AvailableEscalationsPage-ClwAle76.js.map +1 -0
- package/dashboard/dist/assets/{BotPicker-BhKmq7M7.js → BotPicker-DSozotGk.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-BhKmq7M7.js.map → BotPicker-DSozotGk.js.map} +1 -1
- package/dashboard/dist/assets/CapabilitiesPage-CrS_DTA1.js +2 -0
- package/dashboard/dist/assets/CapabilitiesPage-CrS_DTA1.js.map +1 -0
- package/dashboard/dist/assets/{CollapsibleSection-D7SVwNVk.js → CollapsibleSection-1i6bOQ1L.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-D7SVwNVk.js.map → CollapsibleSection-1i6bOQ1L.js.map} +1 -1
- package/dashboard/dist/assets/CopyableId-blg-gZvT.js +2 -0
- package/dashboard/dist/assets/CopyableId-blg-gZvT.js.map +1 -0
- package/dashboard/dist/assets/{CredentialsPage-fat5Z2U9.js → CredentialsPage-BxJio06E.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-fat5Z2U9.js.map → CredentialsPage-BxJio06E.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-OOP4P2mJ.js → CronLabel-BAfIHHz4.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-OOP4P2mJ.js.map → CronLabel-BAfIHHz4.js.map} +1 -1
- package/dashboard/dist/assets/{CustomDurationPicker-COacSAXO.js → CustomDurationPicker-BLF0NFJK.js} +2 -2
- package/dashboard/dist/assets/{CustomDurationPicker-COacSAXO.js.map → CustomDurationPicker-BLF0NFJK.js.map} +1 -1
- package/dashboard/dist/assets/{DataTable-D9yuBv0w.js → DataTable-ZWgVQg7F.js} +2 -2
- package/dashboard/dist/assets/DataTable-ZWgVQg7F.js.map +1 -0
- package/dashboard/dist/assets/{DropZone-Bfw2YLVS.js → DropZone-CEx_wk-g.js} +2 -2
- package/dashboard/dist/assets/{DropZone-Bfw2YLVS.js.map → DropZone-CEx_wk-g.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-CkfCD-m7.js → ElapsedCell-nKGJvznH.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-CkfCD-m7.js.map → ElapsedCell-nKGJvznH.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-BmI8jxlh.js → EscalationsOverview-bNNVA6R2.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-BmI8jxlh.js.map → EscalationsOverview-bNNVA6R2.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-CeKfFk3m.js → EventTable-BCuDdqlU.js} +2 -2
- package/dashboard/dist/assets/{EventTable-CeKfFk3m.js.map → EventTable-BCuDdqlU.js.map} +1 -1
- package/dashboard/dist/assets/FilterBar-BQ2JGg8U.js +2 -0
- package/dashboard/dist/assets/FilterBar-BQ2JGg8U.js.map +1 -0
- package/dashboard/dist/assets/GraphInvokePage-BPAvqHls.js +2 -0
- package/dashboard/dist/assets/GraphInvokePage-BPAvqHls.js.map +1 -0
- package/dashboard/dist/assets/HomePage-BZ1YTrjR.js +2 -0
- package/dashboard/dist/assets/HomePage-BZ1YTrjR.js.map +1 -0
- package/dashboard/dist/assets/{ListToolbar-BJaCzAXS.js → ListToolbar-DIJZfEgu.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-BJaCzAXS.js.map → ListToolbar-DIJZfEgu.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-CvnDG5OB.js → McpOverview-DCfSCfPg.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-CvnDG5OB.js.map → McpOverview-DCfSCfPg.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-DwmSIcIL.js → McpQueryDetailPage-mb7rmtNe.js} +2 -2
- package/dashboard/dist/assets/{McpQueryDetailPage-DwmSIcIL.js.map → McpQueryDetailPage-mb7rmtNe.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryPage-CU6FMEEk.js → McpQueryPage-D9b1T0I3.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-CU6FMEEk.js.map → McpQueryPage-D9b1T0I3.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunDetailPage-8a6lsehv.js → McpRunDetailPage-Bz2UyuNm.js} +2 -2
- package/dashboard/dist/assets/{McpRunDetailPage-8a6lsehv.js.map → McpRunDetailPage-Bz2UyuNm.js.map} +1 -1
- package/dashboard/dist/assets/McpRunsPage-Dw7w_ZO-.js +2 -0
- package/dashboard/dist/assets/McpRunsPage-Dw7w_ZO-.js.map +1 -0
- package/dashboard/dist/assets/{NamespacePill-D6btr6e8.js → NamespacePill-D27vqDXy.js} +2 -2
- package/dashboard/dist/assets/{NamespacePill-D6btr6e8.js.map → NamespacePill-D27vqDXy.js.map} +1 -1
- package/dashboard/dist/assets/OperatorDashboard-CTzSDW3N.js +2 -0
- package/dashboard/dist/assets/{OperatorDashboard-g9o7I925.js.map → OperatorDashboard-CTzSDW3N.js.map} +1 -1
- package/dashboard/dist/assets/PageHeader-B_1zTx2q.js +2 -0
- package/dashboard/dist/assets/PageHeader-B_1zTx2q.js.map +1 -0
- package/dashboard/dist/assets/{PageHeaderWithStats-DJQCZ0FR.js → PageHeaderWithStats-D-cPg7UD.js} +2 -2
- package/dashboard/dist/assets/{PageHeaderWithStats-DJQCZ0FR.js.map → PageHeaderWithStats-D-cPg7UD.js.map} +1 -1
- package/dashboard/dist/assets/PriorityBadge-B4ykBH7f.js +2 -0
- package/dashboard/dist/assets/PriorityBadge-B4ykBH7f.js.map +1 -0
- package/dashboard/dist/assets/{ProcessDetailPage-ByyWCs2A.js → ProcessDetailPage-olG2CS-h.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-ByyWCs2A.js.map → ProcessDetailPage-olG2CS-h.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-BTsXds4l.js → ProcessesListPage-CUZSL06Y.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-BTsXds4l.js.map → ProcessesListPage-CUZSL06Y.js.map} +1 -1
- package/dashboard/dist/assets/RolePill-B-V-31lC.js +2 -0
- package/dashboard/dist/assets/RolePill-B-V-31lC.js.map +1 -0
- package/dashboard/dist/assets/RolesPage-DLnaW6iD.js +2 -0
- package/dashboard/dist/assets/RolesPage-DLnaW6iD.js.map +1 -0
- package/dashboard/dist/assets/RowActions-BA9L9djf.js +2 -0
- package/dashboard/dist/assets/RowActions-BA9L9djf.js.map +1 -0
- package/dashboard/dist/assets/{RunAsSelector-BzkZXpSX.js → RunAsSelector-BoLHF4fy.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-BzkZXpSX.js.map → RunAsSelector-BoLHF4fy.js.map} +1 -1
- package/dashboard/dist/assets/StickyPagination-BEMY1L-H.js +2 -0
- package/dashboard/dist/assets/StickyPagination-BEMY1L-H.js.map +1 -0
- package/dashboard/dist/assets/{StreamMessageDetail-B6ch-6SY.js → StreamMessageDetail-CVRVWXcU.js} +2 -2
- package/dashboard/dist/assets/{StreamMessageDetail-B6ch-6SY.js.map → StreamMessageDetail-CVRVWXcU.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-CjvfUkls.js → SwimlaneTimeline-DDpU0-Jn.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-CjvfUkls.js.map → SwimlaneTimeline-DDpU0-Jn.js.map} +1 -1
- package/dashboard/dist/assets/{TagInput-CZSeyesi.js → TagInput-BHVfG307.js} +2 -2
- package/dashboard/dist/assets/{TagInput-CZSeyesi.js.map → TagInput-BHVfG307.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-BjHU6opi.js → TaskDetailPage-B_xQtJMg.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-BjHU6opi.js.map → TaskDetailPage-B_xQtJMg.js.map} +1 -1
- package/dashboard/dist/assets/{TaskQueuePill-CQrXrSxk.js → TaskQueuePill-CGlxXqWt.js} +2 -2
- package/dashboard/dist/assets/{TaskQueuePill-CQrXrSxk.js.map → TaskQueuePill-CGlxXqWt.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-Bem44zd0.js → TasksListPage-CsrdIOKk.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-Bem44zd0.js.map → TasksListPage-CsrdIOKk.js.map} +1 -1
- package/dashboard/dist/assets/TimeAgo-DmicaxjT.js +2 -0
- package/dashboard/dist/assets/{TimeAgo-CUIYqSt_.js.map → TimeAgo-DmicaxjT.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell--tnreI1i.js → TimestampCell-DeK89eRV.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell--tnreI1i.js.map → TimestampCell-DeK89eRV.js.map} +1 -1
- package/dashboard/dist/assets/{ToolPill-O09jsTQM.js → ToolPill-NV7PxSpA.js} +2 -2
- package/dashboard/dist/assets/{ToolPill-O09jsTQM.js.map → ToolPill-NV7PxSpA.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-OD99H7Pk.js → ToolTestPanel-D3s2n9-9.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-OD99H7Pk.js.map → ToolTestPanel-D3s2n9-9.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-rh_dsTJI.js → TopicDetailPage-qyv7UWT_.js} +3 -3
- package/dashboard/dist/assets/TopicDetailPage-qyv7UWT_.js.map +1 -0
- package/dashboard/dist/assets/TopicsPage-CEUfMoed.js +2 -0
- package/dashboard/dist/assets/TopicsPage-CEUfMoed.js.map +1 -0
- package/dashboard/dist/assets/{UserName-C__c8BN0.js → UserName-Bn_BxI8K.js} +2 -2
- package/dashboard/dist/assets/{UserName-C__c8BN0.js.map → UserName-Bn_BxI8K.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowExecutionPage-Bw6QdtUO.js → WorkflowExecutionPage-DAk2RqpB.js} +2 -2
- package/dashboard/dist/assets/{WorkflowExecutionPage-Bw6QdtUO.js.map → WorkflowExecutionPage-DAk2RqpB.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowPill-CS-IsR0U.js → WorkflowPill-DDR0B6DN.js} +2 -2
- package/dashboard/dist/assets/{WorkflowPill-CS-IsR0U.js.map → WorkflowPill-DDR0B6DN.js.map} +1 -1
- package/dashboard/dist/assets/WorkflowsDashboard-DfBgM80t.js +2 -0
- package/dashboard/dist/assets/WorkflowsDashboard-DfBgM80t.js.map +1 -0
- package/dashboard/dist/assets/{WorkflowsOverview-BRc0QbA7.js → WorkflowsOverview--Dkoo9Jq.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-BRc0QbA7.js.map → WorkflowsOverview--Dkoo9Jq.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-DdzspNQR.js → YamlWorkflowDetailPage-B6HYbfFj.js} +25 -25
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-DdzspNQR.js.map → YamlWorkflowDetailPage-B6HYbfFj.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-Djw5ZbgQ.js → YamlWorkflowsPage-CJE-PxC0.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-Djw5ZbgQ.js.map → YamlWorkflowsPage-CJE-PxC0.js.map} +1 -1
- package/dashboard/dist/assets/{agents-xstNkF6c.js → agents-DUciUZpt.js} +2 -2
- package/dashboard/dist/assets/{agents-xstNkF6c.js.map → agents-DUciUZpt.js.map} +1 -1
- package/dashboard/dist/assets/{bots-BztAI0s_.js → bots-BnyqCfuC.js} +2 -2
- package/dashboard/dist/assets/{bots-BztAI0s_.js.map → bots-BnyqCfuC.js.map} +1 -1
- package/dashboard/dist/assets/{capabilities-CEDwtxNL.js → capabilities-CkTWWT0q.js} +2 -2
- package/dashboard/dist/assets/{capabilities-CEDwtxNL.js.map → capabilities-CkTWWT0q.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-BlGEsRKe.js → controlplane-D9HaFZsC.js} +2 -2
- package/dashboard/dist/assets/{controlplane-BlGEsRKe.js.map → controlplane-D9HaFZsC.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-iI4QKlP-.js → escalation-De9JnTKI.js} +2 -2
- package/dashboard/dist/assets/{escalation-iI4QKlP-.js.map → escalation-De9JnTKI.js.map} +1 -1
- package/dashboard/dist/assets/escalation-columns-Df7Pluzg.js +2 -0
- package/dashboard/dist/assets/escalation-columns-Df7Pluzg.js.map +1 -0
- package/dashboard/dist/assets/index-7hqtQI43.js +2 -0
- package/dashboard/dist/assets/index-7hqtQI43.js.map +1 -0
- package/dashboard/dist/assets/{index-CAqEy2Db.js → index-B07xLlyz.js} +2 -2
- package/dashboard/dist/assets/{index-CAqEy2Db.js.map → index-B07xLlyz.js.map} +1 -1
- package/dashboard/dist/assets/{index-D1xVY4JR.js → index-B1kc6itM.js} +24 -24
- package/dashboard/dist/assets/index-B1kc6itM.js.map +1 -0
- package/dashboard/dist/assets/index-BAhkWcOq.js +9 -0
- package/dashboard/dist/assets/index-BAhkWcOq.js.map +1 -0
- package/dashboard/dist/assets/{index-Dsi5o7dx.js → index-BsIaUbKD.js} +2 -2
- package/dashboard/dist/assets/{index-Dsi5o7dx.js.map → index-BsIaUbKD.js.map} +1 -1
- package/dashboard/dist/assets/index-BxdiKgnH.js +6 -0
- package/dashboard/dist/assets/index-BxdiKgnH.js.map +1 -0
- package/dashboard/dist/assets/{index-B7VC0vjf.js → index-BzMsh6Ui.js} +2 -2
- package/dashboard/dist/assets/{index-B7VC0vjf.js.map → index-BzMsh6Ui.js.map} +1 -1
- package/dashboard/dist/assets/index-CN0efCE9.js +6 -0
- package/dashboard/dist/assets/index-CN0efCE9.js.map +1 -0
- package/dashboard/dist/assets/{index-B5qsp8lb.js → index-CgD9fA9P.js} +2 -2
- package/dashboard/dist/assets/{index-B5qsp8lb.js.map → index-CgD9fA9P.js.map} +1 -1
- package/dashboard/dist/assets/{index-CUfgt3mV.js → index-Cqjf-yVP.js} +2 -2
- package/dashboard/dist/assets/{index-CUfgt3mV.js.map → index-Cqjf-yVP.js.map} +1 -1
- package/dashboard/dist/assets/{index-DjJ6VCuc.js → index-DNugmBs7.js} +2 -2
- package/dashboard/dist/assets/{index-DjJ6VCuc.js.map → index-DNugmBs7.js.map} +1 -1
- package/dashboard/dist/assets/{index-BUmnJ4eT.js → index-DjxTV3cn.js} +2 -2
- package/dashboard/dist/assets/{index-BUmnJ4eT.js.map → index-DjxTV3cn.js.map} +1 -1
- package/dashboard/dist/assets/index-DpAS4-DA.js +2 -0
- package/dashboard/dist/assets/index-DpAS4-DA.js.map +1 -0
- package/dashboard/dist/assets/index-nO0cim3_.css +1 -0
- package/dashboard/dist/assets/{knowledge-BKg0cr39.js → knowledge-D4SvdNv5.js} +2 -2
- package/dashboard/dist/assets/{knowledge-BKg0cr39.js.map → knowledge-D4SvdNv5.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-CVdHpKlz.js → mcp-DVxt4T9J.js} +2 -2
- package/dashboard/dist/assets/{mcp-CVdHpKlz.js.map → mcp-DVxt4T9J.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-CYxZcbwQ.js → mcp-query-CLP9EnnU.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-CYxZcbwQ.js.map → mcp-query-CLP9EnnU.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-BOEv7P6O.js → pipelines-C_x0LTBN.js} +2 -2
- package/dashboard/dist/assets/{pipelines-BOEv7P6O.js.map → pipelines-C_x0LTBN.js.map} +1 -1
- package/dashboard/dist/assets/{roles-c5cV2QYQ.js → roles-QaGFZQ58.js} +2 -2
- package/dashboard/dist/assets/{roles-c5cV2QYQ.js.map → roles-QaGFZQ58.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-JV3BjeEF.js → tasks-1eTuP02d.js} +2 -2
- package/dashboard/dist/assets/{tasks-JV3BjeEF.js.map → tasks-1eTuP02d.js.map} +1 -1
- package/dashboard/dist/assets/{topics-BDaPnhnQ.js → topics-B3p8K0PW.js} +2 -2
- package/dashboard/dist/assets/{topics-BDaPnhnQ.js.map → topics-B3p8K0PW.js.map} +1 -1
- package/dashboard/dist/assets/{useEventHooks-a7Dnh8G4.js → useEventHooks-BNZky4xM.js} +2 -2
- package/dashboard/dist/assets/{useEventHooks-a7Dnh8G4.js.map → useEventHooks-BNZky4xM.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-BSwEV0e9.js → useNamespace-Dx81_JM0.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-BSwEV0e9.js.map → useNamespace-Dx81_JM0.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-BuqvL-cn.js → useYamlActivityEvents-D5T3TbE7.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-BuqvL-cn.js.map → useYamlActivityEvents-D5T3TbE7.js.map} +1 -1
- package/dashboard/dist/assets/users-BEMysNdR.js +2 -0
- package/dashboard/dist/assets/users-BEMysNdR.js.map +1 -0
- package/dashboard/dist/assets/{vendor-icons-D5ycKPA2.js → vendor-icons--Ivmp-RX.js} +132 -112
- package/dashboard/dist/assets/vendor-icons--Ivmp-RX.js.map +1 -0
- package/dashboard/dist/assets/{workflows-DF-9Voyi.js → workflows-C4rjvQbI.js} +2 -2
- package/dashboard/dist/assets/{workflows-DF-9Voyi.js.map → workflows-C4rjvQbI.js.map} +1 -1
- package/dashboard/dist/assets/{yaml-workflows-2roKaSSK.js → yaml-workflows-4rJ5v5rJ.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-2roKaSSK.js.map → yaml-workflows-4rJ5v5rJ.js.map} +1 -1
- package/dashboard/dist/index.html +3 -3
- package/docs/api/http/escalations.md +131 -10
- package/docs/api/http/roles.md +44 -9
- package/docs/api/http/users.md +15 -6
- package/docs/api/mcp/admin.md +8 -2
- package/docs/api/mcp/human-queue.md +34 -2
- package/docs/api/sdk/escalations.md +155 -2
- package/docs/api/sdk/roles.md +11 -0
- package/docs/api/sdk/users.md +26 -1
- package/docs/auth.md +1 -1
- package/docs/dashboard.md +5 -4
- package/docs/data.md +9 -2
- package/docs/faceted-routing.md +221 -0
- package/docs/hitl-guide.md +50 -0
- package/docs/iam.md +31 -0
- package/docs/mcp.md +8 -0
- package/package.json +2 -2
- package/dashboard/dist/assets/AdminDashboard-LTiYLuzq.js +0 -2
- package/dashboard/dist/assets/AgentDetailPage-BSUnDvGp.js.map +0 -1
- package/dashboard/dist/assets/AgentsPage-DpS0cCYe.js +0 -2
- package/dashboard/dist/assets/AvailableEscalationsPage-BEylRqjP.js +0 -2
- package/dashboard/dist/assets/AvailableEscalationsPage-BEylRqjP.js.map +0 -1
- package/dashboard/dist/assets/CapabilitiesPage-DLIleX2L.js +0 -2
- package/dashboard/dist/assets/CapabilitiesPage-DLIleX2L.js.map +0 -1
- package/dashboard/dist/assets/CopyableId-DaT0ZRHg.js +0 -2
- package/dashboard/dist/assets/CopyableId-DaT0ZRHg.js.map +0 -1
- package/dashboard/dist/assets/DataTable-D9yuBv0w.js.map +0 -1
- package/dashboard/dist/assets/FilterBar-Ck4K4rzu.js +0 -2
- package/dashboard/dist/assets/FilterBar-Ck4K4rzu.js.map +0 -1
- package/dashboard/dist/assets/GraphInvokePage-BZBPBCSq.js +0 -2
- package/dashboard/dist/assets/GraphInvokePage-BZBPBCSq.js.map +0 -1
- package/dashboard/dist/assets/HomePage-dM7U2tl6.js +0 -2
- package/dashboard/dist/assets/HomePage-dM7U2tl6.js.map +0 -1
- package/dashboard/dist/assets/McpRunsPage-CPMYWgm_.js +0 -2
- package/dashboard/dist/assets/McpRunsPage-CPMYWgm_.js.map +0 -1
- package/dashboard/dist/assets/OperatorDashboard-g9o7I925.js +0 -2
- package/dashboard/dist/assets/PageHeader-Dk2Pe44Q.js +0 -2
- package/dashboard/dist/assets/PageHeader-Dk2Pe44Q.js.map +0 -1
- package/dashboard/dist/assets/PriorityBadge-DfQY9St9.js +0 -2
- package/dashboard/dist/assets/PriorityBadge-DfQY9St9.js.map +0 -1
- package/dashboard/dist/assets/RolePill-Du-aNnjR.js +0 -2
- package/dashboard/dist/assets/RolePill-Du-aNnjR.js.map +0 -1
- package/dashboard/dist/assets/RolesPage-B2Kdf-L9.js +0 -2
- package/dashboard/dist/assets/RolesPage-B2Kdf-L9.js.map +0 -1
- package/dashboard/dist/assets/RowActions-Dg-Fsm5O.js +0 -2
- package/dashboard/dist/assets/RowActions-Dg-Fsm5O.js.map +0 -1
- package/dashboard/dist/assets/StickyPagination-BWhFSr2d.js +0 -2
- package/dashboard/dist/assets/StickyPagination-BWhFSr2d.js.map +0 -1
- package/dashboard/dist/assets/TimeAgo-CUIYqSt_.js +0 -2
- package/dashboard/dist/assets/TopicDetailPage-rh_dsTJI.js.map +0 -1
- package/dashboard/dist/assets/TopicsPage-CD_40_v-.js +0 -2
- package/dashboard/dist/assets/TopicsPage-CD_40_v-.js.map +0 -1
- package/dashboard/dist/assets/WorkflowsDashboard-BgI-iOP6.js +0 -2
- package/dashboard/dist/assets/WorkflowsDashboard-BgI-iOP6.js.map +0 -1
- package/dashboard/dist/assets/escalation-columns-nVYVt7Gl.js +0 -2
- package/dashboard/dist/assets/escalation-columns-nVYVt7Gl.js.map +0 -1
- package/dashboard/dist/assets/index-CMviPjXQ.js +0 -9
- package/dashboard/dist/assets/index-CMviPjXQ.js.map +0 -1
- package/dashboard/dist/assets/index-CP0JEQhZ.js +0 -6
- package/dashboard/dist/assets/index-CP0JEQhZ.js.map +0 -1
- package/dashboard/dist/assets/index-ClvYSNZd.css +0 -1
- package/dashboard/dist/assets/index-D1xVY4JR.js.map +0 -1
- package/dashboard/dist/assets/index-DPLy-jwO.js +0 -2
- package/dashboard/dist/assets/index-DPLy-jwO.js.map +0 -1
- package/dashboard/dist/assets/index-DzVYjoex.js +0 -6
- package/dashboard/dist/assets/index-DzVYjoex.js.map +0 -1
- package/dashboard/dist/assets/index-FuhiJuHL.js +0 -2
- package/dashboard/dist/assets/index-FuhiJuHL.js.map +0 -1
- package/dashboard/dist/assets/users-Pn85K_3C.js +0 -2
- package/dashboard/dist/assets/users-Pn85K_3C.js.map +0 -1
- package/dashboard/dist/assets/vendor-icons-D5ycKPA2.js.map +0 -1
package/build/api/users.js
CHANGED
|
@@ -48,6 +48,7 @@ const userService = __importStar(require("../services/user"));
|
|
|
48
48
|
* @param input.role — filter by role name
|
|
49
49
|
* @param input.roleType — filter by role type (superadmin, admin, member)
|
|
50
50
|
* @param input.status — filter by user status
|
|
51
|
+
* @param input.search — free-text match on display name, email, or external_id
|
|
51
52
|
* @param input.limit — maximum number of users to return
|
|
52
53
|
* @param input.offset — number of users to skip for pagination
|
|
53
54
|
* @returns `{ status: 200, data: User[] }` on success
|
|
@@ -105,6 +106,17 @@ async function createUser(input) {
|
|
|
105
106
|
error: 'Each role must have a role name and type (superadmin, admin, member)',
|
|
106
107
|
};
|
|
107
108
|
}
|
|
109
|
+
if (r.read_scope !== undefined && !userService.isValidReadScope(r.read_scope)) {
|
|
110
|
+
return { status: 400, error: 'read_scope must be self or all' };
|
|
111
|
+
}
|
|
112
|
+
if (r.write_scope !== undefined && !userService.isValidWriteScope(r.write_scope)) {
|
|
113
|
+
return { status: 400, error: 'write_scope must be none, self, or all' };
|
|
114
|
+
}
|
|
115
|
+
const read = (r.read_scope ?? userService.DEFAULT_READ_SCOPE);
|
|
116
|
+
const write = (r.write_scope ?? userService.DEFAULT_WRITE_SCOPE);
|
|
117
|
+
if (!userService.isValidScopePair(read, write)) {
|
|
118
|
+
return { status: 400, error: 'write_scope=all requires read_scope=all' };
|
|
119
|
+
}
|
|
108
120
|
}
|
|
109
121
|
}
|
|
110
122
|
const user = await userService.createUser({
|
|
@@ -201,7 +213,23 @@ async function addUserRole(input) {
|
|
|
201
213
|
if (!userService.isValidRoleType(input.type)) {
|
|
202
214
|
return { status: 400, error: 'type must be superadmin, admin, or member' };
|
|
203
215
|
}
|
|
204
|
-
|
|
216
|
+
// Work-surface scope (optional; defaults to all/all = full worker). Only
|
|
217
|
+
// meaningful for `member`; admin/superadmin normalize to all/all.
|
|
218
|
+
if (input.read_scope !== undefined && !userService.isValidReadScope(input.read_scope)) {
|
|
219
|
+
return { status: 400, error: 'read_scope must be self or all' };
|
|
220
|
+
}
|
|
221
|
+
if (input.write_scope !== undefined && !userService.isValidWriteScope(input.write_scope)) {
|
|
222
|
+
return { status: 400, error: 'write_scope must be none, self, or all' };
|
|
223
|
+
}
|
|
224
|
+
const read = (input.read_scope ?? userService.DEFAULT_READ_SCOPE);
|
|
225
|
+
const write = (input.write_scope ?? userService.DEFAULT_WRITE_SCOPE);
|
|
226
|
+
if (!userService.isValidScopePair(read, write)) {
|
|
227
|
+
return { status: 400, error: 'write_scope=all requires read_scope=all (cannot act on what you cannot see)' };
|
|
228
|
+
}
|
|
229
|
+
const result = await userService.addUserRole(input.id, input.role, input.type, {
|
|
230
|
+
read_scope: read,
|
|
231
|
+
write_scope: write,
|
|
232
|
+
});
|
|
205
233
|
return { status: 201, data: result };
|
|
206
234
|
}
|
|
207
235
|
catch (err) {
|
package/build/bin/ltc.js
CHANGED
|
@@ -120,6 +120,13 @@ escCmd.command('list')
|
|
|
120
120
|
.option('--status <status>', 'Filter by status (pending, resolved, cancelled)')
|
|
121
121
|
.option('--role <role>', 'Filter by role')
|
|
122
122
|
.option('--limit <n>', 'Max results')
|
|
123
|
+
.option('--facets <json>', 'Required metadata facets, JSON object (metadata @>), e.g. \'{"filament":"pla"}\'')
|
|
124
|
+
.option('--block <json>', 'Exclude rows containing ANY of these facet sets, JSON array')
|
|
125
|
+
.option('--range <json>', 'Numeric ranges over facets, JSON array e.g. \'[{"facet":"confidence","op":"<=","value":0.7}]\'')
|
|
126
|
+
.option('--exists <json>', 'Metadata keys that must be present, JSON array of strings')
|
|
127
|
+
.option('--roles <json>', 'Restrict to these roles, JSON array (narrows within scope)')
|
|
128
|
+
.option('--available <bool>', 'true = unclaimed/expired only; false = held now')
|
|
129
|
+
.option('--order-by <json>', 'Sort keys, JSON array e.g. \'[{"field":"metadata.confidence","numeric":true,"direction":"asc"}]\'')
|
|
123
130
|
.option('--json', 'JSON output')
|
|
124
131
|
.option('-q, --quiet', 'IDs only')
|
|
125
132
|
.action(wrap(esc.listEscalations));
|
|
@@ -153,6 +160,39 @@ escCmd.command('resolve-by-meta <key> <value>')
|
|
|
153
160
|
.option('--assignee <external_id>', 'Resolve on behalf of user (external_id)')
|
|
154
161
|
.option('--meta <json>', 'Merge metadata (JSON object)')
|
|
155
162
|
.action(wrap(esc.resolveByMetadata));
|
|
163
|
+
escCmd.command('resolve-by-ids <ids...>')
|
|
164
|
+
.description('Resolve a set of escalations by id')
|
|
165
|
+
.requiredOption('--payload <json>', 'Resolver payload (JSON string)')
|
|
166
|
+
.option('--metadata <json>', 'Merge metadata (JSON object)')
|
|
167
|
+
.action(wrap(esc.resolveByIds));
|
|
168
|
+
escCmd.command('search-facets')
|
|
169
|
+
.description('Item-level faceted search over a pond (role-scoped)')
|
|
170
|
+
.requiredOption('--role <role>', 'Pond role to search')
|
|
171
|
+
.option('--status <status>', 'Filter by status')
|
|
172
|
+
.option('--available', 'Only available (unclaimed/expired)')
|
|
173
|
+
.option('--facets <json>', 'Required facets (JSON object)')
|
|
174
|
+
.option('--limit <n>', 'Max results')
|
|
175
|
+
.option('--json', 'JSON output')
|
|
176
|
+
.option('-q, --quiet', 'IDs only')
|
|
177
|
+
.action(wrap(esc.searchByFacets));
|
|
178
|
+
escCmd.command('claim-groups')
|
|
179
|
+
.description('Batch-claim complete origin groups in priority order')
|
|
180
|
+
.requiredOption('--role <role>', 'Pond role to claim from')
|
|
181
|
+
.option('--facets <json>', 'Required facets (JSON object)')
|
|
182
|
+
.option('--limit <n>', 'Max groups to claim')
|
|
183
|
+
.option('--duration <minutes>', 'Claim duration in minutes')
|
|
184
|
+
.option('--size-facet <key>', 'Metadata facet declaring group size')
|
|
185
|
+
.option('--json', 'JSON output')
|
|
186
|
+
.action(wrap(esc.claimGroups));
|
|
187
|
+
escCmd.command('claim-by-facets')
|
|
188
|
+
.description('Batch-claim individual rows matching facets')
|
|
189
|
+
.requiredOption('--role <role>', 'Pond role to claim from')
|
|
190
|
+
.option('--facets <json>', 'Required facets (JSON object)')
|
|
191
|
+
.option('--limit <n>', 'Max rows to claim')
|
|
192
|
+
.option('--duration <minutes>', 'Claim duration in minutes')
|
|
193
|
+
.option('--all-or-none', 'Claim all matched rows or none')
|
|
194
|
+
.option('--json', 'JSON output')
|
|
195
|
+
.action(wrap(esc.claimByFacets));
|
|
156
196
|
// ── Workflows ────────────────────────────────────────────────────────────
|
|
157
197
|
const wfCmd = commander_1.program.command('workflows').alias('wf').description('Manage durable workflows');
|
|
158
198
|
wfCmd.command('list')
|
|
@@ -4,6 +4,13 @@ interface ListOptions {
|
|
|
4
4
|
limit?: string;
|
|
5
5
|
json?: boolean;
|
|
6
6
|
quiet?: boolean;
|
|
7
|
+
facets?: string;
|
|
8
|
+
block?: string;
|
|
9
|
+
range?: string;
|
|
10
|
+
exists?: string;
|
|
11
|
+
roles?: string;
|
|
12
|
+
available?: string;
|
|
13
|
+
orderBy?: string;
|
|
7
14
|
}
|
|
8
15
|
export declare function listEscalations(opts: ListOptions): Promise<void>;
|
|
9
16
|
export declare function getEscalation(id: string, opts: {
|
|
@@ -27,4 +34,33 @@ export declare function resolveByMetadata(key: string, value: string, opts: {
|
|
|
27
34
|
assignee?: string;
|
|
28
35
|
meta?: string;
|
|
29
36
|
}): Promise<void>;
|
|
37
|
+
export declare function resolveByIds(ids: string[], opts: {
|
|
38
|
+
payload: string;
|
|
39
|
+
metadata?: string;
|
|
40
|
+
}): Promise<void>;
|
|
41
|
+
export declare function searchByFacets(opts: {
|
|
42
|
+
role: string;
|
|
43
|
+
status?: string;
|
|
44
|
+
available?: boolean;
|
|
45
|
+
facets?: string;
|
|
46
|
+
limit?: string;
|
|
47
|
+
json?: boolean;
|
|
48
|
+
quiet?: boolean;
|
|
49
|
+
}): Promise<void>;
|
|
50
|
+
export declare function claimGroups(opts: {
|
|
51
|
+
role: string;
|
|
52
|
+
facets?: string;
|
|
53
|
+
limit?: string;
|
|
54
|
+
duration?: string;
|
|
55
|
+
sizeFacet?: string;
|
|
56
|
+
json?: boolean;
|
|
57
|
+
}): Promise<void>;
|
|
58
|
+
export declare function claimByFacets(opts: {
|
|
59
|
+
role: string;
|
|
60
|
+
facets?: string;
|
|
61
|
+
limit?: string;
|
|
62
|
+
duration?: string;
|
|
63
|
+
allOrNone?: boolean;
|
|
64
|
+
json?: boolean;
|
|
65
|
+
}): Promise<void>;
|
|
30
66
|
export {};
|
|
@@ -11,6 +11,10 @@ exports.resolveEscalation = resolveEscalation;
|
|
|
11
11
|
exports.findByMetadata = findByMetadata;
|
|
12
12
|
exports.claimByMetadata = claimByMetadata;
|
|
13
13
|
exports.resolveByMetadata = resolveByMetadata;
|
|
14
|
+
exports.resolveByIds = resolveByIds;
|
|
15
|
+
exports.searchByFacets = searchByFacets;
|
|
16
|
+
exports.claimGroups = claimGroups;
|
|
17
|
+
exports.claimByFacets = claimByFacets;
|
|
14
18
|
const picocolors_1 = __importDefault(require("picocolors"));
|
|
15
19
|
const client_1 = require("../client");
|
|
16
20
|
const format_1 = require("../format");
|
|
@@ -30,6 +34,22 @@ async function listEscalations(opts) {
|
|
|
30
34
|
params.set('role', opts.role);
|
|
31
35
|
if (opts.limit)
|
|
32
36
|
params.set('limit', opts.limit);
|
|
37
|
+
// Faceted query elements travel as JSON-encoded query params (the route JSON-parses
|
|
38
|
+
// them). parseJsonOption validates the input and throws a friendly error on bad JSON.
|
|
39
|
+
if (opts.facets)
|
|
40
|
+
params.set('facets', JSON.stringify(parseJsonOption('--facets', opts.facets)));
|
|
41
|
+
if (opts.block)
|
|
42
|
+
params.set('block', JSON.stringify(parseJsonOption('--block', opts.block)));
|
|
43
|
+
if (opts.range)
|
|
44
|
+
params.set('range', JSON.stringify(parseJsonOption('--range', opts.range)));
|
|
45
|
+
if (opts.exists)
|
|
46
|
+
params.set('exists', JSON.stringify(parseJsonOption('--exists', opts.exists)));
|
|
47
|
+
if (opts.roles)
|
|
48
|
+
params.set('roles', JSON.stringify(parseJsonOption('--roles', opts.roles)));
|
|
49
|
+
if (opts.orderBy)
|
|
50
|
+
params.set('orderBy', JSON.stringify(parseJsonOption('--order-by', opts.orderBy)));
|
|
51
|
+
if (opts.available != null)
|
|
52
|
+
params.set('available', opts.available);
|
|
33
53
|
const data = await (0, client_1.apiFetch)(`/escalations?${params}`);
|
|
34
54
|
(0, format_1.output)(data, data.escalations || [], COLUMNS, opts);
|
|
35
55
|
}
|
|
@@ -107,3 +127,81 @@ async function resolveByMetadata(key, value, opts) {
|
|
|
107
127
|
});
|
|
108
128
|
console.log(`\n ${picocolors_1.default.green('✓')} Resolved by ${key}=${value}\n`);
|
|
109
129
|
}
|
|
130
|
+
// --- Faceted routing commands -----------------------------------------------
|
|
131
|
+
function parseJsonOption(label, raw) {
|
|
132
|
+
try {
|
|
133
|
+
return JSON.parse(raw);
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
throw new Error(`Invalid JSON for ${label}: ${raw}`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async function resolveByIds(ids, opts) {
|
|
140
|
+
const resolverPayload = parseJsonOption('--payload', opts.payload);
|
|
141
|
+
const body = { ids, resolverPayload };
|
|
142
|
+
if (opts.metadata)
|
|
143
|
+
body.metadata = parseJsonOption('--metadata', opts.metadata);
|
|
144
|
+
const data = await (0, client_1.apiFetch)('/escalations/resolve-by-ids', {
|
|
145
|
+
method: 'POST',
|
|
146
|
+
body: JSON.stringify(body),
|
|
147
|
+
});
|
|
148
|
+
console.log(`\n ${picocolors_1.default.green('✓')} Resolved ${data.resolved} escalation(s)\n`);
|
|
149
|
+
}
|
|
150
|
+
async function searchByFacets(opts) {
|
|
151
|
+
const query = { role: opts.role };
|
|
152
|
+
if (opts.status)
|
|
153
|
+
query.status = opts.status;
|
|
154
|
+
if (opts.available)
|
|
155
|
+
query.available = true;
|
|
156
|
+
if (opts.facets)
|
|
157
|
+
query.facets = parseJsonOption('--facets', opts.facets);
|
|
158
|
+
if (opts.limit)
|
|
159
|
+
query.limit = parseInt(opts.limit, 10);
|
|
160
|
+
const data = await (0, client_1.apiFetch)('/escalations/search-by-facets', {
|
|
161
|
+
method: 'POST',
|
|
162
|
+
body: JSON.stringify(query),
|
|
163
|
+
});
|
|
164
|
+
(0, format_1.output)(data, data.escalations || [], COLUMNS, opts);
|
|
165
|
+
}
|
|
166
|
+
async function claimGroups(opts) {
|
|
167
|
+
const query = { role: opts.role };
|
|
168
|
+
if (opts.facets)
|
|
169
|
+
query.facets = parseJsonOption('--facets', opts.facets);
|
|
170
|
+
const body = { query };
|
|
171
|
+
if (opts.limit)
|
|
172
|
+
body.limit = parseInt(opts.limit, 10);
|
|
173
|
+
if (opts.duration)
|
|
174
|
+
body.durationMinutes = parseInt(opts.duration, 10);
|
|
175
|
+
if (opts.sizeFacet)
|
|
176
|
+
body.sizeFacet = opts.sizeFacet;
|
|
177
|
+
const data = await (0, client_1.apiFetch)('/escalations/claim-groups', {
|
|
178
|
+
method: 'POST',
|
|
179
|
+
body: JSON.stringify(body),
|
|
180
|
+
});
|
|
181
|
+
if (opts.json) {
|
|
182
|
+
console.log(JSON.stringify(data, null, 2));
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
console.log(`\n ${picocolors_1.default.green('✓')} Claimed ${data.groups?.length || 0} group(s)\n`);
|
|
186
|
+
}
|
|
187
|
+
async function claimByFacets(opts) {
|
|
188
|
+
const query = { role: opts.role };
|
|
189
|
+
if (opts.facets)
|
|
190
|
+
query.facets = parseJsonOption('--facets', opts.facets);
|
|
191
|
+
const body = { query };
|
|
192
|
+
if (opts.limit)
|
|
193
|
+
body.limit = parseInt(opts.limit, 10);
|
|
194
|
+
if (opts.duration)
|
|
195
|
+
body.durationMinutes = parseInt(opts.duration, 10);
|
|
196
|
+
if (opts.allOrNone)
|
|
197
|
+
body.allOrNone = true;
|
|
198
|
+
const data = await (0, client_1.apiFetch)('/escalations/claim-by-facets', {
|
|
199
|
+
method: 'POST',
|
|
200
|
+
body: JSON.stringify(body),
|
|
201
|
+
});
|
|
202
|
+
if (opts.json) {
|
|
203
|
+
console.log(JSON.stringify(data, null, 2));
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
console.log(`\n ${picocolors_1.default.green('✓')} Claimed ${data.claimed?.length || 0} escalation(s)\n`);
|
|
207
|
+
}
|
|
@@ -99,11 +99,16 @@ CREATE OR REPLACE TRIGGER lt_users_updated_at
|
|
|
99
99
|
-- ─── lt_user_roles ───────────────────────────────────────────────────────────
|
|
100
100
|
|
|
101
101
|
CREATE TABLE IF NOT EXISTS lt_user_roles (
|
|
102
|
-
user_id
|
|
103
|
-
role
|
|
104
|
-
type
|
|
105
|
-
|
|
106
|
-
|
|
102
|
+
user_id UUID NOT NULL REFERENCES lt_users(id) ON DELETE CASCADE,
|
|
103
|
+
role TEXT NOT NULL REFERENCES lt_roles(role),
|
|
104
|
+
type TEXT NOT NULL DEFAULT 'member' CHECK (type IN ('superadmin', 'admin', 'member')),
|
|
105
|
+
-- Work-surface scope (orthogonal to `type`, ignored for admin/superadmin).
|
|
106
|
+
-- read governs search, write governs claim/ack/delete. write ⊆ read.
|
|
107
|
+
read_scope TEXT NOT NULL DEFAULT 'all' CHECK (read_scope IN ('self', 'all')),
|
|
108
|
+
write_scope TEXT NOT NULL DEFAULT 'all' CHECK (write_scope IN ('none', 'self', 'all')),
|
|
109
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
110
|
+
PRIMARY KEY (user_id, role),
|
|
111
|
+
CONSTRAINT chk_lt_user_roles_scope CHECK (NOT (write_scope = 'all' AND read_scope = 'self'))
|
|
107
112
|
);
|
|
108
113
|
|
|
109
114
|
CREATE INDEX IF NOT EXISTS idx_lt_user_roles_type ON lt_user_roles (type);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
-- ─── 012: lt_tasks.workflow_id uniqueness ─────────────────────────────────────
|
|
2
|
+
-- A task is 1:1 with its workflow_id. Every createTask caller keys the row by a
|
|
3
|
+
-- deterministic workflow_id (orchestrator childWorkflowId, interceptor
|
|
4
|
+
-- wf.workflowId, escalation triage-<id>), and createTask runs inside a
|
|
5
|
+
-- proxyActivity with retry { maximumAttempts: 3 }. Without a unique constraint a
|
|
6
|
+
-- retry — or a re-driven triage saga — double-inserts a task row. The unique
|
|
7
|
+
-- index lets createTask use ON CONFLICT (workflow_id) so retries converge instead
|
|
8
|
+
-- of duplicating, matching how HotMesh upserts the sibling job by (workflowId, app_id).
|
|
9
|
+
|
|
10
|
+
-- Collapse any pre-existing duplicates, keeping the most recent row per workflow_id
|
|
11
|
+
-- (tie-break on id so exactly one survives and the unique index can be built).
|
|
12
|
+
DELETE FROM lt_tasks a
|
|
13
|
+
USING lt_tasks b
|
|
14
|
+
WHERE a.workflow_id = b.workflow_id
|
|
15
|
+
AND (a.created_at < b.created_at
|
|
16
|
+
OR (a.created_at = b.created_at AND a.id < b.id));
|
|
17
|
+
|
|
18
|
+
-- Replace the non-unique lookup index with a unique one (it still serves lookups).
|
|
19
|
+
DROP INDEX IF EXISTS idx_lt_tasks_workflow_id;
|
|
20
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_lt_tasks_workflow_id ON lt_tasks (workflow_id);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
-- ─── lt_user_roles: read/write work-surface scope ──────────────────────────
|
|
2
|
+
--
|
|
3
|
+
-- Open roles split the worker capability into two orthogonal axes so that
|
|
4
|
+
-- one-time and limited-surface users are first-class:
|
|
5
|
+
--
|
|
6
|
+
-- read_scope (self | all) → governs SEARCH (which items appear)
|
|
7
|
+
-- write_scope (none | self | all) → governs CLAIM / ACK / DELETE
|
|
8
|
+
--
|
|
9
|
+
-- `self` = escalations assigned to the user (assigned_to = userId); `all` = the
|
|
10
|
+
-- whole role queue. The only constraint is write ⊆ read (you cannot act on what
|
|
11
|
+
-- you cannot see). `type` (member/admin/superadmin) is unchanged — it remains the
|
|
12
|
+
-- management/global tier, and admin/superadmin ignore scope (always act on all).
|
|
13
|
+
--
|
|
14
|
+
-- Existing rows default to ('all','all') = today's `member` behavior, so this is
|
|
15
|
+
-- backward compatible with zero data backfill. Idempotent: no-op on fresh installs
|
|
16
|
+
-- where 001_schema.sql already created the columns and the named constraint.
|
|
17
|
+
|
|
18
|
+
ALTER TABLE lt_user_roles
|
|
19
|
+
ADD COLUMN IF NOT EXISTS read_scope TEXT NOT NULL DEFAULT 'all'
|
|
20
|
+
CHECK (read_scope IN ('self', 'all'));
|
|
21
|
+
|
|
22
|
+
ALTER TABLE lt_user_roles
|
|
23
|
+
ADD COLUMN IF NOT EXISTS write_scope TEXT NOT NULL DEFAULT 'all'
|
|
24
|
+
CHECK (write_scope IN ('none', 'self', 'all'));
|
|
25
|
+
|
|
26
|
+
-- write ⊆ read: cannot act on the whole queue while only reading your own.
|
|
27
|
+
-- Guarded so a re-run (or a fresh install where 001 already added it) is a no-op.
|
|
28
|
+
DO $$
|
|
29
|
+
BEGIN
|
|
30
|
+
IF NOT EXISTS (
|
|
31
|
+
SELECT 1 FROM pg_constraint WHERE conname = 'chk_lt_user_roles_scope'
|
|
32
|
+
) THEN
|
|
33
|
+
ALTER TABLE lt_user_roles
|
|
34
|
+
ADD CONSTRAINT chk_lt_user_roles_scope
|
|
35
|
+
CHECK (NOT (write_scope = 'all' AND read_scope = 'self'));
|
|
36
|
+
END IF;
|
|
37
|
+
END $$;
|
|
@@ -7,10 +7,15 @@
|
|
|
7
7
|
*/
|
|
8
8
|
export declare const HOTMESH_VERSION: string;
|
|
9
9
|
/**
|
|
10
|
-
* The long-tail
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
10
|
+
* The long-tail package version.
|
|
11
|
+
*
|
|
12
|
+
* Resolved from long-tail's OWN package.json by walking up from this module's
|
|
13
|
+
* directory to the first package.json named `@hotmeshio/long-tail`. Reading
|
|
14
|
+
* `process.cwd()/package.json` is wrong when long-tail is consumed as a
|
|
15
|
+
* dependency (e.g. mounted as a NestJS module) — cwd is then the HOST app's
|
|
16
|
+
* root, so it reported the host's version. The upward walk resolves correctly in
|
|
17
|
+
* dev (source tree), the standalone Docker image (`/app`), and under
|
|
18
|
+
* `node_modules/@hotmeshio/long-tail`. A static `../package.json` import can't be
|
|
19
|
+
* used: post-compile it resolves to `build/package.json`, which is not shipped.
|
|
15
20
|
*/
|
|
16
21
|
export declare const LONG_TAIL_VERSION: string;
|
package/build/modules/version.js
CHANGED
|
@@ -15,20 +15,36 @@ const package_json_1 = __importDefault(require("@hotmeshio/hotmesh/package.json"
|
|
|
15
15
|
* node_modules), and resolveJsonModule handles the static import at compile time.
|
|
16
16
|
*/
|
|
17
17
|
exports.HOTMESH_VERSION = package_json_1.default.version ?? 'unknown';
|
|
18
|
+
const LONG_TAIL_PACKAGE_NAME = '@hotmeshio/long-tail';
|
|
18
19
|
/**
|
|
19
|
-
* The long-tail
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
20
|
+
* The long-tail package version.
|
|
21
|
+
*
|
|
22
|
+
* Resolved from long-tail's OWN package.json by walking up from this module's
|
|
23
|
+
* directory to the first package.json named `@hotmeshio/long-tail`. Reading
|
|
24
|
+
* `process.cwd()/package.json` is wrong when long-tail is consumed as a
|
|
25
|
+
* dependency (e.g. mounted as a NestJS module) — cwd is then the HOST app's
|
|
26
|
+
* root, so it reported the host's version. The upward walk resolves correctly in
|
|
27
|
+
* dev (source tree), the standalone Docker image (`/app`), and under
|
|
28
|
+
* `node_modules/@hotmeshio/long-tail`. A static `../package.json` import can't be
|
|
29
|
+
* used: post-compile it resolves to `build/package.json`, which is not shipped.
|
|
24
30
|
*/
|
|
25
31
|
exports.LONG_TAIL_VERSION = readLongTailVersion();
|
|
26
32
|
function readLongTailVersion() {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
let dir = __dirname;
|
|
34
|
+
const { root } = (0, path_1.parse)(dir);
|
|
35
|
+
// eslint-disable-next-line no-constant-condition
|
|
36
|
+
while (true) {
|
|
37
|
+
try {
|
|
38
|
+
const pkg = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(dir, 'package.json'), 'utf8'));
|
|
39
|
+
if (pkg.name === LONG_TAIL_PACKAGE_NAME)
|
|
40
|
+
return pkg.version ?? 'unknown';
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
/* no readable package.json here — keep walking up */
|
|
44
|
+
}
|
|
45
|
+
if (dir === root)
|
|
46
|
+
break;
|
|
47
|
+
dir = (0, path_1.dirname)(dir);
|
|
33
48
|
}
|
|
49
|
+
return 'unknown';
|
|
34
50
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
/**
|
|
3
|
+
* Faceted-routing HTTP surface — pond search + batch claim. Each operation targets a
|
|
4
|
+
* single pond `role` and is RBAC-scoped to it (the api layer enforces the gate). These
|
|
5
|
+
* mirror the SDK `escalations.searchByFacets / claimGroups / claimByFacets`.
|
|
6
|
+
*/
|
|
7
|
+
export declare function registerFacetRoutes(router: Router): void;
|
|
@@ -0,0 +1,81 @@
|
|
|
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.registerFacetRoutes = registerFacetRoutes;
|
|
37
|
+
const api = __importStar(require("../../api/escalations"));
|
|
38
|
+
/**
|
|
39
|
+
* Faceted-routing HTTP surface — pond search + batch claim. Each operation targets a
|
|
40
|
+
* single pond `role` and is RBAC-scoped to it (the api layer enforces the gate). These
|
|
41
|
+
* mirror the SDK `escalations.searchByFacets / claimGroups / claimByFacets`.
|
|
42
|
+
*/
|
|
43
|
+
function registerFacetRoutes(router) {
|
|
44
|
+
/**
|
|
45
|
+
* POST /api/escalations/search-by-facets
|
|
46
|
+
* Item-level faceted search over a pond, scoped to the caller's role.
|
|
47
|
+
* Body: FacetQuery — { role, status?, available?, facets?, orderBy?, limit?, offset? }
|
|
48
|
+
*/
|
|
49
|
+
router.post('/search-by-facets', async (req, res) => {
|
|
50
|
+
const result = await api.searchByFacets(req.body ?? {}, req.auth);
|
|
51
|
+
res.status(result.status).json(result.data ?? { error: result.error });
|
|
52
|
+
});
|
|
53
|
+
/**
|
|
54
|
+
* POST /api/escalations/claim-groups
|
|
55
|
+
* Batch-claim complete origin groups in priority order, assigned to the caller.
|
|
56
|
+
* Body: { query: FacetQuery, limit?, durationMinutes?, sizeFacet? }
|
|
57
|
+
*/
|
|
58
|
+
router.post('/claim-groups', async (req, res) => {
|
|
59
|
+
const result = await api.claimGroups({
|
|
60
|
+
query: req.body?.query,
|
|
61
|
+
limit: req.body?.limit,
|
|
62
|
+
durationMinutes: req.body?.durationMinutes,
|
|
63
|
+
sizeFacet: req.body?.sizeFacet,
|
|
64
|
+
}, req.auth);
|
|
65
|
+
res.status(result.status).json(result.data ?? { error: result.error });
|
|
66
|
+
});
|
|
67
|
+
/**
|
|
68
|
+
* POST /api/escalations/claim-by-facets
|
|
69
|
+
* Batch-claim individual rows (FOR UPDATE SKIP LOCKED), assigned to the caller.
|
|
70
|
+
* Body: { query: FacetQuery, limit?, durationMinutes?, allOrNone? }
|
|
71
|
+
*/
|
|
72
|
+
router.post('/claim-by-facets', async (req, res) => {
|
|
73
|
+
const result = await api.claimByFacets({
|
|
74
|
+
query: req.body?.query,
|
|
75
|
+
limit: req.body?.limit,
|
|
76
|
+
durationMinutes: req.body?.durationMinutes,
|
|
77
|
+
allOrNone: req.body?.allOrNone,
|
|
78
|
+
}, req.auth);
|
|
79
|
+
res.status(result.status).json(result.data ?? { error: result.error });
|
|
80
|
+
});
|
|
81
|
+
}
|
|
@@ -6,6 +6,7 @@ const bulk_1 = require("./bulk");
|
|
|
6
6
|
const metadata_1 = require("./metadata");
|
|
7
7
|
const single_1 = require("./single");
|
|
8
8
|
const resolve_1 = require("./resolve");
|
|
9
|
+
const facets_1 = require("./facets");
|
|
9
10
|
const router = (0, express_1.Router)();
|
|
10
11
|
// Registration order matters: literal paths before parameterized /:id routes.
|
|
11
12
|
// GET /, /available, /types, /stats
|
|
@@ -15,6 +16,8 @@ const router = (0, express_1.Router)();
|
|
|
15
16
|
(0, bulk_1.registerBulkRoutes)(router);
|
|
16
17
|
// GET /by-metadata, POST /claim-by-metadata, POST /resolve-by-metadata
|
|
17
18
|
(0, metadata_1.registerMetadataRoutes)(router);
|
|
19
|
+
// POST /search-by-facets, /claim-groups, /claim-by-facets
|
|
20
|
+
(0, facets_1.registerFacetRoutes)(router);
|
|
18
21
|
// PATCH /:id/escalate, GET /by-workflow/:workflowId,
|
|
19
22
|
// GET /:id, POST /:id/claim, POST /:id/release
|
|
20
23
|
(0, single_1.registerSingleRoutes)(router);
|
|
@@ -35,6 +35,21 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.registerListRoutes = registerListRoutes;
|
|
37
37
|
const api = __importStar(require("../../api/escalations"));
|
|
38
|
+
/**
|
|
39
|
+
* Parse a JSON-encoded query param (facets/block/range/exists/orderBy/roles) so the
|
|
40
|
+
* full faceted query rides on a GET URL — keeps the dashboard's copy-URL/curl path
|
|
41
|
+
* reproducible. Returns undefined on absent/invalid JSON (never throws to the caller).
|
|
42
|
+
*/
|
|
43
|
+
function jsonParam(v) {
|
|
44
|
+
if (typeof v !== 'string' || !v)
|
|
45
|
+
return undefined;
|
|
46
|
+
try {
|
|
47
|
+
return JSON.parse(v);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
38
53
|
function registerListRoutes(router) {
|
|
39
54
|
/**
|
|
40
55
|
* POST /api/escalations
|
|
@@ -55,6 +70,13 @@ function registerListRoutes(router) {
|
|
|
55
70
|
envelope: req.body?.envelope,
|
|
56
71
|
metadata: req.body?.metadata,
|
|
57
72
|
escalation_payload: req.body?.escalation_payload,
|
|
73
|
+
// Workflow-linkage (optional): an advert for a running workflow.
|
|
74
|
+
origin_id: req.body?.origin_id,
|
|
75
|
+
parent_id: req.body?.parent_id,
|
|
76
|
+
task_id: req.body?.task_id,
|
|
77
|
+
workflow_id: req.body?.workflow_id,
|
|
78
|
+
task_queue: req.body?.task_queue,
|
|
79
|
+
workflow_type: req.body?.workflow_type,
|
|
58
80
|
}, req.auth);
|
|
59
81
|
res.status(result.status).json(result.data ?? { error: result.error });
|
|
60
82
|
});
|
|
@@ -77,6 +99,14 @@ function registerListRoutes(router) {
|
|
|
77
99
|
sort_by: req.query.sort_by,
|
|
78
100
|
order: req.query.order,
|
|
79
101
|
search: req.query.search,
|
|
102
|
+
// Faceted query elements (JSON-encoded on the URL).
|
|
103
|
+
roles: jsonParam(req.query.roles),
|
|
104
|
+
facets: jsonParam(req.query.facets),
|
|
105
|
+
block: jsonParam(req.query.block),
|
|
106
|
+
range: jsonParam(req.query.range),
|
|
107
|
+
exists: jsonParam(req.query.exists),
|
|
108
|
+
orderBy: jsonParam(req.query.orderBy),
|
|
109
|
+
available: req.query.available != null ? req.query.available === 'true' : undefined,
|
|
80
110
|
}, req.auth);
|
|
81
111
|
res.status(result.status).json(result.data ?? { error: result.error });
|
|
82
112
|
});
|
|
@@ -96,6 +126,13 @@ function registerListRoutes(router) {
|
|
|
96
126
|
sort_by: req.query.sort_by,
|
|
97
127
|
order: req.query.order,
|
|
98
128
|
search: req.query.search,
|
|
129
|
+
// Faceted query elements (JSON-encoded on the URL).
|
|
130
|
+
roles: jsonParam(req.query.roles),
|
|
131
|
+
facets: jsonParam(req.query.facets),
|
|
132
|
+
block: jsonParam(req.query.block),
|
|
133
|
+
range: jsonParam(req.query.range),
|
|
134
|
+
exists: jsonParam(req.query.exists),
|
|
135
|
+
orderBy: jsonParam(req.query.orderBy),
|
|
99
136
|
}, req.auth);
|
|
100
137
|
res.status(result.status).json(result.data ?? { error: result.error });
|
|
101
138
|
});
|
|
@@ -107,6 +144,15 @@ function registerListRoutes(router) {
|
|
|
107
144
|
const result = await api.listDistinctTypes();
|
|
108
145
|
res.status(result.status).json(result.data ?? { error: result.error });
|
|
109
146
|
});
|
|
147
|
+
/**
|
|
148
|
+
* GET /api/escalations/facet-keys
|
|
149
|
+
* Distinct top-level metadata facet keys visible to the caller (role-scoped).
|
|
150
|
+
* Powers the faceted-query UI's key autocomplete.
|
|
151
|
+
*/
|
|
152
|
+
router.get('/facet-keys', async (req, res) => {
|
|
153
|
+
const result = await api.listFacetKeys(undefined, req.auth);
|
|
154
|
+
res.status(result.status).json(result.data ?? { error: result.error });
|
|
155
|
+
});
|
|
110
156
|
/**
|
|
111
157
|
* GET /api/escalations/stats
|
|
112
158
|
* Aggregated escalation statistics.
|
|
@@ -42,10 +42,28 @@ function registerResolveRoutes(router) {
|
|
|
42
42
|
* waiting workflow in place. For webhook callers that know the deterministic
|
|
43
43
|
* signal id. Literal single-segment path — registered before /:id/resolve so
|
|
44
44
|
* it is never shadowed by the parameterized route.
|
|
45
|
-
* Body: { signalKey: string, resolverPayload: Record<string, any> }
|
|
45
|
+
* Body: { signalKey: string, resolverPayload: Record<string, any>, metadata?: Record<string, any> }
|
|
46
46
|
*/
|
|
47
47
|
router.post('/resolve-by-signal-key', async (req, res) => {
|
|
48
|
-
const result = await api.resolveBySignalKey({
|
|
48
|
+
const result = await api.resolveBySignalKey({
|
|
49
|
+
signalKey: req.body?.signalKey,
|
|
50
|
+
resolverPayload: req.body?.resolverPayload,
|
|
51
|
+
metadata: req.body?.metadata,
|
|
52
|
+
}, req.auth);
|
|
53
|
+
res.status(result.status).json(result.data ?? { error: result.error });
|
|
54
|
+
});
|
|
55
|
+
/**
|
|
56
|
+
* POST /api/escalations/resolve-by-ids
|
|
57
|
+
* Resolve a SET of escalations by id in one guarded statement (set-based sibling of
|
|
58
|
+
* /:id/resolve). RBAC: scoped callers may only resolve rows whose role they hold.
|
|
59
|
+
* Body: { ids: string[], resolverPayload: Record<string, any>, metadata?: Record<string, any> }
|
|
60
|
+
*/
|
|
61
|
+
router.post('/resolve-by-ids', async (req, res) => {
|
|
62
|
+
const result = await api.resolveByIds({
|
|
63
|
+
ids: req.body?.ids,
|
|
64
|
+
resolverPayload: req.body?.resolverPayload,
|
|
65
|
+
metadata: req.body?.metadata,
|
|
66
|
+
}, req.auth);
|
|
49
67
|
res.status(result.status).json(result.data ?? { error: result.error });
|
|
50
68
|
});
|
|
51
69
|
/**
|
|
@@ -53,10 +71,10 @@ function registerResolveRoutes(router) {
|
|
|
53
71
|
* Resolve a pending escalation with a human-provided payload. Routes by
|
|
54
72
|
* escalation shape: efficient (signal_key) resumes the job in place; legacy
|
|
55
73
|
* paths signal via routing metadata or re-run the original workflow.
|
|
56
|
-
* Body: { resolverPayload: Record<string, any> }
|
|
74
|
+
* Body: { resolverPayload: Record<string, any>, metadata?: Record<string, any> }
|
|
57
75
|
*/
|
|
58
76
|
router.post('/:id/resolve', async (req, res) => {
|
|
59
|
-
const result = await api.resolveEscalation({ id: req.params.id, resolverPayload: req.body?.resolverPayload }, req.auth);
|
|
77
|
+
const result = await api.resolveEscalation({ id: req.params.id, resolverPayload: req.body?.resolverPayload, metadata: req.body?.metadata }, req.auth);
|
|
60
78
|
res.status(result.status).json(result.data ?? { error: result.error });
|
|
61
79
|
});
|
|
62
80
|
}
|