@hotmeshio/long-tail 0.31.1 → 0.32.0
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/create.js +17 -6
- package/build/api/escalations/files.d.ts +18 -0
- package/build/api/escalations/files.js +73 -0
- package/build/api/escalations/index.d.ts +1 -0
- package/build/api/escalations/index.js +4 -2
- package/build/api/escalations/metadata.js +5 -4
- package/build/api/escalations/resolve.js +6 -4
- package/build/bin/ltc.js +4 -2
- package/build/index.d.ts +2 -0
- package/build/index.js +13 -2
- package/build/lib/cli/commands/escalations.d.ts +2 -0
- package/build/lib/cli/commands/escalations.js +12 -4
- package/build/lib/storage/s3.js +1 -0
- package/build/modules/config.d.ts +9 -0
- package/build/modules/config.js +9 -0
- package/build/routes/escalations/single.js +11 -0
- package/build/sdk/index.d.ts +4 -0
- package/build/sdk/index.js +2 -0
- package/build/services/escalation/aggregate-resolved-sql.d.ts +19 -0
- package/build/services/escalation/aggregate-resolved-sql.js +57 -0
- package/build/services/escalation/aggregate-sql.d.ts +6 -1
- package/build/services/escalation/aggregate-sql.js +33 -12
- package/build/services/escalation/aggregate-validate.d.ts +5 -2
- package/build/services/escalation/aggregate-validate.js +7 -4
- package/build/services/escalation/aggregates.js +5 -3
- package/build/services/escalation/crud.js +3 -0
- package/build/services/escalation/file-links.d.ts +39 -0
- package/build/services/escalation/file-links.js +118 -0
- package/build/services/escalation/resolver-validation.d.ts +33 -0
- package/build/services/escalation/resolver-validation.js +22 -6
- package/build/services/orchestrator/condition.d.ts +20 -4
- package/build/services/orchestrator/condition.js +27 -8
- package/build/shared/form-validation/display-only-widgets.d.ts +3 -2
- package/build/shared/form-validation/display-only-widgets.js +3 -2
- package/build/shared/form-validation/index.d.ts +2 -0
- package/build/shared/form-validation/index.js +2 -0
- package/build/shared/form-validation/x-lt-confidence-facets.d.ts +27 -0
- package/build/shared/form-validation/x-lt-confidence-facets.js +60 -0
- package/build/shared/form-validation/x-lt-confidence.d.ts +57 -0
- package/build/shared/form-validation/x-lt-confidence.js +177 -0
- package/build/shared/form-validation/x-lt-help.d.ts +1 -1
- package/build/shared/form-validation/x-lt-help.js +1 -1
- package/build/system/mcp-servers/admin/escalations.js +4 -2
- package/build/system/mcp-servers/admin/labels-schemas.d.ts +4 -4
- package/build/system/mcp-servers/admin/schemas.d.ts +111 -70
- package/build/system/mcp-servers/admin/schemas.js +8 -3
- package/build/system/mcp-servers/human-queue-files.d.ts +8 -0
- package/build/system/mcp-servers/human-queue-files.js +32 -0
- package/build/system/mcp-servers/human-queue-schemas.d.ts +7 -0
- package/build/system/mcp-servers/human-queue-schemas.js +4 -1
- package/build/system/mcp-servers/human-queue.d.ts +1 -0
- package/build/system/mcp-servers/human-queue.js +23 -16
- package/build/system/seed/tool-manifests-admin.js +1 -1
- package/build/system/seed/tool-manifests-escalation.js +13 -0
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/analytics.d.ts +14 -3
- package/build/types/analytics.js +3 -1
- package/build/types/escalation.d.ts +34 -0
- package/build/types/escalation.js +72 -1
- package/build/types/index.d.ts +4 -4
- package/build/types/index.js +5 -1
- package/dashboard/dist/assets/{AdminDashboard-BafKaq50.js → AdminDashboard-C25co77C.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-BafKaq50.js.map → AdminDashboard-C25co77C.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-CFHf31DT.js → AgentConfigPage-CsCpI15j.js} +5 -5
- package/dashboard/dist/assets/{AgentConfigPage-CFHf31DT.js.map → AgentConfigPage-CsCpI15j.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-CEvz5rJr.js → AgentDetailPage-ByaepsB5.js} +3 -3
- package/dashboard/dist/assets/{AgentDetailPage-CEvz5rJr.js.map → AgentDetailPage-ByaepsB5.js.map} +1 -1
- package/dashboard/dist/assets/{AgentsPage-DjQaio0O.js → AgentsPage-ByHU42SO.js} +2 -2
- package/dashboard/dist/assets/{AgentsPage-DjQaio0O.js.map → AgentsPage-ByHU42SO.js.map} +1 -1
- package/dashboard/dist/assets/{AvailableEscalationsPage-UB03VTJx.js → AvailableEscalationsPage--o6qcz7-.js} +2 -2
- package/dashboard/dist/assets/{AvailableEscalationsPage-UB03VTJx.js.map → AvailableEscalationsPage--o6qcz7-.js.map} +1 -1
- package/dashboard/dist/assets/{BotPicker-C7MNWOF7.js → BotPicker-B3y3H3fs.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-C7MNWOF7.js.map → BotPicker-B3y3H3fs.js.map} +1 -1
- package/dashboard/dist/assets/{BulkAssignModal-h5fX-_cV.js → BulkAssignModal-DMNIkIn6.js} +2 -2
- package/dashboard/dist/assets/{BulkAssignModal-h5fX-_cV.js.map → BulkAssignModal-DMNIkIn6.js.map} +1 -1
- package/dashboard/dist/assets/{CapabilitiesPage-BIzDl-ZT.js → CapabilitiesPage-BekfKHlk.js} +2 -2
- package/dashboard/dist/assets/{CapabilitiesPage-BIzDl-ZT.js.map → CapabilitiesPage-BekfKHlk.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-B5TivtEg.js → CollapsibleSection-BAteHgBG.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-B5TivtEg.js.map → CollapsibleSection-BAteHgBG.js.map} +1 -1
- package/dashboard/dist/assets/{ConfirmDeleteModal-CB4nKePb.js → ConfirmDeleteModal-BNY287W9.js} +2 -2
- package/dashboard/dist/assets/{ConfirmDeleteModal-CB4nKePb.js.map → ConfirmDeleteModal-BNY287W9.js.map} +1 -1
- package/dashboard/dist/assets/{ConnectedAppsPage-B3S5gVWw.js → ConnectedAppsPage-LLiiH3da.js} +2 -2
- package/dashboard/dist/assets/{ConnectedAppsPage-B3S5gVWw.js.map → ConnectedAppsPage-LLiiH3da.js.map} +1 -1
- package/dashboard/dist/assets/{CountdownTimer-BHVIq3kA.js → CountdownTimer-DBLURjxh.js} +2 -2
- package/dashboard/dist/assets/{CountdownTimer-BHVIq3kA.js.map → CountdownTimer-DBLURjxh.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialConfirmModal-w0AGmCIe.js → CredentialConfirmModal-BqpY3yen.js} +2 -2
- package/dashboard/dist/assets/{CredentialConfirmModal-w0AGmCIe.js.map → CredentialConfirmModal-BqpY3yen.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialsPage-BtCGBJrT.js → CredentialsPage-CW3_dbm2.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-BtCGBJrT.js.map → CredentialsPage-CW3_dbm2.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-BG1rZK-5.js → CronLabel-CR6DiZZr.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-BG1rZK-5.js.map → CronLabel-CR6DiZZr.js.map} +1 -1
- package/dashboard/dist/assets/{DataTable-FjFhx0SE.js → DataTable-C-IlbLhY.js} +2 -2
- package/dashboard/dist/assets/{DataTable-FjFhx0SE.js.map → DataTable-C-IlbLhY.js.map} +1 -1
- package/dashboard/dist/assets/{DropZone-D8ZVdEb5.js → DropZone-CHmz59w4.js} +2 -2
- package/dashboard/dist/assets/{DropZone-D8ZVdEb5.js.map → DropZone-CHmz59w4.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-l4m8Yvfv.js → ElapsedCell-CEapQvgU.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-l4m8Yvfv.js.map → ElapsedCell-CEapQvgU.js.map} +1 -1
- package/dashboard/dist/assets/{EntityTimelinePanel-BOHlIaxF.js → EntityTimelinePanel-DqD_BpJM.js} +2 -2
- package/dashboard/dist/assets/{EntityTimelinePanel-BOHlIaxF.js.map → EntityTimelinePanel-DqD_BpJM.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationListSchemaPage-BotlwlX3.js → EscalationListSchemaPage-DDKcrVbb.js} +3 -3
- package/dashboard/dist/assets/{EscalationListSchemaPage-BotlwlX3.js.map → EscalationListSchemaPage-DDKcrVbb.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationSchemaPage-CfZSVOSD.js → EscalationSchemaPage-BZHZfJiQ.js} +3 -3
- package/dashboard/dist/assets/{EscalationSchemaPage-CfZSVOSD.js.map → EscalationSchemaPage-BZHZfJiQ.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationTimeline-CCKpuRBU.js → EscalationTimeline-Dv0XUgQX.js} +2 -2
- package/dashboard/dist/assets/{EscalationTimeline-CCKpuRBU.js.map → EscalationTimeline-Dv0XUgQX.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationTitleSelect-cpTzPHiW.js → EscalationTitleSelect-BN7D52wT.js} +2 -2
- package/dashboard/dist/assets/{EscalationTitleSelect-cpTzPHiW.js.map → EscalationTitleSelect-BN7D52wT.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-DS-nK0qV.js → EscalationsOverview-DE6EPkhT.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-DS-nK0qV.js.map → EscalationsOverview-DE6EPkhT.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-UfebhJf0.js → EventTable-CiV62txY.js} +2 -2
- package/dashboard/dist/assets/{EventTable-UfebhJf0.js.map → EventTable-CiV62txY.js.map} +1 -1
- package/dashboard/dist/assets/{FilterBar-newA5l-X.js → FilterBar-WyNQPyQ1.js} +2 -2
- package/dashboard/dist/assets/{FilterBar-newA5l-X.js.map → FilterBar-WyNQPyQ1.js.map} +1 -1
- package/dashboard/dist/assets/{GraphInvokePage-6SCDyQcK.js → GraphInvokePage--gn48yUD.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-6SCDyQcK.js.map → GraphInvokePage--gn48yUD.js.map} +1 -1
- package/dashboard/dist/assets/{HomePage-BEc-XdKj.js → HomePage-IR_jgBE8.js} +2 -2
- package/dashboard/dist/assets/{HomePage-BEc-XdKj.js.map → HomePage-IR_jgBE8.js.map} +1 -1
- package/dashboard/dist/assets/{LabelJobsPage-BO50zXT5.js → LabelJobsPage-C8LSts4O.js} +2 -2
- package/dashboard/dist/assets/{LabelJobsPage-BO50zXT5.js.map → LabelJobsPage-C8LSts4O.js.map} +1 -1
- package/dashboard/dist/assets/{LinePage-NYxJQ-ex.js → LinePage-CS7uUv00.js} +2 -2
- package/dashboard/dist/assets/{LinePage-NYxJQ-ex.js.map → LinePage-CS7uUv00.js.map} +1 -1
- package/dashboard/dist/assets/{LinesPage-RbWTaQRh.js → LinesPage-CJprjG39.js} +3 -3
- package/dashboard/dist/assets/{LinesPage-RbWTaQRh.js.map → LinesPage-CJprjG39.js.map} +1 -1
- package/dashboard/dist/assets/{ListToolbar-B-E9-toh.js → ListToolbar-YP3uwvXC.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-B-E9-toh.js.map → ListToolbar-YP3uwvXC.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-Shcf9QhZ.js → McpOverview-Ce-m2JON.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-Shcf9QhZ.js.map → McpOverview-Ce-m2JON.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-D8kmjy2v.js → McpQueryDetailPage-CtnUqO1v.js} +2 -2
- package/dashboard/dist/assets/{McpQueryDetailPage-D8kmjy2v.js.map → McpQueryDetailPage-CtnUqO1v.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryPage-ck-o5m8A.js → McpQueryPage-C-lqUPlg.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-ck-o5m8A.js.map → McpQueryPage-C-lqUPlg.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunDetailPage-BJKkM9-3.js → McpRunDetailPage-MnIe0hwz.js} +2 -2
- package/dashboard/dist/assets/{McpRunDetailPage-BJKkM9-3.js.map → McpRunDetailPage-MnIe0hwz.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-DqhHfD5G.js → McpRunsPage-CpYLXVPF.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-DqhHfD5G.js.map → McpRunsPage-CpYLXVPF.js.map} +1 -1
- package/dashboard/dist/assets/{NamespacePill--uIaGtrN.js → NamespacePill-DilSgLyE.js} +2 -2
- package/dashboard/dist/assets/{NamespacePill--uIaGtrN.js.map → NamespacePill-DilSgLyE.js.map} +1 -1
- package/dashboard/dist/assets/{OperationsPage-D6B9Vv__.js → OperationsPage-xe6bAwaq.js} +2 -2
- package/dashboard/dist/assets/{OperationsPage-D6B9Vv__.js.map → OperationsPage-xe6bAwaq.js.map} +1 -1
- package/dashboard/dist/assets/{OperatorDashboard-CIH1cxjQ.js → OperatorDashboard-Cm9_C0EP.js} +2 -2
- package/dashboard/dist/assets/{OperatorDashboard-CIH1cxjQ.js.map → OperatorDashboard-Cm9_C0EP.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeader-DClJ33fV.js → PageHeader-B7SOvLT8.js} +2 -2
- package/dashboard/dist/assets/{PageHeader-DClJ33fV.js.map → PageHeader-B7SOvLT8.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeaderWithStats-C-TrbKQL.js → PageHeaderWithStats-DWKap7gs.js} +2 -2
- package/dashboard/dist/assets/{PageHeaderWithStats-C-TrbKQL.js.map → PageHeaderWithStats-DWKap7gs.js.map} +1 -1
- package/dashboard/dist/assets/{PersonaDetailPage-DjvfyIph.js → PersonaDetailPage-CvstNkh3.js} +2 -2
- package/dashboard/dist/assets/{PersonaDetailPage-DjvfyIph.js.map → PersonaDetailPage-CvstNkh3.js.map} +1 -1
- package/dashboard/dist/assets/{PersonasPage-D7ryA8Vc.js → PersonasPage-ba1KeInW.js} +2 -2
- package/dashboard/dist/assets/{PersonasPage-D7ryA8Vc.js.map → PersonasPage-ba1KeInW.js.map} +1 -1
- package/dashboard/dist/assets/{PortalPage-D3ybr0mo.js → PortalPage-GDgG88TM.js} +2 -2
- package/dashboard/dist/assets/{PortalPage-D3ybr0mo.js.map → PortalPage-GDgG88TM.js.map} +1 -1
- package/dashboard/dist/assets/{PrintLabelsPanel-D0HF5x8b.js → PrintLabelsPanel-BkUN00Qd.js} +2 -2
- package/dashboard/dist/assets/{PrintLabelsPanel-D0HF5x8b.js.map → PrintLabelsPanel-BkUN00Qd.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessDetailPage-0xS9EdHe.js → ProcessDetailPage-BKu9_wWv.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-0xS9EdHe.js.map → ProcessDetailPage-BKu9_wWv.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-93SMj1Fd.js → ProcessesListPage-BfJYTU_v.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-93SMj1Fd.js.map → ProcessesListPage-BfJYTU_v.js.map} +1 -1
- package/dashboard/dist/assets/ResolverForm-DZmY6wJV.js +8 -0
- package/dashboard/dist/assets/ResolverForm-DZmY6wJV.js.map +1 -0
- package/dashboard/dist/assets/{RoleDetailPage-DlUOJWSB.js → RoleDetailPage-vGeth3ve.js} +3 -3
- package/dashboard/dist/assets/{RoleDetailPage-DlUOJWSB.js.map → RoleDetailPage-vGeth3ve.js.map} +1 -1
- package/dashboard/dist/assets/{RolePill-BjD1Qw5y.js → RolePill-KhT-Yehm.js} +2 -2
- package/dashboard/dist/assets/{RolePill-BjD1Qw5y.js.map → RolePill-KhT-Yehm.js.map} +1 -1
- package/dashboard/dist/assets/{RolesPage-DqhHSvaw.js → RolesPage-CwxHOkqF.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-DqhHSvaw.js.map → RolesPage-CwxHOkqF.js.map} +1 -1
- package/dashboard/dist/assets/{RosterWidget-BrIq61HR.js → RosterWidget-DRVj9xyk.js} +2 -2
- package/dashboard/dist/assets/{RosterWidget-BrIq61HR.js.map → RosterWidget-DRVj9xyk.js.map} +1 -1
- package/dashboard/dist/assets/{RunAsSelector-D6zQrCNr.js → RunAsSelector-DvPX3XmA.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-D6zQrCNr.js.map → RunAsSelector-DvPX3XmA.js.map} +1 -1
- package/dashboard/dist/assets/{ScanCodesPage-B2S9DR2f.js → ScanCodesPage-Cptbe7h8.js} +2 -2
- package/dashboard/dist/assets/{ScanCodesPage-B2S9DR2f.js.map → ScanCodesPage-Cptbe7h8.js.map} +1 -1
- package/dashboard/dist/assets/{ScanSchemeDetailPage-gpxKN-pL.js → ScanSchemeDetailPage-DquNJ7Or.js} +4 -4
- package/dashboard/dist/assets/{ScanSchemeDetailPage-gpxKN-pL.js.map → ScanSchemeDetailPage-DquNJ7Or.js.map} +1 -1
- package/dashboard/dist/assets/{ScanStationPage-B-UTgXsG.js → ScanStationPage-DaRfGGa8.js} +2 -2
- package/dashboard/dist/assets/{ScanStationPage-B-UTgXsG.js.map → ScanStationPage-DaRfGGa8.js.map} +1 -1
- package/dashboard/dist/assets/{SchemeMatchFields-BK24aa7K.js → SchemeMatchFields-w-pffi98.js} +2 -2
- package/dashboard/dist/assets/{SchemeMatchFields-BK24aa7K.js.map → SchemeMatchFields-w-pffi98.js.map} +1 -1
- package/dashboard/dist/assets/{ScopeBadge-ofLQ6HW-.js → ScopeBadge-HeuiMJhW.js} +2 -2
- package/dashboard/dist/assets/{ScopeBadge-ofLQ6HW-.js.map → ScopeBadge-HeuiMJhW.js.map} +1 -1
- package/dashboard/dist/assets/{StickyPagination-CgVv7vc_.js → StickyPagination-D6fDHCcJ.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-CgVv7vc_.js.map → StickyPagination-D6fDHCcJ.js.map} +1 -1
- package/dashboard/dist/assets/{StreamMessageDetail-B9sxDVw4.js → StreamMessageDetail-BmYVQrzl.js} +2 -2
- package/dashboard/dist/assets/{StreamMessageDetail-B9sxDVw4.js.map → StreamMessageDetail-BmYVQrzl.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-DQc0CYSL.js → SwimlaneTimeline-KCqA-PeL.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-DQc0CYSL.js.map → SwimlaneTimeline-KCqA-PeL.js.map} +1 -1
- package/dashboard/dist/assets/{TagInput-47qVYzke.js → TagInput-CZBAu1Hy.js} +2 -2
- package/dashboard/dist/assets/{TagInput-47qVYzke.js.map → TagInput-CZBAu1Hy.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-D6VOsA1f.js → TaskDetailPage-WtVv2z7T.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-D6VOsA1f.js.map → TaskDetailPage-WtVv2z7T.js.map} +1 -1
- package/dashboard/dist/assets/{TaskQueuePill-C5KmdXAl.js → TaskQueuePill-DWGn3CWx.js} +2 -2
- package/dashboard/dist/assets/{TaskQueuePill-C5KmdXAl.js.map → TaskQueuePill-DWGn3CWx.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-DG8hvO8G.js → TasksListPage-DMYQNDIw.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-DG8hvO8G.js.map → TasksListPage-DMYQNDIw.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-CL02EhFi.js → TimeAgo-BkY4lahi.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-CL02EhFi.js.map → TimeAgo-BkY4lahi.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-BE7oKVJg.js → TimestampCell-BBPb9TI2.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-BE7oKVJg.js.map → TimestampCell-BBPb9TI2.js.map} +1 -1
- package/dashboard/dist/assets/{ToolPill-Cp9Drk1s.js → ToolPill-B2aRk0o1.js} +2 -2
- package/dashboard/dist/assets/{ToolPill-Cp9Drk1s.js.map → ToolPill-B2aRk0o1.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-CRecLh6S.js → ToolTestPanel-CNMbmymK.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-CRecLh6S.js.map → ToolTestPanel-CNMbmymK.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-QzkinTfN.js → TopicDetailPage-CodBRylU.js} +2 -2
- package/dashboard/dist/assets/{TopicDetailPage-QzkinTfN.js.map → TopicDetailPage-CodBRylU.js.map} +1 -1
- package/dashboard/dist/assets/TopicsPage-BtD8jTU7.js +2 -0
- package/dashboard/dist/assets/{TopicsPage-D8dW6J65.js.map → TopicsPage-BtD8jTU7.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-Dw3R_zrl.js → UserName-D6y9AnuY.js} +2 -2
- package/dashboard/dist/assets/{UserName-Dw3R_zrl.js.map → UserName-D6y9AnuY.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowExecutionPage-BTocv8or.js → WorkflowExecutionPage-BeffqV13.js} +2 -2
- package/dashboard/dist/assets/{WorkflowExecutionPage-BTocv8or.js.map → WorkflowExecutionPage-BeffqV13.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowPill-BiLYq__w.js → WorkflowPill-BNm3R4pP.js} +2 -2
- package/dashboard/dist/assets/{WorkflowPill-BiLYq__w.js.map → WorkflowPill-BNm3R4pP.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsDashboard-CIPEt3et.js → WorkflowsDashboard-m4Co5diK.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-CIPEt3et.js.map → WorkflowsDashboard-m4Co5diK.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-Bj4MJIE-.js → WorkflowsOverview-DNoI9qY8.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-Bj4MJIE-.js.map → WorkflowsOverview-DNoI9qY8.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-DMEk5k9-.js → YamlWorkflowDetailPage-8Vpc4Oxy.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-DMEk5k9-.js.map → YamlWorkflowDetailPage-8Vpc4Oxy.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-F2yyyoiB.js → YamlWorkflowsPage-D1JNwDSg.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-F2yyyoiB.js.map → YamlWorkflowsPage-D1JNwDSg.js.map} +1 -1
- package/dashboard/dist/assets/{agents-mSgxEPpI.js → agents-LTHUsfv3.js} +2 -2
- package/dashboard/dist/assets/{agents-mSgxEPpI.js.map → agents-LTHUsfv3.js.map} +1 -1
- package/dashboard/dist/assets/{bots-p4Hp0CV6.js → bots-CQxehfBo.js} +2 -2
- package/dashboard/dist/assets/{bots-p4Hp0CV6.js.map → bots-CQxehfBo.js.map} +1 -1
- package/dashboard/dist/assets/{capabilities-D_-I_SXR.js → capabilities-DECTnJrK.js} +2 -2
- package/dashboard/dist/assets/{capabilities-D_-I_SXR.js.map → capabilities-DECTnJrK.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-DjdoQnRU.js → controlplane-Dx20db5g.js} +2 -2
- package/dashboard/dist/assets/{controlplane-DjdoQnRU.js.map → controlplane-Dx20db5g.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-columns-R_IEVQjQ.js → escalation-columns-CVFGUB79.js} +2 -2
- package/dashboard/dist/assets/{escalation-columns-R_IEVQjQ.js.map → escalation-columns-CVFGUB79.js.map} +1 -1
- package/dashboard/dist/assets/escalation-items-Bj7bkwWy.js +2 -0
- package/dashboard/dist/assets/escalation-items-Bj7bkwWy.js.map +1 -0
- package/dashboard/dist/assets/index-BD4O-ISx.js +13 -0
- package/dashboard/dist/assets/{index-Dk2KKo0z.js.map → index-BD4O-ISx.js.map} +1 -1
- package/dashboard/dist/assets/{index-D9RAN9sA.js → index-BL8XOMHT.js} +2 -2
- package/dashboard/dist/assets/{index-D9RAN9sA.js.map → index-BL8XOMHT.js.map} +1 -1
- package/dashboard/dist/assets/index-C2vRDf96.js +2 -0
- package/dashboard/dist/assets/{index-C5osluV3.js.map → index-C2vRDf96.js.map} +1 -1
- package/dashboard/dist/assets/{index-DUYAGxwc.js → index-CNgyKRQ8.js} +2 -2
- package/dashboard/dist/assets/{index-DUYAGxwc.js.map → index-CNgyKRQ8.js.map} +1 -1
- package/dashboard/dist/assets/{index-DlJkZ12b.js → index-CdXPbBgs.js} +2 -2
- package/dashboard/dist/assets/{index-DlJkZ12b.js.map → index-CdXPbBgs.js.map} +1 -1
- package/dashboard/dist/assets/{index-BuCEhhnl.js → index-CnBUFCV7.js} +2 -2
- package/dashboard/dist/assets/{index-BuCEhhnl.js.map → index-CnBUFCV7.js.map} +1 -1
- package/dashboard/dist/assets/index-CoLciFzq.css +1 -0
- package/dashboard/dist/assets/{index-D-FYj9jT.js → index-D_TSx-k_.js} +2 -2
- package/dashboard/dist/assets/{index-D-FYj9jT.js.map → index-D_TSx-k_.js.map} +1 -1
- package/dashboard/dist/assets/{index-C_dAJUzh.js → index-Do9Y6Fgt.js} +16 -16
- package/dashboard/dist/assets/index-Do9Y6Fgt.js.map +1 -0
- package/dashboard/dist/assets/{index-D6K_IgCz.js → index-Dq1zjilj.js} +2 -2
- package/dashboard/dist/assets/{index-D6K_IgCz.js.map → index-Dq1zjilj.js.map} +1 -1
- package/dashboard/dist/assets/{index-BEMdD58x.js → index-Dz4LSzA2.js} +2 -2
- package/dashboard/dist/assets/{index-BEMdD58x.js.map → index-Dz4LSzA2.js.map} +1 -1
- package/dashboard/dist/assets/{index-D7L_VoBD.js → index-g1MmARVR.js} +2 -2
- package/dashboard/dist/assets/{index-D7L_VoBD.js.map → index-g1MmARVR.js.map} +1 -1
- package/dashboard/dist/assets/{index-BxbQmeqh.js → index-qEd4FVmN.js} +2 -2
- package/dashboard/dist/assets/{index-BxbQmeqh.js.map → index-qEd4FVmN.js.map} +1 -1
- package/dashboard/dist/assets/index-v4rQ8ctJ.js +3 -0
- package/dashboard/dist/assets/index-v4rQ8ctJ.js.map +1 -0
- package/dashboard/dist/assets/{knowledge-DSsPTqkK.js → knowledge-CT1I1t1S.js} +2 -2
- package/dashboard/dist/assets/{knowledge-DSsPTqkK.js.map → knowledge-CT1I1t1S.js.map} +1 -1
- package/dashboard/dist/assets/{machines-DSgGtqqr.js → machines-Dsuw-l1y.js} +2 -2
- package/dashboard/dist/assets/{machines-DSgGtqqr.js.map → machines-Dsuw-l1y.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-Cg-_uLw8.js → mcp-C3o5wzO8.js} +2 -2
- package/dashboard/dist/assets/{mcp-Cg-_uLw8.js.map → mcp-C3o5wzO8.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-DQombEK_.js → mcp-query-IvkIG7gH.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-DQombEK_.js.map → mcp-query-IvkIG7gH.js.map} +1 -1
- package/dashboard/dist/assets/pdf-CcZYcL52.js +13 -0
- package/dashboard/dist/assets/pdf-CcZYcL52.js.map +1 -0
- package/dashboard/dist/assets/pdf.worker.min-DgRcL-GR.js +2 -0
- package/dashboard/dist/assets/pdf.worker.min-DgRcL-GR.js.map +1 -0
- package/dashboard/dist/assets/pdf.worker.min-yatZIOMy.mjs +21 -0
- package/dashboard/dist/assets/{personas-DYrcoVBu.js → personas-zWlWjj6j.js} +2 -2
- package/dashboard/dist/assets/{personas-DYrcoVBu.js.map → personas-zWlWjj6j.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-wdb4xsey.js → pipelines-BKNvBMdf.js} +2 -2
- package/dashboard/dist/assets/{pipelines-wdb4xsey.js.map → pipelines-BKNvBMdf.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-Bil7gvm9.js → tasks-BQSO3Sjv.js} +2 -2
- package/dashboard/dist/assets/{tasks-Bil7gvm9.js.map → tasks-BQSO3Sjv.js.map} +1 -1
- package/dashboard/dist/assets/{topics-wBqaVhRR.js → topics-Dr_1TtUM.js} +2 -2
- package/dashboard/dist/assets/{topics-wBqaVhRR.js.map → topics-Dr_1TtUM.js.map} +1 -1
- package/dashboard/dist/assets/{useContainerWidth-DSLp1gEm.js → useContainerWidth-D38m8eub.js} +2 -2
- package/dashboard/dist/assets/{useContainerWidth-DSLp1gEm.js.map → useContainerWidth-D38m8eub.js.map} +1 -1
- package/dashboard/dist/assets/{useDebouncedValue-CwrY8TpV.js → useDebouncedValue-C5ESASfo.js} +2 -2
- package/dashboard/dist/assets/{useDebouncedValue-CwrY8TpV.js.map → useDebouncedValue-C5ESASfo.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-Sod_xApz.js → useNamespace-DLLOJRYY.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-Sod_xApz.js.map → useNamespace-DLLOJRYY.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-CKLInV3C.js → useYamlActivityEvents-D0XNXli1.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-CKLInV3C.js.map → useYamlActivityEvents-D0XNXli1.js.map} +1 -1
- package/dashboard/dist/assets/{validate-CYhW1xMJ.js → validate-Be4GWnJ1.js} +2 -2
- package/dashboard/dist/assets/{validate-CYhW1xMJ.js.map → validate-Be4GWnJ1.js.map} +1 -1
- package/dashboard/dist/assets/{vendor-icons-ed7mYQw4.js → vendor-icons-D48ijXZU.js} +209 -189
- package/dashboard/dist/assets/vendor-icons-D48ijXZU.js.map +1 -0
- package/dashboard/dist/assets/{yaml-workflows-C20qHo3L.js → yaml-workflows-BQpO-G-I.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-C20qHo3L.js.map → yaml-workflows-BQpO-G-I.js.map} +1 -1
- package/dashboard/dist/index.html +3 -3
- package/docs/api/http/escalations.md +54 -7
- package/docs/api/mcp/admin.md +7 -5
- package/docs/api/mcp/human-queue.md +17 -1
- package/docs/api/sdk/escalations.md +30 -4
- package/docs/api/sdk/files.md +19 -0
- package/docs/cli.md +4 -1
- package/docs/escalation-analytics.md +17 -0
- package/docs/hitl/files.md +104 -0
- package/docs/hitl/x-lt-confidence.md +139 -0
- package/docs/hitl/x-lt-layout.md +19 -0
- package/docs/hitl/x-lt-widget.md +20 -0
- package/docs/hitl-guide.md +6 -0
- package/docs/mcp.md +2 -1
- package/package.json +1 -1
- package/dashboard/dist/assets/ResolverForm-DfogHDzl.js +0 -8
- package/dashboard/dist/assets/ResolverForm-DfogHDzl.js.map +0 -1
- package/dashboard/dist/assets/TopicsPage-D8dW6J65.js +0 -2
- package/dashboard/dist/assets/escalation-items-BGZlJMpk.js +0 -2
- package/dashboard/dist/assets/escalation-items-BGZlJMpk.js.map +0 -1
- package/dashboard/dist/assets/index-BUmz0NMg.css +0 -1
- package/dashboard/dist/assets/index-C5osluV3.js +0 -2
- package/dashboard/dist/assets/index-C_dAJUzh.js.map +0 -1
- package/dashboard/dist/assets/index-Dk2KKo0z.js +0 -13
- package/dashboard/dist/assets/index-FiNThtNU.js +0 -3
- package/dashboard/dist/assets/index-FiNThtNU.js.map +0 -1
- package/dashboard/dist/assets/vendor-icons-ed7mYQw4.js.map +0 -1
|
@@ -18,9 +18,11 @@
|
|
|
18
18
|
// ---------------------------------------------------------------------------
|
|
19
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
20
|
exports.AnalyticsInputError = void 0;
|
|
21
|
+
exports.facetAlias = facetAlias;
|
|
21
22
|
exports.buildAggregateQuery = buildAggregateQuery;
|
|
22
23
|
exports.buildTimelineQuery = buildTimelineQuery;
|
|
23
24
|
const facet_sql_1 = require("./facet-sql");
|
|
25
|
+
const aggregate_resolved_sql_1 = require("./aggregate-resolved-sql");
|
|
24
26
|
const aggregate_validate_1 = require("./aggregate-validate");
|
|
25
27
|
const types_1 = require("../../types");
|
|
26
28
|
var aggregate_validate_2 = require("./aggregate-validate");
|
|
@@ -60,24 +62,27 @@ function overlapsAfter(liveList, fromParam) {
|
|
|
60
62
|
return `(status IN (${liveList}) OR (status NOT IN (${liveList}) AND COALESCE(resolved_at, updated_at) > ${fromParam}))`;
|
|
61
63
|
}
|
|
62
64
|
/** ORDER BY over the RESULT groups: measure aliases and grouped keys only. */
|
|
63
|
-
function buildAggregateOrder(orderBy, measureKind, columns, facets, stateGrouped = false) {
|
|
65
|
+
function buildAggregateOrder(orderBy, measureKind, columns, facets, stateGrouped = false, bucketed = false) {
|
|
64
66
|
if (!orderBy || !orderBy.length)
|
|
65
|
-
return 'sample_count DESC';
|
|
67
|
+
return bucketed ? 'bucket ASC, sample_count DESC' : 'sample_count DESC';
|
|
66
68
|
const parts = [];
|
|
67
69
|
for (const o of orderBy) {
|
|
68
70
|
const dir = o.direction === 'desc' ? 'DESC' : 'ASC';
|
|
69
71
|
if (o.field === 'state' && stateGrouped) {
|
|
70
72
|
parts.push(`state_label ${dir}`);
|
|
71
73
|
}
|
|
74
|
+
else if (o.field === 'bucket' && bucketed) {
|
|
75
|
+
parts.push(`bucket ${dir}`);
|
|
76
|
+
}
|
|
72
77
|
else if (o.field === 'count') {
|
|
73
|
-
if (measureKind
|
|
74
|
-
throw new aggregate_validate_1.AnalyticsInputError('orderBy "count" applies to membership; use "dwellSeconds" for dwell');
|
|
78
|
+
if (measureKind === 'dwell') {
|
|
79
|
+
throw new aggregate_validate_1.AnalyticsInputError('orderBy "count" applies to membership and resolved; use "dwellSeconds" for dwell');
|
|
75
80
|
}
|
|
76
81
|
parts.push(`"count" ${dir}`);
|
|
77
82
|
}
|
|
78
83
|
else if (o.field === 'dwellSeconds') {
|
|
79
84
|
if (measureKind !== 'dwell') {
|
|
80
|
-
throw new aggregate_validate_1.AnalyticsInputError('orderBy "dwellSeconds" applies to dwell; use "count" for membership');
|
|
85
|
+
throw new aggregate_validate_1.AnalyticsInputError('orderBy "dwellSeconds" applies to dwell; use "count" for membership and resolved');
|
|
81
86
|
}
|
|
82
87
|
parts.push(`dwell_seconds ${dir}`);
|
|
83
88
|
}
|
|
@@ -91,7 +96,7 @@ function buildAggregateOrder(orderBy, measureKind, columns, facets, stateGrouped
|
|
|
91
96
|
parts.push(`${facetAlias(o.field)} ${dir} NULLS LAST`);
|
|
92
97
|
}
|
|
93
98
|
else {
|
|
94
|
-
throw new aggregate_validate_1.AnalyticsInputError(`orderBy field "${o.field}" is not a measure (count, dwellSeconds, sampleCount) or a grouped key`);
|
|
99
|
+
throw new aggregate_validate_1.AnalyticsInputError(`orderBy field "${o.field}" is not a measure (count, dwellSeconds, sampleCount), a bucket, or a grouped key`);
|
|
95
100
|
}
|
|
96
101
|
}
|
|
97
102
|
return parts.join(', ');
|
|
@@ -119,12 +124,13 @@ function buildAggregateQuery(input, opts = {}) {
|
|
|
119
124
|
const liveList = statusLiterals(live);
|
|
120
125
|
const { pageLimit, offset } = (0, aggregate_validate_1.resolvePage)(input.limit, input.offset);
|
|
121
126
|
const measure = input.measure;
|
|
122
|
-
if (measure?.kind !== 'membership' && measure?.kind !== 'dwell') {
|
|
123
|
-
throw new aggregate_validate_1.AnalyticsInputError('measure.kind must be "membership" or "
|
|
127
|
+
if (measure?.kind !== 'membership' && measure?.kind !== 'dwell' && measure?.kind !== 'resolved') {
|
|
128
|
+
throw new aggregate_validate_1.AnalyticsInputError('measure.kind must be "membership", "dwell" or "resolved"');
|
|
124
129
|
}
|
|
130
|
+
const bucket = measure.kind === 'resolved' ? (0, aggregate_resolved_sql_1.resolveBucket)(measure.bucket) : null;
|
|
125
131
|
const params = [];
|
|
126
132
|
const where = (0, facet_sql_1.buildFacetWhere)(query, params);
|
|
127
|
-
const order = buildAggregateOrder(input.orderBy, measure.kind, columns, facets, state);
|
|
133
|
+
const order = buildAggregateOrder(input.orderBy, measure.kind, columns, facets, state, bucket !== null);
|
|
128
134
|
const groupSelect = [];
|
|
129
135
|
const groupKeys = [];
|
|
130
136
|
if (state) {
|
|
@@ -139,6 +145,21 @@ function buildAggregateQuery(input, opts = {}) {
|
|
|
139
145
|
groupSelect.push(`(metadata->>'${key}') AS ${facetAlias(key)}`);
|
|
140
146
|
groupKeys.push(facetAlias(key));
|
|
141
147
|
}
|
|
148
|
+
if (measure.kind === 'resolved') {
|
|
149
|
+
if (input.liveStatuses !== undefined) {
|
|
150
|
+
throw new aggregate_validate_1.AnalyticsInputError('liveStatuses does not apply to the resolved measure, which counts resolved rows');
|
|
151
|
+
}
|
|
152
|
+
if (!query.role && !query.roles?.length) {
|
|
153
|
+
throw new aggregate_validate_1.AnalyticsInputError('the resolved measure requires a role scope: query.role, query.roles or query.entity');
|
|
154
|
+
}
|
|
155
|
+
if (input.distinctBy !== undefined)
|
|
156
|
+
(0, aggregate_validate_1.requireFacetKey)(input.distinctBy, 'distinctBy');
|
|
157
|
+
const built = (0, aggregate_resolved_sql_1.buildResolvedAggregate)({
|
|
158
|
+
window: measure.window, bucket, where, params, groupSelect, groupKeys, order,
|
|
159
|
+
distinctBy: input.distinctBy, pageLimit, offset,
|
|
160
|
+
});
|
|
161
|
+
return { ...built, pageLimit, columns, facets, stateGrouped: state, measureKind: 'resolved', bucketed: bucket !== null };
|
|
162
|
+
}
|
|
142
163
|
const groupBySql = groupKeys.length ? `GROUP BY ${groupKeys.join(', ')}\n` : '';
|
|
143
164
|
if (measure.kind === 'membership') {
|
|
144
165
|
const asOf = (0, aggregate_validate_1.resolveAsOf)(measure.asOf);
|
|
@@ -165,11 +186,11 @@ WHERE ${where}
|
|
|
165
186
|
AND ${intervalPred}
|
|
166
187
|
${groupBySql}ORDER BY ${order}
|
|
167
188
|
LIMIT $${params.length - 1} OFFSET $${params.length}`;
|
|
168
|
-
return { sql, params, pageLimit, columns, facets, stateGrouped: state, measureKind: 'membership', nowAnchored: asOf === null };
|
|
189
|
+
return { sql, params, pageLimit, columns, facets, stateGrouped: state, measureKind: 'membership', bucketed: false, nowAnchored: asOf === null };
|
|
169
190
|
}
|
|
170
191
|
// Dwell: clip each overlapping interval to the window, sum open-seconds.
|
|
171
192
|
if (input.distinctBy !== undefined) {
|
|
172
|
-
throw new aggregate_validate_1.AnalyticsInputError('distinctBy
|
|
193
|
+
throw new aggregate_validate_1.AnalyticsInputError('distinctBy applies to membership and resolved; for per-entity dwell, put the entity facet in groupBy.facets');
|
|
173
194
|
}
|
|
174
195
|
const win = (0, aggregate_validate_1.resolveWindow)(measure.window, 'measure.window');
|
|
175
196
|
if (!win)
|
|
@@ -198,7 +219,7 @@ SELECT ${[...groupKeys, 'SUM(EXTRACT(EPOCH FROM (e - s)))::float8 AS dwell_secon
|
|
|
198
219
|
FROM span
|
|
199
220
|
${groupBySql}ORDER BY ${order}
|
|
200
221
|
LIMIT $${params.length - 1} OFFSET $${params.length}`;
|
|
201
|
-
return { sql, params, pageLimit, columns, facets, stateGrouped: state, measureKind: 'dwell', nowAnchored: win.nowAnchored };
|
|
222
|
+
return { sql, params, pageLimit, columns, facets, stateGrouped: state, measureKind: 'dwell', bucketed: false, nowAnchored: win.nowAnchored };
|
|
202
223
|
}
|
|
203
224
|
/** Build the single-entity interval sequence, created_at-ordered, gaps preserved. */
|
|
204
225
|
function buildTimelineQuery(input) {
|
|
@@ -29,8 +29,11 @@ export declare function resolveTimelinePage(order: 'asc' | 'desc' | undefined, b
|
|
|
29
29
|
before: Date | null;
|
|
30
30
|
};
|
|
31
31
|
export declare function toInstant(value: Date | string, label: string): Date;
|
|
32
|
-
/** Half-open [from, to): ordered, and bounded by LT_ANALYTICS_MAX_WINDOW_DAYS. */
|
|
33
|
-
export declare function resolveWindow(window: AnalyticsWindow | undefined, label?: string
|
|
32
|
+
/** Half-open [from, to): ordered, and bounded by LT_ANALYTICS_MAX_WINDOW_DAYS (or the env var naming `maxDays`). */
|
|
33
|
+
export declare function resolveWindow(window: AnalyticsWindow | undefined, label?: string, maxDays?: {
|
|
34
|
+
days: number;
|
|
35
|
+
envVar: string;
|
|
36
|
+
}): {
|
|
34
37
|
from: Date;
|
|
35
38
|
to: Date;
|
|
36
39
|
nowAnchored: boolean;
|
|
@@ -142,8 +142,11 @@ function toInstant(value, label) {
|
|
|
142
142
|
}
|
|
143
143
|
return d;
|
|
144
144
|
}
|
|
145
|
-
/** Half-open [from, to): ordered, and bounded by LT_ANALYTICS_MAX_WINDOW_DAYS. */
|
|
146
|
-
function resolveWindow(window, label = 'window'
|
|
145
|
+
/** Half-open [from, to): ordered, and bounded by LT_ANALYTICS_MAX_WINDOW_DAYS (or the env var naming `maxDays`). */
|
|
146
|
+
function resolveWindow(window, label = 'window', maxDays = {
|
|
147
|
+
days: config_1.config.LT_ANALYTICS_MAX_WINDOW_DAYS,
|
|
148
|
+
envVar: 'LT_ANALYTICS_MAX_WINDOW_DAYS',
|
|
149
|
+
}) {
|
|
147
150
|
if (!window)
|
|
148
151
|
return null;
|
|
149
152
|
const from = toInstant(window.from, `${label}.from`);
|
|
@@ -152,8 +155,8 @@ function resolveWindow(window, label = 'window') {
|
|
|
152
155
|
throw new AnalyticsInputError(`${label} is empty: from must be before to`);
|
|
153
156
|
}
|
|
154
157
|
const spanDays = (to.getTime() - from.getTime()) / 86_400_000;
|
|
155
|
-
if (spanDays >
|
|
156
|
-
throw new AnalyticsInputError(`${label} spans ${spanDays.toFixed(1)} days; the maximum is ${
|
|
158
|
+
if (spanDays > maxDays.days) {
|
|
159
|
+
throw new AnalyticsInputError(`${label} spans ${spanDays.toFixed(1)} days; the maximum is ${maxDays.days} (${maxDays.envVar})`);
|
|
157
160
|
}
|
|
158
161
|
return { from, to, nowAnchored: to.getTime() >= Date.now() };
|
|
159
162
|
}
|
|
@@ -67,10 +67,12 @@ function toAggregateRow(raw, built, states) {
|
|
|
67
67
|
const row = { facets, sampleCount: Number(raw.sample_count) };
|
|
68
68
|
for (const column of built.columns)
|
|
69
69
|
row[column] = raw[column] ?? undefined;
|
|
70
|
-
if (built.measureKind === '
|
|
71
|
-
row.count = Number(raw.count);
|
|
72
|
-
else
|
|
70
|
+
if (built.measureKind === 'dwell')
|
|
73
71
|
row.dwellSeconds = Number(raw.dwell_seconds);
|
|
72
|
+
else
|
|
73
|
+
row.count = Number(raw.count);
|
|
74
|
+
if (built.bucketed)
|
|
75
|
+
row.bucket = toIso(raw.bucket);
|
|
74
76
|
if (built.stateGrouped) {
|
|
75
77
|
row.state = raw.state_label;
|
|
76
78
|
}
|
|
@@ -58,6 +58,9 @@ async function createEscalation(input) {
|
|
|
58
58
|
if (envelopeObj[escalation_1.ESCALATION_ENVELOPE_KEYS.LOOKUPS] !== undefined) {
|
|
59
59
|
(0, escalation_1.assertLookupRefs)(envelopeObj[escalation_1.ESCALATION_ENVELOPE_KEYS.LOOKUPS]);
|
|
60
60
|
}
|
|
61
|
+
if (envelopeObj[escalation_1.ESCALATION_ENVELOPE_KEYS.FILES] !== undefined) {
|
|
62
|
+
(0, escalation_1.assertFileRefs)(envelopeObj[escalation_1.ESCALATION_ENVELOPE_KEYS.FILES]);
|
|
63
|
+
}
|
|
61
64
|
const client = await (0, client_1.escalations)();
|
|
62
65
|
const entry = await client.create({
|
|
63
66
|
type: input.type,
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type EscalationFileRef, type LTEscalationRecord } from '../../types/escalation';
|
|
2
|
+
/** One file ref answered: a signed link, or the reason there is none. */
|
|
3
|
+
export interface EscalationFileLink {
|
|
4
|
+
as: string;
|
|
5
|
+
path: string;
|
|
6
|
+
name: string;
|
|
7
|
+
contentType: string;
|
|
8
|
+
url?: string;
|
|
9
|
+
expiresAt?: string;
|
|
10
|
+
error?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The refs riding the row's envelope under the reserved key, each checked
|
|
14
|
+
* again at read time: an engine-written envelope can carry refs that never
|
|
15
|
+
* passed the creation check, and nothing outside the store is ever signed.
|
|
16
|
+
*/
|
|
17
|
+
export declare function readFileRefs(envelope: string | Record<string, unknown> | null | undefined): Array<EscalationFileRef | {
|
|
18
|
+
error: string;
|
|
19
|
+
ref: unknown;
|
|
20
|
+
}>;
|
|
21
|
+
/**
|
|
22
|
+
* The `file` form domain without links, keyed by each ref's `as`: what the
|
|
23
|
+
* server's validation pass sees, so a condition on a file's presence
|
|
24
|
+
* evaluates the same on both sides of the wire.
|
|
25
|
+
*/
|
|
26
|
+
export declare function fileContext(envelope: string | Record<string, unknown> | null | undefined): Record<string, Pick<EscalationFileLink, 'as' | 'path' | 'name' | 'contentType'>> | null;
|
|
27
|
+
/** Seconds left on the reader's own live claim, or 0. */
|
|
28
|
+
export declare function claimSecondsLeft(escalation: Pick<LTEscalationRecord, 'assigned_to' | 'assigned_until'>, userId: string, now?: number): number;
|
|
29
|
+
/**
|
|
30
|
+
* How long a link lives: the ref's ask (else the default), stretched to
|
|
31
|
+
* cover the reader's live claim, held within the configured bounds.
|
|
32
|
+
*/
|
|
33
|
+
export declare function fileLinkSeconds(ref: Pick<EscalationFileRef, 'expiresIn'>, claimSeconds: number): number;
|
|
34
|
+
/**
|
|
35
|
+
* Sign every ref. Signing is local to the process (no storage round trip),
|
|
36
|
+
* so a page open costs one signature per file. A ref that cannot be signed
|
|
37
|
+
* answers with `error`; the batch never fails.
|
|
38
|
+
*/
|
|
39
|
+
export declare function signFileRefs(refs: ReturnType<typeof readFileRefs>, claimSeconds: number, now?: number): Promise<EscalationFileLink[]>;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.readFileRefs = readFileRefs;
|
|
7
|
+
exports.fileContext = fileContext;
|
|
8
|
+
exports.claimSecondsLeft = claimSecondsLeft;
|
|
9
|
+
exports.fileLinkSeconds = fileLinkSeconds;
|
|
10
|
+
exports.signFileRefs = signFileRefs;
|
|
11
|
+
const path_1 = __importDefault(require("path"));
|
|
12
|
+
const config_1 = require("../../modules/config");
|
|
13
|
+
const storage_1 = require("../../lib/storage");
|
|
14
|
+
const mime_1 = require("../../lib/storage/mime");
|
|
15
|
+
const escalation_1 = require("../../types/escalation");
|
|
16
|
+
/**
|
|
17
|
+
* The refs riding the row's envelope under the reserved key, each checked
|
|
18
|
+
* again at read time: an engine-written envelope can carry refs that never
|
|
19
|
+
* passed the creation check, and nothing outside the store is ever signed.
|
|
20
|
+
*/
|
|
21
|
+
function readFileRefs(envelope) {
|
|
22
|
+
if (!envelope)
|
|
23
|
+
return [];
|
|
24
|
+
let refs;
|
|
25
|
+
try {
|
|
26
|
+
const parsed = typeof envelope === 'string' ? JSON.parse(envelope) : envelope;
|
|
27
|
+
refs = parsed && typeof parsed === 'object' ? parsed[escalation_1.ESCALATION_ENVELOPE_KEYS.FILES] : undefined;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
if (!Array.isArray(refs))
|
|
33
|
+
return [];
|
|
34
|
+
const seen = new Set();
|
|
35
|
+
return refs.slice(0, escalation_1.ESCALATION_FILE_REFS_MAX).map((ref) => {
|
|
36
|
+
const problem = (0, escalation_1.fileRefProblem)(ref);
|
|
37
|
+
if (problem)
|
|
38
|
+
return { error: problem, ref };
|
|
39
|
+
const alias = ref.as;
|
|
40
|
+
if (seen.has(alias))
|
|
41
|
+
return { error: `File ref ${alias}: "as" names more than one file`, ref };
|
|
42
|
+
seen.add(alias);
|
|
43
|
+
return ref;
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The `file` form domain without links, keyed by each ref's `as`: what the
|
|
48
|
+
* server's validation pass sees, so a condition on a file's presence
|
|
49
|
+
* evaluates the same on both sides of the wire.
|
|
50
|
+
*/
|
|
51
|
+
function fileContext(envelope) {
|
|
52
|
+
const entries = readFileRefs(envelope).filter((r) => !('error' in r));
|
|
53
|
+
if (entries.length === 0)
|
|
54
|
+
return null;
|
|
55
|
+
return Object.fromEntries(entries.map((ref) => {
|
|
56
|
+
const key = (0, escalation_1.normalizeFileRefPath)(ref.path);
|
|
57
|
+
return [ref.as, {
|
|
58
|
+
as: ref.as,
|
|
59
|
+
path: key,
|
|
60
|
+
name: ref.name ?? path_1.default.posix.basename(key),
|
|
61
|
+
contentType: ref.contentType ?? (0, mime_1.mimeFromPath)(key),
|
|
62
|
+
}];
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
65
|
+
/** Seconds left on the reader's own live claim, or 0. */
|
|
66
|
+
function claimSecondsLeft(escalation, userId, now = Date.now()) {
|
|
67
|
+
if (!escalation.assigned_to || escalation.assigned_to !== userId || !escalation.assigned_until)
|
|
68
|
+
return 0;
|
|
69
|
+
const until = new Date(escalation.assigned_until).getTime();
|
|
70
|
+
return Number.isFinite(until) && until > now ? Math.ceil((until - now) / 1000) : 0;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* How long a link lives: the ref's ask (else the default), stretched to
|
|
74
|
+
* cover the reader's live claim, held within the configured bounds.
|
|
75
|
+
*/
|
|
76
|
+
function fileLinkSeconds(ref, claimSeconds) {
|
|
77
|
+
const asked = ref.expiresIn ?? config_1.config.LT_ESCALATION_FILE_URL_TTL_SECONDS;
|
|
78
|
+
const wanted = Math.max(asked, claimSeconds);
|
|
79
|
+
const min = config_1.config.LT_ESCALATION_FILE_URL_MIN_SECONDS;
|
|
80
|
+
const max = Math.max(min, config_1.config.LT_ESCALATION_FILE_URL_MAX_SECONDS);
|
|
81
|
+
return Math.min(Math.max(wanted, min), max);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Sign every ref. Signing is local to the process (no storage round trip),
|
|
85
|
+
* so a page open costs one signature per file. A ref that cannot be signed
|
|
86
|
+
* answers with `error`; the batch never fails.
|
|
87
|
+
*/
|
|
88
|
+
async function signFileRefs(refs, claimSeconds, now = Date.now()) {
|
|
89
|
+
const storage = (0, storage_1.getStorageBackend)();
|
|
90
|
+
return Promise.all(refs.map(async (entry) => {
|
|
91
|
+
if ('error' in entry) {
|
|
92
|
+
const raw = (entry.ref ?? {});
|
|
93
|
+
return {
|
|
94
|
+
as: typeof raw.as === 'string' ? raw.as : '',
|
|
95
|
+
path: typeof raw.path === 'string' ? raw.path : '',
|
|
96
|
+
name: '',
|
|
97
|
+
contentType: '',
|
|
98
|
+
error: entry.error,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
const key = (0, escalation_1.normalizeFileRefPath)(entry.path);
|
|
102
|
+
const link = {
|
|
103
|
+
as: entry.as,
|
|
104
|
+
path: key,
|
|
105
|
+
name: entry.name ?? path_1.default.posix.basename(key),
|
|
106
|
+
contentType: entry.contentType ?? (0, mime_1.mimeFromPath)(key),
|
|
107
|
+
};
|
|
108
|
+
const seconds = fileLinkSeconds(entry, claimSeconds);
|
|
109
|
+
try {
|
|
110
|
+
link.url = await storage.getSignedUrl(key, seconds);
|
|
111
|
+
link.expiresAt = new Date(now + seconds * 1000).toISOString();
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
link.error = err?.message ?? 'The file link could not be signed';
|
|
115
|
+
}
|
|
116
|
+
return link;
|
|
117
|
+
}));
|
|
118
|
+
}
|
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-side resolver schema enforcement — the API-first counterpart of the
|
|
3
|
+
* dashboard's pre-submission pass. Every resolve surface (HTTP, SDK, MCP)
|
|
4
|
+
* calls checkResolverPayload before committing a resolution; roles that opt in
|
|
5
|
+
* via enforce_schema get their form_schema enforced as an API contract, and
|
|
6
|
+
* violations surface as the canonical 422 body (types/validation.ts).
|
|
7
|
+
*
|
|
8
|
+
* Production shape: the gate consults the cached enforcing-role set first, so
|
|
9
|
+
* when no involved role enforces, a resolve costs zero additional SQL. Schema
|
|
10
|
+
* reads for enforcing roles come from the enforcement cache (immutable pinned
|
|
11
|
+
* snapshots cached indefinitely; latest schemas under a short TTL).
|
|
12
|
+
*
|
|
13
|
+
* Schema resolution matches the resolve UI, most specific first:
|
|
14
|
+
* 1. metadata.form_schema — a full form embedded on the row
|
|
15
|
+
* 2. the lt_role_schemas snapshot pinned by metadata.schema_version
|
|
16
|
+
* 3. the role's live (latest) form_schema
|
|
17
|
+
* A role that enforces but declares no schema has no contract to enforce —
|
|
18
|
+
* the gate passes.
|
|
19
|
+
*/
|
|
20
|
+
import { type ReviewFacets } from '../../shared/form-validation';
|
|
1
21
|
import { type LTFieldViolation, type LTValidationErrorBody } from '../../types/validation';
|
|
2
22
|
/** The row fields the gate reads — every resolve surface already holds these. */
|
|
3
23
|
export interface ResolvableEscalationRow {
|
|
@@ -14,6 +34,12 @@ export interface ResolverSchemaViolationReport {
|
|
|
14
34
|
schemaVersion: number | null;
|
|
15
35
|
violations: LTFieldViolation[];
|
|
16
36
|
}
|
|
37
|
+
/** The gate's verdict, plus the review facets a passing answer stamps. */
|
|
38
|
+
export interface ResolverPayloadAssessment {
|
|
39
|
+
violation: ResolverSchemaViolationReport | null;
|
|
40
|
+
/** Review summary for the row's metadata, when the form opts in (x-lt-confidence facets). */
|
|
41
|
+
facets: ReviewFacets | null;
|
|
42
|
+
}
|
|
17
43
|
/**
|
|
18
44
|
* Validate a submitted resolverPayload against the escalation's enforced form
|
|
19
45
|
* schema. Returns null when the resolution may proceed (role does not enforce,
|
|
@@ -24,5 +50,12 @@ export interface ResolverSchemaViolationReport {
|
|
|
24
50
|
* It is only invoked when the role actually enforces.
|
|
25
51
|
*/
|
|
26
52
|
export declare function checkResolverPayload(escalation: ResolvableEscalationRow, resolverPayload: Record<string, any>, loadEnvelope?: () => Promise<Record<string, any>>, resolvingUserId?: string): Promise<ResolverSchemaViolationReport | null>;
|
|
53
|
+
/**
|
|
54
|
+
* The same gate, also returning the review facets a passing answer stamps
|
|
55
|
+
* onto the row. Single-row resolve paths merge `facets` into the outcome
|
|
56
|
+
* patch, so they commit inside the guarded resolve UPDATE. Computed from the
|
|
57
|
+
* schema and context the gate already loaded: no extra reads.
|
|
58
|
+
*/
|
|
59
|
+
export declare function assessResolverPayload(escalation: ResolvableEscalationRow, resolverPayload: Record<string, any>, loadEnvelope?: () => Promise<Record<string, any>>, resolvingUserId?: string): Promise<ResolverPayloadAssessment>;
|
|
27
60
|
/** The canonical 422 body for a violation report (types/validation.ts). */
|
|
28
61
|
export declare function toValidationErrorBody(report: ResolverSchemaViolationReport): LTValidationErrorBody;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.checkResolverPayload = checkResolverPayload;
|
|
4
|
+
exports.assessResolverPayload = assessResolverPayload;
|
|
4
5
|
exports.toValidationErrorBody = toValidationErrorBody;
|
|
5
6
|
/**
|
|
6
7
|
* Server-side resolver schema enforcement — the API-first counterpart of the
|
|
@@ -24,6 +25,7 @@ exports.toValidationErrorBody = toValidationErrorBody;
|
|
|
24
25
|
const form_validation_1 = require("../../shared/form-validation");
|
|
25
26
|
const submit_guard_1 = require("./submit-guard");
|
|
26
27
|
const roster_1 = require("./roster");
|
|
28
|
+
const file_links_1 = require("./file-links");
|
|
27
29
|
const enforcement_cache_1 = require("../role/enforcement-cache");
|
|
28
30
|
const knowledge_1 = require("../knowledge");
|
|
29
31
|
const escalation_1 = require("../../types/escalation");
|
|
@@ -48,6 +50,7 @@ function pinnedVersionOf(metadata) {
|
|
|
48
50
|
return parseInt(raw, 10);
|
|
49
51
|
return null;
|
|
50
52
|
}
|
|
53
|
+
const PASS = { violation: null, facets: null };
|
|
51
54
|
/**
|
|
52
55
|
* Validate a submitted resolverPayload against the escalation's enforced form
|
|
53
56
|
* schema. Returns null when the resolution may proceed (role does not enforce,
|
|
@@ -58,12 +61,22 @@ function pinnedVersionOf(metadata) {
|
|
|
58
61
|
* It is only invoked when the role actually enforces.
|
|
59
62
|
*/
|
|
60
63
|
async function checkResolverPayload(escalation, resolverPayload, loadEnvelope, resolvingUserId) {
|
|
64
|
+
const { violation } = await assessResolverPayload(escalation, resolverPayload, loadEnvelope, resolvingUserId);
|
|
65
|
+
return violation;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The same gate, also returning the review facets a passing answer stamps
|
|
69
|
+
* onto the row. Single-row resolve paths merge `facets` into the outcome
|
|
70
|
+
* patch, so they commit inside the guarded resolve UPDATE. Computed from the
|
|
71
|
+
* schema and context the gate already loaded: no extra reads.
|
|
72
|
+
*/
|
|
73
|
+
async function assessResolverPayload(escalation, resolverPayload, loadEnvelope, resolvingUserId) {
|
|
61
74
|
const role = escalation.role;
|
|
62
75
|
if (!role)
|
|
63
|
-
return
|
|
76
|
+
return PASS;
|
|
64
77
|
const enforcing = await (0, enforcement_cache_1.getEnforcingRoles)();
|
|
65
78
|
if (!enforcing.has(role))
|
|
66
|
-
return
|
|
79
|
+
return PASS;
|
|
67
80
|
const metadata = (escalation.metadata ?? {});
|
|
68
81
|
const pin = pinnedVersionOf(metadata);
|
|
69
82
|
const embedded = metadata[escalation_1.ESCALATION_METADATA_KEYS.FORM_SCHEMA];
|
|
@@ -71,7 +84,7 @@ async function checkResolverPayload(escalation, resolverPayload, loadEnvelope, r
|
|
|
71
84
|
? embedded
|
|
72
85
|
: await (0, enforcement_cache_1.getEnforcedFormSchema)(role, pin);
|
|
73
86
|
if (!schema)
|
|
74
|
-
return
|
|
87
|
+
return PASS;
|
|
75
88
|
const envelope = loadEnvelope
|
|
76
89
|
? await loadEnvelope()
|
|
77
90
|
: parseJsonOrNull(escalation.envelope) ?? {};
|
|
@@ -79,12 +92,14 @@ async function checkResolverPayload(escalation, resolverPayload, loadEnvelope, r
|
|
|
79
92
|
// immutable snapshot cache, so enforcement reads the exact editions the
|
|
80
93
|
// form rendered from. Rows without refs cost zero SQL here.
|
|
81
94
|
const lookup = await (0, knowledge_1.resolveLookupContext)(envelope[escalation_1.ESCALATION_ENVELOPE_KEYS.LOOKUPS]);
|
|
95
|
+
const file = (0, file_links_1.fileContext)(envelope);
|
|
82
96
|
const ctx = {
|
|
83
97
|
escalation: escalation,
|
|
84
98
|
metadata,
|
|
85
99
|
envelope,
|
|
86
100
|
payload: parseJsonOrNull(escalation.escalation_payload),
|
|
87
101
|
...(lookup ? { lookup } : {}),
|
|
102
|
+
...(file ? { file } : {}),
|
|
88
103
|
};
|
|
89
104
|
// Roster counts read the submitted form values (an `in` source may name a
|
|
90
105
|
// form field), then join the context so showIf and the guard see them.
|
|
@@ -98,9 +113,10 @@ async function checkResolverPayload(escalation, resolverPayload, loadEnvelope, r
|
|
|
98
113
|
// contract, so a raw-API resolve honors the gate the dashboard shows.
|
|
99
114
|
const guardViolation = await (0, submit_guard_1.checkSubmitGuard)(schema, ctx, resolvingUserId);
|
|
100
115
|
const allViolations = guardViolation ? [...violations, guardViolation] : violations;
|
|
101
|
-
if (allViolations.length
|
|
102
|
-
return null;
|
|
103
|
-
|
|
116
|
+
if (allViolations.length > 0) {
|
|
117
|
+
return { violation: { role, schemaVersion: pin, violations: allViolations }, facets: null };
|
|
118
|
+
}
|
|
119
|
+
return { violation: null, facets: (0, form_validation_1.buildReviewFacets)(schema, ctx, formValues) };
|
|
104
120
|
}
|
|
105
121
|
/** The canonical 422 body for a violation report (types/validation.ts). */
|
|
106
122
|
function toValidationErrorBody(report) {
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import type { Types } from '@hotmeshio/hotmesh';
|
|
2
|
-
import { type AccumulateConfig, type AccumulatorResult, type EscalationLookupRef } from '../../types/escalation';
|
|
2
|
+
import { type AccumulateConfig, type AccumulatorResult, type EscalationLookupRef, type EscalationFileRef } from '../../types/escalation';
|
|
3
3
|
/**
|
|
4
4
|
* HotMesh's escalation config plus long-tail sugar. `schemaVersion` pins the
|
|
5
5
|
* role form version (lt_role_schemas) the resolve UI renders; `lookups` names
|
|
6
6
|
* the knowledge entries the form may read (the `lookup.*` context domain, see
|
|
7
7
|
* docs/hitl/lookups.md), each pinned to an edition or following the current
|
|
8
|
-
* one
|
|
9
|
-
*
|
|
8
|
+
* one; `files` names the stored files the form shows (the `file.*` context
|
|
9
|
+
* domain, see docs/hitl/files.md). All are set by the workflow author and
|
|
10
|
+
* folded before the config reaches the engine:
|
|
10
11
|
* schemaVersion into the GIN-indexed metadata (a queryable facet), lookups
|
|
11
|
-
* into the unindexed envelope (form plumbing, never a facet). Folding is a
|
|
12
|
+
* and files into the unindexed envelope (form plumbing, never a facet). Folding is a
|
|
12
13
|
* pure transform — no query, no activity — so a pinned `conditional` costs
|
|
13
14
|
* exactly what an unpinned one does. Omit `schemaVersion` and the resolve UI
|
|
14
15
|
* renders the role's latest form when the escalation is fetched.
|
|
@@ -16,6 +17,7 @@ import { type AccumulateConfig, type AccumulatorResult, type EscalationLookupRef
|
|
|
16
17
|
export type ConditionEscalationConfig = Types.ConditionQueueConfig & {
|
|
17
18
|
schemaVersion?: number;
|
|
18
19
|
lookups?: EscalationLookupRef[];
|
|
20
|
+
files?: EscalationFileRef[];
|
|
19
21
|
};
|
|
20
22
|
/**
|
|
21
23
|
* Wait for a signal and resolve the associated escalation automatically.
|
|
@@ -74,6 +76,20 @@ export type ConditionEscalationConfig = Types.ConditionQueueConfig & {
|
|
|
74
76
|
* });
|
|
75
77
|
* ```
|
|
76
78
|
*
|
|
79
|
+
* **Stored files: documents the form shows.** Each ref names an object in
|
|
80
|
+
* file storage and the address the form reads it at (`file.<as>`). The
|
|
81
|
+
* resolve UI fetches time-limited signed links when the page opens and again
|
|
82
|
+
* on claim; a `document` widget renders PDFs and images inline.
|
|
83
|
+
*
|
|
84
|
+
* ```typescript
|
|
85
|
+
* const decision = await conditional<IntakeReviewV1>(signalId, {
|
|
86
|
+
* role: 'intake-verifier',
|
|
87
|
+
* description: instructions,
|
|
88
|
+
* envelope: { formDefaults: extracted, confidence: scores },
|
|
89
|
+
* files: [{ path: `referrals/${referralId}.pdf`, as: 'referral' }],
|
|
90
|
+
* });
|
|
91
|
+
* ```
|
|
92
|
+
*
|
|
77
93
|
* **With an SLA (hotmesh 0.25.1+) — add `timeout` to the config.** The same
|
|
78
94
|
* single wait arms a resume timer alongside the escalation row: when the timer
|
|
79
95
|
* fires first, this helper returns `false`, the row transitions to
|
|
@@ -42,25 +42,30 @@ const interceptorActivities = __importStar(require("../interceptor/activities"))
|
|
|
42
42
|
const LT_ACTIVITY_QUEUE = 'lt-interceptor';
|
|
43
43
|
/**
|
|
44
44
|
* Fold the sugar before the config reaches the engine: schemaVersion into the
|
|
45
|
-
* GIN-indexed metadata (it is a queryable pin), lookups into the
|
|
46
|
-
* envelope (they are form plumbing, never a facet). Everything
|
|
47
|
-
* through.
|
|
45
|
+
* GIN-indexed metadata (it is a queryable pin), lookups and files into the
|
|
46
|
+
* unindexed envelope (they are form plumbing, never a facet). Everything
|
|
47
|
+
* else passes through.
|
|
48
48
|
*/
|
|
49
49
|
function toEngineConfig(escalation) {
|
|
50
|
-
if (!escalation || (escalation.schemaVersion == null && escalation.lookups == null)) {
|
|
50
|
+
if (!escalation || (escalation.schemaVersion == null && escalation.lookups == null && escalation.files == null)) {
|
|
51
51
|
return escalation;
|
|
52
52
|
}
|
|
53
|
-
const { schemaVersion, lookups, ...config } = escalation;
|
|
53
|
+
const { schemaVersion, lookups, files, ...config } = escalation;
|
|
54
54
|
if (lookups != null)
|
|
55
55
|
(0, escalation_1.assertLookupRefs)(lookups);
|
|
56
|
+
if (files != null)
|
|
57
|
+
(0, escalation_1.assertFileRefs)(files);
|
|
58
|
+
const envelope = {
|
|
59
|
+
...config.envelope,
|
|
60
|
+
...(lookups != null ? { [escalation_1.ESCALATION_ENVELOPE_KEYS.LOOKUPS]: lookups } : {}),
|
|
61
|
+
...(files != null ? { [escalation_1.ESCALATION_ENVELOPE_KEYS.FILES]: files } : {}),
|
|
62
|
+
};
|
|
56
63
|
return {
|
|
57
64
|
...config,
|
|
58
65
|
...(schemaVersion != null
|
|
59
66
|
? { metadata: { ...config.metadata, [escalation_1.ESCALATION_METADATA_KEYS.SCHEMA_VERSION]: schemaVersion } }
|
|
60
67
|
: {}),
|
|
61
|
-
...(lookups != null
|
|
62
|
-
? { envelope: { ...config.envelope, [escalation_1.ESCALATION_ENVELOPE_KEYS.LOOKUPS]: lookups } }
|
|
63
|
-
: {}),
|
|
68
|
+
...(lookups != null || files != null ? { envelope } : {}),
|
|
64
69
|
};
|
|
65
70
|
}
|
|
66
71
|
/**
|
|
@@ -120,6 +125,20 @@ function toEngineConfig(escalation) {
|
|
|
120
125
|
* });
|
|
121
126
|
* ```
|
|
122
127
|
*
|
|
128
|
+
* **Stored files: documents the form shows.** Each ref names an object in
|
|
129
|
+
* file storage and the address the form reads it at (`file.<as>`). The
|
|
130
|
+
* resolve UI fetches time-limited signed links when the page opens and again
|
|
131
|
+
* on claim; a `document` widget renders PDFs and images inline.
|
|
132
|
+
*
|
|
133
|
+
* ```typescript
|
|
134
|
+
* const decision = await conditional<IntakeReviewV1>(signalId, {
|
|
135
|
+
* role: 'intake-verifier',
|
|
136
|
+
* description: instructions,
|
|
137
|
+
* envelope: { formDefaults: extracted, confidence: scores },
|
|
138
|
+
* files: [{ path: `referrals/${referralId}.pdf`, as: 'referral' }],
|
|
139
|
+
* });
|
|
140
|
+
* ```
|
|
141
|
+
*
|
|
123
142
|
* **With an SLA (hotmesh 0.25.1+) — add `timeout` to the config.** The same
|
|
124
143
|
* single wait arms a resume timer alongside the escalation row: when the timer
|
|
125
144
|
* fires first, this helper returns `false`, the row transitions to
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Widgets that render from the escalation context and produce no answer of
|
|
3
|
-
* their own: navigation links, embedded records and lists,
|
|
4
|
-
*
|
|
3
|
+
* their own: navigation links, embedded records and lists, invoke controls,
|
|
4
|
+
* and stored documents. Their form slot exists only to place them in the layout, so
|
|
5
5
|
* the payload mapper drops them and the server never sees a value.
|
|
6
6
|
*/
|
|
7
7
|
export declare const DISPLAY_ONLY_WIDGET_NAMES: {
|
|
@@ -10,6 +10,7 @@ export declare const DISPLAY_ONLY_WIDGET_NAMES: {
|
|
|
10
10
|
readonly ESCALATION_LIST: "escalation-list";
|
|
11
11
|
readonly INVOKE: "invoke";
|
|
12
12
|
readonly ROSTER: "roster";
|
|
13
|
+
readonly DOCUMENT: "document";
|
|
13
14
|
};
|
|
14
15
|
export declare const DISPLAY_ONLY_WIDGETS: ReadonlySet<string>;
|
|
15
16
|
export declare function isDisplayOnlyWidget(name: unknown): boolean;
|
|
@@ -5,8 +5,8 @@ exports.isDisplayOnlyWidget = isDisplayOnlyWidget;
|
|
|
5
5
|
exports.isDisplayOnlyField = isDisplayOnlyField;
|
|
6
6
|
/**
|
|
7
7
|
* Widgets that render from the escalation context and produce no answer of
|
|
8
|
-
* their own: navigation links, embedded records and lists,
|
|
9
|
-
*
|
|
8
|
+
* their own: navigation links, embedded records and lists, invoke controls,
|
|
9
|
+
* and stored documents. Their form slot exists only to place them in the layout, so
|
|
10
10
|
* the payload mapper drops them and the server never sees a value.
|
|
11
11
|
*/
|
|
12
12
|
exports.DISPLAY_ONLY_WIDGET_NAMES = {
|
|
@@ -15,6 +15,7 @@ exports.DISPLAY_ONLY_WIDGET_NAMES = {
|
|
|
15
15
|
ESCALATION_LIST: 'escalation-list',
|
|
16
16
|
INVOKE: 'invoke',
|
|
17
17
|
ROSTER: 'roster',
|
|
18
|
+
DOCUMENT: 'document',
|
|
18
19
|
};
|
|
19
20
|
exports.DISPLAY_ONLY_WIDGETS = new Set(Object.values(exports.DISPLAY_ONLY_WIDGET_NAMES));
|
|
20
21
|
function isDisplayOnlyWidget(name) {
|
|
@@ -41,3 +41,5 @@ __exportStar(require("./x-lt-invoke"), exports);
|
|
|
41
41
|
__exportStar(require("./x-lt-scan"), exports);
|
|
42
42
|
__exportStar(require("./x-lt-roster"), exports);
|
|
43
43
|
__exportStar(require("./x-lt-actions"), exports);
|
|
44
|
+
__exportStar(require("./x-lt-confidence"), exports);
|
|
45
|
+
__exportStar(require("./x-lt-confidence-facets"), exports);
|