@hotmeshio/long-tail 0.18.1 → 0.19.1
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/index.d.ts +1 -1
- package/build/api/escalations/index.js +2 -1
- package/build/api/escalations/list.d.ts +11 -0
- package/build/api/escalations/list.js +31 -2
- package/build/api/users.d.ts +11 -0
- package/build/api/users.js +19 -0
- package/build/api/workflows/config.d.ts +5 -1
- package/build/api/workflows/config.js +9 -1
- package/build/api/workflows/index.d.ts +3 -0
- package/build/api/workflows/index.js +7 -1
- package/build/api/workflows/input-validation.d.ts +13 -0
- package/build/api/workflows/input-validation.js +38 -0
- package/build/api/workflows/invocable.d.ts +19 -0
- package/build/api/workflows/invocable.js +106 -0
- package/build/api/workflows/invocation.js +6 -0
- package/build/lib/db/schemas/034_workflow_input_schema.sql +13 -0
- package/build/lib/uuid.d.ts +11 -0
- package/build/lib/uuid.js +20 -0
- package/build/routes/escalations/list.js +10 -1
- package/build/routes/users.js +9 -0
- package/build/routes/workflows/config.js +2 -0
- package/build/routes/workflows/discovery.js +14 -0
- package/build/scripts/ortho-populate.d.ts +3 -1
- package/build/scripts/ortho-populate.js +15 -5
- package/build/sdk/index.d.ts +1 -0
- package/build/services/config/cache.js +2 -0
- package/build/services/config/read.js +4 -0
- package/build/services/config/sql.d.ts +2 -2
- package/build/services/config/sql.js +7 -5
- package/build/services/config/write.js +11 -1
- package/build/services/escalation/batch.js +3 -0
- package/build/services/escalation/bulk.js +8 -0
- package/build/services/escalation/crud.js +26 -0
- package/build/services/escalation/queries.d.ts +14 -1
- package/build/services/escalation/queries.js +49 -7
- package/build/services/escalation/sql.d.ts +4 -2
- package/build/services/escalation/sql.js +4 -0
- package/build/services/interceptor/index.js +7 -0
- package/build/services/invocation-access.d.ts +18 -0
- package/build/services/invocation-access.js +32 -0
- package/build/services/role/types.d.ts +1 -1
- package/build/services/role/types.js +1 -1
- package/build/services/user/auth.js +2 -2
- package/build/services/user/crud.d.ts +13 -0
- package/build/services/user/crud.js +26 -3
- package/build/services/user/index.d.ts +1 -1
- package/build/services/user/index.js +2 -1
- package/build/services/user/sql.d.ts +11 -5
- package/build/services/user/sql.js +18 -6
- package/build/services/workflow-invocation.js +4 -9
- package/build/shared/form-validation/index.d.ts +1 -0
- package/build/shared/form-validation/index.js +1 -0
- package/build/shared/form-validation/invoke-context.d.ts +7 -0
- package/build/shared/form-validation/invoke-context.js +11 -0
- package/build/shared/form-validation/validate-resolver-payload.d.ts +1 -1
- package/build/shared/form-validation/validate-resolver-payload.js +1 -0
- package/build/shared/form-validation/x-lt-help.d.ts +2 -2
- package/build/shared/form-validation/x-lt-help.js +2 -2
- package/build/shared/form-validation/x-lt-show-if.d.ts +1 -0
- package/build/shared/form-validation/x-lt-show-if.js +3 -0
- package/build/start/workers.js +2 -0
- package/build/system/mcp-servers/admin/workflows.js +15 -2
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/config.d.ts +6 -0
- package/build/types/index.d.ts +2 -0
- package/build/types/index.js +4 -1
- package/build/types/startup.d.ts +10 -0
- package/build/types/validation.d.ts +4 -2
- package/build/types/workflow-icons.d.ts +86 -0
- package/build/types/workflow-icons.js +92 -0
- package/dashboard/dist/assets/{AdminDashboard-DDY8bceq.js → AdminDashboard-Drs-9TRM.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-DDY8bceq.js.map → AdminDashboard-Drs-9TRM.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-D47sHnup.js → AgentConfigPage-BDPDZ7-v.js} +3 -3
- package/dashboard/dist/assets/{AgentConfigPage-D47sHnup.js.map → AgentConfigPage-BDPDZ7-v.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-DwrfByA2.js → AgentDetailPage-CGBulM4_.js} +3 -3
- package/dashboard/dist/assets/{AgentDetailPage-DwrfByA2.js.map → AgentDetailPage-CGBulM4_.js.map} +1 -1
- package/dashboard/dist/assets/AgentsPage-D77JeViQ.js +2 -0
- package/dashboard/dist/assets/{AgentsPage-CLSjlyXy.js.map → AgentsPage-D77JeViQ.js.map} +1 -1
- package/dashboard/dist/assets/{AutoGrowTextarea-DgEQeRQw.js → AutoGrowTextarea-7X3T9La8.js} +2 -2
- package/dashboard/dist/assets/{AutoGrowTextarea-DgEQeRQw.js.map → AutoGrowTextarea-7X3T9La8.js.map} +1 -1
- package/dashboard/dist/assets/AvailableEscalationsPage-CqM_MOMy.js +2 -0
- package/dashboard/dist/assets/AvailableEscalationsPage-CqM_MOMy.js.map +1 -0
- package/dashboard/dist/assets/{BotPicker-CbL7gQFq.js → BotPicker-CC5vI_Sv.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-CbL7gQFq.js.map → BotPicker-CC5vI_Sv.js.map} +1 -1
- package/dashboard/dist/assets/BulkAssignModal-BXiJnlqt.js +2 -0
- package/dashboard/dist/assets/BulkAssignModal-BXiJnlqt.js.map +1 -0
- package/dashboard/dist/assets/{CapabilitiesPage-Q9Pe0y_p.js → CapabilitiesPage-D9TC2iKy.js} +2 -2
- package/dashboard/dist/assets/{CapabilitiesPage-Q9Pe0y_p.js.map → CapabilitiesPage-D9TC2iKy.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-BZOtaWPR.js → CollapsibleSection-D10lGw_u.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-BZOtaWPR.js.map → CollapsibleSection-D10lGw_u.js.map} +1 -1
- package/dashboard/dist/assets/{ConfirmDeleteModal-6CidwpPx.js → ConfirmDeleteModal-BJdLN6No.js} +2 -2
- package/dashboard/dist/assets/{ConfirmDeleteModal-6CidwpPx.js.map → ConfirmDeleteModal-BJdLN6No.js.map} +1 -1
- package/dashboard/dist/assets/{CopyableId-4Lqlc5cU.js → CopyableId-Bn02zYxt.js} +2 -2
- package/dashboard/dist/assets/{CopyableId-4Lqlc5cU.js.map → CopyableId-Bn02zYxt.js.map} +1 -1
- package/dashboard/dist/assets/CountdownTimer-D9B-BjQ7.js +2 -0
- package/dashboard/dist/assets/CountdownTimer-D9B-BjQ7.js.map +1 -0
- package/dashboard/dist/assets/{CredentialsPage-dxjrUEyO.js → CredentialsPage-hniUAFBK.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-dxjrUEyO.js.map → CredentialsPage-hniUAFBK.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-D8oo8eaA.js → CronLabel-v9DCD2FX.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-D8oo8eaA.js.map → CronLabel-v9DCD2FX.js.map} +1 -1
- package/dashboard/dist/assets/{DataTable-DFPMeqyQ.js → DataTable-7C7riavf.js} +2 -2
- package/dashboard/dist/assets/{DataTable-DFPMeqyQ.js.map → DataTable-7C7riavf.js.map} +1 -1
- package/dashboard/dist/assets/{DropZone-CWCh5ItZ.js → DropZone-XlcY8hEH.js} +2 -2
- package/dashboard/dist/assets/{DropZone-CWCh5ItZ.js.map → DropZone-XlcY8hEH.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-FHHQ69G3.js → ElapsedCell-_xvVTK8N.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-FHHQ69G3.js.map → ElapsedCell-_xvVTK8N.js.map} +1 -1
- package/dashboard/dist/assets/{EmptyState-lpUFYfun.js → EmptyState-DgC_6njU.js} +2 -2
- package/dashboard/dist/assets/{EmptyState-lpUFYfun.js.map → EmptyState-DgC_6njU.js.map} +1 -1
- package/dashboard/dist/assets/EntityTimelinePanel-1lT3jkCM.js +2 -0
- package/dashboard/dist/assets/EntityTimelinePanel-1lT3jkCM.js.map +1 -0
- package/dashboard/dist/assets/{EscalationListSchemaPage-D5L5lDNb.js → EscalationListSchemaPage-BeQUTUEO.js} +3 -3
- package/dashboard/dist/assets/{EscalationListSchemaPage-D5L5lDNb.js.map → EscalationListSchemaPage-BeQUTUEO.js.map} +1 -1
- package/dashboard/dist/assets/EscalationListView-uuZRMSLB.js +2 -0
- package/dashboard/dist/assets/EscalationListView-uuZRMSLB.js.map +1 -0
- package/dashboard/dist/assets/{EscalationSchemaPage-bYbfEpSB.js → EscalationSchemaPage-D4VlEwyS.js} +3 -3
- package/dashboard/dist/assets/{EscalationSchemaPage-bYbfEpSB.js.map → EscalationSchemaPage-D4VlEwyS.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-DjtIjL1b.js → EscalationsOverview-Bx6Zrzm-.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-DjtIjL1b.js.map → EscalationsOverview-Bx6Zrzm-.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-CihVTREC.js → EventTable-KEC3YWBf.js} +2 -2
- package/dashboard/dist/assets/{EventTable-CihVTREC.js.map → EventTable-KEC3YWBf.js.map} +1 -1
- package/dashboard/dist/assets/{FilterBar-Fin1IqHc.js → FilterBar-xwN_b5fj.js} +2 -2
- package/dashboard/dist/assets/{FilterBar-Fin1IqHc.js.map → FilterBar-xwN_b5fj.js.map} +1 -1
- package/dashboard/dist/assets/{GraphInvokePage-D77ILPd3.js → GraphInvokePage-DV7Y0fe2.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-D77ILPd3.js.map → GraphInvokePage-DV7Y0fe2.js.map} +1 -1
- package/dashboard/dist/assets/HomePage-G785SWcW.js +2 -0
- package/dashboard/dist/assets/HomePage-G785SWcW.js.map +1 -0
- package/dashboard/dist/assets/ListToolbar-zPVYPg3W.js +2 -0
- package/dashboard/dist/assets/{ListToolbar-DyHaJBTk.js.map → ListToolbar-zPVYPg3W.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-qz7Ivf0G.js → McpOverview-CMGUq8hx.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-qz7Ivf0G.js.map → McpOverview-CMGUq8hx.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-D6MB4CZM.js → McpQueryDetailPage-CdhLhaKn.js} +3 -3
- package/dashboard/dist/assets/{McpQueryDetailPage-D6MB4CZM.js.map → McpQueryDetailPage-CdhLhaKn.js.map} +1 -1
- package/dashboard/dist/assets/McpQueryPage-CNSNMagY.js +2 -0
- package/dashboard/dist/assets/{McpQueryPage-BqqRF5cQ.js.map → McpQueryPage-CNSNMagY.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunDetailPage-DxLEhzhn.js → McpRunDetailPage-DBm8hUaW.js} +2 -2
- package/dashboard/dist/assets/{McpRunDetailPage-DxLEhzhn.js.map → McpRunDetailPage-DBm8hUaW.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-BOsS4Hdf.js → McpRunsPage-B6rb5QBf.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-BOsS4Hdf.js.map → McpRunsPage-B6rb5QBf.js.map} +1 -1
- package/dashboard/dist/assets/NamespacePill-Bb3revqD.js +2 -0
- package/dashboard/dist/assets/{NamespacePill-CJikgGzE.js.map → NamespacePill-Bb3revqD.js.map} +1 -1
- package/dashboard/dist/assets/OperationsPage-Dxk1fAMg.js +3 -0
- package/dashboard/dist/assets/OperationsPage-Dxk1fAMg.js.map +1 -0
- package/dashboard/dist/assets/OperatorDashboard-DBOscDnf.js +2 -0
- package/dashboard/dist/assets/{OperatorDashboard-C5rlijvh.js.map → OperatorDashboard-DBOscDnf.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeader-DZmymFBS.js → PageHeader-Di5Sz3an.js} +2 -2
- package/dashboard/dist/assets/{PageHeader-DZmymFBS.js.map → PageHeader-Di5Sz3an.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeaderWithStats-DuAm6YK2.js → PageHeaderWithStats-DutKJ-h2.js} +2 -2
- package/dashboard/dist/assets/{PageHeaderWithStats-DuAm6YK2.js.map → PageHeaderWithStats-DutKJ-h2.js.map} +1 -1
- package/dashboard/dist/assets/{PersonaDetailPage-JBdVvT5g.js → PersonaDetailPage-BGRdGpeR.js} +2 -2
- package/dashboard/dist/assets/{PersonaDetailPage-JBdVvT5g.js.map → PersonaDetailPage-BGRdGpeR.js.map} +1 -1
- package/dashboard/dist/assets/PersonasPage-DRzOZcVa.js +2 -0
- package/dashboard/dist/assets/PersonasPage-DRzOZcVa.js.map +1 -0
- package/dashboard/dist/assets/{PriorityBadge-BETdj4M-.js → PriorityBadge-r33mpDju.js} +2 -2
- package/dashboard/dist/assets/{PriorityBadge-BETdj4M-.js.map → PriorityBadge-r33mpDju.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessDetailPage-CHnzOzQn.js → ProcessDetailPage-BLGjZXpM.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-CHnzOzQn.js.map → ProcessDetailPage-BLGjZXpM.js.map} +1 -1
- package/dashboard/dist/assets/ProcessesListPage-5NnysKFC.js +2 -0
- package/dashboard/dist/assets/{ProcessesListPage-DuXTS5-v.js.map → ProcessesListPage-5NnysKFC.js.map} +1 -1
- package/dashboard/dist/assets/ResolverForm-Dy0yirtP.js +2 -0
- package/dashboard/dist/assets/ResolverForm-Dy0yirtP.js.map +1 -0
- package/dashboard/dist/assets/RoleDetailPage-C_LIoe1j.js +8 -0
- package/dashboard/dist/assets/RoleDetailPage-C_LIoe1j.js.map +1 -0
- package/dashboard/dist/assets/{RolePill-C9LSs1aK.js → RolePill-DhnVPK4q.js} +2 -2
- package/dashboard/dist/assets/{RolePill-C9LSs1aK.js.map → RolePill-DhnVPK4q.js.map} +1 -1
- package/dashboard/dist/assets/RolesPage-BmW1LzkU.js +2 -0
- package/dashboard/dist/assets/{RolesPage-h77-JOLd.js.map → RolesPage-BmW1LzkU.js.map} +1 -1
- package/dashboard/dist/assets/{RowActions-eYrzgQSj.js → RowActions-Bdd7z4eB.js} +2 -2
- package/dashboard/dist/assets/{RowActions-eYrzgQSj.js.map → RowActions-Bdd7z4eB.js.map} +1 -1
- package/dashboard/dist/assets/RunAsSelector-BwZTJ4Yj.js +2 -0
- package/dashboard/dist/assets/{RunAsSelector-DoLFJ0mZ.js.map → RunAsSelector-BwZTJ4Yj.js.map} +1 -1
- package/dashboard/dist/assets/ScanCodesPage-FiYIYB-m.js +2 -0
- package/dashboard/dist/assets/{ScanCodesPage-b5NZM_-f.js.map → ScanCodesPage-FiYIYB-m.js.map} +1 -1
- package/dashboard/dist/assets/{ScanSchemeDetailPage-t7X6ekaW.js → ScanSchemeDetailPage-BiAqtD-a.js} +2 -2
- package/dashboard/dist/assets/{ScanSchemeDetailPage-t7X6ekaW.js.map → ScanSchemeDetailPage-BiAqtD-a.js.map} +1 -1
- package/dashboard/dist/assets/ScanStationPage-8CdOtbCD.js +2 -0
- package/dashboard/dist/assets/{ScanStationPage-r02hkTAG.js.map → ScanStationPage-8CdOtbCD.js.map} +1 -1
- package/dashboard/dist/assets/{ScopeBadge-CjyC7iyO.js → ScopeBadge-CXUg0FHo.js} +2 -2
- package/dashboard/dist/assets/{ScopeBadge-CjyC7iyO.js.map → ScopeBadge-CXUg0FHo.js.map} +1 -1
- package/dashboard/dist/assets/{SegmentedTabs-DXNzY05q.js → SegmentedTabs-BpJh4Hwn.js} +2 -2
- package/dashboard/dist/assets/{SegmentedTabs-DXNzY05q.js.map → SegmentedTabs-BpJh4Hwn.js.map} +1 -1
- package/dashboard/dist/assets/{StatCard-BXQ8dD9Y.js → StatCard-nWY4sndl.js} +2 -2
- package/dashboard/dist/assets/{StatCard-BXQ8dD9Y.js.map → StatCard-nWY4sndl.js.map} +1 -1
- package/dashboard/dist/assets/{StatusBadge-BDeUwPtb.js → StatusBadge-DHVwxre2.js} +2 -2
- package/dashboard/dist/assets/{StatusBadge-BDeUwPtb.js.map → StatusBadge-DHVwxre2.js.map} +1 -1
- package/dashboard/dist/assets/{StickyPagination-BGHQbp0_.js → StickyPagination-DRuqKhZt.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-BGHQbp0_.js.map → StickyPagination-DRuqKhZt.js.map} +1 -1
- package/dashboard/dist/assets/{StreamMessageDetail-C-wfdbLJ.js → StreamMessageDetail-JwlbRiMn.js} +2 -2
- package/dashboard/dist/assets/{StreamMessageDetail-C-wfdbLJ.js.map → StreamMessageDetail-JwlbRiMn.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-Dnoz-me3.js → SwimlaneTimeline-hu3c4bCJ.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-Dnoz-me3.js.map → SwimlaneTimeline-hu3c4bCJ.js.map} +1 -1
- package/dashboard/dist/assets/{TagInput-D-vLSMQC.js → TagInput-BZ8vb2oW.js} +2 -2
- package/dashboard/dist/assets/{TagInput-D-vLSMQC.js.map → TagInput-BZ8vb2oW.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-c9IiAhVJ.js → TaskDetailPage-NqVZF3jW.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-c9IiAhVJ.js.map → TaskDetailPage-NqVZF3jW.js.map} +1 -1
- package/dashboard/dist/assets/{TaskQueuePill-sFRMrQ5D.js → TaskQueuePill-Bxir8WRl.js} +2 -2
- package/dashboard/dist/assets/{TaskQueuePill-sFRMrQ5D.js.map → TaskQueuePill-Bxir8WRl.js.map} +1 -1
- package/dashboard/dist/assets/TasksListPage-BQNaSzCn.js +2 -0
- package/dashboard/dist/assets/{TasksListPage-Dor8LSc5.js.map → TasksListPage-BQNaSzCn.js.map} +1 -1
- package/dashboard/dist/assets/TimeAgo-Cv35DOiI.js +2 -0
- package/dashboard/dist/assets/{TimeAgo-Dd8vmRnM.js.map → TimeAgo-Cv35DOiI.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-qJfC6-iT.js → TimestampCell-DHUXey9s.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-qJfC6-iT.js.map → TimestampCell-DHUXey9s.js.map} +1 -1
- package/dashboard/dist/assets/{ToolPill-OQ3mC11d.js → ToolPill-FkgTXIhq.js} +2 -2
- package/dashboard/dist/assets/{ToolPill-OQ3mC11d.js.map → ToolPill-FkgTXIhq.js.map} +1 -1
- package/dashboard/dist/assets/ToolTestPanel-DvuLFWqQ.js +2 -0
- package/dashboard/dist/assets/{ToolTestPanel-CEGY5jss.js.map → ToolTestPanel-DvuLFWqQ.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-SI80ZTVv.js → TopicDetailPage-TXX3QNSo.js} +3 -3
- package/dashboard/dist/assets/{TopicDetailPage-SI80ZTVv.js.map → TopicDetailPage-TXX3QNSo.js.map} +1 -1
- package/dashboard/dist/assets/{TopicsPage-DiVB8tNr.js → TopicsPage-h-oyTeEJ.js} +2 -2
- package/dashboard/dist/assets/{TopicsPage-DiVB8tNr.js.map → TopicsPage-h-oyTeEJ.js.map} +1 -1
- package/dashboard/dist/assets/UserName-BceRCeDF.js +2 -0
- package/dashboard/dist/assets/UserName-BceRCeDF.js.map +1 -0
- package/dashboard/dist/assets/WorkflowExecutionPage-CmHGcaN9.js +2 -0
- package/dashboard/dist/assets/{WorkflowExecutionPage-e-Q57yiJ.js.map → WorkflowExecutionPage-CmHGcaN9.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowPill-Dh3hIW1l.js → WorkflowPill--AYMW7u_.js} +2 -2
- package/dashboard/dist/assets/WorkflowPill--AYMW7u_.js.map +1 -0
- package/dashboard/dist/assets/WorkflowsDashboard-B0r2lQXk.js +2 -0
- package/dashboard/dist/assets/{WorkflowsDashboard-DLKzN80h.js.map → WorkflowsDashboard-B0r2lQXk.js.map} +1 -1
- package/dashboard/dist/assets/WorkflowsOverview-BTMc2PJ_.js +2 -0
- package/dashboard/dist/assets/{WorkflowsOverview-J-ITQiO5.js.map → WorkflowsOverview-BTMc2PJ_.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-B_-ahhf1.js → YamlWorkflowDetailPage-DUiCVnZp.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-B_-ahhf1.js.map → YamlWorkflowDetailPage-DUiCVnZp.js.map} +1 -1
- package/dashboard/dist/assets/YamlWorkflowsPage-BAuXfwi0.js +2 -0
- package/dashboard/dist/assets/{YamlWorkflowsPage-DQNeERXU.js.map → YamlWorkflowsPage-BAuXfwi0.js.map} +1 -1
- package/dashboard/dist/assets/{agents-BsJ-MizQ.js → agents-BvmLCk4h.js} +2 -2
- package/dashboard/dist/assets/{agents-BsJ-MizQ.js.map → agents-BvmLCk4h.js.map} +1 -1
- package/dashboard/dist/assets/{bots-q1UYqaIh.js → bots-f_tyhl4I.js} +2 -2
- package/dashboard/dist/assets/{bots-q1UYqaIh.js.map → bots-f_tyhl4I.js.map} +1 -1
- package/dashboard/dist/assets/capabilities-DNo5bqLx.js +2 -0
- package/dashboard/dist/assets/{capabilities-BvjPXUcJ.js.map → capabilities-DNo5bqLx.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-BwlNpoJ_.js → controlplane-Dyyj2Irb.js} +2 -2
- package/dashboard/dist/assets/{controlplane-BwlNpoJ_.js.map → controlplane-Dyyj2Irb.js.map} +1 -1
- package/dashboard/dist/assets/escalation-columns-DIigeTOK.js +2 -0
- package/dashboard/dist/assets/escalation-columns-DIigeTOK.js.map +1 -0
- package/dashboard/dist/assets/index-BMlQYOE1.js +67 -0
- package/dashboard/dist/assets/index-BMlQYOE1.js.map +1 -0
- package/dashboard/dist/assets/index-BNZknxFY.js +2 -0
- package/dashboard/dist/assets/{index-cvmt1plS.js.map → index-BNZknxFY.js.map} +1 -1
- package/dashboard/dist/assets/index-Bpvfr4OW.css +1 -0
- package/dashboard/dist/assets/{index-CldVY0UQ.js → index-C-Xr2V3F.js} +2 -2
- package/dashboard/dist/assets/{index-CldVY0UQ.js.map → index-C-Xr2V3F.js.map} +1 -1
- package/dashboard/dist/assets/index-CegPUKpc.js +3 -0
- package/dashboard/dist/assets/index-CegPUKpc.js.map +1 -0
- package/dashboard/dist/assets/{index-O9uuK2yO.js → index-CsKiRyhy.js} +2 -2
- package/dashboard/dist/assets/{index-O9uuK2yO.js.map → index-CsKiRyhy.js.map} +1 -1
- package/dashboard/dist/assets/index-D7ESqn22.js +2 -0
- package/dashboard/dist/assets/{index-BhzsR_gZ.js.map → index-D7ESqn22.js.map} +1 -1
- package/dashboard/dist/assets/{index-Hbbox1A4.js → index-DL83W7Gu.js} +2 -2
- package/dashboard/dist/assets/{index-Hbbox1A4.js.map → index-DL83W7Gu.js.map} +1 -1
- package/dashboard/dist/assets/index-DPLssnMW.js +6 -0
- package/dashboard/dist/assets/index-DPLssnMW.js.map +1 -0
- package/dashboard/dist/assets/{index-DsKqDMs4.js → index-DWse7ERF.js} +2 -2
- package/dashboard/dist/assets/{index-DsKqDMs4.js.map → index-DWse7ERF.js.map} +1 -1
- package/dashboard/dist/assets/index-DoETPlJP.js +11 -0
- package/dashboard/dist/assets/index-DoETPlJP.js.map +1 -0
- package/dashboard/dist/assets/{index-8Gmtvd8e.js → index-DvxxrFBo.js} +2 -2
- package/dashboard/dist/assets/{index-8Gmtvd8e.js.map → index-DvxxrFBo.js.map} +1 -1
- package/dashboard/dist/assets/{index-DDHoDZRg.js → index-PcyGjmBm.js} +2 -2
- package/dashboard/dist/assets/{index-DDHoDZRg.js.map → index-PcyGjmBm.js.map} +1 -1
- package/dashboard/dist/assets/{index-BvGIyZUt.js → index-e2X-s0EQ.js} +2 -2
- package/dashboard/dist/assets/{index-BvGIyZUt.js.map → index-e2X-s0EQ.js.map} +1 -1
- package/dashboard/dist/assets/{knowledge-DM0tNphj.js → knowledge-Coo6CKzo.js} +2 -2
- package/dashboard/dist/assets/{knowledge-DM0tNphj.js.map → knowledge-Coo6CKzo.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-CQ_TD2P9.js → mcp-Cz5eFnP_.js} +2 -2
- package/dashboard/dist/assets/{mcp-CQ_TD2P9.js.map → mcp-Cz5eFnP_.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-BP7KSGhc.js → mcp-query-BtnuO4LF.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-BP7KSGhc.js.map → mcp-query-BtnuO4LF.js.map} +1 -1
- package/dashboard/dist/assets/{personas-DclHdHKK.js → personas-C2-LgpHQ.js} +2 -2
- package/dashboard/dist/assets/{personas-DclHdHKK.js.map → personas-C2-LgpHQ.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-LwuKJfj-.js → pipelines-TuXQvUA-.js} +2 -2
- package/dashboard/dist/assets/{pipelines-LwuKJfj-.js.map → pipelines-TuXQvUA-.js.map} +1 -1
- package/dashboard/dist/assets/resolver-payload-C1dXB3n6.js +2 -0
- package/dashboard/dist/assets/resolver-payload-C1dXB3n6.js.map +1 -0
- package/dashboard/dist/assets/seed-form-json-DvPsISxD.js +2 -0
- package/dashboard/dist/assets/seed-form-json-DvPsISxD.js.map +1 -0
- package/dashboard/dist/assets/{tasks-CDs-Li2v.js → tasks-OUzpu__z.js} +2 -2
- package/dashboard/dist/assets/{tasks-CDs-Li2v.js.map → tasks-OUzpu__z.js.map} +1 -1
- package/dashboard/dist/assets/{topics-BeOSelBX.js → topics-B8bdrBaW.js} +2 -2
- package/dashboard/dist/assets/{topics-BeOSelBX.js.map → topics-B8bdrBaW.js.map} +1 -1
- package/dashboard/dist/assets/useDebouncedValue-Cp5ZOtVE.js +2 -0
- package/dashboard/dist/assets/{useDebouncedValue-DhhAKjDC.js.map → useDebouncedValue-Cp5ZOtVE.js.map} +1 -1
- package/dashboard/dist/assets/{useFilterParams-crmlBw_l.js → useFilterParams-DBRw1Hcv.js} +2 -2
- package/dashboard/dist/assets/{useFilterParams-crmlBw_l.js.map → useFilterParams-DBRw1Hcv.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-C-E2gNEK.js → useNamespace-DtQe3wZ5.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-C-E2gNEK.js.map → useNamespace-DtQe3wZ5.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-CmLzX3YU.js → useYamlActivityEvents-CS22c15X.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-CmLzX3YU.js.map → useYamlActivityEvents-CS22c15X.js.map} +1 -1
- package/dashboard/dist/assets/{vendor-icons-R9b9gQ04.js → vendor-icons-DeBdvyKJ.js} +368 -143
- package/dashboard/dist/assets/vendor-icons-DeBdvyKJ.js.map +1 -0
- package/dashboard/dist/assets/vendor-query-DvWWuNIB.js +18 -0
- package/dashboard/dist/assets/vendor-query-DvWWuNIB.js.map +1 -0
- package/dashboard/dist/assets/{vendor-react-CdqEC2zv.js → vendor-react-_9U4mKFr.js} +2 -2
- package/dashboard/dist/assets/{vendor-react-CdqEC2zv.js.map → vendor-react-_9U4mKFr.js.map} +1 -1
- package/dashboard/dist/assets/{yaml-workflows-BgAsc6-I.js → yaml-workflows-HQIki3hI.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-BgAsc6-I.js.map → yaml-workflows-HQIki3hI.js.map} +1 -1
- package/dashboard/dist/index.html +5 -5
- package/docs/api/http/workflows.md +25 -1
- package/docs/code-owned-configuration.md +1 -1
- package/docs/dashboard.md +179 -80
- package/docs/events.md +3 -1
- package/docs/faceted-routing.md +5 -1
- package/docs/hitl/iframe.md +35 -6
- package/docs/hitl/invoke-form.md +98 -0
- package/docs/hitl/x-lt-list-schema.md +3 -0
- package/docs/hitl/x-lt-show-if.md +11 -0
- package/docs/hitl-guide.md +4 -2
- package/docs/iam.md +1 -1
- package/docs/operations.md +61 -60
- package/docs/scan-codes.md +30 -3
- package/docs/workflows.md +1 -1
- package/package.json +1 -1
- package/dashboard/dist/assets/AgentsPage-CLSjlyXy.js +0 -2
- package/dashboard/dist/assets/AvailableEscalationsPage-D2ukvuQh.js +0 -2
- package/dashboard/dist/assets/AvailableEscalationsPage-D2ukvuQh.js.map +0 -1
- package/dashboard/dist/assets/BulkAssignModal-CMSgvHIs.js +0 -2
- package/dashboard/dist/assets/BulkAssignModal-CMSgvHIs.js.map +0 -1
- package/dashboard/dist/assets/CountdownTimer-B5lM7PfE.js +0 -2
- package/dashboard/dist/assets/CountdownTimer-B5lM7PfE.js.map +0 -1
- package/dashboard/dist/assets/EntityTimelinePanel-B5NuHnPF.js +0 -2
- package/dashboard/dist/assets/EntityTimelinePanel-B5NuHnPF.js.map +0 -1
- package/dashboard/dist/assets/HomePage-8XsQFqKL.js +0 -2
- package/dashboard/dist/assets/HomePage-8XsQFqKL.js.map +0 -1
- package/dashboard/dist/assets/ListToolbar-DyHaJBTk.js +0 -2
- package/dashboard/dist/assets/McpQueryPage-BqqRF5cQ.js +0 -2
- package/dashboard/dist/assets/NamespacePill-CJikgGzE.js +0 -2
- package/dashboard/dist/assets/OperationsPage-Cj1mJLMC.js +0 -3
- package/dashboard/dist/assets/OperationsPage-Cj1mJLMC.js.map +0 -1
- package/dashboard/dist/assets/OperatorDashboard-C5rlijvh.js +0 -2
- package/dashboard/dist/assets/PersonasPage-Xp_Gt6El.js +0 -2
- package/dashboard/dist/assets/PersonasPage-Xp_Gt6El.js.map +0 -1
- package/dashboard/dist/assets/ProcessesListPage-DuXTS5-v.js +0 -2
- package/dashboard/dist/assets/RoleDetailPage-C9GGHNf4.js +0 -8
- package/dashboard/dist/assets/RoleDetailPage-C9GGHNf4.js.map +0 -1
- package/dashboard/dist/assets/RolesPage-h77-JOLd.js +0 -2
- package/dashboard/dist/assets/RunAsSelector-DoLFJ0mZ.js +0 -2
- package/dashboard/dist/assets/ScanCodesPage-b5NZM_-f.js +0 -2
- package/dashboard/dist/assets/ScanStationPage-r02hkTAG.js +0 -2
- package/dashboard/dist/assets/TasksListPage-Dor8LSc5.js +0 -2
- package/dashboard/dist/assets/TimeAgo-Dd8vmRnM.js +0 -2
- package/dashboard/dist/assets/ToolTestPanel-CEGY5jss.js +0 -2
- package/dashboard/dist/assets/UserName-Dmm456xT.js +0 -2
- package/dashboard/dist/assets/UserName-Dmm456xT.js.map +0 -1
- package/dashboard/dist/assets/WorkflowExecutionPage-e-Q57yiJ.js +0 -2
- package/dashboard/dist/assets/WorkflowPill-Dh3hIW1l.js.map +0 -1
- package/dashboard/dist/assets/WorkflowsDashboard-DLKzN80h.js +0 -2
- package/dashboard/dist/assets/WorkflowsOverview-J-ITQiO5.js +0 -2
- package/dashboard/dist/assets/YamlWorkflowsPage-DQNeERXU.js +0 -2
- package/dashboard/dist/assets/capabilities-BvjPXUcJ.js +0 -2
- package/dashboard/dist/assets/escalation-columns-Bo3PfIZj.js +0 -2
- package/dashboard/dist/assets/escalation-columns-Bo3PfIZj.js.map +0 -1
- package/dashboard/dist/assets/index-B8JfGtQB.js +0 -3
- package/dashboard/dist/assets/index-B8JfGtQB.js.map +0 -1
- package/dashboard/dist/assets/index-Bb9ZZUyB.js +0 -5
- package/dashboard/dist/assets/index-Bb9ZZUyB.js.map +0 -1
- package/dashboard/dist/assets/index-BhzsR_gZ.js +0 -2
- package/dashboard/dist/assets/index-D88VWEVp.js +0 -67
- package/dashboard/dist/assets/index-D88VWEVp.js.map +0 -1
- package/dashboard/dist/assets/index-DBvkaa-B.js +0 -6
- package/dashboard/dist/assets/index-DBvkaa-B.js.map +0 -1
- package/dashboard/dist/assets/index-cvmt1plS.js +0 -2
- package/dashboard/dist/assets/index-qU_dXqP4.css +0 -1
- package/dashboard/dist/assets/useDebouncedValue-DhhAKjDC.js +0 -2
- package/dashboard/dist/assets/vendor-icons-R9b9gQ04.js.map +0 -1
- package/dashboard/dist/assets/vendor-query-RUZdMvN6.js +0 -18
- package/dashboard/dist/assets/vendor-query-RUZdMvN6.js.map +0 -1
- package/dashboard/dist/assets/workflows-CYv1CTU0.js +0 -2
- package/dashboard/dist/assets/workflows-CYv1CTU0.js.map +0 -1
|
@@ -178,7 +178,7 @@ async function ensureSideQuestRoles() {
|
|
|
178
178
|
console.log(`[${ts()}] Entity declared on ${declared} role(s): order_id`);
|
|
179
179
|
}
|
|
180
180
|
// ── Side-quest escalations (standalone rows — no workflow behind them) ────────
|
|
181
|
-
async function createSideEscalation(role, workflowId, orderId, runId, description, authorizedAt) {
|
|
181
|
+
async function createSideEscalation(role, workflowId, orderId, runId, description, authorizedAt, facility) {
|
|
182
182
|
try {
|
|
183
183
|
await api('POST', '/api/escalations', {
|
|
184
184
|
type: 'ortho-stage',
|
|
@@ -186,8 +186,8 @@ async function createSideEscalation(role, workflowId, orderId, runId, descriptio
|
|
|
186
186
|
role,
|
|
187
187
|
description,
|
|
188
188
|
workflow_id: workflowId,
|
|
189
|
-
envelope: JSON.stringify({ order_id: orderId }),
|
|
190
|
-
metadata: { order_id: orderId, source: 'populate', run_id: runId, authorized_at: authorizedAt },
|
|
189
|
+
envelope: JSON.stringify({ order_id: orderId, ...(facility ? { facility } : {}) }),
|
|
190
|
+
metadata: { order_id: orderId, source: 'populate', run_id: runId, authorized_at: authorizedAt, ...(facility ? { facility } : {}) },
|
|
191
191
|
});
|
|
192
192
|
return true;
|
|
193
193
|
}
|
|
@@ -261,7 +261,7 @@ async function resolveBatch(batchTag, runId) {
|
|
|
261
261
|
// order's authorized_at rides along from the ordering escalation.
|
|
262
262
|
if (esc.role === 'ordering') {
|
|
263
263
|
const orderId = esc.metadata?.order_id ?? '';
|
|
264
|
-
await createSideEscalation('inserting', esc.workflow_id, orderId, runId, `Stuff inserts into shoes for ${orderId}`, esc.metadata?.authorized_at ?? new Date().toISOString());
|
|
264
|
+
await createSideEscalation('inserting', esc.workflow_id, orderId, runId, `Stuff inserts into shoes for ${orderId}`, esc.metadata?.authorized_at ?? new Date().toISOString(), esc.metadata?.facility);
|
|
265
265
|
}
|
|
266
266
|
}
|
|
267
267
|
catch (err) {
|
|
@@ -275,6 +275,10 @@ async function resolveBatch(batchTag, runId) {
|
|
|
275
275
|
return 0;
|
|
276
276
|
}
|
|
277
277
|
}
|
|
278
|
+
// Two manufacturing sites — each order is assigned one at arrival and every
|
|
279
|
+
// escalation it spawns carries it, so the Pace Board's facet scope
|
|
280
|
+
// (facility = north|south) has real data to narrow.
|
|
281
|
+
const FACILITIES = ['north', 'south'];
|
|
278
282
|
async function runOrders(batchTag, runId, plan, target) {
|
|
279
283
|
let done = false;
|
|
280
284
|
const workflowIds = [];
|
|
@@ -295,6 +299,9 @@ async function runOrders(batchTag, runId, plan, target) {
|
|
|
295
299
|
data: {
|
|
296
300
|
order_id: order.orderId,
|
|
297
301
|
item_type: 'insole-standard',
|
|
302
|
+
// Stamped on the envelope; the workflow applies it to every stage
|
|
303
|
+
// escalation's metadata as the facility facet.
|
|
304
|
+
facility: order.facility,
|
|
298
305
|
metadata: { source: 'populate', run_id: runId, authorized_at: authorizedAt },
|
|
299
306
|
},
|
|
300
307
|
metadata: { source: 'populate', run_id: runId, shoes: order.shoes },
|
|
@@ -308,7 +315,7 @@ async function runOrders(batchTag, runId, plan, target) {
|
|
|
308
315
|
continue;
|
|
309
316
|
}
|
|
310
317
|
if (order.shoes) {
|
|
311
|
-
const ok = await createSideEscalation('ordering', `${order.wfId}-shoes`, order.orderId, runId, `Order shoes for ${order.orderId}`, authorizedAt);
|
|
318
|
+
const ok = await createSideEscalation('ordering', `${order.wfId}-shoes`, order.orderId, runId, `Order shoes for ${order.orderId}`, authorizedAt, order.facility);
|
|
312
319
|
if (!ok)
|
|
313
320
|
target.value -= 2;
|
|
314
321
|
}
|
|
@@ -372,6 +379,9 @@ async function main() {
|
|
|
372
379
|
wfId: `${batchTag}-${i}`,
|
|
373
380
|
orderId: `ORD-${runId}-${i}`,
|
|
374
381
|
shoes: hasShoes(i),
|
|
382
|
+
// Pseudo-random per order (hashed on the workflow id): reproducible across
|
|
383
|
+
// re-runs, roughly balanced across both sites.
|
|
384
|
+
facility: FACILITIES[Math.floor(jitter(`${batchTag}-${i}`, 'facility') * FACILITIES.length)],
|
|
375
385
|
}));
|
|
376
386
|
const shoeCount = plan.filter((o) => o.shoes).length;
|
|
377
387
|
// Each order resolves 8 manufacturing stages; a shoe order adds
|
package/build/sdk/index.d.ts
CHANGED
|
@@ -123,6 +123,7 @@ export declare function createClient(options?: LTClientOptions): {
|
|
|
123
123
|
}, auth?: LTApiAuth) => Promise<LTApiResult<any>>;
|
|
124
124
|
getStationMetrics: (input: {
|
|
125
125
|
period?: string;
|
|
126
|
+
facets?: Record<string, unknown>;
|
|
126
127
|
}, auth?: LTApiAuth) => Promise<LTApiResult<any>>;
|
|
127
128
|
get: (input: {
|
|
128
129
|
id: string;
|
|
@@ -16,6 +16,8 @@ async function loadAllConfigs() {
|
|
|
16
16
|
consumes: c.consumes,
|
|
17
17
|
toolTags: c.tool_tags || [],
|
|
18
18
|
envelopeSchema: c.envelope_schema ?? null,
|
|
19
|
+
inputSchema: c.input_schema ?? null,
|
|
20
|
+
icon: c.icon ?? null,
|
|
19
21
|
resolverSchema: c.resolver_schema ?? null,
|
|
20
22
|
cronSchedule: c.cron_schedule ?? null,
|
|
21
23
|
executeAs: c.execute_as ?? null,
|
|
@@ -26,6 +26,8 @@ async function getWorkflowConfig(workflowType) {
|
|
|
26
26
|
consumes: wf.consumes || [],
|
|
27
27
|
tool_tags: wf.tool_tags || [],
|
|
28
28
|
envelope_schema: wf.envelope_schema ?? null,
|
|
29
|
+
input_schema: wf.input_schema ?? null,
|
|
30
|
+
icon: wf.icon ?? null,
|
|
29
31
|
resolver_schema: wf.resolver_schema ?? null,
|
|
30
32
|
cron_schedule: wf.cron_schedule ?? null,
|
|
31
33
|
execute_as: wf.execute_as ?? null,
|
|
@@ -64,6 +66,8 @@ async function listWorkflowConfigs() {
|
|
|
64
66
|
consumes: wf.consumes || [],
|
|
65
67
|
tool_tags: wf.tool_tags || [],
|
|
66
68
|
envelope_schema: wf.envelope_schema ?? null,
|
|
69
|
+
input_schema: wf.input_schema ?? null,
|
|
70
|
+
icon: wf.icon ?? null,
|
|
67
71
|
resolver_schema: wf.resolver_schema ?? null,
|
|
68
72
|
cron_schedule: wf.cron_schedule ?? null,
|
|
69
73
|
execute_as: wf.execute_as ?? null,
|
|
@@ -5,13 +5,13 @@ export declare const LIST_ALL_WORKFLOWS = "SELECT * FROM lt_config_workflows ORD
|
|
|
5
5
|
export declare const LIST_ALL_ROLES = "SELECT * FROM lt_config_roles ORDER BY workflow_type, role";
|
|
6
6
|
export declare const LIST_ALL_INVOCATION_ROLES = "SELECT * FROM lt_config_invocation_roles ORDER BY workflow_type, role";
|
|
7
7
|
export declare const ENSURE_ROLE_EXISTS = "INSERT INTO lt_roles (role) VALUES ($1) ON CONFLICT DO NOTHING";
|
|
8
|
-
export declare const UPSERT_WORKFLOW = "INSERT INTO lt_config_workflows\n (workflow_type, invocable, task_queue, default_role, description, consumes, envelope_schema, resolver_schema, cron_schedule, tool_tags, execute_as, certified, read_safe)\nVALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)\nON CONFLICT (workflow_type) DO UPDATE SET\n invocable = EXCLUDED.invocable,\n task_queue = EXCLUDED.task_queue,\n default_role = EXCLUDED.default_role,\n description = EXCLUDED.description,\n consumes = EXCLUDED.consumes,\n envelope_schema = EXCLUDED.envelope_schema,\n resolver_schema = EXCLUDED.resolver_schema,\n cron_schedule = EXCLUDED.cron_schedule,\n tool_tags = EXCLUDED.tool_tags,\n execute_as = EXCLUDED.execute_as,\n certified = EXCLUDED.certified,\n read_safe = EXCLUDED.read_safe";
|
|
8
|
+
export declare const UPSERT_WORKFLOW = "INSERT INTO lt_config_workflows\n (workflow_type, invocable, task_queue, default_role, description, consumes, envelope_schema, resolver_schema, cron_schedule, tool_tags, execute_as, certified, read_safe, input_schema, icon)\nVALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)\nON CONFLICT (workflow_type) DO UPDATE SET\n invocable = EXCLUDED.invocable,\n task_queue = EXCLUDED.task_queue,\n default_role = EXCLUDED.default_role,\n description = EXCLUDED.description,\n consumes = EXCLUDED.consumes,\n envelope_schema = EXCLUDED.envelope_schema,\n resolver_schema = EXCLUDED.resolver_schema,\n cron_schedule = EXCLUDED.cron_schedule,\n tool_tags = EXCLUDED.tool_tags,\n execute_as = EXCLUDED.execute_as,\n certified = EXCLUDED.certified,\n read_safe = EXCLUDED.read_safe,\n input_schema = EXCLUDED.input_schema,\n icon = EXCLUDED.icon";
|
|
9
9
|
export declare const DELETE_CONFIG_ROLES = "DELETE FROM lt_config_roles WHERE workflow_type = $1";
|
|
10
10
|
export declare const INSERT_CONFIG_ROLE = "INSERT INTO lt_config_roles (workflow_type, role) VALUES ($1, $2)";
|
|
11
11
|
export declare const DELETE_INVOCATION_ROLES = "DELETE FROM lt_config_invocation_roles WHERE workflow_type = $1";
|
|
12
12
|
export declare const INSERT_INVOCATION_ROLE = "INSERT INTO lt_config_invocation_roles (workflow_type, role) VALUES ($1, $2)";
|
|
13
13
|
export declare const DELETE_WORKFLOW = "DELETE FROM lt_config_workflows WHERE workflow_type = $1";
|
|
14
|
-
export declare const SEED_WORKFLOW_CONFIG = "INSERT INTO lt_config_workflows\n (workflow_type, invocable, task_queue, default_role, description, consumes, envelope_schema, resolver_schema, cron_schedule, tool_tags, execute_as, certified, read_safe)\nVALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)\nON CONFLICT (workflow_type) DO NOTHING";
|
|
14
|
+
export declare const SEED_WORKFLOW_CONFIG = "INSERT INTO lt_config_workflows\n (workflow_type, invocable, task_queue, default_role, description, consumes, envelope_schema, resolver_schema, cron_schedule, tool_tags, execute_as, certified, read_safe, input_schema, icon)\nVALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)\nON CONFLICT (workflow_type) DO NOTHING";
|
|
15
15
|
export declare const SEED_CONFIG_ROLE = "INSERT INTO lt_config_roles (workflow_type, role) VALUES ($1, $2)\nON CONFLICT (workflow_type, role) DO NOTHING";
|
|
16
16
|
export declare const SEED_INVOCATION_ROLE = "INSERT INTO lt_config_invocation_roles (workflow_type, role) VALUES ($1, $2)\nON CONFLICT (workflow_type, role) DO NOTHING";
|
|
17
17
|
export declare const GET_PROVIDER_DATA = "SELECT workflow_type, data, completed_at\n FROM lt_tasks\n WHERE origin_id = $1\n AND workflow_type = ANY($2)\n AND status = 'completed'\n ORDER BY completed_at DESC";
|
|
@@ -23,8 +23,8 @@ exports.ENSURE_ROLE_EXISTS = `\
|
|
|
23
23
|
INSERT INTO lt_roles (role) VALUES ($1) ON CONFLICT DO NOTHING`;
|
|
24
24
|
exports.UPSERT_WORKFLOW = `\
|
|
25
25
|
INSERT INTO lt_config_workflows
|
|
26
|
-
(workflow_type, invocable, task_queue, default_role, description, consumes, envelope_schema, resolver_schema, cron_schedule, tool_tags, execute_as, certified, read_safe)
|
|
27
|
-
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
|
|
26
|
+
(workflow_type, invocable, task_queue, default_role, description, consumes, envelope_schema, resolver_schema, cron_schedule, tool_tags, execute_as, certified, read_safe, input_schema, icon)
|
|
27
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)
|
|
28
28
|
ON CONFLICT (workflow_type) DO UPDATE SET
|
|
29
29
|
invocable = EXCLUDED.invocable,
|
|
30
30
|
task_queue = EXCLUDED.task_queue,
|
|
@@ -37,7 +37,9 @@ ON CONFLICT (workflow_type) DO UPDATE SET
|
|
|
37
37
|
tool_tags = EXCLUDED.tool_tags,
|
|
38
38
|
execute_as = EXCLUDED.execute_as,
|
|
39
39
|
certified = EXCLUDED.certified,
|
|
40
|
-
read_safe = EXCLUDED.read_safe
|
|
40
|
+
read_safe = EXCLUDED.read_safe,
|
|
41
|
+
input_schema = EXCLUDED.input_schema,
|
|
42
|
+
icon = EXCLUDED.icon`;
|
|
41
43
|
exports.DELETE_CONFIG_ROLES = `\
|
|
42
44
|
DELETE FROM lt_config_roles WHERE workflow_type = $1`;
|
|
43
45
|
exports.INSERT_CONFIG_ROLE = `\
|
|
@@ -53,8 +55,8 @@ DELETE FROM lt_config_workflows WHERE workflow_type = $1`;
|
|
|
53
55
|
// ------------------------------------------------------------------ //
|
|
54
56
|
exports.SEED_WORKFLOW_CONFIG = `\
|
|
55
57
|
INSERT INTO lt_config_workflows
|
|
56
|
-
(workflow_type, invocable, task_queue, default_role, description, consumes, envelope_schema, resolver_schema, cron_schedule, tool_tags, execute_as, certified, read_safe)
|
|
57
|
-
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
|
|
58
|
+
(workflow_type, invocable, task_queue, default_role, description, consumes, envelope_schema, resolver_schema, cron_schedule, tool_tags, execute_as, certified, read_safe, input_schema, icon)
|
|
59
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)
|
|
58
60
|
ON CONFLICT (workflow_type) DO NOTHING`;
|
|
59
61
|
exports.SEED_CONFIG_ROLE = `\
|
|
60
62
|
INSERT INTO lt_config_roles (workflow_type, role) VALUES ($1, $2)
|
|
@@ -53,6 +53,8 @@ async function replaceWorkflowConfig(config, certified) {
|
|
|
53
53
|
config.execute_as ?? null,
|
|
54
54
|
certified,
|
|
55
55
|
config.read_safe ?? false,
|
|
56
|
+
config.input_schema ?? null,
|
|
57
|
+
config.icon ?? null,
|
|
56
58
|
]);
|
|
57
59
|
// Replace roles
|
|
58
60
|
await client.query(sql_1.DELETE_CONFIG_ROLES, [config.workflow_type]);
|
|
@@ -114,6 +116,8 @@ async function seedWorkflowConfig(config) {
|
|
|
114
116
|
config.execute_as ?? null,
|
|
115
117
|
resolveCertified(config),
|
|
116
118
|
config.read_safe ?? false,
|
|
119
|
+
config.input_schema ?? null,
|
|
120
|
+
config.icon ?? null,
|
|
117
121
|
]);
|
|
118
122
|
const inserted = (rowCount ?? 0) > 0;
|
|
119
123
|
if (inserted) {
|
|
@@ -144,6 +148,10 @@ async function seedWorkflowConfig(config) {
|
|
|
144
148
|
drifts.push('envelope_schema');
|
|
145
149
|
if (JSON.stringify(config.resolver_schema) !== JSON.stringify(existing.resolver_schema))
|
|
146
150
|
drifts.push('resolver_schema');
|
|
151
|
+
if (JSON.stringify(config.input_schema ?? null) !== JSON.stringify(existing.input_schema ?? null))
|
|
152
|
+
drifts.push('input_schema');
|
|
153
|
+
if ((config.icon ?? null) !== (existing.icon ?? null))
|
|
154
|
+
drifts.push('icon');
|
|
147
155
|
if (drifts.length) {
|
|
148
156
|
logger_1.loggerRegistry.warn(`[long-tail] config drift: ${config.workflow_type} — ${drifts.join(', ')} differ between code and DB`);
|
|
149
157
|
}
|
|
@@ -181,7 +189,9 @@ async function applyWorkflowConfig(config) {
|
|
|
181
189
|
sortedEqual(existing.roles ?? [], config.roles ?? []) &&
|
|
182
190
|
sortedEqual(existing.invocation_roles ?? [], config.invocation_roles ?? []) &&
|
|
183
191
|
(0, node_util_1.isDeepStrictEqual)(existing.envelope_schema ?? null, config.envelope_schema ?? null) &&
|
|
184
|
-
(0, node_util_1.isDeepStrictEqual)(existing.resolver_schema ?? null, config.resolver_schema ?? null)
|
|
192
|
+
(0, node_util_1.isDeepStrictEqual)(existing.resolver_schema ?? null, config.resolver_schema ?? null) &&
|
|
193
|
+
(0, node_util_1.isDeepStrictEqual)(existing.input_schema ?? null, config.input_schema ?? null) &&
|
|
194
|
+
(existing.icon ?? null) === (config.icon ?? null);
|
|
185
195
|
if (unchanged)
|
|
186
196
|
return 'unchanged';
|
|
187
197
|
}
|
|
@@ -4,6 +4,7 @@ exports.resolveBatchItem = resolveBatchItem;
|
|
|
4
4
|
exports.resolveBatchItemBySignalKey = resolveBatchItemBySignalKey;
|
|
5
5
|
exports.resolveBatchItemByMetadata = resolveBatchItemByMetadata;
|
|
6
6
|
const escalation_wire_1 = require("../../lib/events/escalation-wire");
|
|
7
|
+
const uuid_1 = require("../../lib/uuid");
|
|
7
8
|
const client_1 = require("./client");
|
|
8
9
|
const crud_1 = require("./crud");
|
|
9
10
|
const map_1 = require("./map");
|
|
@@ -15,6 +16,8 @@ const map_1 = require("./map");
|
|
|
15
16
|
* outcomes publish nothing — the row was untouched.
|
|
16
17
|
*/
|
|
17
18
|
async function resolveBatchItem(id, itemKey, payload, metadata, assertClaim, resolvedBy) {
|
|
19
|
+
if (!(0, uuid_1.isUuid)(id))
|
|
20
|
+
return { outcome: 'not-found', remaining: -1, escalation: null };
|
|
18
21
|
const client = await (0, client_1.escalations)();
|
|
19
22
|
const result = await client.resolveBatchItem({
|
|
20
23
|
id,
|
|
@@ -8,6 +8,7 @@ exports.bulkUnassignEscalations = bulkUnassignEscalations;
|
|
|
8
8
|
exports.bulkEscalateToRole = bulkEscalateToRole;
|
|
9
9
|
exports.bulkCancelEscalations = bulkCancelEscalations;
|
|
10
10
|
exports.bulkResolveForTriage = bulkResolveForTriage;
|
|
11
|
+
const uuid_1 = require("../../lib/uuid");
|
|
11
12
|
const db_1 = require("../../lib/db");
|
|
12
13
|
const client_1 = require("./client");
|
|
13
14
|
const map_1 = require("./map");
|
|
@@ -17,6 +18,7 @@ const sql_1 = require("./sql");
|
|
|
17
18
|
* Items already claimed by another active user are skipped.
|
|
18
19
|
*/
|
|
19
20
|
async function bulkClaimEscalations(ids, userId, durationMinutes = 30) {
|
|
21
|
+
ids = (0, uuid_1.onlyUuids)(ids);
|
|
20
22
|
if (ids.length === 0)
|
|
21
23
|
return { claimed: 0, skipped: 0 };
|
|
22
24
|
const client = await (0, client_1.escalations)();
|
|
@@ -27,6 +29,7 @@ async function bulkClaimEscalations(ids, userId, durationMinutes = 30) {
|
|
|
27
29
|
* Items already claimed by another active user are skipped.
|
|
28
30
|
*/
|
|
29
31
|
async function bulkAssignEscalations(ids, targetUserId, durationMinutes = 30) {
|
|
32
|
+
ids = (0, uuid_1.onlyUuids)(ids);
|
|
30
33
|
if (ids.length === 0)
|
|
31
34
|
return { assigned: 0, skipped: 0 };
|
|
32
35
|
const client = await (0, client_1.escalations)();
|
|
@@ -60,6 +63,7 @@ async function bulkAssignEscalationsByQuery(query, targetUserId, durationMinutes
|
|
|
60
63
|
* returned row carries its pre-update assignee for the event.
|
|
61
64
|
*/
|
|
62
65
|
async function bulkReassignEscalations(ids, targetUserId, durationMinutes = 30) {
|
|
66
|
+
ids = (0, uuid_1.onlyUuids)(ids);
|
|
63
67
|
if (ids.length === 0)
|
|
64
68
|
return { assigned: 0, skipped: 0, changes: [] };
|
|
65
69
|
await (0, client_1.ensureEscalationCompatView)();
|
|
@@ -77,6 +81,7 @@ async function bulkReassignEscalations(ids, targetUserId, durationMinutes = 30)
|
|
|
77
81
|
* statement; unclaimed and terminal rows are skipped.
|
|
78
82
|
*/
|
|
79
83
|
async function bulkUnassignEscalations(ids) {
|
|
84
|
+
ids = (0, uuid_1.onlyUuids)(ids);
|
|
80
85
|
if (ids.length === 0)
|
|
81
86
|
return { unassigned: 0, skipped: 0, changes: [] };
|
|
82
87
|
await (0, client_1.ensureEscalationCompatView)();
|
|
@@ -93,6 +98,7 @@ async function bulkUnassignEscalations(ids) {
|
|
|
93
98
|
* Clears assignment on all affected rows.
|
|
94
99
|
*/
|
|
95
100
|
async function bulkEscalateToRole(ids, targetRole) {
|
|
101
|
+
ids = (0, uuid_1.onlyUuids)(ids);
|
|
96
102
|
if (ids.length === 0)
|
|
97
103
|
return 0;
|
|
98
104
|
const client = await (0, client_1.escalations)();
|
|
@@ -104,6 +110,7 @@ async function bulkEscalateToRole(ids, targetRole) {
|
|
|
104
110
|
* successfully cancelled.
|
|
105
111
|
*/
|
|
106
112
|
async function bulkCancelEscalations(ids) {
|
|
113
|
+
ids = (0, uuid_1.onlyUuids)(ids);
|
|
107
114
|
if (ids.length === 0)
|
|
108
115
|
return { cancelled: 0, skipped: 0 };
|
|
109
116
|
const client = await (0, client_1.escalations)();
|
|
@@ -126,6 +133,7 @@ async function bulkCancelEscalations(ids) {
|
|
|
126
133
|
* `pending`; only the returned rows enter triage.
|
|
127
134
|
*/
|
|
128
135
|
async function bulkResolveForTriage(ids, hint) {
|
|
136
|
+
ids = (0, uuid_1.onlyUuids)(ids);
|
|
129
137
|
if (ids.length === 0)
|
|
130
138
|
return [];
|
|
131
139
|
const client = await (0, client_1.escalations)();
|
|
@@ -29,6 +29,7 @@ const db_1 = require("../../lib/db");
|
|
|
29
29
|
const publish_1 = require("../../lib/events/publish");
|
|
30
30
|
const escalation_wire_1 = require("../../lib/events/escalation-wire");
|
|
31
31
|
const escalation_1 = require("../../types/escalation");
|
|
32
|
+
const uuid_1 = require("../../lib/uuid");
|
|
32
33
|
const client_1 = require("./client");
|
|
33
34
|
const queries_1 = require("./queries");
|
|
34
35
|
const map_1 = require("./map");
|
|
@@ -95,6 +96,8 @@ async function createEscalation(input) {
|
|
|
95
96
|
* user re-claims (extends expiry). Returns null when the row is not claimable.
|
|
96
97
|
*/
|
|
97
98
|
async function claimEscalation(id, userId, durationMinutes = 30) {
|
|
99
|
+
if (!(0, uuid_1.isUuid)(id))
|
|
100
|
+
return null;
|
|
98
101
|
const client = await (0, client_1.escalations)();
|
|
99
102
|
const result = await client.claim({ id, assignee: userId, durationMinutes });
|
|
100
103
|
if (!result.ok)
|
|
@@ -132,6 +135,8 @@ async function claimEscalation(id, userId, durationMinutes = 30) {
|
|
|
132
135
|
* the stored `resolver_payload`.
|
|
133
136
|
*/
|
|
134
137
|
async function resolveEscalation(id, resolverPayload, metadata, assertClaim, resolvedBy) {
|
|
138
|
+
if (!(0, uuid_1.isUuid)(id))
|
|
139
|
+
return null;
|
|
135
140
|
const client = await (0, client_1.escalations)();
|
|
136
141
|
// `assertClaim` rides the SDK's guarded UPDATE: no active claim lock may
|
|
137
142
|
// stand against this assignee, or the resolve blocks (claim-expired /
|
|
@@ -169,6 +174,7 @@ async function resolveEscalation(id, resolverPayload, metadata, assertClaim, res
|
|
|
169
174
|
* `resolveEscalation` (which delivers the signal).
|
|
170
175
|
*/
|
|
171
176
|
async function resolveEscalationsByIds(ids, resolverPayload, metadata) {
|
|
177
|
+
ids = (0, uuid_1.onlyUuids)(ids);
|
|
172
178
|
if (ids.length === 0)
|
|
173
179
|
return [];
|
|
174
180
|
const client = await (0, client_1.escalations)();
|
|
@@ -209,6 +215,12 @@ async function resolveEscalationsByIds(ids, resolverPayload, metadata) {
|
|
|
209
215
|
async function resolveEscalationsAllOrNone(items, metadata, assertAssignee, resolvedBy) {
|
|
210
216
|
if (items.length === 0)
|
|
211
217
|
return { ok: true, escalations: [] };
|
|
218
|
+
// A malformed id blocks the batch exactly like a well-formed missing one —
|
|
219
|
+
// and never reaches the uuid cast.
|
|
220
|
+
const malformed = items.filter((i) => !(0, uuid_1.isUuid)(i.id));
|
|
221
|
+
if (malformed.length > 0) {
|
|
222
|
+
return { ok: false, failed: malformed.map((i) => ({ id: i.id, reason: 'not-found' })) };
|
|
223
|
+
}
|
|
212
224
|
const client = await (0, client_1.escalations)();
|
|
213
225
|
const result = await client.resolveAllOrNone({ items, metadata, assertAssignee, resolvedBy });
|
|
214
226
|
if (!result.ok)
|
|
@@ -235,6 +247,7 @@ async function resolveEscalationsAllOrNone(items, metadata, assertAssignee, reso
|
|
|
235
247
|
* fields — signal routing shape, `metadata.form_schema` for redaction.
|
|
236
248
|
*/
|
|
237
249
|
async function getEscalationsByIds(ids) {
|
|
250
|
+
ids = (0, uuid_1.onlyUuids)(ids);
|
|
238
251
|
if (ids.length === 0)
|
|
239
252
|
return [];
|
|
240
253
|
const client = await (0, client_1.escalations)();
|
|
@@ -278,6 +291,8 @@ async function resolveEscalationBySignalKey(signalKey, resolverPayload, metadata
|
|
|
278
291
|
* already terminal.
|
|
279
292
|
*/
|
|
280
293
|
async function cancelEscalation(id) {
|
|
294
|
+
if (!(0, uuid_1.isUuid)(id))
|
|
295
|
+
return null;
|
|
281
296
|
const client = await (0, client_1.escalations)();
|
|
282
297
|
const result = await client.cancel(id);
|
|
283
298
|
if (!result.ok)
|
|
@@ -301,6 +316,7 @@ async function cancelEscalation(id) {
|
|
|
301
316
|
* updated.
|
|
302
317
|
*/
|
|
303
318
|
async function updateEscalationsPriority(ids, priority) {
|
|
319
|
+
ids = (0, uuid_1.onlyUuids)(ids);
|
|
304
320
|
if (ids.length === 0)
|
|
305
321
|
return 0;
|
|
306
322
|
const client = await (0, client_1.escalations)();
|
|
@@ -311,6 +327,7 @@ async function updateEscalationsPriority(ids, priority) {
|
|
|
311
327
|
* Used for permission validation before bulk operations.
|
|
312
328
|
*/
|
|
313
329
|
async function getEscalationRoles(ids) {
|
|
330
|
+
ids = (0, uuid_1.onlyUuids)(ids);
|
|
314
331
|
if (ids.length === 0)
|
|
315
332
|
return [];
|
|
316
333
|
const client = await (0, client_1.escalations)();
|
|
@@ -323,6 +340,7 @@ async function getEscalationRoles(ids) {
|
|
|
323
340
|
* write_self by ownership (assigned_to = caller). One query, no N+1.
|
|
324
341
|
*/
|
|
325
342
|
async function getEscalationScopeRows(ids) {
|
|
343
|
+
ids = (0, uuid_1.onlyUuids)(ids);
|
|
326
344
|
if (ids.length === 0)
|
|
327
345
|
return [];
|
|
328
346
|
const client = await (0, client_1.escalations)();
|
|
@@ -344,6 +362,8 @@ async function getEscalationScopeRows(ids) {
|
|
|
344
362
|
* stays loud.
|
|
345
363
|
*/
|
|
346
364
|
async function releaseEscalation(id, userId, opts) {
|
|
365
|
+
if (!(0, uuid_1.isUuid)(id))
|
|
366
|
+
return null;
|
|
347
367
|
const client = await (0, client_1.escalations)();
|
|
348
368
|
const result = await client.release({ id, assignee: userId });
|
|
349
369
|
if (!result.ok)
|
|
@@ -381,6 +401,8 @@ async function releaseExpiredClaims() {
|
|
|
381
401
|
* Clears the current assignment so it becomes available to the new role.
|
|
382
402
|
*/
|
|
383
403
|
async function escalateToRole(id, targetRole) {
|
|
404
|
+
if (!(0, uuid_1.isUuid)(id))
|
|
405
|
+
return null;
|
|
384
406
|
const client = await (0, client_1.escalations)();
|
|
385
407
|
// The departing role is read before the move: the returned entry already
|
|
386
408
|
// carries the target role, and role-scoped subscribers of the OLD queue
|
|
@@ -414,6 +436,8 @@ async function escalateToRole(id, targetRole) {
|
|
|
414
436
|
return escalation;
|
|
415
437
|
}
|
|
416
438
|
async function getEscalation(id) {
|
|
439
|
+
if (!(0, uuid_1.isUuid)(id))
|
|
440
|
+
return null;
|
|
417
441
|
const client = await (0, client_1.escalations)();
|
|
418
442
|
const entry = await client.get(id);
|
|
419
443
|
return entry ? (0, map_1.toEscalationRecord)(entry) : null;
|
|
@@ -474,6 +498,8 @@ async function cancelEscalationsByWorkflowId(workflowId) {
|
|
|
474
498
|
return rows.length;
|
|
475
499
|
}
|
|
476
500
|
async function enrichEscalationRouting(id, metadataPatch, workflowFields) {
|
|
501
|
+
if (!(0, uuid_1.isUuid)(id))
|
|
502
|
+
return null;
|
|
477
503
|
const client = await (0, client_1.escalations)();
|
|
478
504
|
const entry = await client.update({
|
|
479
505
|
id,
|
|
@@ -54,6 +54,19 @@ export declare function listFacetKeys(opts: {
|
|
|
54
54
|
selfRoles?: string[];
|
|
55
55
|
meUserId?: string;
|
|
56
56
|
}): Promise<string[]>;
|
|
57
|
+
/**
|
|
58
|
+
* Distinct VALUES for one metadata facet key, visible to the caller — feeds
|
|
59
|
+
* the value picker (e.g. facility → [north, south]) so a bound scope offers
|
|
60
|
+
* real choices. Role-scoped with the same predicate as {@link listFacetKeys};
|
|
61
|
+
* the key is parameterized (never interpolated) and charset-validated, so a
|
|
62
|
+
* malformed key returns [] rather than reaching an unguarded path.
|
|
63
|
+
*/
|
|
64
|
+
export declare function listFacetValues(key: string, opts: {
|
|
65
|
+
global?: boolean;
|
|
66
|
+
visibleRoles?: string[];
|
|
67
|
+
selfRoles?: string[];
|
|
68
|
+
meUserId?: string;
|
|
69
|
+
}): Promise<string[]>;
|
|
57
70
|
export declare function getEscalationStats(visibleRoles?: string[], period?: string): Promise<EscalationStats>;
|
|
58
71
|
export declare function listDistinctTypes(): Promise<string[]>;
|
|
59
72
|
export declare function listEscalations(filters: {
|
|
@@ -108,4 +121,4 @@ export declare function listAvailableEscalations(filters: {
|
|
|
108
121
|
export declare function invalidateEscalationAggregates(): void;
|
|
109
122
|
/** Test hook: drop cached period metrics AND escalation stats so tests observe fresh rows. */
|
|
110
123
|
export declare function resetStationMetricsCache(): void;
|
|
111
|
-
export declare function getStationMetrics(visibleRoles: string[] | undefined, period?: string): Promise<StationMetric[]>;
|
|
124
|
+
export declare function getStationMetrics(visibleRoles: string[] | undefined, period?: string, facets?: Record<string, unknown>): Promise<StationMetric[]>;
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.searchEscalationsFaceted = searchEscalationsFaceted;
|
|
4
4
|
exports.getEscalationWithFormSchema = getEscalationWithFormSchema;
|
|
5
5
|
exports.listFacetKeys = listFacetKeys;
|
|
6
|
+
exports.listFacetValues = listFacetValues;
|
|
6
7
|
exports.getEscalationStats = getEscalationStats;
|
|
7
8
|
exports.listDistinctTypes = listDistinctTypes;
|
|
8
9
|
exports.listEscalations = listEscalations;
|
|
@@ -42,13 +43,13 @@ function buildSearchOrderBy(sortBy, order) {
|
|
|
42
43
|
}
|
|
43
44
|
return 'priority ASC, created_at ASC';
|
|
44
45
|
}
|
|
45
|
-
const
|
|
46
|
+
const uuid_1 = require("../../lib/uuid");
|
|
46
47
|
/**
|
|
47
48
|
* The id arm of the correlation search binds a uuid param only when the term
|
|
48
49
|
* parses as one — comparing `id::text = $term` casts the uuid column and has
|
|
49
50
|
* no index path, which drags the whole OR into a full history scan.
|
|
50
51
|
*/
|
|
51
|
-
const asUuidOrNull = (term) => term && UUID_RE.test(term) ? term : null;
|
|
52
|
+
const asUuidOrNull = (term) => term && uuid_1.UUID_RE.test(term) ? term : null;
|
|
52
53
|
/**
|
|
53
54
|
* Server-side free-text search over the `lt_escalations` view. Runs when a
|
|
54
55
|
* caller supplies a non-empty `search` term — the SDK `client.list()` cannot do
|
|
@@ -155,6 +156,9 @@ async function searchEscalationsFaceted(opts) {
|
|
|
155
156
|
* cast is guarded, so a non-numeric pin simply falls through to the latest form.
|
|
156
157
|
*/
|
|
157
158
|
async function getEscalationWithFormSchema(id) {
|
|
159
|
+
// A non-UUID is definitionally not-found — it must never reach the uuid cast.
|
|
160
|
+
if (!(0, uuid_1.isUuid)(id))
|
|
161
|
+
return null;
|
|
158
162
|
await (0, client_1.ensureEscalationCompatView)();
|
|
159
163
|
const pool = (0, db_1.getPool)();
|
|
160
164
|
const { rows } = await pool.query(`SELECT e.*, COALESCE(ps.form_schema, r.form_schema) AS resolved_form_schema
|
|
@@ -216,6 +220,39 @@ async function listFacetKeys(opts) {
|
|
|
216
220
|
}
|
|
217
221
|
return [...actualKeys].sort();
|
|
218
222
|
}
|
|
223
|
+
// Mirrors the server-side facet key rule — metadata keys become a JSON path,
|
|
224
|
+
// so a lookup key is strictly validated before it reaches SQL.
|
|
225
|
+
const FACET_KEY_RE = /^[a-zA-Z0-9_]+$/;
|
|
226
|
+
/**
|
|
227
|
+
* Distinct VALUES for one metadata facet key, visible to the caller — feeds
|
|
228
|
+
* the value picker (e.g. facility → [north, south]) so a bound scope offers
|
|
229
|
+
* real choices. Role-scoped with the same predicate as {@link listFacetKeys};
|
|
230
|
+
* the key is parameterized (never interpolated) and charset-validated, so a
|
|
231
|
+
* malformed key returns [] rather than reaching an unguarded path.
|
|
232
|
+
*/
|
|
233
|
+
async function listFacetValues(key, opts) {
|
|
234
|
+
if (!FACET_KEY_RE.test(key))
|
|
235
|
+
return [];
|
|
236
|
+
await (0, client_1.ensureEscalationCompatView)();
|
|
237
|
+
const pool = (0, db_1.getPool)();
|
|
238
|
+
const params = [key];
|
|
239
|
+
const clauses = ["jsonb_typeof(metadata) = 'object'", 'metadata ? $1'];
|
|
240
|
+
if (!opts.global) {
|
|
241
|
+
const ai = params.push(opts.visibleRoles?.length ? opts.visibleRoles : null);
|
|
242
|
+
const si = params.push(opts.selfRoles?.length ? opts.selfRoles : null);
|
|
243
|
+
const mi = params.push(opts.meUserId || null);
|
|
244
|
+
clauses.push(`(($${ai}::text[] IS NULL AND $${si}::text[] IS NULL)
|
|
245
|
+
OR ($${ai}::text[] IS NOT NULL AND role = ANY($${ai}))
|
|
246
|
+
OR ($${si}::text[] IS NOT NULL AND role = ANY($${si}) AND assigned_to = $${mi}))`);
|
|
247
|
+
}
|
|
248
|
+
const { rows } = await pool.query(`SELECT DISTINCT metadata->>$1 AS value
|
|
249
|
+
FROM public.lt_escalations
|
|
250
|
+
WHERE ${clauses.join('\n AND ')}
|
|
251
|
+
AND metadata->>$1 IS NOT NULL
|
|
252
|
+
ORDER BY value
|
|
253
|
+
LIMIT 200`, params);
|
|
254
|
+
return rows.map((r) => r.value);
|
|
255
|
+
}
|
|
219
256
|
// Escalation stats back the home + overview surfaces and refresh on every
|
|
220
257
|
// escalation event. As of hotmesh 0.25.0 the SDK stats query reads three
|
|
221
258
|
// bounded, index-only sources (pending backlog, created window, resolved
|
|
@@ -388,7 +425,7 @@ function resetStationMetricsCache() {
|
|
|
388
425
|
invalidateEscalationAggregates();
|
|
389
426
|
}
|
|
390
427
|
const toNum = (v) => (v != null ? Number(v) : null);
|
|
391
|
-
async function getStationMetrics(visibleRoles, period) {
|
|
428
|
+
async function getStationMetrics(visibleRoles, period, facets) {
|
|
392
429
|
await (0, client_1.ensureEscalationCompatView)();
|
|
393
430
|
// hasOwnProperty: a caller-supplied period like 'constructor' must fall back
|
|
394
431
|
// to 24h, not resolve to an inherited Object.prototype member.
|
|
@@ -396,13 +433,18 @@ async function getStationMetrics(visibleRoles, period) {
|
|
|
396
433
|
? types_1.VALID_PERIODS[period]
|
|
397
434
|
: '24 hours';
|
|
398
435
|
const roles = visibleRoles ?? null;
|
|
436
|
+
// Facet scope rides both queries as a GIN-served `metadata @>` arm; null = no
|
|
437
|
+
// filter. It never widens role scope — it only narrows within it.
|
|
438
|
+
const facetJson = facets && Object.keys(facets).length ? JSON.stringify(facets) : null;
|
|
399
439
|
const pool = (0, db_1.getPool)();
|
|
400
440
|
// Live counts: always fresh (cheap — bounded pending working set).
|
|
401
|
-
// Period metrics: cached ~30s, single-flight (expensive percentile sort).
|
|
402
|
-
|
|
441
|
+
// Period metrics: cached ~30s, single-flight (expensive percentile sort). The
|
|
442
|
+
// facet scope is part of the cache key — a scoped board never reads unscoped
|
|
443
|
+
// rows, and vice versa.
|
|
444
|
+
const cacheKey = `${period ?? '24h'}::${roles ? [...roles].sort().join(',') : 'ALL'}::${facetJson ?? ''}`;
|
|
403
445
|
const [countsResult, periodRows] = await Promise.all([
|
|
404
|
-
pool.query(sql_1.STATION_LIVE_COUNTS_SQL, [roles]),
|
|
405
|
-
stationPeriodCache.resolve(cacheKey, async () => (await pool.query(sql_1.STATION_PERIOD_METRICS_SQL, [roles, intervalStr])).rows),
|
|
446
|
+
pool.query(sql_1.STATION_LIVE_COUNTS_SQL, [roles, facetJson]),
|
|
447
|
+
stationPeriodCache.resolve(cacheKey, async () => (await pool.query(sql_1.STATION_PERIOD_METRICS_SQL, [roles, intervalStr, facetJson])).rows),
|
|
406
448
|
]);
|
|
407
449
|
const periodByRole = new Map(periodRows.map((r) => [r.role, r]));
|
|
408
450
|
return countsResult.rows.map((c) => {
|
|
@@ -80,6 +80,7 @@ export declare const RESOLVE_BY_METADATA_ATOMIC = "WITH target AS MATERIALIZED (
|
|
|
80
80
|
* Live counts — pending, active claims, and priority (past-threshold) per role.
|
|
81
81
|
*
|
|
82
82
|
* $1 TEXT[] — role filter (NULL = all roles / superadmin).
|
|
83
|
+
* $2 JSONB — metadata facet scope (NULL = no filter; `metadata @>`, GIN-served).
|
|
83
84
|
*
|
|
84
85
|
* Hits idx_hmsh_esc_pending_role_created (role, created_at DESC) WHERE
|
|
85
86
|
* status='pending'. The pending working set is bounded by real backlog depth,
|
|
@@ -102,13 +103,14 @@ export declare const RESOLVE_BY_METADATA_ATOMIC = "WITH target AS MATERIALIZED (
|
|
|
102
103
|
* with a facet configured, items missing the key or holding an unparseable
|
|
103
104
|
* value do not count (NULL age never passes the comparison).
|
|
104
105
|
*/
|
|
105
|
-
export declare const STATION_LIVE_COUNTS_SQL = "\nWITH role_targets AS (\n SELECT role, sla_minutes, priority_threshold_minutes, priority_facet\n FROM lt_roles\n WHERE ($1::text[] IS NULL OR role = ANY($1::text[]))\n),\nlive_counts AS (\n SELECT\n e.role,\n COUNT(*) AS pending,\n COUNT(*) FILTER (WHERE e.assigned_to IS NOT NULL AND e.assigned_until > NOW()) AS claimed,\n COUNT(*) FILTER (\n WHERE COALESCE(rt.priority_threshold_minutes, rt.sla_minutes) IS NOT NULL\n AND (e.assigned_to IS NULL OR e.assigned_until IS NULL OR e.assigned_until <= NOW())\n AND CASE\n WHEN rt.priority_facet IS NULL THEN e.created_at\n WHEN pg_input_is_valid(e.metadata->>rt.priority_facet, 'timestamptz')\n THEN (e.metadata->>rt.priority_facet)::timestamptz\n ELSE NULL\n END < NOW() - (COALESCE(rt.priority_threshold_minutes, rt.sla_minutes) * INTERVAL '1 minute')\n ) AS priority_count\n FROM hmsh_escalations e\n JOIN role_targets rt ON rt.role = e.role\n WHERE e.status = 'pending'\n GROUP BY e.role\n)\nSELECT\n rt.role,\n COALESCE(lc.pending, 0) AS pending,\n COALESCE(lc.claimed, 0) AS claimed,\n COALESCE(lc.priority_count, 0) AS priority_count\nFROM role_targets rt\nLEFT JOIN live_counts lc ON lc.role = rt.role\nORDER BY rt.role\n";
|
|
106
|
+
export declare const STATION_LIVE_COUNTS_SQL = "\nWITH role_targets AS (\n SELECT role, sla_minutes, priority_threshold_minutes, priority_facet\n FROM lt_roles\n WHERE ($1::text[] IS NULL OR role = ANY($1::text[]))\n),\nlive_counts AS (\n SELECT\n e.role,\n COUNT(*) AS pending,\n COUNT(*) FILTER (WHERE e.assigned_to IS NOT NULL AND e.assigned_until > NOW()) AS claimed,\n COUNT(*) FILTER (\n WHERE COALESCE(rt.priority_threshold_minutes, rt.sla_minutes) IS NOT NULL\n AND (e.assigned_to IS NULL OR e.assigned_until IS NULL OR e.assigned_until <= NOW())\n AND CASE\n WHEN rt.priority_facet IS NULL THEN e.created_at\n WHEN pg_input_is_valid(e.metadata->>rt.priority_facet, 'timestamptz')\n THEN (e.metadata->>rt.priority_facet)::timestamptz\n ELSE NULL\n END < NOW() - (COALESCE(rt.priority_threshold_minutes, rt.sla_minutes) * INTERVAL '1 minute')\n ) AS priority_count\n FROM hmsh_escalations e\n JOIN role_targets rt ON rt.role = e.role\n WHERE e.status = 'pending'\n AND ($2::jsonb IS NULL OR e.metadata @> $2::jsonb)\n GROUP BY e.role\n)\nSELECT\n rt.role,\n COALESCE(lc.pending, 0) AS pending,\n COALESCE(lc.claimed, 0) AS claimed,\n COALESCE(lc.priority_count, 0) AS priority_count\nFROM role_targets rt\nLEFT JOIN live_counts lc ON lc.role = rt.role\nORDER BY rt.role\n";
|
|
106
107
|
/**
|
|
107
108
|
* Period metrics — resolved count, throughput efficiency, and P99/P50/avg/max
|
|
108
109
|
* latency for wait (queue time) and work (processing) per role.
|
|
109
110
|
*
|
|
110
111
|
* $1 TEXT[] — role filter (NULL = all roles / superadmin).
|
|
111
112
|
* $2 INTERVAL — time window (e.g. '24 hours', '15 minutes').
|
|
113
|
+
* $3 JSONB — metadata facet scope (NULL = no filter; `metadata @>`, GIN-served).
|
|
112
114
|
*
|
|
113
115
|
* Hits idx_hmsh_esc_resolved_cover (role, resolved_at DESC, claimed_at,
|
|
114
116
|
* created_at) WHERE status='resolved' — a covering index, so the percentile
|
|
@@ -119,4 +121,4 @@ export declare const STATION_LIVE_COUNTS_SQL = "\nWITH role_targets AS (\n SELE
|
|
|
119
121
|
* mix of resolved + in-flight — a clean "how did completed work perform?" read.
|
|
120
122
|
* throughput_pct is NULL when the role has no target_per_hour (NULLIF guard).
|
|
121
123
|
*/
|
|
122
|
-
export declare const STATION_PERIOD_METRICS_SQL = "\nWITH role_targets AS (\n SELECT role, target_per_hour\n FROM lt_roles\n WHERE ($1::text[] IS NULL OR role = ANY($1::text[]))\n),\nperiod_metrics AS (\n SELECT\n e.role,\n COUNT(*) AS resolved,\n ROUND((PERCENTILE_CONT(0.99) WITHIN GROUP (\n ORDER BY EXTRACT(EPOCH FROM (e.claimed_at - e.created_at)) / 60)\n FILTER (WHERE e.claimed_at IS NOT NULL))::numeric, 3) AS p99_wait_min,\n ROUND((PERCENTILE_CONT(0.50) WITHIN GROUP (\n ORDER BY EXTRACT(EPOCH FROM (e.claimed_at - e.created_at)) / 60)\n FILTER (WHERE e.claimed_at IS NOT NULL))::numeric, 3) AS p50_wait_min,\n ROUND((AVG(EXTRACT(EPOCH FROM (e.claimed_at - e.created_at)) / 60)\n FILTER (WHERE e.claimed_at IS NOT NULL))::numeric, 3) AS avg_wait_min,\n ROUND((MAX(EXTRACT(EPOCH FROM (e.claimed_at - e.created_at)) / 60)\n FILTER (WHERE e.claimed_at IS NOT NULL))::numeric, 3) AS max_wait_min,\n ROUND((PERCENTILE_CONT(0.99) WITHIN GROUP (\n ORDER BY EXTRACT(EPOCH FROM (e.resolved_at - e.claimed_at)) / 60)\n FILTER (WHERE e.claimed_at IS NOT NULL))::numeric, 3) AS p99_work_min,\n ROUND((PERCENTILE_CONT(0.50) WITHIN GROUP (\n ORDER BY EXTRACT(EPOCH FROM (e.resolved_at - e.claimed_at)) / 60)\n FILTER (WHERE e.claimed_at IS NOT NULL))::numeric, 3) AS p50_work_min,\n ROUND((AVG(EXTRACT(EPOCH FROM (e.resolved_at - e.claimed_at)) / 60)\n FILTER (WHERE e.claimed_at IS NOT NULL))::numeric, 3) AS avg_work_min,\n ROUND((MAX(EXTRACT(EPOCH FROM (e.resolved_at - e.claimed_at)) / 60)\n FILTER (WHERE e.claimed_at IS NOT NULL))::numeric, 3) AS max_work_min\n FROM hmsh_escalations e\n WHERE e.status = 'resolved'\n AND e.resolved_at >= NOW() - $2::interval\n AND ($1::text[] IS NULL OR e.role = ANY($1::text[]))\n GROUP BY e.role\n)\nSELECT\n rt.role,\n COALESCE(pm.resolved, 0) AS resolved,\n ROUND(\n (COALESCE(pm.resolved, 0)::numeric\n / NULLIF(rt.target_per_hour::numeric * EXTRACT(EPOCH FROM $2::interval) / 3600.0, 0)\n * 100\n )::numeric, 1\n ) AS throughput_pct,\n pm.p99_wait_min,\n pm.p50_wait_min,\n pm.avg_wait_min,\n pm.max_wait_min,\n pm.p99_work_min,\n pm.p50_work_min,\n pm.avg_work_min,\n pm.max_work_min\nFROM role_targets rt\nLEFT JOIN period_metrics pm ON pm.role = rt.role\nORDER BY rt.role\n";
|
|
124
|
+
export declare const STATION_PERIOD_METRICS_SQL = "\nWITH role_targets AS (\n SELECT role, target_per_hour\n FROM lt_roles\n WHERE ($1::text[] IS NULL OR role = ANY($1::text[]))\n),\nperiod_metrics AS (\n SELECT\n e.role,\n COUNT(*) AS resolved,\n ROUND((PERCENTILE_CONT(0.99) WITHIN GROUP (\n ORDER BY EXTRACT(EPOCH FROM (e.claimed_at - e.created_at)) / 60)\n FILTER (WHERE e.claimed_at IS NOT NULL))::numeric, 3) AS p99_wait_min,\n ROUND((PERCENTILE_CONT(0.50) WITHIN GROUP (\n ORDER BY EXTRACT(EPOCH FROM (e.claimed_at - e.created_at)) / 60)\n FILTER (WHERE e.claimed_at IS NOT NULL))::numeric, 3) AS p50_wait_min,\n ROUND((AVG(EXTRACT(EPOCH FROM (e.claimed_at - e.created_at)) / 60)\n FILTER (WHERE e.claimed_at IS NOT NULL))::numeric, 3) AS avg_wait_min,\n ROUND((MAX(EXTRACT(EPOCH FROM (e.claimed_at - e.created_at)) / 60)\n FILTER (WHERE e.claimed_at IS NOT NULL))::numeric, 3) AS max_wait_min,\n ROUND((PERCENTILE_CONT(0.99) WITHIN GROUP (\n ORDER BY EXTRACT(EPOCH FROM (e.resolved_at - e.claimed_at)) / 60)\n FILTER (WHERE e.claimed_at IS NOT NULL))::numeric, 3) AS p99_work_min,\n ROUND((PERCENTILE_CONT(0.50) WITHIN GROUP (\n ORDER BY EXTRACT(EPOCH FROM (e.resolved_at - e.claimed_at)) / 60)\n FILTER (WHERE e.claimed_at IS NOT NULL))::numeric, 3) AS p50_work_min,\n ROUND((AVG(EXTRACT(EPOCH FROM (e.resolved_at - e.claimed_at)) / 60)\n FILTER (WHERE e.claimed_at IS NOT NULL))::numeric, 3) AS avg_work_min,\n ROUND((MAX(EXTRACT(EPOCH FROM (e.resolved_at - e.claimed_at)) / 60)\n FILTER (WHERE e.claimed_at IS NOT NULL))::numeric, 3) AS max_work_min\n FROM hmsh_escalations e\n WHERE e.status = 'resolved'\n AND e.resolved_at >= NOW() - $2::interval\n AND ($1::text[] IS NULL OR e.role = ANY($1::text[]))\n AND ($3::jsonb IS NULL OR e.metadata @> $3::jsonb)\n GROUP BY e.role\n)\nSELECT\n rt.role,\n COALESCE(pm.resolved, 0) AS resolved,\n ROUND(\n (COALESCE(pm.resolved, 0)::numeric\n / NULLIF(rt.target_per_hour::numeric * EXTRACT(EPOCH FROM $2::interval) / 3600.0, 0)\n * 100\n )::numeric, 1\n ) AS throughput_pct,\n pm.p99_wait_min,\n pm.p50_wait_min,\n pm.avg_wait_min,\n pm.max_wait_min,\n pm.p99_work_min,\n pm.p50_work_min,\n pm.avg_work_min,\n pm.max_work_min\nFROM role_targets rt\nLEFT JOIN period_metrics pm ON pm.role = rt.role\nORDER BY rt.role\n";
|
|
@@ -270,6 +270,7 @@ LEFT JOIN written ON written.id = target.id`;
|
|
|
270
270
|
* Live counts — pending, active claims, and priority (past-threshold) per role.
|
|
271
271
|
*
|
|
272
272
|
* $1 TEXT[] — role filter (NULL = all roles / superadmin).
|
|
273
|
+
* $2 JSONB — metadata facet scope (NULL = no filter; `metadata @>`, GIN-served).
|
|
273
274
|
*
|
|
274
275
|
* Hits idx_hmsh_esc_pending_role_created (role, created_at DESC) WHERE
|
|
275
276
|
* status='pending'. The pending working set is bounded by real backlog depth,
|
|
@@ -316,6 +317,7 @@ live_counts AS (
|
|
|
316
317
|
FROM hmsh_escalations e
|
|
317
318
|
JOIN role_targets rt ON rt.role = e.role
|
|
318
319
|
WHERE e.status = 'pending'
|
|
320
|
+
AND ($2::jsonb IS NULL OR e.metadata @> $2::jsonb)
|
|
319
321
|
GROUP BY e.role
|
|
320
322
|
)
|
|
321
323
|
SELECT
|
|
@@ -333,6 +335,7 @@ ORDER BY rt.role
|
|
|
333
335
|
*
|
|
334
336
|
* $1 TEXT[] — role filter (NULL = all roles / superadmin).
|
|
335
337
|
* $2 INTERVAL — time window (e.g. '24 hours', '15 minutes').
|
|
338
|
+
* $3 JSONB — metadata facet scope (NULL = no filter; `metadata @>`, GIN-served).
|
|
336
339
|
*
|
|
337
340
|
* Hits idx_hmsh_esc_resolved_cover (role, resolved_at DESC, claimed_at,
|
|
338
341
|
* created_at) WHERE status='resolved' — a covering index, so the percentile
|
|
@@ -377,6 +380,7 @@ period_metrics AS (
|
|
|
377
380
|
WHERE e.status = 'resolved'
|
|
378
381
|
AND e.resolved_at >= NOW() - $2::interval
|
|
379
382
|
AND ($1::text[] IS NULL OR e.role = ANY($1::text[]))
|
|
383
|
+
AND ($3::jsonb IS NULL OR e.metadata @> $3::jsonb)
|
|
380
384
|
GROUP BY e.role
|
|
381
385
|
)
|
|
382
386
|
SELECT
|
|
@@ -47,6 +47,11 @@ const context_2 = require("../iam/context");
|
|
|
47
47
|
const publish_1 = require("../../lib/events/publish");
|
|
48
48
|
const envelope_1 = require("../iam/envelope");
|
|
49
49
|
const DEFAULT_ACTIVITY_QUEUE = 'lt-interceptor';
|
|
50
|
+
/** The result payload a completed event carries: the workflow's `data` when it returned the envelope shape. */
|
|
51
|
+
function resultData(result) {
|
|
52
|
+
const data = result?.data;
|
|
53
|
+
return data && typeof data === 'object' && !Array.isArray(data) ? data : undefined;
|
|
54
|
+
}
|
|
50
55
|
/**
|
|
51
56
|
* Register the Long Tail interceptors in a single call.
|
|
52
57
|
*
|
|
@@ -120,6 +125,7 @@ function createLTInterceptor(options) {
|
|
|
120
125
|
workflowName: wf.workflowName,
|
|
121
126
|
taskQueue: taskQueue0,
|
|
122
127
|
status: 'completed',
|
|
128
|
+
data: resultData(result0),
|
|
123
129
|
});
|
|
124
130
|
return result0;
|
|
125
131
|
}
|
|
@@ -138,6 +144,7 @@ function createLTInterceptor(options) {
|
|
|
138
144
|
workflowName: wf.workflowName,
|
|
139
145
|
taskQueue: taskQueue2,
|
|
140
146
|
status: 'completed',
|
|
147
|
+
data: resultData(result2),
|
|
141
148
|
});
|
|
142
149
|
return result2;
|
|
143
150
|
}
|