@hotmeshio/long-tail 0.10.2 → 0.10.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/build/api/bot-accounts.d.ts +4 -0
- package/build/api/bot-accounts.js +3 -1
- package/build/api/escalations/metadata.js +21 -1
- package/build/api/escalations/resolve.d.ts +8 -0
- package/build/api/escalations/resolve.js +82 -3
- package/build/api/roles.d.ts +2 -0
- package/build/api/roles.js +4 -0
- package/build/bin/ltc.js +10 -1
- package/build/index.js +7 -1
- package/build/lib/cli/client.d.ts +4 -1
- package/build/lib/cli/client.js +4 -2
- package/build/lib/db/schemas/023_role_enforce_schema.sql +18 -0
- package/build/lib/typed-resolution.d.ts +35 -0
- package/build/lib/typed-resolution.js +37 -0
- package/build/modules/branding.d.ts +21 -2
- package/build/modules/branding.js +22 -1
- package/build/modules/config.d.ts +1 -0
- package/build/modules/config.js +5 -0
- package/build/routes/bot-accounts.js +3 -1
- package/build/routes/settings.js +21 -0
- package/build/sdk/index.d.ts +4 -0
- package/build/sdk/index.js +14 -0
- package/build/services/escalation/crud.d.ts +18 -6
- package/build/services/escalation/crud.js +18 -2
- package/build/services/escalation/index.d.ts +1 -0
- package/build/services/escalation/index.js +1 -0
- package/build/services/escalation/resolver-validation.d.ts +28 -0
- package/build/services/escalation/resolver-validation.js +95 -0
- package/build/services/escalation/sql.d.ts +12 -2
- package/build/services/escalation/sql.js +22 -2
- package/build/services/iam/bots.d.ts +4 -1
- package/build/services/iam/bots.js +5 -3
- package/build/services/iam/sql.d.ts +2 -2
- package/build/services/iam/sql.js +15 -1
- package/build/services/role/enforcement-cache.d.ts +21 -0
- package/build/services/role/enforcement-cache.js +0 -0
- package/build/services/role/index.js +5 -0
- package/build/services/role/sql.d.ts +12 -2
- package/build/services/role/sql.js +15 -2
- package/build/services/role/types.d.ts +9 -0
- package/build/shared/form-validation/derive-field-label.d.ts +14 -0
- package/build/shared/form-validation/derive-field-label.js +31 -0
- package/build/shared/form-validation/field-validator.d.ts +45 -0
- package/build/shared/form-validation/field-validator.js +214 -0
- package/build/shared/form-validation/index.d.ts +12 -0
- package/build/shared/form-validation/index.js +28 -0
- package/build/shared/form-validation/validate-resolver-payload.d.ts +41 -0
- package/build/shared/form-validation/validate-resolver-payload.js +62 -0
- package/build/shared/form-validation/x-lt-bind.d.ts +41 -0
- package/build/shared/form-validation/x-lt-bind.js +110 -0
- package/build/shared/form-validation/x-lt-help.d.ts +21 -0
- package/build/shared/form-validation/x-lt-help.js +91 -0
- package/build/shared/form-validation/x-lt-show-if.d.ts +7 -0
- package/build/shared/form-validation/x-lt-show-if.js +84 -0
- package/build/system/mcp-servers/admin/schemas.d.ts +3 -0
- package/build/system/mcp-servers/admin/schemas.js +1 -0
- package/build/system/mcp-servers/admin/users.js +3 -1
- package/build/system/mcp-servers/human-queue-schemas.d.ts +4 -4
- package/build/system/mcp-servers/human-queue-schemas.js +4 -1
- package/build/system/mcp-servers/human-queue.js +41 -2
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/sdk.d.ts +6 -1
- package/build/types/startup.d.ts +26 -0
- package/build/types/validation.d.ts +43 -0
- package/build/types/validation.js +28 -0
- package/dashboard/dist/assets/{AdminDashboard-Dy031e9g.js → AdminDashboard-Cma2NGsF.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-Dy031e9g.js.map → AdminDashboard-Cma2NGsF.js.map} +1 -1
- package/dashboard/dist/assets/AgentConfigPage-CbIhM-fa.js +16 -0
- package/dashboard/dist/assets/AgentConfigPage-CbIhM-fa.js.map +1 -0
- package/dashboard/dist/assets/AgentDetailPage-DuLEKzRT.js +4 -0
- package/dashboard/dist/assets/AgentDetailPage-DuLEKzRT.js.map +1 -0
- package/dashboard/dist/assets/AgentsPage-DZO9i7Nl.js +2 -0
- package/dashboard/dist/assets/AgentsPage-DZO9i7Nl.js.map +1 -0
- package/dashboard/dist/assets/AvailableEscalationsPage-DlVoNd8B.js +2 -0
- package/dashboard/dist/assets/AvailableEscalationsPage-DlVoNd8B.js.map +1 -0
- package/dashboard/dist/assets/{BotPicker-2QEIpc-K.js → BotPicker-CidlGr6f.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-2QEIpc-K.js.map → BotPicker-CidlGr6f.js.map} +1 -1
- package/dashboard/dist/assets/CapabilitiesPage-BMNNTa0D.js +2 -0
- package/dashboard/dist/assets/{CapabilitiesPage-lQJGZ_-t.js.map → CapabilitiesPage-BMNNTa0D.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-CHWP0WI6.js → CollapsibleSection-W9F9lziT.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-CHWP0WI6.js.map → CollapsibleSection-W9F9lziT.js.map} +1 -1
- package/dashboard/dist/assets/ConfirmDeleteModal-BUh-Dzba.js +2 -0
- package/dashboard/dist/assets/{ConfirmDeleteModal-C0x0HcHX.js.map → ConfirmDeleteModal-BUh-Dzba.js.map} +1 -1
- package/dashboard/dist/assets/{CopyableId-uot2mE_g.js → CopyableId-B1mxKfVb.js} +2 -2
- package/dashboard/dist/assets/{CopyableId-uot2mE_g.js.map → CopyableId-B1mxKfVb.js.map} +1 -1
- package/dashboard/dist/assets/CountdownTimer-lkv_7msa.js +2 -0
- package/dashboard/dist/assets/{CountdownTimer-TXsRlTU4.js.map → CountdownTimer-lkv_7msa.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialsPage-BKxS-1sA.js → CredentialsPage-DyOgfnPB.js} +2 -2
- package/dashboard/dist/assets/CredentialsPage-DyOgfnPB.js.map +1 -0
- package/dashboard/dist/assets/{CronLabel-Bd2G0Rap.js → CronLabel-geum95dj.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-Bd2G0Rap.js.map → CronLabel-geum95dj.js.map} +1 -1
- package/dashboard/dist/assets/CustomDurationPicker-ClufO2ew.js +2 -0
- package/dashboard/dist/assets/CustomDurationPicker-ClufO2ew.js.map +1 -0
- package/dashboard/dist/assets/DataTable-BTu2AaEl.js +2 -0
- package/dashboard/dist/assets/DataTable-BTu2AaEl.js.map +1 -0
- package/dashboard/dist/assets/{DropZone-DNDEgMpJ.js → DropZone-C3hOjJtC.js} +2 -2
- package/dashboard/dist/assets/{DropZone-DNDEgMpJ.js.map → DropZone-C3hOjJtC.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-g7GO7f8L.js → ElapsedCell-DFOW9T4b.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-g7GO7f8L.js.map → ElapsedCell-DFOW9T4b.js.map} +1 -1
- package/dashboard/dist/assets/EscalationListSchemaPage-_IhqXIQu.js +20 -0
- package/dashboard/dist/assets/EscalationListSchemaPage-_IhqXIQu.js.map +1 -0
- package/dashboard/dist/assets/EscalationSchemaPage-BCC7iscN.js +9 -0
- package/dashboard/dist/assets/EscalationSchemaPage-BCC7iscN.js.map +1 -0
- package/dashboard/dist/assets/EscalationsOverview-CvIdOtoP.js +2 -0
- package/dashboard/dist/assets/EscalationsOverview-CvIdOtoP.js.map +1 -0
- package/dashboard/dist/assets/EventTable-DJWJ7J0m.js +2 -0
- package/dashboard/dist/assets/EventTable-DJWJ7J0m.js.map +1 -0
- package/dashboard/dist/assets/FilterBar-BR3ztZ8y.js +2 -0
- package/dashboard/dist/assets/FilterBar-BR3ztZ8y.js.map +1 -0
- package/dashboard/dist/assets/GraphInvokePage-Cwn-8Glr.js +2 -0
- package/dashboard/dist/assets/GraphInvokePage-Cwn-8Glr.js.map +1 -0
- package/dashboard/dist/assets/HomePage-D8RVntg0.js +2 -0
- package/dashboard/dist/assets/HomePage-D8RVntg0.js.map +1 -0
- package/dashboard/dist/assets/ListToolbar-DuoEdVtK.js +2 -0
- package/dashboard/dist/assets/ListToolbar-DuoEdVtK.js.map +1 -0
- package/dashboard/dist/assets/McpOverview-NXKsGiWU.js +2 -0
- package/dashboard/dist/assets/McpOverview-NXKsGiWU.js.map +1 -0
- package/dashboard/dist/assets/McpQueryDetailPage-BC-iXfIx.js +5 -0
- package/dashboard/dist/assets/McpQueryDetailPage-BC-iXfIx.js.map +1 -0
- package/dashboard/dist/assets/{McpQueryPage-CsKNXUhb.js → McpQueryPage-BPJmFYOY.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-CsKNXUhb.js.map → McpQueryPage-BPJmFYOY.js.map} +1 -1
- package/dashboard/dist/assets/McpRunDetailPage-B49nUXEl.js +2 -0
- package/dashboard/dist/assets/McpRunDetailPage-B49nUXEl.js.map +1 -0
- package/dashboard/dist/assets/McpRunsPage-Ce_XIYpP.js +2 -0
- package/dashboard/dist/assets/McpRunsPage-Ce_XIYpP.js.map +1 -0
- package/dashboard/dist/assets/NamespacePill-LWvZXt_g.js +2 -0
- package/dashboard/dist/assets/NamespacePill-LWvZXt_g.js.map +1 -0
- package/dashboard/dist/assets/OperationsPage-DI7AQO9f.js +2 -0
- package/dashboard/dist/assets/OperationsPage-DI7AQO9f.js.map +1 -0
- package/dashboard/dist/assets/OperatorDashboard-DpXjhs-3.js +2 -0
- package/dashboard/dist/assets/{OperatorDashboard-_axS17fp.js.map → OperatorDashboard-DpXjhs-3.js.map} +1 -1
- package/dashboard/dist/assets/PageHeader-DvEmMMP6.js +2 -0
- package/dashboard/dist/assets/PageHeader-DvEmMMP6.js.map +1 -0
- package/dashboard/dist/assets/PageHeaderWithStats-X0eAmu-x.js +2 -0
- package/dashboard/dist/assets/PageHeaderWithStats-X0eAmu-x.js.map +1 -0
- package/dashboard/dist/assets/{PriorityBadge-B4ykBH7f.js → PriorityBadge-CCERr9vQ.js} +2 -2
- package/dashboard/dist/assets/PriorityBadge-CCERr9vQ.js.map +1 -0
- package/dashboard/dist/assets/ProcessDetailPage-DpYSMRj1.js +2 -0
- package/dashboard/dist/assets/ProcessDetailPage-DpYSMRj1.js.map +1 -0
- package/dashboard/dist/assets/{ProcessesListPage-CoQEi_Su.js → ProcessesListPage-CQ9tSw7U.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-CoQEi_Su.js.map → ProcessesListPage-CQ9tSw7U.js.map} +1 -1
- package/dashboard/dist/assets/RoleDetailPage-DKeQKDkW.js +8 -0
- package/dashboard/dist/assets/RoleDetailPage-DKeQKDkW.js.map +1 -0
- package/dashboard/dist/assets/RolePill-CWhoLwef.js +2 -0
- package/dashboard/dist/assets/RolePill-CWhoLwef.js.map +1 -0
- package/dashboard/dist/assets/RolesPage-D-6kIact.js +2 -0
- package/dashboard/dist/assets/RolesPage-D-6kIact.js.map +1 -0
- package/dashboard/dist/assets/RunAsSelector-DzYcpQTm.js +2 -0
- package/dashboard/dist/assets/RunAsSelector-DzYcpQTm.js.map +1 -0
- package/dashboard/dist/assets/StatCard-DBANWIss.js +2 -0
- package/dashboard/dist/assets/StatCard-DBANWIss.js.map +1 -0
- package/dashboard/dist/assets/StatusBadge-BbqghFMi.js +2 -0
- package/dashboard/dist/assets/StatusBadge-BbqghFMi.js.map +1 -0
- package/dashboard/dist/assets/{StickyPagination-Cd83AHd_.js → StickyPagination-BTGfmGV3.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-Cd83AHd_.js.map → StickyPagination-BTGfmGV3.js.map} +1 -1
- package/dashboard/dist/assets/StreamMessageDetail-DqRpzA_6.js +2 -0
- package/dashboard/dist/assets/StreamMessageDetail-DqRpzA_6.js.map +1 -0
- package/dashboard/dist/assets/SwimlaneTimeline-CA106TYo.js +2 -0
- package/dashboard/dist/assets/SwimlaneTimeline-CA106TYo.js.map +1 -0
- package/dashboard/dist/assets/TagInput-CoR4MzsW.js +2 -0
- package/dashboard/dist/assets/TagInput-CoR4MzsW.js.map +1 -0
- package/dashboard/dist/assets/{TaskDetailPage-DnjhW7qv.js → TaskDetailPage-BRg-w2Ev.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-DnjhW7qv.js.map → TaskDetailPage-BRg-w2Ev.js.map} +1 -1
- package/dashboard/dist/assets/TaskQueuePill-Dw3YN8M-.js +2 -0
- package/dashboard/dist/assets/TaskQueuePill-Dw3YN8M-.js.map +1 -0
- package/dashboard/dist/assets/{TasksListPage-DySfZFgs.js → TasksListPage-kB_j9G8o.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-DySfZFgs.js.map → TasksListPage-kB_j9G8o.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-BKOl-7Tt.js → TimeAgo-D7dSIY7-.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-BKOl-7Tt.js.map → TimeAgo-D7dSIY7-.js.map} +1 -1
- package/dashboard/dist/assets/TimestampCell-BZe6bx18.js +2 -0
- package/dashboard/dist/assets/TimestampCell-BZe6bx18.js.map +1 -0
- package/dashboard/dist/assets/ToolPill-xX-buQtY.js +2 -0
- package/dashboard/dist/assets/ToolPill-xX-buQtY.js.map +1 -0
- package/dashboard/dist/assets/ToolTestPanel-U3NaF_T_.js +2 -0
- package/dashboard/dist/assets/ToolTestPanel-U3NaF_T_.js.map +1 -0
- package/dashboard/dist/assets/TopicDetailPage-BpALvXP1.js +9 -0
- package/dashboard/dist/assets/TopicDetailPage-BpALvXP1.js.map +1 -0
- package/dashboard/dist/assets/TopicsPage-Cy3chaca.js +2 -0
- package/dashboard/dist/assets/{TopicsPage-5yW63ELl.js.map → TopicsPage-Cy3chaca.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-DcXhOSVm.js → UserName-VXM1oHMC.js} +2 -2
- package/dashboard/dist/assets/{UserName-DcXhOSVm.js.map → UserName-VXM1oHMC.js.map} +1 -1
- package/dashboard/dist/assets/WorkflowExecutionPage-BCq2cR1V.js +2 -0
- package/dashboard/dist/assets/WorkflowExecutionPage-BCq2cR1V.js.map +1 -0
- package/dashboard/dist/assets/WorkflowPill-CQ1AmhlC.js +2 -0
- package/dashboard/dist/assets/WorkflowPill-CQ1AmhlC.js.map +1 -0
- package/dashboard/dist/assets/{WorkflowsDashboard-C0Bbrd5M.js → WorkflowsDashboard-BbM69MnB.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-C0Bbrd5M.js.map → WorkflowsDashboard-BbM69MnB.js.map} +1 -1
- package/dashboard/dist/assets/WorkflowsOverview-D5HthpAW.js +2 -0
- package/dashboard/dist/assets/WorkflowsOverview-D5HthpAW.js.map +1 -0
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-BcbrYhDI.js → YamlWorkflowDetailPage-CDDVMYWi.js} +10 -10
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-BcbrYhDI.js.map → YamlWorkflowDetailPage-CDDVMYWi.js.map} +1 -1
- package/dashboard/dist/assets/YamlWorkflowsPage-FFjWwydj.js +2 -0
- package/dashboard/dist/assets/YamlWorkflowsPage-FFjWwydj.js.map +1 -0
- package/dashboard/dist/assets/{agents-CopQ3t5o.js → agents-BwiSNu73.js} +2 -2
- package/dashboard/dist/assets/{agents-CopQ3t5o.js.map → agents-BwiSNu73.js.map} +1 -1
- package/dashboard/dist/assets/bots-ClgSrxel.js +2 -0
- package/dashboard/dist/assets/bots-ClgSrxel.js.map +1 -0
- package/dashboard/dist/assets/{capabilities-5JRieYUy.js → capabilities-JUaKsby4.js} +2 -2
- package/dashboard/dist/assets/{capabilities-5JRieYUy.js.map → capabilities-JUaKsby4.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-B4rT6tIw.js → controlplane-CuTQ7eUE.js} +2 -2
- package/dashboard/dist/assets/{controlplane-B4rT6tIw.js.map → controlplane-CuTQ7eUE.js.map} +1 -1
- package/dashboard/dist/assets/escalation-columns-CS0c7cAr.js +2 -0
- package/dashboard/dist/assets/escalation-columns-CS0c7cAr.js.map +1 -0
- package/dashboard/dist/assets/index-BBA4AxmL.js +2 -0
- package/dashboard/dist/assets/index-BBA4AxmL.js.map +1 -0
- package/dashboard/dist/assets/index-C-8xXyvr.js +63 -0
- package/dashboard/dist/assets/index-C-8xXyvr.js.map +1 -0
- package/dashboard/dist/assets/index-C1t0YIXC.js +5 -0
- package/dashboard/dist/assets/index-C1t0YIXC.js.map +1 -0
- package/dashboard/dist/assets/index-C9o2UNhC.js +2 -0
- package/dashboard/dist/assets/index-C9o2UNhC.js.map +1 -0
- package/dashboard/dist/assets/index-CBj-vstO.js +2 -0
- package/dashboard/dist/assets/{index-Dd1RxGNw.js.map → index-CBj-vstO.js.map} +1 -1
- package/dashboard/dist/assets/index-CUguKMXZ.js +2 -0
- package/dashboard/dist/assets/index-CUguKMXZ.js.map +1 -0
- package/dashboard/dist/assets/index-Cavwd8UU.js +6 -0
- package/dashboard/dist/assets/index-Cavwd8UU.js.map +1 -0
- package/dashboard/dist/assets/index-CnsPBTXL.js +2 -0
- package/dashboard/dist/assets/index-CnsPBTXL.js.map +1 -0
- package/dashboard/dist/assets/index-CoPWHo_H.js +2 -0
- package/dashboard/dist/assets/index-CoPWHo_H.js.map +1 -0
- package/dashboard/dist/assets/index-CwQVaa7x.js +2 -0
- package/dashboard/dist/assets/index-CwQVaa7x.js.map +1 -0
- package/dashboard/dist/assets/index-DSa-6Ux8.js +2 -0
- package/dashboard/dist/assets/index-DSa-6Ux8.js.map +1 -0
- package/dashboard/dist/assets/index-DeMs_aBT.css +1 -0
- package/dashboard/dist/assets/index-Ikj_NTuy.js +5 -0
- package/dashboard/dist/assets/index-Ikj_NTuy.js.map +1 -0
- package/dashboard/dist/assets/index-Xd1jcHe7.js +2 -0
- package/dashboard/dist/assets/index-Xd1jcHe7.js.map +1 -0
- package/dashboard/dist/assets/{knowledge-B9bmoXOe.js → knowledge-BHBt-6kW.js} +2 -2
- package/dashboard/dist/assets/{knowledge-B9bmoXOe.js.map → knowledge-BHBt-6kW.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-DYMFBOFz.js → mcp-CBcz4BCS.js} +2 -2
- package/dashboard/dist/assets/{mcp-DYMFBOFz.js.map → mcp-CBcz4BCS.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-wloSpyPM.js → mcp-query-C4fKTOYo.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-wloSpyPM.js.map → mcp-query-C4fKTOYo.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-DBXX6TEi.js → pipelines-CmAAH3B6.js} +2 -2
- package/dashboard/dist/assets/{pipelines-DBXX6TEi.js.map → pipelines-CmAAH3B6.js.map} +1 -1
- package/dashboard/dist/assets/role-display-Dvo2lDpU.js +2 -0
- package/dashboard/dist/assets/role-display-Dvo2lDpU.js.map +1 -0
- package/dashboard/dist/assets/task-queues-7-sHKPsN.js +2 -0
- package/dashboard/dist/assets/task-queues-7-sHKPsN.js.map +1 -0
- package/dashboard/dist/assets/{tasks-CD3-C7tP.js → tasks-BAEsqcz2.js} +2 -2
- package/dashboard/dist/assets/{tasks-CD3-C7tP.js.map → tasks-BAEsqcz2.js.map} +1 -1
- package/dashboard/dist/assets/{topics-D8pKi6zA.js → topics-CY0pJ6_o.js} +2 -2
- package/dashboard/dist/assets/{topics-D8pKi6zA.js.map → topics-CY0pJ6_o.js.map} +1 -1
- package/dashboard/dist/assets/{useEventHooks-DV9pLDOW.js → useEventHooks-BlpwRvHO.js} +2 -2
- package/dashboard/dist/assets/{useEventHooks-DV9pLDOW.js.map → useEventHooks-BlpwRvHO.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-DykYhZY9.js → useNamespace-CoNUlZ6Z.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-DykYhZY9.js.map → useNamespace-CoNUlZ6Z.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-By044UAv.js → useYamlActivityEvents-8GUn5Wie.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-By044UAv.js.map → useYamlActivityEvents-8GUn5Wie.js.map} +1 -1
- package/dashboard/dist/assets/{users-mI9goDjj.js → users-uGtDRGxR.js} +2 -2
- package/dashboard/dist/assets/{users-mI9goDjj.js.map → users-uGtDRGxR.js.map} +1 -1
- package/dashboard/dist/assets/{vendor-icons-ihWGa7_d.js → vendor-icons-DKCAtTJ9.js} +135 -130
- package/dashboard/dist/assets/vendor-icons-DKCAtTJ9.js.map +1 -0
- package/dashboard/dist/assets/{workflows-DCUilz68.js → workflows-DoX-AtHN.js} +2 -2
- package/dashboard/dist/assets/{workflows-DCUilz68.js.map → workflows-DoX-AtHN.js.map} +1 -1
- package/dashboard/dist/assets/{yaml-workflows-DWNMP1PT.js → yaml-workflows-DM3jVem2.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-DWNMP1PT.js.map → yaml-workflows-DM3jVem2.js.map} +1 -1
- package/dashboard/dist/index.html +3 -3
- package/docs/api/http/escalations.md +15 -1
- package/docs/api/http/roles.md +2 -0
- package/docs/design-principles.md +234 -0
- package/docs/hitl/design.md +228 -0
- package/docs/hitl/form.md +21 -1
- package/docs/hitl/iframe.md +1 -1
- package/docs/hitl/x-lt-display.md +56 -0
- package/docs/hitl/x-lt-layout.md +20 -1
- package/docs/hitl/x-lt-list-schema.md +8 -1
- package/docs/hitl/x-lt-widget.md +23 -0
- package/docs/hitl-guide.md +4 -2
- package/docs/schema-enforcement.md +149 -0
- package/package.json +1 -1
- package/dashboard/dist/assets/AgentConfigPage-CqmtYBbC.js +0 -16
- package/dashboard/dist/assets/AgentConfigPage-CqmtYBbC.js.map +0 -1
- package/dashboard/dist/assets/AgentDetailPage-oYLBrN74.js +0 -4
- package/dashboard/dist/assets/AgentDetailPage-oYLBrN74.js.map +0 -1
- package/dashboard/dist/assets/AgentsPage-CHczRx5N.js +0 -2
- package/dashboard/dist/assets/AgentsPage-CHczRx5N.js.map +0 -1
- package/dashboard/dist/assets/AvailableEscalationsPage-DDVuivEE.js +0 -2
- package/dashboard/dist/assets/AvailableEscalationsPage-DDVuivEE.js.map +0 -1
- package/dashboard/dist/assets/CapabilitiesPage-lQJGZ_-t.js +0 -2
- package/dashboard/dist/assets/ConfirmDeleteModal-C0x0HcHX.js +0 -2
- package/dashboard/dist/assets/CountdownTimer-TXsRlTU4.js +0 -2
- package/dashboard/dist/assets/CredentialsPage-BKxS-1sA.js.map +0 -1
- package/dashboard/dist/assets/CustomDurationPicker-j4bBrDJ6.js +0 -2
- package/dashboard/dist/assets/CustomDurationPicker-j4bBrDJ6.js.map +0 -1
- package/dashboard/dist/assets/DataTable-Byn3oyT9.js +0 -2
- package/dashboard/dist/assets/DataTable-Byn3oyT9.js.map +0 -1
- package/dashboard/dist/assets/EscalationListSchemaPage-CIJ-OgVC.js +0 -20
- package/dashboard/dist/assets/EscalationListSchemaPage-CIJ-OgVC.js.map +0 -1
- package/dashboard/dist/assets/EscalationSchemaPage-C7dHgG8e.js +0 -9
- package/dashboard/dist/assets/EscalationSchemaPage-C7dHgG8e.js.map +0 -1
- package/dashboard/dist/assets/EscalationsOverview-D8NrATg2.js +0 -2
- package/dashboard/dist/assets/EscalationsOverview-D8NrATg2.js.map +0 -1
- package/dashboard/dist/assets/EventTable-DBV1P2ME.js +0 -2
- package/dashboard/dist/assets/EventTable-DBV1P2ME.js.map +0 -1
- package/dashboard/dist/assets/FilterBar-B5Vk5tBF.js +0 -2
- package/dashboard/dist/assets/FilterBar-B5Vk5tBF.js.map +0 -1
- package/dashboard/dist/assets/GraphInvokePage-DbHvggQ_.js +0 -2
- package/dashboard/dist/assets/GraphInvokePage-DbHvggQ_.js.map +0 -1
- package/dashboard/dist/assets/HomePage-BpexnDO_.js +0 -2
- package/dashboard/dist/assets/HomePage-BpexnDO_.js.map +0 -1
- package/dashboard/dist/assets/ListToolbar-KC6LGtKP.js +0 -2
- package/dashboard/dist/assets/ListToolbar-KC6LGtKP.js.map +0 -1
- package/dashboard/dist/assets/McpOverview-BDZC9Hvl.js +0 -2
- package/dashboard/dist/assets/McpOverview-BDZC9Hvl.js.map +0 -1
- package/dashboard/dist/assets/McpQueryDetailPage-CXhgX1pS.js +0 -5
- package/dashboard/dist/assets/McpQueryDetailPage-CXhgX1pS.js.map +0 -1
- package/dashboard/dist/assets/McpRunDetailPage-BM3mUSlH.js +0 -2
- package/dashboard/dist/assets/McpRunDetailPage-BM3mUSlH.js.map +0 -1
- package/dashboard/dist/assets/McpRunsPage-f5hDbpLo.js +0 -2
- package/dashboard/dist/assets/McpRunsPage-f5hDbpLo.js.map +0 -1
- package/dashboard/dist/assets/NamespacePill-C4u6Go1W.js +0 -2
- package/dashboard/dist/assets/NamespacePill-C4u6Go1W.js.map +0 -1
- package/dashboard/dist/assets/OperationsPage-D37cZ8Qh.js +0 -2
- package/dashboard/dist/assets/OperationsPage-D37cZ8Qh.js.map +0 -1
- package/dashboard/dist/assets/OperatorDashboard-_axS17fp.js +0 -2
- package/dashboard/dist/assets/PageHeader-Bxa1XFz0.js +0 -2
- package/dashboard/dist/assets/PageHeader-Bxa1XFz0.js.map +0 -1
- package/dashboard/dist/assets/PageHeaderWithStats-D_sO0MqJ.js +0 -2
- package/dashboard/dist/assets/PageHeaderWithStats-D_sO0MqJ.js.map +0 -1
- package/dashboard/dist/assets/PriorityBadge-B4ykBH7f.js.map +0 -1
- package/dashboard/dist/assets/ProcessDetailPage-D8pAWUXx.js +0 -2
- package/dashboard/dist/assets/ProcessDetailPage-D8pAWUXx.js.map +0 -1
- package/dashboard/dist/assets/RoleDetailPage-ufbypNNR.js +0 -8
- package/dashboard/dist/assets/RoleDetailPage-ufbypNNR.js.map +0 -1
- package/dashboard/dist/assets/RolePill-DLwmVMam.js +0 -2
- package/dashboard/dist/assets/RolePill-DLwmVMam.js.map +0 -1
- package/dashboard/dist/assets/RolesPage-CxpXm4Sw.js +0 -2
- package/dashboard/dist/assets/RolesPage-CxpXm4Sw.js.map +0 -1
- package/dashboard/dist/assets/RunAsSelector-BebF8Lib.js +0 -2
- package/dashboard/dist/assets/RunAsSelector-BebF8Lib.js.map +0 -1
- package/dashboard/dist/assets/SlidePanel-BDVDuwIf.js +0 -2
- package/dashboard/dist/assets/SlidePanel-BDVDuwIf.js.map +0 -1
- package/dashboard/dist/assets/StatCard-DrdlUeQz.js +0 -2
- package/dashboard/dist/assets/StatCard-DrdlUeQz.js.map +0 -1
- package/dashboard/dist/assets/StatusBadge-CEQMRmSQ.js +0 -2
- package/dashboard/dist/assets/StatusBadge-CEQMRmSQ.js.map +0 -1
- package/dashboard/dist/assets/StreamMessageDetail-BIXbrZM0.js +0 -2
- package/dashboard/dist/assets/StreamMessageDetail-BIXbrZM0.js.map +0 -1
- package/dashboard/dist/assets/SwimlaneTimeline-CC5qZjYo.js +0 -2
- package/dashboard/dist/assets/SwimlaneTimeline-CC5qZjYo.js.map +0 -1
- package/dashboard/dist/assets/TagInput-C2gi47M8.js +0 -2
- package/dashboard/dist/assets/TagInput-C2gi47M8.js.map +0 -1
- package/dashboard/dist/assets/TaskQueuePill-BPP0Almh.js +0 -2
- package/dashboard/dist/assets/TaskQueuePill-BPP0Almh.js.map +0 -1
- package/dashboard/dist/assets/TimestampCell-DGOsba-A.js +0 -2
- package/dashboard/dist/assets/TimestampCell-DGOsba-A.js.map +0 -1
- package/dashboard/dist/assets/ToolPill-D74TkYB-.js +0 -2
- package/dashboard/dist/assets/ToolPill-D74TkYB-.js.map +0 -1
- package/dashboard/dist/assets/ToolTestPanel-Bez6OyRL.js +0 -2
- package/dashboard/dist/assets/ToolTestPanel-Bez6OyRL.js.map +0 -1
- package/dashboard/dist/assets/TopicDetailPage-BHccgkU_.js +0 -9
- package/dashboard/dist/assets/TopicDetailPage-BHccgkU_.js.map +0 -1
- package/dashboard/dist/assets/TopicsPage-5yW63ELl.js +0 -2
- package/dashboard/dist/assets/WorkflowExecutionPage-CDDLled5.js +0 -2
- package/dashboard/dist/assets/WorkflowExecutionPage-CDDLled5.js.map +0 -1
- package/dashboard/dist/assets/WorkflowPill-Fjc2q9U9.js +0 -2
- package/dashboard/dist/assets/WorkflowPill-Fjc2q9U9.js.map +0 -1
- package/dashboard/dist/assets/WorkflowsOverview-D8MkSMex.js +0 -2
- package/dashboard/dist/assets/WorkflowsOverview-D8MkSMex.js.map +0 -1
- package/dashboard/dist/assets/YamlWorkflowsPage-9Ki54d-9.js +0 -2
- package/dashboard/dist/assets/YamlWorkflowsPage-9Ki54d-9.js.map +0 -1
- package/dashboard/dist/assets/bots-CAYJYL9E.js +0 -2
- package/dashboard/dist/assets/bots-CAYJYL9E.js.map +0 -1
- package/dashboard/dist/assets/escalation-columns-BbS5X61l.js +0 -2
- package/dashboard/dist/assets/escalation-columns-BbS5X61l.js.map +0 -1
- package/dashboard/dist/assets/index-B68A3v-S.js +0 -2
- package/dashboard/dist/assets/index-B68A3v-S.js.map +0 -1
- package/dashboard/dist/assets/index-BAi89Xpm.js +0 -2
- package/dashboard/dist/assets/index-BAi89Xpm.js.map +0 -1
- package/dashboard/dist/assets/index-BJ0jjFsI.js +0 -5
- package/dashboard/dist/assets/index-BJ0jjFsI.js.map +0 -1
- package/dashboard/dist/assets/index-BOJMUk4F.js +0 -2
- package/dashboard/dist/assets/index-BOJMUk4F.js.map +0 -1
- package/dashboard/dist/assets/index-BrgYykPV.js +0 -2
- package/dashboard/dist/assets/index-BrgYykPV.js.map +0 -1
- package/dashboard/dist/assets/index-BxgtIqvl.js +0 -2
- package/dashboard/dist/assets/index-BxgtIqvl.js.map +0 -1
- package/dashboard/dist/assets/index-C0cHXaX-.css +0 -1
- package/dashboard/dist/assets/index-CDHDoHYz.js +0 -6
- package/dashboard/dist/assets/index-CDHDoHYz.js.map +0 -1
- package/dashboard/dist/assets/index-CUZJHXew.js +0 -2
- package/dashboard/dist/assets/index-CUZJHXew.js.map +0 -1
- package/dashboard/dist/assets/index-D5n_e59T.js +0 -2
- package/dashboard/dist/assets/index-D5n_e59T.js.map +0 -1
- package/dashboard/dist/assets/index-DIgiIoou.js +0 -63
- package/dashboard/dist/assets/index-DIgiIoou.js.map +0 -1
- package/dashboard/dist/assets/index-Dd1RxGNw.js +0 -2
- package/dashboard/dist/assets/index-iOb3sGsC.js +0 -5
- package/dashboard/dist/assets/index-iOb3sGsC.js.map +0 -1
- package/dashboard/dist/assets/index-mcAkQblr.js +0 -2
- package/dashboard/dist/assets/index-mcAkQblr.js.map +0 -1
- package/dashboard/dist/assets/vendor-icons-ihWGa7_d.js.map +0 -1
package/README.md
CHANGED
|
@@ -231,6 +231,7 @@ All modes share PostgreSQL and scale independently. See [Cloud Deployment](https
|
|
|
231
231
|
| [Compiler](https://github.com/hotmeshio/long-tail/blob/main/docs/compiler.md) | `ltc compile` — durable TypeScript to YAML DAGs |
|
|
232
232
|
| [CLI](https://github.com/hotmeshio/long-tail/blob/main/docs/cli.md) | `ltc` — terminal access to workflows, escalations, knowledge, MCP |
|
|
233
233
|
| [Escalation Strategies](https://github.com/hotmeshio/long-tail/blob/main/docs/escalation-strategies.md) | Default, MCP triage, custom handlers |
|
|
234
|
+
| [Schema Enforcement](https://github.com/hotmeshio/long-tail/blob/main/docs/schema-enforcement.md) | form_schema as an enforced API contract on every resolve surface |
|
|
234
235
|
| [Faceted Routing](https://github.com/hotmeshio/long-tail/blob/main/docs/faceted-routing.md) | Query and atomically claim the queue by facets; dispatcher pattern |
|
|
235
236
|
| [SDK](https://github.com/hotmeshio/long-tail/blob/main/docs/sdk.md) | Embedded usage, `createClient`, event subscriptions |
|
|
236
237
|
| [Architecture](https://github.com/hotmeshio/long-tail/blob/main/docs/architecture.md) | Project structure, conventions, discovery |
|
|
@@ -4,11 +4,15 @@ import type { LTApiResult, LTApiAuth } from '../types/sdk';
|
|
|
4
4
|
*
|
|
5
5
|
* @param input.limit — maximum number of bots to return (default 50)
|
|
6
6
|
* @param input.offset — number of bots to skip for pagination (default 0)
|
|
7
|
+
* @param input.status — filter by account status
|
|
8
|
+
* @param input.search — free-text match on display name, external id, or description
|
|
7
9
|
* @returns `{ status: 200, data: Bot[] }` paginated list of bots
|
|
8
10
|
*/
|
|
9
11
|
export declare function listBots(input: {
|
|
10
12
|
limit?: number;
|
|
11
13
|
offset?: number;
|
|
14
|
+
status?: string;
|
|
15
|
+
search?: string;
|
|
12
16
|
}): Promise<LTApiResult>;
|
|
13
17
|
/**
|
|
14
18
|
* Retrieve a single bot account by ID.
|
|
@@ -51,13 +51,15 @@ const user_1 = require("../services/user");
|
|
|
51
51
|
*
|
|
52
52
|
* @param input.limit — maximum number of bots to return (default 50)
|
|
53
53
|
* @param input.offset — number of bots to skip for pagination (default 0)
|
|
54
|
+
* @param input.status — filter by account status
|
|
55
|
+
* @param input.search — free-text match on display name, external id, or description
|
|
54
56
|
* @returns `{ status: 200, data: Bot[] }` paginated list of bots
|
|
55
57
|
*/
|
|
56
58
|
async function listBots(input) {
|
|
57
59
|
try {
|
|
58
60
|
const limit = input.limit ?? 50;
|
|
59
61
|
const offset = input.offset ?? 0;
|
|
60
|
-
const result = await iam.listBots(limit, offset);
|
|
62
|
+
const result = await iam.listBots(limit, offset, { status: input.status, search: input.search });
|
|
61
63
|
return { status: 200, data: result };
|
|
62
64
|
}
|
|
63
65
|
catch (err) {
|
|
@@ -38,6 +38,9 @@ exports.claimByMetadata = claimByMetadata;
|
|
|
38
38
|
exports.resolveByMetadata = resolveByMetadata;
|
|
39
39
|
const escalationService = __importStar(require("../../services/escalation"));
|
|
40
40
|
const helpers_1 = require("./helpers");
|
|
41
|
+
const resolver_validation_1 = require("../../services/escalation/resolver-validation");
|
|
42
|
+
const enforcement_cache_1 = require("../../services/role/enforcement-cache");
|
|
43
|
+
const resolve_1 = require("./resolve");
|
|
41
44
|
/**
|
|
42
45
|
* Find escalations by a metadata key-value pair.
|
|
43
46
|
*
|
|
@@ -130,7 +133,24 @@ async function resolveByMetadata(input, auth) {
|
|
|
130
133
|
const writeScope = await (0, helpers_1.getEscalationWriteScope)(auth.userId);
|
|
131
134
|
const writeAllRoles = writeScope.global ? null : writeScope.allRoles;
|
|
132
135
|
const writeSelfRoles = writeScope.global ? null : writeScope.selfRoles;
|
|
133
|
-
|
|
136
|
+
// Schema enforcement rides the atomic statement: with the cached enforcing
|
|
137
|
+
// set empty (the common case) the single-call behavior is unchanged. When
|
|
138
|
+
// the picked row's role enforces, the statement returns the row WITHOUT
|
|
139
|
+
// writing; the payload validates here, then a second asserted pass claims
|
|
140
|
+
// + resolves the same row with pending re-checked inside the statement.
|
|
141
|
+
const enforcing = await (0, enforcement_cache_1.getEnforcingRoles)();
|
|
142
|
+
let result = await escalationService.resolveByMetadataAtomic(input.key, input.value, resolveUserId, input.resolverPayload, input.metadata, writeAllRoles, writeSelfRoles, enforcing.size > 0 ? [...enforcing] : null);
|
|
143
|
+
if (result.outcome === 'validation_required' && result.row) {
|
|
144
|
+
const report = await (0, resolver_validation_1.checkResolverPayload)(result.row, input.resolverPayload);
|
|
145
|
+
if (report)
|
|
146
|
+
return (0, resolve_1.validationFailure)(report);
|
|
147
|
+
result = await escalationService.resolveByMetadataAtomic(input.key, input.value, resolveUserId, input.resolverPayload, input.metadata, writeAllRoles, writeSelfRoles, null, result.row.id);
|
|
148
|
+
// The asserted row left pending between the two passes — a concurrent
|
|
149
|
+
// resolution won the row; surface it as the conflict it is.
|
|
150
|
+
if (result.outcome === 'not_found') {
|
|
151
|
+
return { status: 409, error: 'A concurrent resolution is already in progress for this escalation' };
|
|
152
|
+
}
|
|
153
|
+
}
|
|
134
154
|
if (result.outcome === 'not_found') {
|
|
135
155
|
return { status: 404, error: 'No pending escalation found for this metadata, or insufficient role permissions' };
|
|
136
156
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ResolverSchemaViolationReport } from '../../services/escalation/resolver-validation';
|
|
1
2
|
import type { LTApiResult, LTApiAuth } from '../../types/sdk';
|
|
2
3
|
/**
|
|
3
4
|
* Resolve a pending escalation with a human-provided payload.
|
|
@@ -72,3 +73,10 @@ export declare function resolveAllOrNone(input: {
|
|
|
72
73
|
metadata?: Record<string, any>;
|
|
73
74
|
requireClaimed?: boolean;
|
|
74
75
|
}, auth: LTApiAuth): Promise<LTApiResult>;
|
|
76
|
+
/**
|
|
77
|
+
* The canonical 422 for a schema-validation rejection. The full body rides in
|
|
78
|
+
* `data` (routes serialize `data ?? { error }`), so every transport — HTTP,
|
|
79
|
+
* SDK, CLI, dashboard — receives the same shape: error, code, violations,
|
|
80
|
+
* role, schemaVersion. `code` also sits on the envelope for SDK branching.
|
|
81
|
+
*/
|
|
82
|
+
export declare function validationFailure(report: ResolverSchemaViolationReport): LTApiResult;
|
|
@@ -37,6 +37,7 @@ exports.resolveEscalation = resolveEscalation;
|
|
|
37
37
|
exports.resolveBySignalKey = resolveBySignalKey;
|
|
38
38
|
exports.resolveByIds = resolveByIds;
|
|
39
39
|
exports.resolveAllOrNone = resolveAllOrNone;
|
|
40
|
+
exports.validationFailure = validationFailure;
|
|
40
41
|
const escalationService = __importStar(require("../../services/escalation"));
|
|
41
42
|
const taskService = __importStar(require("../../services/task"));
|
|
42
43
|
const escalation_strategy_1 = require("../../services/escalation-strategy");
|
|
@@ -45,6 +46,8 @@ const deployer_1 = require("../../services/yaml-workflow/deployer");
|
|
|
45
46
|
const workers_1 = require("../../workers");
|
|
46
47
|
const defaults_1 = require("../../modules/defaults");
|
|
47
48
|
const helpers_1 = require("./helpers");
|
|
49
|
+
const resolver_validation_1 = require("../../services/escalation/resolver-validation");
|
|
50
|
+
const enforcement_cache_1 = require("../../services/role/enforcement-cache");
|
|
48
51
|
// ── Orchestrator ─────────────────────────────────────────────────────────
|
|
49
52
|
/**
|
|
50
53
|
* Resolve a pending escalation with a human-provided payload.
|
|
@@ -90,6 +93,13 @@ async function resolveEscalation(input, auth) {
|
|
|
90
93
|
const stale = (0, helpers_1.assertLiveClaimant)(auth.userId, escalation);
|
|
91
94
|
if (stale)
|
|
92
95
|
return stale;
|
|
96
|
+
// Schema enforcement (enforce_schema roles): validate the payload against
|
|
97
|
+
// the escalation's resolved form schema BEFORE any resolution path runs.
|
|
98
|
+
// Costs nothing when the role does not enforce (cached role set); the
|
|
99
|
+
// task-fallback envelope read only happens for enforcing roles.
|
|
100
|
+
const violation = await (0, resolver_validation_1.checkResolverPayload)(escalation, resolverPayload, () => reconstructEnvelope(escalation));
|
|
101
|
+
if (violation)
|
|
102
|
+
return validationFailure(violation);
|
|
93
103
|
// The resolver payload is stored exactly as submitted — its shape is the
|
|
94
104
|
// workflow's contract, formed by the caller (the React app maps the form to
|
|
95
105
|
// the payload via x-lt-bind before submitting). No server-side transform.
|
|
@@ -161,6 +171,11 @@ async function resolveBySignalKey(input, auth) {
|
|
|
161
171
|
const denied = await (0, helpers_1.assertWriteAccess)(auth.userId, escalation);
|
|
162
172
|
if (denied)
|
|
163
173
|
return { status: 404, error: 'Escalation not found' };
|
|
174
|
+
// Schema enforcement — the row (envelope included) is already loaded, so
|
|
175
|
+
// this costs zero extra reads beyond the cached schema.
|
|
176
|
+
const violation = await (0, resolver_validation_1.checkResolverPayload)(escalation, resolverPayload);
|
|
177
|
+
if (violation)
|
|
178
|
+
return validationFailure(violation);
|
|
164
179
|
// The payload is delivered as the signal the parked workflow's condition()
|
|
165
180
|
// receives — stored exactly as submitted (the caller formed its shape).
|
|
166
181
|
return resolveViaSignalKey(escalation, resolverPayload, metadata);
|
|
@@ -195,17 +210,39 @@ async function resolveByIds(input, auth) {
|
|
|
195
210
|
// resolve any item in the role; write_self roles may resolve only items assigned
|
|
196
211
|
// to the caller (same rule single-resolve applies via assertWriteAccess). Global
|
|
197
212
|
// bypasses. A missing id or any out-of-scope item → 404 (non-disclosure), and
|
|
198
|
-
// nothing is resolved.
|
|
213
|
+
// nothing is resolved. The scope-row read is shared with the enforcement
|
|
214
|
+
// gate below — one indexed read serves both.
|
|
199
215
|
const writeScope = await (0, helpers_1.getEscalationWriteScope)(auth.userId);
|
|
216
|
+
const enforcing = await (0, enforcement_cache_1.getEnforcingRoles)();
|
|
217
|
+
let scopeRows = null;
|
|
200
218
|
if (!writeScope.global) {
|
|
201
219
|
const allSet = new Set(writeScope.allRoles);
|
|
202
220
|
const selfSet = new Set(writeScope.selfRoles);
|
|
203
|
-
|
|
221
|
+
scopeRows = await escalationService.getEscalationScopeRows(ids);
|
|
204
222
|
const writable = (r) => allSet.has(r.role) || (selfSet.has(r.role) && r.assigned_to === auth.userId);
|
|
205
|
-
if (
|
|
223
|
+
if (scopeRows.length !== ids.length || !scopeRows.every(writable)) {
|
|
206
224
|
return { status: 404, error: 'One or more escalations not found' };
|
|
207
225
|
}
|
|
208
226
|
}
|
|
227
|
+
// Schema enforcement (enforce_schema roles): with the cached enforcing set
|
|
228
|
+
// empty this path adds zero reads. Otherwise the scope rows identify which
|
|
229
|
+
// targets enforce, and only those rows load in full for validation — the
|
|
230
|
+
// one payload is validated against each enforcing row's own context.
|
|
231
|
+
if (enforcing.size > 0) {
|
|
232
|
+
const rows = scopeRows ?? await escalationService.getEscalationScopeRows(ids);
|
|
233
|
+
const involved = rows.filter((r) => enforcing.has(r.role)).map((r) => r.id);
|
|
234
|
+
if (involved.length > 0) {
|
|
235
|
+
const fullRows = await escalationService.getEscalationsByIds(involved);
|
|
236
|
+
const failed = [];
|
|
237
|
+
for (const row of fullRows) {
|
|
238
|
+
const report = await (0, resolver_validation_1.checkResolverPayload)(row, resolverPayload);
|
|
239
|
+
if (report)
|
|
240
|
+
failed.push({ id: row.id, report });
|
|
241
|
+
}
|
|
242
|
+
if (failed.length > 0)
|
|
243
|
+
return bulkValidationFailure(failed);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
209
246
|
const resolved = await escalationService.resolveEscalationsByIds(ids, resolverPayload, metadata);
|
|
210
247
|
return { status: 200, data: { resolved: resolved.length, escalationIds: resolved.map((e) => e.id) } };
|
|
211
248
|
}
|
|
@@ -286,6 +323,24 @@ async function resolveAllOrNone(input, auth) {
|
|
|
286
323
|
const error = 'One or more escalations require the single-resolve path (legacy signal routing)';
|
|
287
324
|
return { status: 409, error, data: { error, failedIds: failed.map((f) => f.id), failed } };
|
|
288
325
|
}
|
|
326
|
+
// Schema enforcement (enforce_schema roles): every item validates against
|
|
327
|
+
// its own row's context before ANYTHING resolves — all-or-none extends to
|
|
328
|
+
// validation. Rows are already in hand, so the only added reads are the
|
|
329
|
+
// cached schemas of enforcing roles.
|
|
330
|
+
const enforcing = await (0, enforcement_cache_1.getEnforcingRoles)();
|
|
331
|
+
if (enforcing.size > 0) {
|
|
332
|
+
const failed = [];
|
|
333
|
+
for (const item of items) {
|
|
334
|
+
const row = rowById.get(item.id);
|
|
335
|
+
if (!row || !row.role || !enforcing.has(row.role))
|
|
336
|
+
continue;
|
|
337
|
+
const report = await (0, resolver_validation_1.checkResolverPayload)(row, item.resolverPayload);
|
|
338
|
+
if (report)
|
|
339
|
+
failed.push({ id: item.id, report });
|
|
340
|
+
}
|
|
341
|
+
if (failed.length > 0)
|
|
342
|
+
return bulkValidationFailure(failed);
|
|
343
|
+
}
|
|
289
344
|
// Per-row password redaction against each row's own form schema — the
|
|
290
345
|
// payload enters the signal store and the audit record; plaintext never.
|
|
291
346
|
const serviceItems = await Promise.all(items.map(async (item) => ({
|
|
@@ -448,6 +503,30 @@ function signaledResult(escalation, workflowId) {
|
|
|
448
503
|
data: { signaled: true, escalationId: escalation.id, workflowId },
|
|
449
504
|
};
|
|
450
505
|
}
|
|
506
|
+
/**
|
|
507
|
+
* The canonical 422 for a schema-validation rejection. The full body rides in
|
|
508
|
+
* `data` (routes serialize `data ?? { error }`), so every transport — HTTP,
|
|
509
|
+
* SDK, CLI, dashboard — receives the same shape: error, code, violations,
|
|
510
|
+
* role, schemaVersion. `code` also sits on the envelope for SDK branching.
|
|
511
|
+
*/
|
|
512
|
+
function validationFailure(report) {
|
|
513
|
+
const body = (0, resolver_validation_1.toValidationErrorBody)(report);
|
|
514
|
+
return { status: 422, error: body.error, code: body.code, data: body };
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* The bulk-surface 422: violations from every failing row, each tagged with
|
|
518
|
+
* its escalationId so callers can attribute them. Role/schemaVersion echo the
|
|
519
|
+
* first failing report (bulk resolves target homogeneous role groups).
|
|
520
|
+
*/
|
|
521
|
+
function bulkValidationFailure(failed) {
|
|
522
|
+
const violations = failed.flatMap(({ id, report }) => report.violations.map((v) => ({ ...v, escalationId: id })));
|
|
523
|
+
const body = {
|
|
524
|
+
...(0, resolver_validation_1.toValidationErrorBody)(failed[0].report),
|
|
525
|
+
error: `resolverPayload failed schema validation for ${failed.length} escalation${failed.length === 1 ? '' : 's'} (${violations.length} violation${violations.length === 1 ? '' : 's'})`,
|
|
526
|
+
violations,
|
|
527
|
+
};
|
|
528
|
+
return { status: 422, error: body.error, code: body.code, data: body };
|
|
529
|
+
}
|
|
451
530
|
/** Replace password fields with ephemeral tokens so plaintext never enters the signal store. */
|
|
452
531
|
async function redactPasswords(payload, formSchema) {
|
|
453
532
|
if (!formSchema?.properties)
|
package/build/api/roles.d.ts
CHANGED
|
@@ -104,6 +104,8 @@ export declare function updateRole(input: {
|
|
|
104
104
|
priority_threshold_minutes?: number | null;
|
|
105
105
|
/** Escalation metadata key holding the age origin (ISO 8601 UTC timestamp). Falls back to created_at. */
|
|
106
106
|
priority_facet?: string | null;
|
|
107
|
+
/** Turn server-side resolver schema validation on/off for this role. */
|
|
108
|
+
enforce_schema?: boolean;
|
|
107
109
|
/** Replace the upstream-input set (omitted = preserve; null or [] = clear). */
|
|
108
110
|
upstream_roles?: string[] | null;
|
|
109
111
|
/** Recorded on the schema snapshot when this update changes a schema field. */
|
package/build/api/roles.js
CHANGED
|
@@ -225,6 +225,9 @@ async function updateRole(input) {
|
|
|
225
225
|
if (input.ops_visible !== undefined && typeof input.ops_visible !== 'boolean') {
|
|
226
226
|
return { status: 400, error: 'ops_visible must be a boolean' };
|
|
227
227
|
}
|
|
228
|
+
if (input.enforce_schema !== undefined && typeof input.enforce_schema !== 'boolean') {
|
|
229
|
+
return { status: 400, error: 'enforce_schema must be a boolean' };
|
|
230
|
+
}
|
|
228
231
|
if (input.parent_role != null && input.parent_role === input.role) {
|
|
229
232
|
return { status: 400, error: 'parent_role must reference a different role' };
|
|
230
233
|
}
|
|
@@ -265,6 +268,7 @@ async function updateRole(input) {
|
|
|
265
268
|
worker_count: input.worker_count,
|
|
266
269
|
priority_threshold_minutes: input.priority_threshold_minutes,
|
|
267
270
|
priority_facet: input.priority_facet,
|
|
271
|
+
enforce_schema: input.enforce_schema,
|
|
268
272
|
upstream_roles: input.upstream_roles,
|
|
269
273
|
change_summary: input.change_summary,
|
|
270
274
|
});
|
package/build/bin/ltc.js
CHANGED
|
@@ -62,7 +62,16 @@ const envLoaded = fs.existsSync(envPath);
|
|
|
62
62
|
// ── Error handler ────────────────────────────────────────────────────────
|
|
63
63
|
function handleError(err) {
|
|
64
64
|
const msg = err.message || String(err);
|
|
65
|
-
console.error(`\n ${picocolors_1.default.red('✗')} ${msg}
|
|
65
|
+
console.error(`\n ${picocolors_1.default.red('✗')} ${msg}`);
|
|
66
|
+
// Schema-validation rejections carry field-level violations — print each
|
|
67
|
+
// one the way the dashboard's errors panel lists them.
|
|
68
|
+
if (Array.isArray(err.violations)) {
|
|
69
|
+
for (const v of err.violations) {
|
|
70
|
+
const where = v.escalationId ? `${v.escalationId} · ${v.field}` : v.field;
|
|
71
|
+
console.error(` ${picocolors_1.default.dim('·')} ${picocolors_1.default.bold(where)} — ${v.message}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
console.error('');
|
|
66
75
|
process.exit(1);
|
|
67
76
|
}
|
|
68
77
|
function wrap(fn) {
|
package/build/index.js
CHANGED
|
@@ -40,6 +40,7 @@ exports.registerMcpTool = exports.getToolContext = exports.getActivityIdentity =
|
|
|
40
40
|
exports.LTExpressAdapter = exports.api = exports.KnowledgeApi = exports.resolveCredential = exports.mimeFromPath = exports.getStorageBackend = exports.listOAuthConnections = exports.getFreshAccessToken = exports.createClient = exports.CallbackEventAdapter = exports.builtinMcpServerFactories = exports.getSystemAgents = exports.getSystemWorkers = void 0;
|
|
41
41
|
const config_1 = require("./modules/config");
|
|
42
42
|
const logger_1 = require("./lib/logger");
|
|
43
|
+
const midnight_1 = require("./examples/themes/midnight");
|
|
43
44
|
const start_1 = require("./start");
|
|
44
45
|
// ─── Package Exports ─────────────────────────────────────────────────────────
|
|
45
46
|
var start_2 = require("./start");
|
|
@@ -170,7 +171,12 @@ async function main() {
|
|
|
170
171
|
escalation: {
|
|
171
172
|
strategy: 'mcp',
|
|
172
173
|
},
|
|
173
|
-
branding:
|
|
174
|
+
branding: {
|
|
175
|
+
...(process.env.WHITE_LABEL ? { appName: process.env.WHITE_LABEL } : {}),
|
|
176
|
+
// Midnight ships as a registered theme — the working proof that a
|
|
177
|
+
// deployment-supplied stylesheet controls the entire design system.
|
|
178
|
+
themes: [midnight_1.midnightTheme],
|
|
179
|
+
},
|
|
174
180
|
telemetry: honeycombKey ? { honeycomb: { apiKey: honeycombKey } } : undefined,
|
|
175
181
|
events: config_1.config.EVENT_TRANSPORT === 'nats'
|
|
176
182
|
? { nats: { url: config_1.config.NATS_URL, wsUrl: config_1.config.NATS_WS_URL || undefined, token: config_1.config.NATS_TOKEN || undefined } }
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { type LTFieldViolation } from '../../types/validation';
|
|
1
2
|
export declare class CLIError extends Error {
|
|
2
3
|
status?: number | undefined;
|
|
3
|
-
|
|
4
|
+
/** Field-level violations from a schema_validation 422, when present. */
|
|
5
|
+
violations?: LTFieldViolation[];
|
|
6
|
+
constructor(message: string, status?: number | undefined, violations?: LTFieldViolation[]);
|
|
4
7
|
}
|
|
5
8
|
/** Authenticated fetch against the Long Tail API */
|
|
6
9
|
export declare function apiFetch<T = any>(path: string, options?: RequestInit): Promise<T>;
|
package/build/lib/cli/client.js
CHANGED
|
@@ -3,11 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.CLIError = void 0;
|
|
4
4
|
exports.apiFetch = apiFetch;
|
|
5
5
|
const auth_1 = require("./auth");
|
|
6
|
+
const validation_1 = require("../../types/validation");
|
|
6
7
|
class CLIError extends Error {
|
|
7
|
-
constructor(message, status) {
|
|
8
|
+
constructor(message, status, violations) {
|
|
8
9
|
super(message);
|
|
9
10
|
this.status = status;
|
|
10
11
|
this.name = 'CLIError';
|
|
12
|
+
this.violations = violations;
|
|
11
13
|
}
|
|
12
14
|
}
|
|
13
15
|
exports.CLIError = CLIError;
|
|
@@ -25,7 +27,7 @@ async function apiFetch(path, options) {
|
|
|
25
27
|
});
|
|
26
28
|
const body = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
|
|
27
29
|
if (!res.ok) {
|
|
28
|
-
throw new CLIError(body.error || `HTTP ${res.status}`, res.status);
|
|
30
|
+
throw new CLIError(body.error || `HTTP ${res.status}`, res.status, (0, validation_1.isValidationErrorBody)(body) ? body.violations : undefined);
|
|
29
31
|
}
|
|
30
32
|
return body;
|
|
31
33
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
-- Migration 023: Role-level resolver schema enforcement
|
|
2
|
+
--
|
|
3
|
+
-- enforce_schema makes the role's form_schema an enforced API contract: every
|
|
4
|
+
-- resolve surface (by id, by signal key, by ids, all-or-none, by metadata, and
|
|
5
|
+
-- the MCP resolve tools) validates the submitted resolverPayload against the
|
|
6
|
+
-- escalation's resolved form schema (metadata.form_schema override, else the
|
|
7
|
+
-- pinned lt_role_schemas snapshot, else the role's latest) and rejects
|
|
8
|
+
-- violations with 422 before any state changes. The validation pass is the
|
|
9
|
+
-- same isomorphic code the dashboard runs pre-submission, so a payload that
|
|
10
|
+
-- passes the client panel passes the gate and a 422 carries the identical
|
|
11
|
+
-- field-error list.
|
|
12
|
+
--
|
|
13
|
+
-- Opt-in per role (default false) so surfaces migrate deliberately: flip it on
|
|
14
|
+
-- a role once its submitters (dashboard, sim workforce, webhooks) are known to
|
|
15
|
+
-- send complete payloads. Roles with it off resolve exactly as before.
|
|
16
|
+
|
|
17
|
+
ALTER TABLE lt_roles
|
|
18
|
+
ADD COLUMN IF NOT EXISTS enforce_schema BOOLEAN NOT NULL DEFAULT false;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed resolution parsing — the workflow-side half of the resolver contract.
|
|
3
|
+
*
|
|
4
|
+
* Server-side enforcement (enforce_schema roles) guarantees a resolution
|
|
5
|
+
* matched the role's form schema when it was submitted. This module gives
|
|
6
|
+
* workflow and activity code the consuming half: declare the payload shape
|
|
7
|
+
* once as a zod schema, and parse the resolution through it to get a TYPED
|
|
8
|
+
* value with runtime assurance — a drifted or legacy payload fails loud here
|
|
9
|
+
* instead of propagating `any` into business logic.
|
|
10
|
+
*
|
|
11
|
+
* const IntakeV1 = z.object({ customer: z.object({ name: z.string() }) });
|
|
12
|
+
* const intake = parseResolverPayload(IntakeV1, response);
|
|
13
|
+
* intake.customer.name; // typed AND runtime-checked
|
|
14
|
+
*/
|
|
15
|
+
import type { ZodType } from 'zod';
|
|
16
|
+
import type { LTFieldViolation } from '../types/validation';
|
|
17
|
+
/**
|
|
18
|
+
* A resolution that failed its declared zod schema. Carries the same
|
|
19
|
+
* `{ field, message }` violation list the validation surfaces use, and the
|
|
20
|
+
* original ZodError as `cause`.
|
|
21
|
+
*/
|
|
22
|
+
export declare class ResolverPayloadTypeError extends Error {
|
|
23
|
+
violations: LTFieldViolation[];
|
|
24
|
+
cause?: unknown;
|
|
25
|
+
constructor(violations: LTFieldViolation[], options?: {
|
|
26
|
+
cause?: unknown;
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Parse a resolution payload through its declared zod schema. Returns the
|
|
31
|
+
* typed value; throws {@link ResolverPayloadTypeError} when the payload does
|
|
32
|
+
* not conform. The generic flows from the schema to the return value — no
|
|
33
|
+
* casting at the call site.
|
|
34
|
+
*/
|
|
35
|
+
export declare function parseResolverPayload<T>(schema: ZodType<T>, payload: unknown): T;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ResolverPayloadTypeError = void 0;
|
|
4
|
+
exports.parseResolverPayload = parseResolverPayload;
|
|
5
|
+
/**
|
|
6
|
+
* A resolution that failed its declared zod schema. Carries the same
|
|
7
|
+
* `{ field, message }` violation list the validation surfaces use, and the
|
|
8
|
+
* original ZodError as `cause`.
|
|
9
|
+
*/
|
|
10
|
+
class ResolverPayloadTypeError extends Error {
|
|
11
|
+
constructor(violations, options) {
|
|
12
|
+
const n = violations.length;
|
|
13
|
+
super(`resolver payload failed its declared schema (${n} violation${n === 1 ? '' : 's'}): `
|
|
14
|
+
+ violations.map((v) => `${v.field}: ${v.message}`).join('; '));
|
|
15
|
+
this.name = 'ResolverPayloadTypeError';
|
|
16
|
+
this.violations = violations;
|
|
17
|
+
this.cause = options?.cause;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
exports.ResolverPayloadTypeError = ResolverPayloadTypeError;
|
|
21
|
+
/**
|
|
22
|
+
* Parse a resolution payload through its declared zod schema. Returns the
|
|
23
|
+
* typed value; throws {@link ResolverPayloadTypeError} when the payload does
|
|
24
|
+
* not conform. The generic flows from the schema to the return value — no
|
|
25
|
+
* casting at the call site.
|
|
26
|
+
*/
|
|
27
|
+
function parseResolverPayload(schema, payload) {
|
|
28
|
+
const result = schema.safeParse(payload);
|
|
29
|
+
if (!result.success) {
|
|
30
|
+
const violations = result.error.issues.map((issue) => ({
|
|
31
|
+
field: issue.path.length > 0 ? issue.path.join('.') : '(root)',
|
|
32
|
+
message: issue.message,
|
|
33
|
+
}));
|
|
34
|
+
throw new ResolverPayloadTypeError(violations, { cause: result.error });
|
|
35
|
+
}
|
|
36
|
+
return result.data;
|
|
37
|
+
}
|
|
@@ -4,10 +4,29 @@
|
|
|
4
4
|
* The `appName` defaults to 'LongTail' and can be overridden via the
|
|
5
5
|
* `branding` block of the `start()` config — no env-var required, since
|
|
6
6
|
* this is a per-deployment product decision, not an ops toggle.
|
|
7
|
+
*
|
|
8
|
+
* `customCss` and `themes` carry the deployment's design-system overrides.
|
|
9
|
+
* Theme metadata (id, label, swatch, dark) rides the /api/settings JSON so
|
|
10
|
+
* the picker can render; the CSS itself is served separately at
|
|
11
|
+
* GET /api/settings/custom.css so the browser caches it as a stylesheet.
|
|
7
12
|
*/
|
|
8
|
-
export
|
|
13
|
+
export interface LTBrandingTheme {
|
|
14
|
+
id: string;
|
|
15
|
+
label: string;
|
|
16
|
+
swatch: string;
|
|
17
|
+
css: string;
|
|
18
|
+
dark?: boolean;
|
|
19
|
+
}
|
|
20
|
+
export interface LTBrandingConfig {
|
|
9
21
|
appName?: string;
|
|
10
|
-
|
|
22
|
+
customCss?: string;
|
|
23
|
+
themes?: LTBrandingTheme[];
|
|
24
|
+
}
|
|
25
|
+
export declare function configureBranding(patch?: LTBrandingConfig): void;
|
|
26
|
+
/** Metadata only — the CSS never rides the settings JSON. */
|
|
11
27
|
export declare function getBranding(): {
|
|
12
28
|
appName: string;
|
|
29
|
+
themes: Array<Omit<LTBrandingTheme, 'css'>>;
|
|
13
30
|
};
|
|
31
|
+
/** The full stylesheet served at /api/settings/custom.css. */
|
|
32
|
+
export declare function getCustomCss(): string;
|
|
@@ -5,15 +5,36 @@
|
|
|
5
5
|
* The `appName` defaults to 'LongTail' and can be overridden via the
|
|
6
6
|
* `branding` block of the `start()` config — no env-var required, since
|
|
7
7
|
* this is a per-deployment product decision, not an ops toggle.
|
|
8
|
+
*
|
|
9
|
+
* `customCss` and `themes` carry the deployment's design-system overrides.
|
|
10
|
+
* Theme metadata (id, label, swatch, dark) rides the /api/settings JSON so
|
|
11
|
+
* the picker can render; the CSS itself is served separately at
|
|
12
|
+
* GET /api/settings/custom.css so the browser caches it as a stylesheet.
|
|
8
13
|
*/
|
|
9
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
15
|
exports.configureBranding = configureBranding;
|
|
11
16
|
exports.getBranding = getBranding;
|
|
17
|
+
exports.getCustomCss = getCustomCss;
|
|
12
18
|
let _appName = 'LongTail';
|
|
19
|
+
let _customCss = '';
|
|
20
|
+
let _themes = [];
|
|
13
21
|
function configureBranding(patch) {
|
|
14
22
|
if (patch?.appName)
|
|
15
23
|
_appName = patch.appName;
|
|
24
|
+
if (typeof patch?.customCss === 'string')
|
|
25
|
+
_customCss = patch.customCss;
|
|
26
|
+
if (Array.isArray(patch?.themes))
|
|
27
|
+
_themes = patch.themes;
|
|
16
28
|
}
|
|
29
|
+
/** Metadata only — the CSS never rides the settings JSON. */
|
|
17
30
|
function getBranding() {
|
|
18
|
-
return {
|
|
31
|
+
return {
|
|
32
|
+
appName: _appName,
|
|
33
|
+
themes: _themes.map(({ id, label, swatch, dark }) => ({ id, label, swatch, dark })),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/** The full stylesheet served at /api/settings/custom.css. */
|
|
37
|
+
function getCustomCss() {
|
|
38
|
+
const parts = [_customCss, ..._themes.map((t) => t.css)].filter(Boolean);
|
|
39
|
+
return parts.join('\n\n');
|
|
19
40
|
}
|
package/build/modules/config.js
CHANGED
|
@@ -19,6 +19,11 @@ exports.config = {
|
|
|
19
19
|
NODE_ENV: process.env.NODE_ENV || 'development',
|
|
20
20
|
JWT_SECRET: process.env.JWT_SECRET || '',
|
|
21
21
|
HONEYCOMB_API_KEY: process.env.HONEYCOMB_API_KEY || '',
|
|
22
|
+
// Resolver schema enforcement: TTL for the cached enforcing-role set and
|
|
23
|
+
// latest role form schemas. Bounds cross-container staleness after a role
|
|
24
|
+
// admin flips enforce_schema or edits a schema; pinned snapshots are
|
|
25
|
+
// immutable and cache indefinitely.
|
|
26
|
+
ROLE_ENFORCEMENT_CACHE_TTL_MS: parseInt(process.env.ROLE_ENFORCEMENT_CACHE_TTL_MS || '30000', 10),
|
|
22
27
|
};
|
|
23
28
|
exports.postgres_options = {
|
|
24
29
|
host: exports.config.POSTGRES_HOST,
|
|
@@ -43,12 +43,14 @@ router.use(auth_1.requireBuilder);
|
|
|
43
43
|
/**
|
|
44
44
|
* GET /api/bot-accounts
|
|
45
45
|
* List all bot accounts.
|
|
46
|
-
* Query: ?limit=50&offset=0
|
|
46
|
+
* Query: ?limit=50&offset=0&status=active&search=mcp
|
|
47
47
|
*/
|
|
48
48
|
router.get('/', async (req, res) => {
|
|
49
49
|
const result = await api.listBots({
|
|
50
50
|
limit: req.query.limit ? parseInt(req.query.limit, 10) : undefined,
|
|
51
51
|
offset: req.query.offset ? parseInt(req.query.offset, 10) : undefined,
|
|
52
|
+
status: req.query.status || undefined,
|
|
53
|
+
search: req.query.search || undefined,
|
|
52
54
|
});
|
|
53
55
|
res.status(result.status).json(result.data ?? { error: result.error });
|
|
54
56
|
});
|
package/build/routes/settings.js
CHANGED
|
@@ -33,8 +33,10 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const crypto_1 = require("crypto");
|
|
36
37
|
const express_1 = require("express");
|
|
37
38
|
const api = __importStar(require("../api/settings"));
|
|
39
|
+
const branding_1 = require("../modules/branding");
|
|
38
40
|
const router = (0, express_1.Router)();
|
|
39
41
|
/**
|
|
40
42
|
* GET /api/settings
|
|
@@ -44,4 +46,23 @@ router.get('/', async (req, res) => {
|
|
|
44
46
|
const result = await api.getSettings(req);
|
|
45
47
|
res.status(result.status).json(result.data ?? { error: result.error });
|
|
46
48
|
});
|
|
49
|
+
/**
|
|
50
|
+
* GET /api/settings/custom.css
|
|
51
|
+
* The deployment's registered design-system overrides (branding.customCss +
|
|
52
|
+
* registered theme blocks). Always 200 text/css — empty when nothing is
|
|
53
|
+
* registered — so the dashboard references it unconditionally with no flash
|
|
54
|
+
* and no conditional logic. ETag lets the browser cache it across loads.
|
|
55
|
+
*/
|
|
56
|
+
router.get('/custom.css', (req, res) => {
|
|
57
|
+
const css = (0, branding_1.getCustomCss)();
|
|
58
|
+
const etag = `"${(0, crypto_1.createHash)('sha1').update(css).digest('hex')}"`;
|
|
59
|
+
if (req.headers['if-none-match'] === etag) {
|
|
60
|
+
res.status(304).end();
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
res.setHeader('Content-Type', 'text/css; charset=utf-8');
|
|
64
|
+
res.setHeader('ETag', etag);
|
|
65
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
66
|
+
res.status(200).send(css);
|
|
67
|
+
});
|
|
47
68
|
exports.default = router;
|
package/build/sdk/index.d.ts
CHANGED
|
@@ -466,3 +466,7 @@ export declare function createClient(options?: LTClientOptions): {
|
|
|
466
466
|
};
|
|
467
467
|
/** The return type of createClient(). */
|
|
468
468
|
export type LTClient = ReturnType<typeof createClient>;
|
|
469
|
+
export { LT_ERROR_CODES, isValidationErrorBody, } from '../types/validation';
|
|
470
|
+
export type { LTErrorCode, LTFieldViolation, LTValidationErrorBody, } from '../types/validation';
|
|
471
|
+
export type { LTApiAuth, LTApiResult } from '../types/sdk';
|
|
472
|
+
export { parseResolverPayload, ResolverPayloadTypeError } from '../lib/typed-resolution';
|
package/build/sdk/index.js
CHANGED
|
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.ResolverPayloadTypeError = exports.parseResolverPayload = exports.isValidationErrorBody = exports.LT_ERROR_CODES = void 0;
|
|
36
37
|
exports.createClient = createClient;
|
|
37
38
|
const tasksApi = __importStar(require("../api/tasks"));
|
|
38
39
|
const escalationsApi = __importStar(require("../api/escalations"));
|
|
@@ -365,3 +366,16 @@ function createClient(options = {}) {
|
|
|
365
366
|
},
|
|
366
367
|
};
|
|
367
368
|
}
|
|
369
|
+
// ── Canonical error shapes ──────────────────────────────────────────────
|
|
370
|
+
// A 422 from any resolve surface carries the full LTValidationErrorBody in
|
|
371
|
+
// `result.data` with `result.code === LT_ERROR_CODES.SCHEMA_VALIDATION`.
|
|
372
|
+
// `isValidationErrorBody(result.data)` narrows it for typed handling.
|
|
373
|
+
var validation_1 = require("../types/validation");
|
|
374
|
+
Object.defineProperty(exports, "LT_ERROR_CODES", { enumerable: true, get: function () { return validation_1.LT_ERROR_CODES; } });
|
|
375
|
+
Object.defineProperty(exports, "isValidationErrorBody", { enumerable: true, get: function () { return validation_1.isValidationErrorBody; } });
|
|
376
|
+
// ── Typed resolution parsing ────────────────────────────────────────────
|
|
377
|
+
// Workflow/activity code declares its payload shape as a zod schema and
|
|
378
|
+
// parses resolutions through it — typed values with runtime assurance.
|
|
379
|
+
var typed_resolution_1 = require("../lib/typed-resolution");
|
|
380
|
+
Object.defineProperty(exports, "parseResolverPayload", { enumerable: true, get: function () { return typed_resolution_1.parseResolverPayload; } });
|
|
381
|
+
Object.defineProperty(exports, "ResolverPayloadTypeError", { enumerable: true, get: function () { return typed_resolution_1.ResolverPayloadTypeError; } });
|