@hotmeshio/long-tail 0.24.2 → 0.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/api/escalations/accumulate.js +8 -4
- package/build/api/escalations/metadata.js +4 -3
- package/build/api/escalations/related.d.ts +1 -1
- package/build/api/escalations/related.js +28 -18
- package/build/services/domain/seed.d.ts +12 -10
- package/build/services/domain/seed.js +31 -25
- package/build/services/escalation/accumulate.d.ts +3 -1
- package/build/services/escalation/facet-sql.js +4 -2
- package/build/services/escalation/index.d.ts +1 -0
- package/build/services/escalation/index.js +4 -1
- package/build/services/escalation/related-extremes.d.ts +17 -0
- package/build/services/escalation/related-extremes.js +65 -0
- package/build/services/escalation/related.d.ts +4 -0
- package/build/services/escalation/related.js +2 -0
- package/build/services/escalation/resolver-validation.js +7 -0
- package/build/services/escalation/roster.d.ts +13 -0
- package/build/services/escalation/roster.js +37 -0
- package/build/services/escalation/submit-guard.d.ts +3 -0
- package/build/services/escalation/submit-guard.js +21 -2
- package/build/services/mcp/server-tools.js +1 -1
- package/build/shared/form-validation/display-only-widgets.d.ts +1 -0
- package/build/shared/form-validation/display-only-widgets.js +1 -0
- package/build/shared/form-validation/index.d.ts +1 -0
- package/build/shared/form-validation/index.js +1 -0
- package/build/shared/form-validation/validate-resolver-payload.d.ts +1 -0
- package/build/shared/form-validation/validate-resolver-payload.js +2 -1
- package/build/shared/form-validation/x-lt-help.d.ts +1 -1
- package/build/shared/form-validation/x-lt-help.js +2 -1
- package/build/shared/form-validation/x-lt-roster.d.ts +92 -0
- package/build/shared/form-validation/x-lt-roster.js +253 -0
- package/build/shared/form-validation/x-lt-show-if.d.ts +8 -0
- package/build/shared/form-validation/x-lt-show-if.js +13 -0
- package/build/shared/form-validation/x-lt-submit-guard.d.ts +14 -1
- package/build/shared/form-validation/x-lt-submit-guard.js +4 -1
- package/build/shared/list-schema/aggregate.d.ts +19 -0
- package/build/shared/list-schema/aggregate.js +66 -0
- package/build/shared/list-schema/index.d.ts +2 -0
- package/build/shared/list-schema/index.js +7 -1
- package/build/shared/list-schema/types.d.ts +15 -2
- package/build/shared/list-schema/types.js +6 -1
- package/build/shared/list-schema/validate.js +28 -2
- package/build/start/workers.d.ts +3 -0
- package/build/start/workers.js +15 -5
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/startup.d.ts +8 -1
- package/dashboard/dist/assets/{AdminDashboard-B3mkMIOT.js → AdminDashboard-C_0ShYrm.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-B3mkMIOT.js.map → AdminDashboard-C_0ShYrm.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-CQj2B678.js → AgentConfigPage-Cc9dI8lO.js} +6 -6
- package/dashboard/dist/assets/{AgentConfigPage-CQj2B678.js.map → AgentConfigPage-Cc9dI8lO.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-CzrD8JJI.js → AgentDetailPage-Sdmt5j-k.js} +3 -3
- package/dashboard/dist/assets/{AgentDetailPage-CzrD8JJI.js.map → AgentDetailPage-Sdmt5j-k.js.map} +1 -1
- package/dashboard/dist/assets/{AgentsPage-jg2OFwyW.js → AgentsPage-BuzXc1mg.js} +2 -2
- package/dashboard/dist/assets/{AgentsPage-jg2OFwyW.js.map → AgentsPage-BuzXc1mg.js.map} +1 -1
- package/dashboard/dist/assets/AvailableEscalationsPage-DU84iaBN.js +2 -0
- package/dashboard/dist/assets/{AvailableEscalationsPage-IS28XBRe.js.map → AvailableEscalationsPage-DU84iaBN.js.map} +1 -1
- package/dashboard/dist/assets/{BotPicker-DvEJFpwS.js → BotPicker-Ci5PUrkl.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-DvEJFpwS.js.map → BotPicker-Ci5PUrkl.js.map} +1 -1
- package/dashboard/dist/assets/{BulkAssignModal-BoQCi-YC.js → BulkAssignModal-PLx7SLvF.js} +2 -2
- package/dashboard/dist/assets/{BulkAssignModal-BoQCi-YC.js.map → BulkAssignModal-PLx7SLvF.js.map} +1 -1
- package/dashboard/dist/assets/{CapabilitiesPage-kwlrcb_t.js → CapabilitiesPage-DuSfgr6i.js} +2 -2
- package/dashboard/dist/assets/{CapabilitiesPage-kwlrcb_t.js.map → CapabilitiesPage-DuSfgr6i.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-UMIV4KIj.js → CollapsibleSection-KOO37qs6.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-UMIV4KIj.js.map → CollapsibleSection-KOO37qs6.js.map} +1 -1
- package/dashboard/dist/assets/{ConfirmDeleteModal-C5puwMg7.js → ConfirmDeleteModal-CI1eE-Nr.js} +2 -2
- package/dashboard/dist/assets/{ConfirmDeleteModal-C5puwMg7.js.map → ConfirmDeleteModal-CI1eE-Nr.js.map} +1 -1
- package/dashboard/dist/assets/{ConnectedAppsPage-drZa65kP.js → ConnectedAppsPage-DZgbCC0G.js} +2 -2
- package/dashboard/dist/assets/{ConnectedAppsPage-drZa65kP.js.map → ConnectedAppsPage-DZgbCC0G.js.map} +1 -1
- package/dashboard/dist/assets/CountdownTimer-C-Ngk8oq.js +2 -0
- package/dashboard/dist/assets/CountdownTimer-C-Ngk8oq.js.map +1 -0
- package/dashboard/dist/assets/{CredentialsPage-CaFQ6vLb.js → CredentialsPage-BR7s6eVu.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-CaFQ6vLb.js.map → CredentialsPage-BR7s6eVu.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-Co5j7tzW.js → CronLabel-BQ7Y1Nfd.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-Co5j7tzW.js.map → CronLabel-BQ7Y1Nfd.js.map} +1 -1
- package/dashboard/dist/assets/{DropZone-B1Tdfddc.js → DropZone-DCZpORx-.js} +2 -2
- package/dashboard/dist/assets/{DropZone-B1Tdfddc.js.map → DropZone-DCZpORx-.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-WJyE9G0T.js → ElapsedCell-BT49mUIc.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-WJyE9G0T.js.map → ElapsedCell-BT49mUIc.js.map} +1 -1
- package/dashboard/dist/assets/{EntityTimelinePanel-CDFFfX9d.js → EntityTimelinePanel-BtARWy3R.js} +2 -2
- package/dashboard/dist/assets/{EntityTimelinePanel-CDFFfX9d.js.map → EntityTimelinePanel-BtARWy3R.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationListSchemaPage-CMrUlaKI.js → EscalationListSchemaPage-EEBsNpTe.js} +3 -3
- package/dashboard/dist/assets/{EscalationListSchemaPage-CMrUlaKI.js.map → EscalationListSchemaPage-EEBsNpTe.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationSchemaPage-Dx2Lyfrz.js → EscalationSchemaPage-BHSC46Ow.js} +3 -3
- package/dashboard/dist/assets/{EscalationSchemaPage-Dx2Lyfrz.js.map → EscalationSchemaPage-BHSC46Ow.js.map} +1 -1
- package/dashboard/dist/assets/EscalationTimeline-BWTUBxUf.js +2 -0
- package/dashboard/dist/assets/{EscalationTimeline-d3nvshOk.js.map → EscalationTimeline-BWTUBxUf.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationTitleSelect-DWQieOM9.js → EscalationTitleSelect-DOsfY4u8.js} +2 -2
- package/dashboard/dist/assets/{EscalationTitleSelect-DWQieOM9.js.map → EscalationTitleSelect-DOsfY4u8.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-BX8Cpi0X.js → EscalationsOverview-Bl8g53x-.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-BX8Cpi0X.js.map → EscalationsOverview-Bl8g53x-.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-D1-ITVXS.js → EventTable-Bjx17W_i.js} +2 -2
- package/dashboard/dist/assets/{EventTable-D1-ITVXS.js.map → EventTable-Bjx17W_i.js.map} +1 -1
- package/dashboard/dist/assets/{FilterBar-ABC9ctin.js → FilterBar-Dnse0soD.js} +2 -2
- package/dashboard/dist/assets/{FilterBar-ABC9ctin.js.map → FilterBar-Dnse0soD.js.map} +1 -1
- package/dashboard/dist/assets/{FormattedValue-k27T4bG7.js → FormattedValue-DeVrRJy4.js} +2 -2
- package/dashboard/dist/assets/{FormattedValue-k27T4bG7.js.map → FormattedValue-DeVrRJy4.js.map} +1 -1
- package/dashboard/dist/assets/{GraphInvokePage-DKUErxWc.js → GraphInvokePage-HQEvbHTd.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-DKUErxWc.js.map → GraphInvokePage-HQEvbHTd.js.map} +1 -1
- package/dashboard/dist/assets/{HomePage-C6u9dIpR.js → HomePage-DizTklVg.js} +2 -2
- package/dashboard/dist/assets/{HomePage-C6u9dIpR.js.map → HomePage-DizTklVg.js.map} +1 -1
- package/dashboard/dist/assets/{ListToolbar-gA5rFzkz.js → ListToolbar-B0qe2QZ5.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-gA5rFzkz.js.map → ListToolbar-B0qe2QZ5.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-BOPo3J_i.js → McpOverview-DmH-qtX9.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-BOPo3J_i.js.map → McpOverview-DmH-qtX9.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-BRVVi0Zh.js → McpQueryDetailPage-B-qtmwLd.js} +2 -2
- package/dashboard/dist/assets/{McpQueryDetailPage-BRVVi0Zh.js.map → McpQueryDetailPage-B-qtmwLd.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryPage-Dmbb6SAc.js → McpQueryPage-DX1T-Ugq.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-Dmbb6SAc.js.map → McpQueryPage-DX1T-Ugq.js.map} +1 -1
- package/dashboard/dist/assets/McpRunDetailPage-DNdl10nB.js +2 -0
- package/dashboard/dist/assets/{McpRunDetailPage-bMXNO-6V.js.map → McpRunDetailPage-DNdl10nB.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-Bi9AMWja.js → McpRunsPage-DVXVB4AJ.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-Bi9AMWja.js.map → McpRunsPage-DVXVB4AJ.js.map} +1 -1
- package/dashboard/dist/assets/{NamespacePill-DwM5pNA4.js → NamespacePill-CSZT2fA4.js} +2 -2
- package/dashboard/dist/assets/{NamespacePill-DwM5pNA4.js.map → NamespacePill-CSZT2fA4.js.map} +1 -1
- package/dashboard/dist/assets/{OperationsPage-CvR74ZUJ.js → OperationsPage-BxgWQq8v.js} +3 -3
- package/dashboard/dist/assets/{OperationsPage-CvR74ZUJ.js.map → OperationsPage-BxgWQq8v.js.map} +1 -1
- package/dashboard/dist/assets/OperatorDashboard-Cw86vOPg.js +2 -0
- package/dashboard/dist/assets/{OperatorDashboard-DctmZw10.js.map → OperatorDashboard-Cw86vOPg.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeader-CMd3f4bz.js → PageHeader-C4z1ExF7.js} +2 -2
- package/dashboard/dist/assets/{PageHeader-CMd3f4bz.js.map → PageHeader-C4z1ExF7.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeaderWithStats-DHj8Mqox.js → PageHeaderWithStats-B_f_Sz_Q.js} +2 -2
- package/dashboard/dist/assets/{PageHeaderWithStats-DHj8Mqox.js.map → PageHeaderWithStats-B_f_Sz_Q.js.map} +1 -1
- package/dashboard/dist/assets/{PersonaDetailPage-Ubqm2rQH.js → PersonaDetailPage-BTIJ4A6p.js} +2 -2
- package/dashboard/dist/assets/{PersonaDetailPage-Ubqm2rQH.js.map → PersonaDetailPage-BTIJ4A6p.js.map} +1 -1
- package/dashboard/dist/assets/{PersonasPage-BpFL2rpo.js → PersonasPage-D11PokPb.js} +2 -2
- package/dashboard/dist/assets/{PersonasPage-BpFL2rpo.js.map → PersonasPage-D11PokPb.js.map} +1 -1
- package/dashboard/dist/assets/PortalPage-1rXm0cNK.js +2 -0
- package/dashboard/dist/assets/{PortalPage-Dfc_Q02R.js.map → PortalPage-1rXm0cNK.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessDetailPage-liJspvQh.js → ProcessDetailPage-Cp5-969g.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-liJspvQh.js.map → ProcessDetailPage-Cp5-969g.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-C3OM5ZUy.js → ProcessesListPage-assXQe-x.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-C3OM5ZUy.js.map → ProcessesListPage-assXQe-x.js.map} +1 -1
- package/dashboard/dist/assets/ResolverForm-CMzNjmGG.js +8 -0
- package/dashboard/dist/assets/ResolverForm-CMzNjmGG.js.map +1 -0
- package/dashboard/dist/assets/{RoleDetailPage-CrlYCh-R.js → RoleDetailPage-c_Qij0Tf.js} +3 -3
- package/dashboard/dist/assets/{RoleDetailPage-CrlYCh-R.js.map → RoleDetailPage-c_Qij0Tf.js.map} +1 -1
- package/dashboard/dist/assets/{RolePill-Di2CAHuD.js → RolePill-Bw_n7EpR.js} +2 -2
- package/dashboard/dist/assets/{RolePill-Di2CAHuD.js.map → RolePill-Bw_n7EpR.js.map} +1 -1
- package/dashboard/dist/assets/{RolesPage-BaazL_pt.js → RolesPage-D4oaYgTg.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-BaazL_pt.js.map → RolesPage-D4oaYgTg.js.map} +1 -1
- package/dashboard/dist/assets/{RunAsSelector-DxuV0fa1.js → RunAsSelector-Fptil_sB.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-DxuV0fa1.js.map → RunAsSelector-Fptil_sB.js.map} +1 -1
- package/dashboard/dist/assets/{ScanCodesPage-C0mvmYTq.js → ScanCodesPage-BeZA_YJW.js} +2 -2
- package/dashboard/dist/assets/{ScanCodesPage-C0mvmYTq.js.map → ScanCodesPage-BeZA_YJW.js.map} +1 -1
- package/dashboard/dist/assets/{ScanSchemeDetailPage-CiJgt5dZ.js → ScanSchemeDetailPage-Bxi15xNr.js} +2 -2
- package/dashboard/dist/assets/{ScanSchemeDetailPage-CiJgt5dZ.js.map → ScanSchemeDetailPage-Bxi15xNr.js.map} +1 -1
- package/dashboard/dist/assets/ScanStationPage-t5Bz957t.js +2 -0
- package/dashboard/dist/assets/ScanStationPage-t5Bz957t.js.map +1 -0
- package/dashboard/dist/assets/{ScopeBadge-CSItPVOH.js → ScopeBadge-CKgfwTy3.js} +2 -2
- package/dashboard/dist/assets/{ScopeBadge-CSItPVOH.js.map → ScopeBadge-CKgfwTy3.js.map} +1 -1
- package/dashboard/dist/assets/{StickyPagination-CqbjVY6T.js → StickyPagination-C2drZk7w.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-CqbjVY6T.js.map → StickyPagination-C2drZk7w.js.map} +1 -1
- package/dashboard/dist/assets/{StreamMessageDetail-wX3i0aqs.js → StreamMessageDetail-x-l5653y.js} +2 -2
- package/dashboard/dist/assets/{StreamMessageDetail-wX3i0aqs.js.map → StreamMessageDetail-x-l5653y.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-C50PsFoV.js → SwimlaneTimeline-Ds_CqLXL.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-C50PsFoV.js.map → SwimlaneTimeline-Ds_CqLXL.js.map} +1 -1
- package/dashboard/dist/assets/{TagInput-CAgdLN_b.js → TagInput-B6fMAqxd.js} +2 -2
- package/dashboard/dist/assets/{TagInput-CAgdLN_b.js.map → TagInput-B6fMAqxd.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-bbNSv4Ae.js → TaskDetailPage-BJGKEnIo.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-bbNSv4Ae.js.map → TaskDetailPage-BJGKEnIo.js.map} +1 -1
- package/dashboard/dist/assets/{TaskQueuePill-h0oorVMe.js → TaskQueuePill-BnDp_DE6.js} +2 -2
- package/dashboard/dist/assets/{TaskQueuePill-h0oorVMe.js.map → TaskQueuePill-BnDp_DE6.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-CDWnm_d9.js → TasksListPage-DyLaZvTT.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-CDWnm_d9.js.map → TasksListPage-DyLaZvTT.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-BLjqlfoX.js → TimeAgo-B_Ta97uy.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-BLjqlfoX.js.map → TimeAgo-B_Ta97uy.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-CnW0ENb5.js → TimestampCell-CiTYBQw-.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-CnW0ENb5.js.map → TimestampCell-CiTYBQw-.js.map} +1 -1
- package/dashboard/dist/assets/{ToolPill-CQCsVdzD.js → ToolPill-BRZWo4l8.js} +2 -2
- package/dashboard/dist/assets/{ToolPill-CQCsVdzD.js.map → ToolPill-BRZWo4l8.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-DkMgCB-k.js → ToolTestPanel-Dw8Zu6xr.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-DkMgCB-k.js.map → ToolTestPanel-Dw8Zu6xr.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-g3pljKKX.js → TopicDetailPage-DPMAWKTN.js} +4 -4
- package/dashboard/dist/assets/{TopicDetailPage-g3pljKKX.js.map → TopicDetailPage-DPMAWKTN.js.map} +1 -1
- package/dashboard/dist/assets/{TopicsPage-CVcCYdy-.js → TopicsPage-0Z2lAE0d.js} +2 -2
- package/dashboard/dist/assets/{TopicsPage-CVcCYdy-.js.map → TopicsPage-0Z2lAE0d.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-D6zGIK2i.js → UserName-DrAbCpdY.js} +2 -2
- package/dashboard/dist/assets/{UserName-D6zGIK2i.js.map → UserName-DrAbCpdY.js.map} +1 -1
- package/dashboard/dist/assets/WorkflowExecutionPage-DQITqX-6.js +2 -0
- package/dashboard/dist/assets/{WorkflowExecutionPage-B8g81FCJ.js.map → WorkflowExecutionPage-DQITqX-6.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowPill-Dg7BDTyM.js → WorkflowPill-Cly9Ln_3.js} +2 -2
- package/dashboard/dist/assets/{WorkflowPill-Dg7BDTyM.js.map → WorkflowPill-Cly9Ln_3.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsDashboard-nxT3bv6W.js → WorkflowsDashboard-CMJPiR6G.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-nxT3bv6W.js.map → WorkflowsDashboard-CMJPiR6G.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-grI-KAI2.js → WorkflowsOverview-DwVMLe1y.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-grI-KAI2.js.map → WorkflowsOverview-DwVMLe1y.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-BoZ-hfBE.js → YamlWorkflowDetailPage-Do6s_wmW.js} +12 -12
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-BoZ-hfBE.js.map → YamlWorkflowDetailPage-Do6s_wmW.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-Bf04rwRv.js → YamlWorkflowsPage-8Sr6rZMZ.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-Bf04rwRv.js.map → YamlWorkflowsPage-8Sr6rZMZ.js.map} +1 -1
- package/dashboard/dist/assets/{agents-Dphpdi8l.js → agents-Maom-dbf.js} +2 -2
- package/dashboard/dist/assets/{agents-Dphpdi8l.js.map → agents-Maom-dbf.js.map} +1 -1
- package/dashboard/dist/assets/{bots-DIFE298x.js → bots-BESWftTA.js} +2 -2
- package/dashboard/dist/assets/{bots-DIFE298x.js.map → bots-BESWftTA.js.map} +1 -1
- package/dashboard/dist/assets/{capabilities-D7Y7LClY.js → capabilities-BnvJAmFQ.js} +2 -2
- package/dashboard/dist/assets/{capabilities-D7Y7LClY.js.map → capabilities-BnvJAmFQ.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-D1TGcYsS.js → controlplane-Cu7TD1RX.js} +2 -2
- package/dashboard/dist/assets/{controlplane-D1TGcYsS.js.map → controlplane-Cu7TD1RX.js.map} +1 -1
- package/dashboard/dist/assets/escalation-columns-BPSH8qMx.js +2 -0
- package/dashboard/dist/assets/escalation-columns-BPSH8qMx.js.map +1 -0
- package/dashboard/dist/assets/escalation-items-uDQTphVW.js +2 -0
- package/dashboard/dist/assets/escalation-items-uDQTphVW.js.map +1 -0
- package/dashboard/dist/assets/index-AJNPDsTI.js +2 -0
- package/dashboard/dist/assets/{index-CxdjT1Yk.js.map → index-AJNPDsTI.js.map} +1 -1
- package/dashboard/dist/assets/{index-ag2pCAPu.js → index-B4SNhwgt.js} +2 -2
- package/dashboard/dist/assets/{index-ag2pCAPu.js.map → index-B4SNhwgt.js.map} +1 -1
- package/dashboard/dist/assets/{index-BzYcUPdD.js → index-BG7OpNg7.js} +2 -2
- package/dashboard/dist/assets/{index-BzYcUPdD.js.map → index-BG7OpNg7.js.map} +1 -1
- package/dashboard/dist/assets/index-BLbZsMRG.js +67 -0
- package/dashboard/dist/assets/index-BLbZsMRG.js.map +1 -0
- package/dashboard/dist/assets/{index-DpKOr311.js → index-BLlg1aVG.js} +2 -2
- package/dashboard/dist/assets/{index-DpKOr311.js.map → index-BLlg1aVG.js.map} +1 -1
- package/dashboard/dist/assets/{index-Dl_8hbYI.js → index-BkVarz6E.js} +2 -2
- package/dashboard/dist/assets/{index-Dl_8hbYI.js.map → index-BkVarz6E.js.map} +1 -1
- package/dashboard/dist/assets/{index-Dy1wWu2e.js → index-BpWutGxS.js} +2 -2
- package/dashboard/dist/assets/{index-Dy1wWu2e.js.map → index-BpWutGxS.js.map} +1 -1
- package/dashboard/dist/assets/{index-DAvi5_2T.js → index-BvI2_dSt.js} +2 -2
- package/dashboard/dist/assets/{index-DAvi5_2T.js.map → index-BvI2_dSt.js.map} +1 -1
- package/dashboard/dist/assets/index-CnU7Jjz3.css +1 -0
- package/dashboard/dist/assets/{index-HLu98Sqh.js → index-D5JQweUm.js} +2 -2
- package/dashboard/dist/assets/{index-HLu98Sqh.js.map → index-D5JQweUm.js.map} +1 -1
- package/dashboard/dist/assets/{index-DN-kX7hL.js → index-WA8py2Yc.js} +2 -2
- package/dashboard/dist/assets/{index-DN-kX7hL.js.map → index-WA8py2Yc.js.map} +1 -1
- package/dashboard/dist/assets/{index-ChV7pBjM.js → index-_yHsJJTS.js} +2 -2
- package/dashboard/dist/assets/{index-ChV7pBjM.js.map → index-_yHsJJTS.js.map} +1 -1
- package/dashboard/dist/assets/index-kGSUZCOb.js +3 -0
- package/dashboard/dist/assets/index-kGSUZCOb.js.map +1 -0
- package/dashboard/dist/assets/index-qY2KDGkM.js +13 -0
- package/dashboard/dist/assets/{index-gkxPN7Vx.js.map → index-qY2KDGkM.js.map} +1 -1
- package/dashboard/dist/assets/{knowledge-DnMs-SOJ.js → knowledge-DCFRNG8R.js} +2 -2
- package/dashboard/dist/assets/{knowledge-DnMs-SOJ.js.map → knowledge-DCFRNG8R.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-CwW-K3r4.js → mcp-CZhOocmN.js} +2 -2
- package/dashboard/dist/assets/{mcp-CwW-K3r4.js.map → mcp-CZhOocmN.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-BZt5e8_Q.js → mcp-query-Wt8z6yAL.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-BZt5e8_Q.js.map → mcp-query-Wt8z6yAL.js.map} +1 -1
- package/dashboard/dist/assets/{personas-UA-Xn60f.js → personas-D2_foqJm.js} +2 -2
- package/dashboard/dist/assets/{personas-UA-Xn60f.js.map → personas-D2_foqJm.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-Cu3PARum.js → pipelines-Bb159fNz.js} +2 -2
- package/dashboard/dist/assets/{pipelines-Cu3PARum.js.map → pipelines-Bb159fNz.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-BO6h8GJE.js → tasks-xAU6C6tb.js} +2 -2
- package/dashboard/dist/assets/{tasks-BO6h8GJE.js.map → tasks-xAU6C6tb.js.map} +1 -1
- package/dashboard/dist/assets/{topics-CWjCR-17.js → topics-DFdqb2Te.js} +2 -2
- package/dashboard/dist/assets/{topics-CWjCR-17.js.map → topics-DFdqb2Te.js.map} +1 -1
- package/dashboard/dist/assets/{useDebouncedValue-6t0jx1RB.js → useDebouncedValue-CbHmpS4w.js} +2 -2
- package/dashboard/dist/assets/{useDebouncedValue-6t0jx1RB.js.map → useDebouncedValue-CbHmpS4w.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-CqpoQx6D.js → useNamespace-B_00X1yb.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-CqpoQx6D.js.map → useNamespace-B_00X1yb.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-hmCQQwzB.js → useYamlActivityEvents-B4F-s9g0.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-hmCQQwzB.js.map → useYamlActivityEvents-B4F-s9g0.js.map} +1 -1
- package/dashboard/dist/assets/{vendor-icons-CeVtUKyP.js → vendor-icons-C_DQEeBy.js} +2 -2
- package/dashboard/dist/assets/{vendor-icons-CeVtUKyP.js.map → vendor-icons-C_DQEeBy.js.map} +1 -1
- package/dashboard/dist/assets/{yaml-workflows-ziUdZhKY.js → yaml-workflows-DyjbPFVp.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-ziUdZhKY.js.map → yaml-workflows-DyjbPFVp.js.map} +1 -1
- package/dashboard/dist/index.html +3 -3
- package/docs/code-owned-configuration.md +2 -2
- package/docs/domain-dictionary.md +19 -3
- package/docs/faceted-routing.md +15 -1
- package/docs/hitl/x-lt-display.md +1 -1
- package/docs/hitl/x-lt-embed.md +4 -1
- package/docs/hitl/x-lt-list-schema.md +19 -2
- package/docs/hitl/x-lt-roster.md +112 -0
- package/docs/hitl/x-lt-show-if.md +15 -0
- package/docs/hitl/x-lt-widget.md +1 -0
- package/docs/hitl-guide.md +3 -1
- package/docs/scan-codes.md +4 -0
- package/docs/schema-enforcement.md +5 -0
- package/package.json +2 -2
- package/dashboard/dist/assets/AvailableEscalationsPage-IS28XBRe.js +0 -2
- package/dashboard/dist/assets/CountdownTimer-LG03dVgR.js +0 -2
- package/dashboard/dist/assets/CountdownTimer-LG03dVgR.js.map +0 -1
- package/dashboard/dist/assets/EscalationTimeline-d3nvshOk.js +0 -2
- package/dashboard/dist/assets/McpRunDetailPage-bMXNO-6V.js +0 -2
- package/dashboard/dist/assets/OperatorDashboard-DctmZw10.js +0 -2
- package/dashboard/dist/assets/PortalPage-Dfc_Q02R.js +0 -2
- package/dashboard/dist/assets/ResolverForm-B1_x8Blv.js +0 -8
- package/dashboard/dist/assets/ResolverForm-B1_x8Blv.js.map +0 -1
- package/dashboard/dist/assets/ScanStationPage-DzGaXc40.js +0 -2
- package/dashboard/dist/assets/ScanStationPage-DzGaXc40.js.map +0 -1
- package/dashboard/dist/assets/WorkflowExecutionPage-B8g81FCJ.js +0 -2
- package/dashboard/dist/assets/escalation-columns-cwZE6xyo.js +0 -2
- package/dashboard/dist/assets/escalation-columns-cwZE6xyo.js.map +0 -1
- package/dashboard/dist/assets/index-CeCtqujG.js +0 -67
- package/dashboard/dist/assets/index-CeCtqujG.js.map +0 -1
- package/dashboard/dist/assets/index-CniRa65p.js +0 -3
- package/dashboard/dist/assets/index-CniRa65p.js.map +0 -1
- package/dashboard/dist/assets/index-CxdjT1Yk.js +0 -2
- package/dashboard/dist/assets/index-gkxPN7Vx.js +0 -13
- package/dashboard/dist/assets/index-m9A3UYst.css +0 -1
- package/dashboard/dist/assets/validate-BIRn4a6d.js +0 -2
- package/dashboard/dist/assets/validate-BIRn4a6d.js.map +0 -1
|
@@ -177,6 +177,10 @@ async function gateReciprocal(input, auth) {
|
|
|
177
177
|
}
|
|
178
178
|
return { reciprocal: { id: row.id, payload: input.payload } };
|
|
179
179
|
}
|
|
180
|
+
/** The reciprocal of an add, stamped with who added it, as the container is. */
|
|
181
|
+
function completedBy(reciprocal, userId) {
|
|
182
|
+
return reciprocal ? { ...reciprocal, metadata: { resolved_by: userId } } : undefined;
|
|
183
|
+
}
|
|
180
184
|
/** Validates the item payload against the container's versioned role form. */
|
|
181
185
|
async function gatePayload(escalation, payload, userId) {
|
|
182
186
|
if (payload === undefined)
|
|
@@ -245,7 +249,7 @@ async function accumulateItem(input, auth) {
|
|
|
245
249
|
actor: initiator.actor,
|
|
246
250
|
assertClaim: input.assertClaim ? auth.userId : undefined,
|
|
247
251
|
resolvedBy: await (0, resolve_1.resolverIdentity)(auth),
|
|
248
|
-
reciprocal: reciprocal.reciprocal,
|
|
252
|
+
reciprocal: completedBy(reciprocal.reciprocal, auth.userId),
|
|
249
253
|
});
|
|
250
254
|
return accumulateOutcomeResult(result, itemKey, escalation.workflow_id);
|
|
251
255
|
}
|
|
@@ -291,7 +295,7 @@ async function accumulateItemBySignalKey(input, auth) {
|
|
|
291
295
|
metadata: { ...metadata, resolved_by: auth.userId },
|
|
292
296
|
actor: initiator.actor,
|
|
293
297
|
resolvedBy: await (0, resolve_1.resolverIdentity)(auth),
|
|
294
|
-
reciprocal: reciprocal.reciprocal,
|
|
298
|
+
reciprocal: completedBy(reciprocal.reciprocal, auth.userId),
|
|
295
299
|
});
|
|
296
300
|
return accumulateOutcomeResult(result, itemKey, escalation.workflow_id);
|
|
297
301
|
}
|
|
@@ -344,7 +348,7 @@ async function accumulateItemByMetadata(input, auth) {
|
|
|
344
348
|
actor: initiator.actor,
|
|
345
349
|
resolvedBy,
|
|
346
350
|
roles: allowedRoles ?? undefined,
|
|
347
|
-
reciprocal: reciprocal.reciprocal,
|
|
351
|
+
reciprocal: completedBy(reciprocal.reciprocal, auth.userId),
|
|
348
352
|
});
|
|
349
353
|
if (result.outcome === 'not-found')
|
|
350
354
|
return { status: 404, error: NO_ACCUMULATOR_FOR_FACET };
|
|
@@ -364,7 +368,7 @@ async function accumulateItemByMetadata(input, auth) {
|
|
|
364
368
|
metadata: outcome,
|
|
365
369
|
actor: initiator.actor,
|
|
366
370
|
resolvedBy,
|
|
367
|
-
reciprocal: reciprocal.reciprocal,
|
|
371
|
+
reciprocal: completedBy(reciprocal.reciprocal, auth.userId),
|
|
368
372
|
});
|
|
369
373
|
if (result.outcome === 'not-found') {
|
|
370
374
|
return { status: 409, error: 'A concurrent change is already in progress for this escalation' };
|
|
@@ -175,12 +175,13 @@ async function resolveByMetadata(input, auth) {
|
|
|
175
175
|
// writing; the payload validates here, then a second asserted pass claims
|
|
176
176
|
// + resolves the same row with pending re-checked inside the statement.
|
|
177
177
|
const enforcing = await (0, enforcement_cache_1.getEnforcingRoles)();
|
|
178
|
-
|
|
178
|
+
const outcome = { ...input.metadata, resolved_by: auth.userId };
|
|
179
|
+
let result = await escalationService.resolveByMetadataAtomic(input.key, input.value, resolveUserId, input.resolverPayload, outcome, writeAllRoles, writeSelfRoles, enforcing.size > 0 ? [...enforcing] : null, input.assertId ?? null, input.extraFacets, input.availability);
|
|
179
180
|
if (result.outcome === 'validation_required' && result.row) {
|
|
180
181
|
const report = await (0, resolver_validation_1.checkResolverPayload)(result.row, input.resolverPayload, undefined, resolveUserId);
|
|
181
182
|
if (report)
|
|
182
183
|
return (0, resolve_1.validationFailure)(report);
|
|
183
|
-
result = await escalationService.resolveByMetadataAtomic(input.key, input.value, resolveUserId, input.resolverPayload,
|
|
184
|
+
result = await escalationService.resolveByMetadataAtomic(input.key, input.value, resolveUserId, input.resolverPayload, outcome, writeAllRoles, writeSelfRoles, null, result.row.id, input.extraFacets, input.availability);
|
|
184
185
|
// The asserted row left pending between the two passes — a concurrent
|
|
185
186
|
// resolution won the row; surface it as the conflict it is.
|
|
186
187
|
if (result.outcome === 'not_found') {
|
|
@@ -199,7 +200,7 @@ async function resolveByMetadata(input, auth) {
|
|
|
199
200
|
// Atomic conditional escalation (signal_key set) — SDK resolve atomically marks
|
|
200
201
|
// resolved AND delivers the signal to the waiting condition(), resuming the workflow.
|
|
201
202
|
if (result.signalKey) {
|
|
202
|
-
const resolved = await escalationService.resolveEscalation(result.escalationId, input.resolverPayload);
|
|
203
|
+
const resolved = await escalationService.resolveEscalation(result.escalationId, input.resolverPayload, outcome);
|
|
203
204
|
if (!resolved) {
|
|
204
205
|
return { status: 409, error: 'Escalation not available for resolution' };
|
|
205
206
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { LTApiAuth, LTApiResult } from '../../types/sdk';
|
|
2
2
|
/**
|
|
3
3
|
* Aggregate every related set the role's list schema declares, for one page
|
|
4
|
-
* of host rows. One statement per (set,
|
|
4
|
+
* of host rows. One statement per (set, aggregate) pair, whatever the page size.
|
|
5
5
|
*/
|
|
6
6
|
export declare function getRelatedAggregates(input: {
|
|
7
7
|
role: string;
|
|
@@ -84,16 +84,24 @@ async function resolveQueryRoles(query, readScope) {
|
|
|
84
84
|
const restricted = readScope.global ? [] : roles.filter((r) => !readScope.allRoles.includes(r));
|
|
85
85
|
return { roles, roleLabels, restricted };
|
|
86
86
|
}
|
|
87
|
-
/** The
|
|
88
|
-
function
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
87
|
+
/** The distinct aggregates the declared columns ask of one set; an unsplit count when none does. */
|
|
88
|
+
function asksFor(relations, set, source) {
|
|
89
|
+
const asks = new Map();
|
|
90
|
+
for (const col of relations.columns.filter((c) => c.related === set)) {
|
|
91
|
+
const key = (0, list_schema_1.relatedAggregateKey)(col, source);
|
|
92
|
+
if (asks.has(key))
|
|
93
|
+
continue;
|
|
94
|
+
asks.set(key, (0, list_schema_1.isExtremeAggregate)(col.aggregate)
|
|
95
|
+
? { key, extreme: { fold: col.aggregate, path: (0, list_schema_1.relatedValuePath)(source, col.value) } }
|
|
96
|
+
: { key, ...(col.splitBy ? { splitBy: col.splitBy } : {}) });
|
|
97
|
+
}
|
|
98
|
+
if (!asks.size)
|
|
99
|
+
asks.set('', { key: '' });
|
|
100
|
+
return [...asks.values()];
|
|
93
101
|
}
|
|
94
102
|
/**
|
|
95
103
|
* Aggregate every related set the role's list schema declares, for one page
|
|
96
|
-
* of host rows. One statement per (set,
|
|
104
|
+
* of host rows. One statement per (set, aggregate) pair, whatever the page size.
|
|
97
105
|
*/
|
|
98
106
|
async function getRelatedAggregates(input, auth) {
|
|
99
107
|
try {
|
|
@@ -118,11 +126,13 @@ async function getRelatedAggregates(input, auth) {
|
|
|
118
126
|
const result = { source: decl.source, aggregates: {} };
|
|
119
127
|
if (decl.source === list_schema_1.RELATED_SOURCES.ITEMS) {
|
|
120
128
|
const roles = new Set();
|
|
121
|
-
for (const
|
|
122
|
-
|
|
123
|
-
hostIds, scope,
|
|
124
|
-
|
|
125
|
-
|
|
129
|
+
for (const ask of asksFor(relations, name, decl.source)) {
|
|
130
|
+
if (ask.extreme) {
|
|
131
|
+
result.aggregates[ask.key] = await escalationService.extremeRelatedItems({ hostIds, scope, ...ask.extreme });
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
const read = await escalationService.aggregateRelatedItems({ hostIds, scope, splitBy: ask.splitBy });
|
|
135
|
+
result.aggregates[ask.key] = read.aggregates;
|
|
126
136
|
read.roles.forEach((r) => roles.add(r));
|
|
127
137
|
}
|
|
128
138
|
if (roles.size)
|
|
@@ -142,14 +152,14 @@ async function getRelatedAggregates(input, auth) {
|
|
|
142
152
|
else
|
|
143
153
|
unresolved.push(host.id);
|
|
144
154
|
}
|
|
145
|
-
for (const
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
155
|
+
for (const ask of asksFor(relations, name, decl.source)) {
|
|
156
|
+
const query = { hosts: matched, roles: resolved.roles, status: decl.query.status ?? DEFAULT_STATUS, scope };
|
|
157
|
+
const agg = ask.extreme
|
|
158
|
+
? await escalationService.extremeRelatedQuery({ ...query, ...ask.extreme })
|
|
159
|
+
: await escalationService.aggregateRelatedQuery({ ...query, splitBy: ask.splitBy });
|
|
150
160
|
for (const id of unresolved)
|
|
151
161
|
agg[id] = { count: 0, unresolved: true };
|
|
152
|
-
result.aggregates[
|
|
162
|
+
result.aggregates[ask.key] = agg;
|
|
153
163
|
}
|
|
154
164
|
}
|
|
155
165
|
data.sets[name] = result;
|
|
@@ -1,18 +1,20 @@
|
|
|
1
|
+
import type { DomainDictionary } from '../../types';
|
|
1
2
|
/**
|
|
2
|
-
* Seed the domain dictionary
|
|
3
|
+
* Seed the domain dictionary declared by the host: inline in the start
|
|
4
|
+
* config, or in a JSON file named by path.
|
|
3
5
|
*
|
|
4
6
|
* Default (db-owned): the same insert-if-absent + drift-log contract as
|
|
5
|
-
* seedWorkflowConfig/seedMcpServer
|
|
6
|
-
* row is never overwritten, and a name/version mismatch against the
|
|
7
|
-
* one drift warning.
|
|
7
|
+
* seedWorkflowConfig/seedMcpServer: the DB row is runtime truth, an existing
|
|
8
|
+
* row is never overwritten, and a name/version mismatch against the declared
|
|
9
|
+
* document logs one drift warning.
|
|
8
10
|
*
|
|
9
|
-
* With `apply` (code-owned): the
|
|
10
|
-
* as parsed values; a changed document is written through the same
|
|
11
|
-
* PUT path uses, advancing the row's version counter exactly once.
|
|
12
|
-
* identical document is a no-op.
|
|
11
|
+
* With `apply` (code-owned): the declared document is compared against the
|
|
12
|
+
* stored one as parsed values; a changed document is written through the same
|
|
13
|
+
* upsert the PUT path uses, advancing the row's version counter exactly once.
|
|
14
|
+
* An identical document is a no-op.
|
|
13
15
|
*
|
|
14
16
|
* WARN-ONLY validation: hosts commonly seed roles after long-tail boots, so
|
|
15
17
|
* unknown references log warnings here (the PUT path enforces them hard).
|
|
16
|
-
* Never throws
|
|
18
|
+
* Never throws: a missing or malformed file must not brick boot.
|
|
17
19
|
*/
|
|
18
|
-
export declare function seedDomainDictionary(
|
|
20
|
+
export declare function seedDomainDictionary(source: string | DomainDictionary, apply?: boolean): Promise<void>;
|
|
@@ -14,38 +14,27 @@ const write_1 = require("./write");
|
|
|
14
14
|
const read_1 = require("./read");
|
|
15
15
|
const sql_1 = require("./sql");
|
|
16
16
|
/**
|
|
17
|
-
* Seed the domain dictionary
|
|
17
|
+
* Seed the domain dictionary declared by the host: inline in the start
|
|
18
|
+
* config, or in a JSON file named by path.
|
|
18
19
|
*
|
|
19
20
|
* Default (db-owned): the same insert-if-absent + drift-log contract as
|
|
20
|
-
* seedWorkflowConfig/seedMcpServer
|
|
21
|
-
* row is never overwritten, and a name/version mismatch against the
|
|
22
|
-
* one drift warning.
|
|
21
|
+
* seedWorkflowConfig/seedMcpServer: the DB row is runtime truth, an existing
|
|
22
|
+
* row is never overwritten, and a name/version mismatch against the declared
|
|
23
|
+
* document logs one drift warning.
|
|
23
24
|
*
|
|
24
|
-
* With `apply` (code-owned): the
|
|
25
|
-
* as parsed values; a changed document is written through the same
|
|
26
|
-
* PUT path uses, advancing the row's version counter exactly once.
|
|
27
|
-
* identical document is a no-op.
|
|
25
|
+
* With `apply` (code-owned): the declared document is compared against the
|
|
26
|
+
* stored one as parsed values; a changed document is written through the same
|
|
27
|
+
* upsert the PUT path uses, advancing the row's version counter exactly once.
|
|
28
|
+
* An identical document is a no-op.
|
|
28
29
|
*
|
|
29
30
|
* WARN-ONLY validation: hosts commonly seed roles after long-tail boots, so
|
|
30
31
|
* unknown references log warnings here (the PUT path enforces them hard).
|
|
31
|
-
* Never throws
|
|
32
|
+
* Never throws: a missing or malformed file must not brick boot.
|
|
32
33
|
*/
|
|
33
|
-
async function seedDomainDictionary(
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
: path_1.default.join(process.cwd(), dictionaryPath);
|
|
37
|
-
let dictionary;
|
|
38
|
-
try {
|
|
39
|
-
if (!(0, fs_1.existsSync)(resolved)) {
|
|
40
|
-
logger_1.loggerRegistry.warn(`[lt-domain] domainDictionaryPath not found: ${resolved}`);
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
dictionary = JSON.parse((0, fs_1.readFileSync)(resolved, 'utf-8'));
|
|
44
|
-
}
|
|
45
|
-
catch (err) {
|
|
46
|
-
logger_1.loggerRegistry.warn(`[lt-domain] dictionary file unreadable (${resolved}): ${err.message}`);
|
|
34
|
+
async function seedDomainDictionary(source, apply = false) {
|
|
35
|
+
const dictionary = typeof source === 'string' ? readDictionaryFile(source) : source;
|
|
36
|
+
if (!dictionary)
|
|
47
37
|
return;
|
|
48
|
-
}
|
|
49
38
|
try {
|
|
50
39
|
const registry = await (0, write_1.snapshotRegistries)();
|
|
51
40
|
const { errors, warnings, dictionary: derived } = (0, validate_1.validateDictionary)(dictionary, registry);
|
|
@@ -75,10 +64,27 @@ async function seedDomainDictionary(dictionaryPath, apply = false) {
|
|
|
75
64
|
// Row already existed — drift check on name/version only (no deep diff).
|
|
76
65
|
if (doc && (doc.name !== dictionary.name || doc.version !== dictionary.version)) {
|
|
77
66
|
logger_1.loggerRegistry.warn(`[lt-domain] dictionary drift: DB holds "${doc.name}" v${doc.version}, ` +
|
|
78
|
-
`
|
|
67
|
+
`start config declares "${dictionary.name}" v${dictionary.version}; DB is runtime truth`);
|
|
79
68
|
}
|
|
80
69
|
}
|
|
81
70
|
catch (err) {
|
|
82
71
|
logger_1.loggerRegistry.warn(`[lt-domain] dictionary seed failed: ${err.message}`);
|
|
83
72
|
}
|
|
84
73
|
}
|
|
74
|
+
/** The dictionary in a JSON file, resolved against the host cwd; null (logged) when missing or unreadable. */
|
|
75
|
+
function readDictionaryFile(dictionaryPath) {
|
|
76
|
+
const resolved = path_1.default.isAbsolute(dictionaryPath)
|
|
77
|
+
? dictionaryPath
|
|
78
|
+
: path_1.default.join(process.cwd(), dictionaryPath);
|
|
79
|
+
try {
|
|
80
|
+
if (!(0, fs_1.existsSync)(resolved)) {
|
|
81
|
+
logger_1.loggerRegistry.warn(`[lt-domain] domainDictionaryPath not found: ${resolved}`);
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
return JSON.parse((0, fs_1.readFileSync)(resolved, 'utf-8'));
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
logger_1.loggerRegistry.warn(`[lt-domain] dictionary file unreadable (${resolved}): ${err.message}`);
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -8,6 +8,8 @@ export interface AccumulateReciprocal {
|
|
|
8
8
|
roles?: string[];
|
|
9
9
|
/** Stored as the reciprocal entry's payload. */
|
|
10
10
|
payload?: Record<string, any>;
|
|
11
|
+
/** Merge patch for the reciprocal row's metadata, same statement. */
|
|
12
|
+
metadata?: Record<string, any>;
|
|
11
13
|
}
|
|
12
14
|
export interface AccumulateItemInput {
|
|
13
15
|
itemKey: string;
|
|
@@ -43,7 +45,7 @@ export interface AccumulateItemServiceOutcome {
|
|
|
43
45
|
export interface RemoveItemInput {
|
|
44
46
|
itemKey: string;
|
|
45
47
|
actor?: string;
|
|
46
|
-
reciprocal?: Omit<AccumulateReciprocal, 'payload'>;
|
|
48
|
+
reciprocal?: Omit<AccumulateReciprocal, 'payload' | 'metadata'>;
|
|
47
49
|
}
|
|
48
50
|
export interface RemoveItemServiceOutcome {
|
|
49
51
|
outcome: RemoveAccumulatedItemOutcome;
|
|
@@ -13,7 +13,9 @@ exports.buildFacetOrder = buildFacetOrder;
|
|
|
13
13
|
exports.buildGroupOrder = buildGroupOrder;
|
|
14
14
|
// Top-level columns a caller may sort/range on directly. Anything else must be a
|
|
15
15
|
// `metadata.<key>` facet. Keeps interpolation to a fixed, audited set.
|
|
16
|
-
const ORDER_COLUMNS = new Set(['priority', 'created_at', 'updated_at', 'status', 'role']);
|
|
16
|
+
const ORDER_COLUMNS = new Set(['priority', 'created_at', 'updated_at', 'resolved_at', 'status', 'role']);
|
|
17
|
+
// Columns a pending row leaves empty: they sort after every value, either direction.
|
|
18
|
+
const NULLABLE_ORDER_COLUMNS = new Set(['resolved_at']);
|
|
17
19
|
const RANGE_OPS = new Set(['<', '<=', '>', '>=', '=']);
|
|
18
20
|
// Metadata keys are interpolated (as a JSON path), so they are strictly validated.
|
|
19
21
|
// Exported so role config (priority_facet) validates keys against the same rule.
|
|
@@ -140,7 +142,7 @@ function buildFacetOrder(orderBy) {
|
|
|
140
142
|
for (const o of orderBy) {
|
|
141
143
|
const dir = o.direction === 'desc' ? 'DESC' : 'ASC';
|
|
142
144
|
if (ORDER_COLUMNS.has(o.field)) {
|
|
143
|
-
parts.push(`${o.field} ${dir}`);
|
|
145
|
+
parts.push(`${o.field} ${dir}${NULLABLE_ORDER_COLUMNS.has(o.field) ? ' NULLS LAST' : ''}`);
|
|
144
146
|
}
|
|
145
147
|
else if (o.field.startsWith('metadata.')) {
|
|
146
148
|
const key = o.field.slice('metadata.'.length);
|
|
@@ -14,3 +14,4 @@ export { searchEscalationsGrouped } from './grouped-list';
|
|
|
14
14
|
export type { EscalationGroup } from './grouped-list';
|
|
15
15
|
export { aggregateRelatedItems, listRelatedItems, aggregateRelatedQuery, listRelatedQueryRows, readRelatedHosts, } from './related';
|
|
16
16
|
export type { RelatedQueryHost } from './related';
|
|
17
|
+
export { extremeRelatedItems, extremeRelatedQuery } from './related-extremes';
|
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.readRelatedHosts = exports.listRelatedQueryRows = exports.aggregateRelatedQuery = exports.listRelatedItems = exports.aggregateRelatedItems = exports.searchEscalationsGrouped = exports.AnalyticsInputError = exports.resetAnalyticsCaches = exports.resolveEntitySystem = exports.timelineByFacet = exports.aggregateByFacets = exports.claimByFacets = exports.claimGroups = exports.countByFacets = exports.searchGroups = exports.searchByFacets = exports.ensureFacetReady = exports.ensureEscalationCompatView = exports.claimAssertedByMetadata = void 0;
|
|
17
|
+
exports.extremeRelatedQuery = exports.extremeRelatedItems = exports.readRelatedHosts = exports.listRelatedQueryRows = exports.aggregateRelatedQuery = exports.listRelatedItems = exports.aggregateRelatedItems = exports.searchEscalationsGrouped = exports.AnalyticsInputError = exports.resetAnalyticsCaches = exports.resolveEntitySystem = exports.timelineByFacet = exports.aggregateByFacets = exports.claimByFacets = exports.claimGroups = exports.countByFacets = exports.searchGroups = exports.searchByFacets = exports.ensureFacetReady = exports.ensureEscalationCompatView = exports.claimAssertedByMetadata = void 0;
|
|
18
18
|
__exportStar(require("./types"), exports);
|
|
19
19
|
__exportStar(require("./crud"), exports);
|
|
20
20
|
var claim_asserted_1 = require("./claim-asserted");
|
|
@@ -48,3 +48,6 @@ Object.defineProperty(exports, "listRelatedItems", { enumerable: true, get: func
|
|
|
48
48
|
Object.defineProperty(exports, "aggregateRelatedQuery", { enumerable: true, get: function () { return related_1.aggregateRelatedQuery; } });
|
|
49
49
|
Object.defineProperty(exports, "listRelatedQueryRows", { enumerable: true, get: function () { return related_1.listRelatedQueryRows; } });
|
|
50
50
|
Object.defineProperty(exports, "readRelatedHosts", { enumerable: true, get: function () { return related_1.readRelatedHosts; } });
|
|
51
|
+
var related_extremes_1 = require("./related-extremes");
|
|
52
|
+
Object.defineProperty(exports, "extremeRelatedItems", { enumerable: true, get: function () { return related_extremes_1.extremeRelatedItems; } });
|
|
53
|
+
Object.defineProperty(exports, "extremeRelatedQuery", { enumerable: true, get: function () { return related_extremes_1.extremeRelatedQuery; } });
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type RelatedExtreme, type RelatedHostAggregate } from '../../shared/list-schema';
|
|
2
|
+
import { type RelatedQueryInput } from './related';
|
|
3
|
+
import type { ReadScopeInput } from './read-scope-sql';
|
|
4
|
+
type Aggregates = Record<string, RelatedHostAggregate>;
|
|
5
|
+
/** The least or greatest `payload.<path>` among each host's items. */
|
|
6
|
+
export declare function extremeRelatedItems(opts: {
|
|
7
|
+
hostIds: string[];
|
|
8
|
+
scope: ReadScopeInput;
|
|
9
|
+
fold: RelatedExtreme;
|
|
10
|
+
path: string;
|
|
11
|
+
}): Promise<Aggregates>;
|
|
12
|
+
/** The least or greatest `metadata.<key>` among the rows sharing each host's facets. */
|
|
13
|
+
export declare function extremeRelatedQuery(input: RelatedQueryInput & {
|
|
14
|
+
fold: RelatedExtreme;
|
|
15
|
+
path: string;
|
|
16
|
+
}): Promise<Aggregates>;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// min/max over a related set: the least or greatest item payload value, or
|
|
4
|
+
// related row metadata value, per host. One statement per (set, value) pair,
|
|
5
|
+
// under the same read scope as the set's counts.
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.extremeRelatedItems = extremeRelatedItems;
|
|
9
|
+
exports.extremeRelatedQuery = extremeRelatedQuery;
|
|
10
|
+
const db_1 = require("../../lib/db");
|
|
11
|
+
const list_schema_1 = require("../../shared/list-schema");
|
|
12
|
+
const client_1 = require("./client");
|
|
13
|
+
const related_1 = require("./related");
|
|
14
|
+
const NUMBER_TEXT = '^-?[0-9]+(\\.[0-9]+)?([eE][-+]?[0-9]+)?$';
|
|
15
|
+
/**
|
|
16
|
+
* Per host: how many values, whether every one is numeric, and the extreme
|
|
17
|
+
* as a number and as text. `v` is the jsonb value; objects, arrays, nulls and
|
|
18
|
+
* blanks are not values. Text compares in code-unit order, as the dashboard folds.
|
|
19
|
+
*/
|
|
20
|
+
function extremeSelect(fold, hostId, v, from) {
|
|
21
|
+
const fn = fold === list_schema_1.RELATED_AGGREGATES.MIN ? 'min' : 'max';
|
|
22
|
+
return `SELECT host_id, count(*)::int AS n, bool_and(t ~ '${NUMBER_TEXT}') AS numeric,
|
|
23
|
+
${fn}(CASE WHEN t ~ '${NUMBER_TEXT}' THEN t::numeric END)::text AS num,
|
|
24
|
+
${fn}(t COLLATE "C") AS txt
|
|
25
|
+
FROM (SELECT h_id AS host_id, x #>> '{}' AS t
|
|
26
|
+
FROM (SELECT ${hostId}::text AS h_id, ${v} AS x ${from}) raw
|
|
27
|
+
WHERE jsonb_typeof(x) IN ('string', 'number', 'boolean') AND x #>> '{}' <> '') vals
|
|
28
|
+
GROUP BY host_id`;
|
|
29
|
+
}
|
|
30
|
+
function foldExtremeRows(rows, hostIds) {
|
|
31
|
+
const out = {};
|
|
32
|
+
for (const id of hostIds)
|
|
33
|
+
out[id] = { count: 0 };
|
|
34
|
+
for (const row of rows) {
|
|
35
|
+
if (!out[row.host_id])
|
|
36
|
+
continue;
|
|
37
|
+
const value = row.numeric && row.num !== null ? Number(row.num) : row.txt;
|
|
38
|
+
out[row.host_id] = value === null ? { count: row.n } : { count: row.n, value };
|
|
39
|
+
}
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
42
|
+
/** The least or greatest `payload.<path>` among each host's items. */
|
|
43
|
+
async function extremeRelatedItems(opts) {
|
|
44
|
+
if (!opts.hostIds.length)
|
|
45
|
+
return {};
|
|
46
|
+
await (0, client_1.ensureEscalationCompatView)();
|
|
47
|
+
const params = [];
|
|
48
|
+
const cte = (0, related_1.itemEntriesCte)(params, opts.scope, opts.hostIds);
|
|
49
|
+
const pi = params.push(opts.path.slice(list_schema_1.SPLIT_PATHS.PAYLOAD.length).split('.'));
|
|
50
|
+
const v = `(CASE WHEN en.acc THEN en.entry->'payload' ELSE en.entry END) #> $${pi}::text[]`;
|
|
51
|
+
const { rows } = await (0, db_1.getPool)().query(`WITH ${cte} ${extremeSelect(opts.fold, 'en.host_id', v, 'FROM entries en')}`, params);
|
|
52
|
+
return foldExtremeRows(rows, opts.hostIds);
|
|
53
|
+
}
|
|
54
|
+
/** The least or greatest `metadata.<key>` among the rows sharing each host's facets. */
|
|
55
|
+
async function extremeRelatedQuery(input) {
|
|
56
|
+
const hostIds = input.hosts.map((h) => h.hostId);
|
|
57
|
+
if (!hostIds.length || !input.roles.length)
|
|
58
|
+
return foldExtremeRows([], hostIds);
|
|
59
|
+
await (0, client_1.ensureEscalationCompatView)();
|
|
60
|
+
const params = [];
|
|
61
|
+
const from = (0, related_1.querySetFrom)(params, input);
|
|
62
|
+
const ki = params.push(input.path.slice(list_schema_1.SPLIT_PATHS.METADATA.length));
|
|
63
|
+
const { rows } = await (0, db_1.getPool)().query(extremeSelect(input.fold, 'h.host_id', `e.metadata->$${ki}`, from), params);
|
|
64
|
+
return foldExtremeRows(rows, hostIds);
|
|
65
|
+
}
|
|
@@ -12,6 +12,8 @@ export interface RelatedQueryInput {
|
|
|
12
12
|
scope: ReadScopeInput;
|
|
13
13
|
}
|
|
14
14
|
type Aggregates = Record<string, RelatedHostAggregate>;
|
|
15
|
+
/** The hosts and their item entries, read under the caller's scope. */
|
|
16
|
+
export declare function itemEntriesCte(params: unknown[], scope: ReadScopeInput, hostIds: string[]): string;
|
|
15
17
|
/**
|
|
16
18
|
* Count each host's items, optionally split by `payload.<path>` or
|
|
17
19
|
* `reciprocal.metadata.<key>`. A reciprocal split counts only reciprocal rows
|
|
@@ -35,6 +37,8 @@ export declare function listRelatedItems(opts: {
|
|
|
35
37
|
rows: RelatedRow[];
|
|
36
38
|
total: number;
|
|
37
39
|
}>;
|
|
40
|
+
/** The shared FROM/WHERE of a query set: hosts unnested beside their matches. */
|
|
41
|
+
export declare function querySetFrom(params: unknown[], input: RelatedQueryInput): string;
|
|
38
42
|
/**
|
|
39
43
|
* Count the rows that share each host's facets, grouped by role and an
|
|
40
44
|
* optional `metadata.<key>` split. The GIN index serves each host's match.
|
|
@@ -7,8 +7,10 @@
|
|
|
7
7
|
// the page size or the item count.
|
|
8
8
|
// ---------------------------------------------------------------------------
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.itemEntriesCte = itemEntriesCte;
|
|
10
11
|
exports.aggregateRelatedItems = aggregateRelatedItems;
|
|
11
12
|
exports.listRelatedItems = listRelatedItems;
|
|
13
|
+
exports.querySetFrom = querySetFrom;
|
|
12
14
|
exports.aggregateRelatedQuery = aggregateRelatedQuery;
|
|
13
15
|
exports.listRelatedQueryRows = listRelatedQueryRows;
|
|
14
16
|
exports.readRelatedHosts = readRelatedHosts;
|
|
@@ -23,6 +23,7 @@ exports.toValidationErrorBody = toValidationErrorBody;
|
|
|
23
23
|
*/
|
|
24
24
|
const form_validation_1 = require("../../shared/form-validation");
|
|
25
25
|
const submit_guard_1 = require("./submit-guard");
|
|
26
|
+
const roster_1 = require("./roster");
|
|
26
27
|
const enforcement_cache_1 = require("../role/enforcement-cache");
|
|
27
28
|
const knowledge_1 = require("../knowledge");
|
|
28
29
|
const escalation_1 = require("../../types/escalation");
|
|
@@ -85,6 +86,12 @@ async function checkResolverPayload(escalation, resolverPayload, loadEnvelope, r
|
|
|
85
86
|
payload: parseJsonOrNull(escalation.escalation_payload),
|
|
86
87
|
...(lookup ? { lookup } : {}),
|
|
87
88
|
};
|
|
89
|
+
// Roster counts read the submitted form values (an `in` source may name a
|
|
90
|
+
// form field), then join the context so showIf and the guard see them.
|
|
91
|
+
const formValues = (0, form_validation_1.mapPayloadToForm)(resolverPayload, schema);
|
|
92
|
+
const roster = await (0, roster_1.loadRosterCounts)(schema, { ...ctx, resolver: formValues, input: formValues });
|
|
93
|
+
if (Object.keys(roster).length)
|
|
94
|
+
ctx.roster = roster;
|
|
88
95
|
const violations = (0, form_validation_1.validateResolverPayload)(schema, resolverPayload, ctx);
|
|
89
96
|
// The query precondition (x-lt-submit-guard): reject while the embedded query
|
|
90
97
|
// still returns rows. Enforced on the same enforce_schema opt-in as the field
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-side roster counts: the API-first counterpart of the dashboard's
|
|
3
|
+
* roster widget. For each `x-lt-roster` field of a form schema, the member
|
|
4
|
+
* rows are read with the same query the widget runs and the shared
|
|
5
|
+
* `computeRoster` turns them into counts, so `roster.*` showIf conditions and
|
|
6
|
+
* a roster submit guard evaluate at resolve exactly as the form showed them.
|
|
7
|
+
*
|
|
8
|
+
* Member rows are read with `global: true`: a resolver who cannot see a
|
|
9
|
+
* member must never be told the roster is complete.
|
|
10
|
+
*/
|
|
11
|
+
import { type RosterCounts, type ShowIfContext } from '../../shared/form-validation';
|
|
12
|
+
/** Each roster field's counts, keyed by field name; empty when the schema declares none. */
|
|
13
|
+
export declare function loadRosterCounts(schema: Record<string, unknown> | null | undefined, ctx: ShowIfContext): Promise<Record<string, RosterCounts>>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.loadRosterCounts = loadRosterCounts;
|
|
4
|
+
/**
|
|
5
|
+
* Server-side roster counts: the API-first counterpart of the dashboard's
|
|
6
|
+
* roster widget. For each `x-lt-roster` field of a form schema, the member
|
|
7
|
+
* rows are read with the same query the widget runs and the shared
|
|
8
|
+
* `computeRoster` turns them into counts, so `roster.*` showIf conditions and
|
|
9
|
+
* a roster submit guard evaluate at resolve exactly as the form showed them.
|
|
10
|
+
*
|
|
11
|
+
* Member rows are read with `global: true`: a resolver who cannot see a
|
|
12
|
+
* member must never be told the roster is complete.
|
|
13
|
+
*/
|
|
14
|
+
const form_validation_1 = require("../../shared/form-validation");
|
|
15
|
+
const queries_1 = require("./queries");
|
|
16
|
+
/** Each roster field's counts, keyed by field name; empty when the schema declares none. */
|
|
17
|
+
async function loadRosterCounts(schema, ctx) {
|
|
18
|
+
const defs = (0, form_validation_1.readRosterDefs)(schema);
|
|
19
|
+
const counts = {};
|
|
20
|
+
for (const [field, def] of Object.entries(defs)) {
|
|
21
|
+
counts[field] = (0, form_validation_1.computeRoster)(def, ctx, await readMemberRows(def, ctx)).counts;
|
|
22
|
+
}
|
|
23
|
+
return counts;
|
|
24
|
+
}
|
|
25
|
+
async function readMemberRows(def, ctx) {
|
|
26
|
+
const query = (0, form_validation_1.rosterQueryOf)(def);
|
|
27
|
+
const scoped = query ? (0, form_validation_1.resolveRosterQuery)(query, ctx) : null;
|
|
28
|
+
if (!scoped)
|
|
29
|
+
return [];
|
|
30
|
+
const { escalations } = await (0, queries_1.searchEscalationsFaceted)({
|
|
31
|
+
global: true,
|
|
32
|
+
facet: { roles: scoped.roles, status: scoped.status, facets: scoped.facets },
|
|
33
|
+
limit: scoped.limit,
|
|
34
|
+
offset: 0,
|
|
35
|
+
});
|
|
36
|
+
return escalations.map((row) => (0, form_validation_1.rosterRowContext)(row));
|
|
37
|
+
}
|
|
@@ -15,6 +15,9 @@
|
|
|
15
15
|
* - A guard whose scope cannot be evaluated (e.g. `assigned:'me'` on a surface
|
|
16
16
|
* with no resolving user, like an MCP resolve) is skipped here; the consuming
|
|
17
17
|
* workflow's own verification remains the durable backstop.
|
|
18
|
+
*
|
|
19
|
+
* A roster guard reads the counts the caller placed under `ctx.roster`
|
|
20
|
+
* (services/escalation/roster.ts) and rejects while entries are outstanding.
|
|
18
21
|
*/
|
|
19
22
|
import { type ShowIfContext } from '../../shared/form-validation';
|
|
20
23
|
import type { LTFieldViolation } from '../../types/validation';
|
|
@@ -19,6 +19,9 @@ exports.checkSubmitGuard = checkSubmitGuard;
|
|
|
19
19
|
* - A guard whose scope cannot be evaluated (e.g. `assigned:'me'` on a surface
|
|
20
20
|
* with no resolving user, like an MCP resolve) is skipped here; the consuming
|
|
21
21
|
* workflow's own verification remains the durable backstop.
|
|
22
|
+
*
|
|
23
|
+
* A roster guard reads the counts the caller placed under `ctx.roster`
|
|
24
|
+
* (services/escalation/roster.ts) and rejects while entries are outstanding.
|
|
22
25
|
*/
|
|
23
26
|
const form_validation_1 = require("../../shared/form-validation");
|
|
24
27
|
const queries_1 = require("./queries");
|
|
@@ -34,6 +37,10 @@ async function checkSubmitGuard(schema, ctx, resolvingUserId) {
|
|
|
34
37
|
const guard = (0, form_validation_1.readSubmitGuard)(schema);
|
|
35
38
|
if (!guard || guard.mustBeEmpty === false)
|
|
36
39
|
return null;
|
|
40
|
+
if (guard.roster)
|
|
41
|
+
return checkRosterGuard(guard, ctx);
|
|
42
|
+
if (!guard.query)
|
|
43
|
+
return null;
|
|
37
44
|
const scoped = (0, form_validation_1.resolveScopedQuery)(guard.query, ctx, resolvingUserId);
|
|
38
45
|
if (!scoped.enabled)
|
|
39
46
|
return null;
|
|
@@ -51,7 +58,19 @@ async function checkSubmitGuard(schema, ctx, resolvingUserId) {
|
|
|
51
58
|
});
|
|
52
59
|
if (total <= 0)
|
|
53
60
|
return null;
|
|
54
|
-
|
|
55
|
-
|
|
61
|
+
return guardViolation(guard.message ?? form_validation_1.SUBMIT_GUARD_DEFAULT_MESSAGE, total, ctx);
|
|
62
|
+
}
|
|
63
|
+
/** A roster guard: outstanding entries reject; a roster the schema does not declare rejects too. */
|
|
64
|
+
function checkRosterGuard(guard, ctx) {
|
|
65
|
+
const counts = ctx.roster?.[guard.roster];
|
|
66
|
+
if (!counts) {
|
|
67
|
+
return { field: exports.SUBMIT_GUARD_VIOLATION_FIELD, message: `Submit guard names roster "${guard.roster}", which the form does not declare` };
|
|
68
|
+
}
|
|
69
|
+
if (counts.outstanding <= 0)
|
|
70
|
+
return null;
|
|
71
|
+
return guardViolation(guard.message ?? form_validation_1.ROSTER_GUARD_DEFAULT_MESSAGE, counts.outstanding, ctx);
|
|
72
|
+
}
|
|
73
|
+
function guardViolation(template, count, ctx) {
|
|
74
|
+
const message = (0, form_validation_1.interpolateHelp)(template.replace(/\{\{count\}\}/g, String(count)), ctx);
|
|
56
75
|
return { field: exports.SUBMIT_GUARD_VIOLATION_FIELD, message };
|
|
57
76
|
}
|
|
@@ -225,7 +225,7 @@ function registerHumanQueueTools(server) {
|
|
|
225
225
|
isError: true,
|
|
226
226
|
};
|
|
227
227
|
}
|
|
228
|
-
const resolved = await escalationService.resolveEscalation(args.escalation_id, args.payload, args.metadata);
|
|
228
|
+
const resolved = await escalationService.resolveEscalation(args.escalation_id, args.payload, { ...args.metadata, resolved_by: args.resolver_id });
|
|
229
229
|
if (!resolved) {
|
|
230
230
|
return {
|
|
231
231
|
content: [{
|
|
@@ -9,6 +9,7 @@ export declare const DISPLAY_ONLY_WIDGET_NAMES: {
|
|
|
9
9
|
readonly ESCALATION: "escalation";
|
|
10
10
|
readonly ESCALATION_LIST: "escalation-list";
|
|
11
11
|
readonly INVOKE: "invoke";
|
|
12
|
+
readonly ROSTER: "roster";
|
|
12
13
|
};
|
|
13
14
|
export declare const DISPLAY_ONLY_WIDGETS: ReadonlySet<string>;
|
|
14
15
|
export declare function isDisplayOnlyWidget(name: unknown): boolean;
|
|
@@ -14,6 +14,7 @@ exports.DISPLAY_ONLY_WIDGET_NAMES = {
|
|
|
14
14
|
ESCALATION: 'escalation',
|
|
15
15
|
ESCALATION_LIST: 'escalation-list',
|
|
16
16
|
INVOKE: 'invoke',
|
|
17
|
+
ROSTER: 'roster',
|
|
17
18
|
};
|
|
18
19
|
exports.DISPLAY_ONLY_WIDGETS = new Set(Object.values(exports.DISPLAY_ONLY_WIDGET_NAMES));
|
|
19
20
|
function isDisplayOnlyWidget(name) {
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* Semantics per field:
|
|
10
10
|
* - x-lt-showIf-hidden fields are skipped entirely (a field the submitter
|
|
11
11
|
* cannot see never blocks submission)
|
|
12
|
+
* - x-lt-hidden fields are never required; a value they carry is checked
|
|
12
13
|
* - required (schema.required membership), with checklist/empty-object rules
|
|
13
14
|
* - declared-type check (string/number/integer/boolean/array/object)
|
|
14
15
|
* - enum membership
|