@hotmeshio/long-tail 0.10.13 → 0.10.14
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 +2 -4
- package/build/api/escalations/metadata.js +1 -1
- package/build/api/escalations/resolve.js +4 -4
- package/build/services/escalation/resolver-validation.d.ts +1 -1
- package/build/services/escalation/resolver-validation.js +12 -5
- package/build/services/escalation/submit-guard.d.ts +29 -0
- package/build/services/escalation/submit-guard.js +57 -0
- package/build/shared/form-validation/index.d.ts +4 -0
- package/build/shared/form-validation/index.js +4 -0
- package/build/shared/form-validation/x-lt-labels.d.ts +28 -0
- package/build/shared/form-validation/x-lt-labels.js +42 -0
- package/build/shared/form-validation/x-lt-query.d.ts +56 -0
- package/build/shared/form-validation/x-lt-query.js +49 -0
- package/build/shared/form-validation/x-lt-submit-guard.d.ts +46 -0
- package/build/shared/form-validation/x-lt-submit-guard.js +25 -0
- package/build/shared/form-validation/x-lt-submit-on-claim.d.ts +22 -0
- package/build/shared/form-validation/x-lt-submit-on-claim.js +28 -0
- package/build/tsconfig.tsbuildinfo +1 -1
- package/dashboard/dist/assets/{AdminDashboard-Bv3pHBzn.js → AdminDashboard-Chg69wlx.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-Bv3pHBzn.js.map → AdminDashboard-Chg69wlx.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-Dk2zlvDb.js → AgentConfigPage-DRTFwbfC.js} +2 -2
- package/dashboard/dist/assets/{AgentConfigPage-Dk2zlvDb.js.map → AgentConfigPage-DRTFwbfC.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-DUno6EGs.js → AgentDetailPage-JKByfFIi.js} +3 -3
- package/dashboard/dist/assets/{AgentDetailPage-DUno6EGs.js.map → AgentDetailPage-JKByfFIi.js.map} +1 -1
- package/dashboard/dist/assets/AgentsPage-BlgEmKhA.js +2 -0
- package/dashboard/dist/assets/{AgentsPage-CToVu1qj.js.map → AgentsPage-BlgEmKhA.js.map} +1 -1
- package/dashboard/dist/assets/AvailableEscalationsPage-C_7y692Q.js +2 -0
- package/dashboard/dist/assets/{AvailableEscalationsPage-DldboL4W.js.map → AvailableEscalationsPage-C_7y692Q.js.map} +1 -1
- package/dashboard/dist/assets/{BotPicker-DQOpVB4M.js → BotPicker-CCVcz4Cq.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-DQOpVB4M.js.map → BotPicker-CCVcz4Cq.js.map} +1 -1
- package/dashboard/dist/assets/{CapabilitiesPage-Dmf46PUJ.js → CapabilitiesPage-Czi9jUwD.js} +2 -2
- package/dashboard/dist/assets/{CapabilitiesPage-Dmf46PUJ.js.map → CapabilitiesPage-Czi9jUwD.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-CDADefUY.js → CollapsibleSection-8YE965QX.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-CDADefUY.js.map → CollapsibleSection-8YE965QX.js.map} +1 -1
- package/dashboard/dist/assets/CountdownTimer-Bxvq3D7j.js +2 -0
- package/dashboard/dist/assets/CountdownTimer-Bxvq3D7j.js.map +1 -0
- package/dashboard/dist/assets/{CredentialsPage-8LIEvomi.js → CredentialsPage-Bn7_SX6-.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-8LIEvomi.js.map → CredentialsPage-Bn7_SX6-.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-CK3WSsM5.js → CronLabel-Bn4mX_Yn.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-CK3WSsM5.js.map → CronLabel-Bn4mX_Yn.js.map} +1 -1
- package/dashboard/dist/assets/{CustomDurationPicker-FPmlA6cE.js → CustomDurationPicker-pMcrFyW6.js} +2 -2
- package/dashboard/dist/assets/{CustomDurationPicker-FPmlA6cE.js.map → CustomDurationPicker-pMcrFyW6.js.map} +1 -1
- package/dashboard/dist/assets/{DropZone-CL9gA7pu.js → DropZone-zCEGjjk-.js} +2 -2
- package/dashboard/dist/assets/{DropZone-CL9gA7pu.js.map → DropZone-zCEGjjk-.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-BZVkVxE0.js → ElapsedCell-BGO7IXEg.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-BZVkVxE0.js.map → ElapsedCell-BGO7IXEg.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationListSchemaPage-kYLdUtZX.js → EscalationListSchemaPage-CFDxbd50.js} +3 -3
- package/dashboard/dist/assets/{EscalationListSchemaPage-kYLdUtZX.js.map → EscalationListSchemaPage-CFDxbd50.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationSchemaPage-kUmCDivo.js → EscalationSchemaPage-DnXPnDkz.js} +3 -3
- package/dashboard/dist/assets/{EscalationSchemaPage-kUmCDivo.js.map → EscalationSchemaPage-DnXPnDkz.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-D17auO-m.js → EscalationsOverview-BZMVXrkK.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-D17auO-m.js.map → EscalationsOverview-BZMVXrkK.js.map} +1 -1
- package/dashboard/dist/assets/EventTable-Bfi-f8as.js +2 -0
- package/dashboard/dist/assets/EventTable-Bfi-f8as.js.map +1 -0
- package/dashboard/dist/assets/FilterBar-Do7yR4xM.js +2 -0
- package/dashboard/dist/assets/FilterBar-Do7yR4xM.js.map +1 -0
- package/dashboard/dist/assets/{GraphInvokePage-D11uOnZi.js → GraphInvokePage-d1ie4T7f.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-D11uOnZi.js.map → GraphInvokePage-d1ie4T7f.js.map} +1 -1
- package/dashboard/dist/assets/{HomePage-Bcq10Bxx.js → HomePage-BEeodImU.js} +2 -2
- package/dashboard/dist/assets/{HomePage-Bcq10Bxx.js.map → HomePage-BEeodImU.js.map} +1 -1
- package/dashboard/dist/assets/{ListToolbar-IPXsTb3Q.js → ListToolbar-CLtw-1QN.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-IPXsTb3Q.js.map → ListToolbar-CLtw-1QN.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-Dx2j0KkF.js → McpOverview-DIsy9TB3.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-Dx2j0KkF.js.map → McpOverview-DIsy9TB3.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-CzF_bna8.js → McpQueryDetailPage-6PomdsyD.js} +2 -2
- package/dashboard/dist/assets/{McpQueryDetailPage-CzF_bna8.js.map → McpQueryDetailPage-6PomdsyD.js.map} +1 -1
- package/dashboard/dist/assets/McpQueryPage-YMdQCXm9.js +2 -0
- package/dashboard/dist/assets/{McpQueryPage-CNsuiw_q.js.map → McpQueryPage-YMdQCXm9.js.map} +1 -1
- package/dashboard/dist/assets/McpRunDetailPage-DsD1Gm2o.js +2 -0
- package/dashboard/dist/assets/McpRunDetailPage-DsD1Gm2o.js.map +1 -0
- package/dashboard/dist/assets/{McpRunsPage-CK96s3Nt.js → McpRunsPage--a5Jgb33.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-CK96s3Nt.js.map → McpRunsPage--a5Jgb33.js.map} +1 -1
- package/dashboard/dist/assets/{NamespacePill-B9Vc_Pz2.js → NamespacePill-wV6L4VW1.js} +2 -2
- package/dashboard/dist/assets/{NamespacePill-B9Vc_Pz2.js.map → NamespacePill-wV6L4VW1.js.map} +1 -1
- package/dashboard/dist/assets/OperationsPage-B2v9k3DT.js +2 -0
- package/dashboard/dist/assets/{OperationsPage-DvWrLuH6.js.map → OperationsPage-B2v9k3DT.js.map} +1 -1
- package/dashboard/dist/assets/OperatorDashboard-CkLfbxEh.js +2 -0
- package/dashboard/dist/assets/{OperatorDashboard-C-jE0IRA.js.map → OperatorDashboard-CkLfbxEh.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeader-Ce4GcIYo.js → PageHeader-BtIr6r-8.js} +2 -2
- package/dashboard/dist/assets/{PageHeader-Ce4GcIYo.js.map → PageHeader-BtIr6r-8.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeaderWithStats-Ck0KZvXD.js → PageHeaderWithStats-C2sGqFQG.js} +2 -2
- package/dashboard/dist/assets/{PageHeaderWithStats-Ck0KZvXD.js.map → PageHeaderWithStats-C2sGqFQG.js.map} +1 -1
- package/dashboard/dist/assets/{PersonaDetailPage-CJ6jqo7h.js → PersonaDetailPage-CCmOgKQb.js} +2 -2
- package/dashboard/dist/assets/{PersonaDetailPage-CJ6jqo7h.js.map → PersonaDetailPage-CCmOgKQb.js.map} +1 -1
- package/dashboard/dist/assets/{PersonasPage-D8hL3kL5.js → PersonasPage-BJkSuDTN.js} +2 -2
- package/dashboard/dist/assets/{PersonasPage-D8hL3kL5.js.map → PersonasPage-BJkSuDTN.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessDetailPage-Vnx8Z5_y.js → ProcessDetailPage-DT9BlJXK.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-Vnx8Z5_y.js.map → ProcessDetailPage-DT9BlJXK.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-DRYtvS3N.js → ProcessesListPage-DgSGzTDT.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-DRYtvS3N.js.map → ProcessesListPage-DgSGzTDT.js.map} +1 -1
- package/dashboard/dist/assets/{RoleDetailPage-BKkUvTO-.js → RoleDetailPage-DMphTvro.js} +2 -2
- package/dashboard/dist/assets/{RoleDetailPage-BKkUvTO-.js.map → RoleDetailPage-DMphTvro.js.map} +1 -1
- package/dashboard/dist/assets/{RolePill-CnuBPhPw.js → RolePill-BBYjhAPj.js} +2 -2
- package/dashboard/dist/assets/{RolePill-CnuBPhPw.js.map → RolePill-BBYjhAPj.js.map} +1 -1
- package/dashboard/dist/assets/{RolesPage-BHzWK9n6.js → RolesPage-gi_kaot1.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-BHzWK9n6.js.map → RolesPage-gi_kaot1.js.map} +1 -1
- package/dashboard/dist/assets/RunAsSelector-CateuvcC.js +2 -0
- package/dashboard/dist/assets/{RunAsSelector-CS3KQ-BF.js.map → RunAsSelector-CateuvcC.js.map} +1 -1
- package/dashboard/dist/assets/{ScanCodesPage-BW4P4zWf.js → ScanCodesPage-CQ8RxMug.js} +2 -2
- package/dashboard/dist/assets/{ScanCodesPage-BW4P4zWf.js.map → ScanCodesPage-CQ8RxMug.js.map} +1 -1
- package/dashboard/dist/assets/{ScanSchemeDetailPage-BLykA4j-.js → ScanSchemeDetailPage-puSbuxcV.js} +2 -2
- package/dashboard/dist/assets/{ScanSchemeDetailPage-BLykA4j-.js.map → ScanSchemeDetailPage-puSbuxcV.js.map} +1 -1
- package/dashboard/dist/assets/{ScopeBadge-BUpYpS3x.js → ScopeBadge-xs2Nhjy4.js} +2 -2
- package/dashboard/dist/assets/{ScopeBadge-BUpYpS3x.js.map → ScopeBadge-xs2Nhjy4.js.map} +1 -1
- package/dashboard/dist/assets/SegmentedTabs-DXNzY05q.js +2 -0
- package/dashboard/dist/assets/SegmentedTabs-DXNzY05q.js.map +1 -0
- package/dashboard/dist/assets/StickyPagination-Cg-QdYWL.js +2 -0
- package/dashboard/dist/assets/StickyPagination-Cg-QdYWL.js.map +1 -0
- package/dashboard/dist/assets/{StreamMessageDetail-DyJyZwBl.js → StreamMessageDetail-DEeuh4_-.js} +2 -2
- package/dashboard/dist/assets/{StreamMessageDetail-DyJyZwBl.js.map → StreamMessageDetail-DEeuh4_-.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-BlzV74V5.js → SwimlaneTimeline-DMY0jL2F.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-BlzV74V5.js.map → SwimlaneTimeline-DMY0jL2F.js.map} +1 -1
- package/dashboard/dist/assets/{TagInput-BbZ25nNe.js → TagInput-BMmiV-MD.js} +2 -2
- package/dashboard/dist/assets/{TagInput-BbZ25nNe.js.map → TagInput-BMmiV-MD.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-B0p_Z4J_.js → TaskDetailPage-CPbkIvfF.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-B0p_Z4J_.js.map → TaskDetailPage-CPbkIvfF.js.map} +1 -1
- package/dashboard/dist/assets/{TaskQueuePill-D0QKBrN3.js → TaskQueuePill-DLgYaw1x.js} +2 -2
- package/dashboard/dist/assets/{TaskQueuePill-D0QKBrN3.js.map → TaskQueuePill-DLgYaw1x.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-CiGR2QiQ.js → TasksListPage-CtHudKhQ.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-CiGR2QiQ.js.map → TasksListPage-CtHudKhQ.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-D_DA9ucC.js → TimeAgo-BdHOizWg.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-D_DA9ucC.js.map → TimeAgo-BdHOizWg.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-C7rkC9nh.js → TimestampCell-FVukzKRe.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-C7rkC9nh.js.map → TimestampCell-FVukzKRe.js.map} +1 -1
- package/dashboard/dist/assets/{ToolPill-8xY9rkoc.js → ToolPill-BvS53hxP.js} +2 -2
- package/dashboard/dist/assets/{ToolPill-8xY9rkoc.js.map → ToolPill-BvS53hxP.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-E8efYGYs.js → ToolTestPanel-HN0OCYTL.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-E8efYGYs.js.map → ToolTestPanel-HN0OCYTL.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-B455XrRc.js → TopicDetailPage-DHdSpN61.js} +4 -4
- package/dashboard/dist/assets/{TopicDetailPage-B455XrRc.js.map → TopicDetailPage-DHdSpN61.js.map} +1 -1
- package/dashboard/dist/assets/{TopicsPage-1VAc29Qw.js → TopicsPage-Clr6Tl5P.js} +2 -2
- package/dashboard/dist/assets/{TopicsPage-1VAc29Qw.js.map → TopicsPage-Clr6Tl5P.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-DikzjQHJ.js → UserName-BUVYyIAS.js} +2 -2
- package/dashboard/dist/assets/{UserName-DikzjQHJ.js.map → UserName-BUVYyIAS.js.map} +1 -1
- package/dashboard/dist/assets/WorkflowExecutionPage-kncWFfe5.js +2 -0
- package/dashboard/dist/assets/WorkflowExecutionPage-kncWFfe5.js.map +1 -0
- package/dashboard/dist/assets/{WorkflowPill-Da406nEj.js → WorkflowPill-BPC_Dc_I.js} +2 -2
- package/dashboard/dist/assets/{WorkflowPill-Da406nEj.js.map → WorkflowPill-BPC_Dc_I.js.map} +1 -1
- package/dashboard/dist/assets/WorkflowsDashboard-4ypPDGKx.js +2 -0
- package/dashboard/dist/assets/{WorkflowsDashboard-BMQd_0tW.js.map → WorkflowsDashboard-4ypPDGKx.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-CdxjVifp.js → WorkflowsOverview-CeQlZkkd.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-CdxjVifp.js.map → WorkflowsOverview-CeQlZkkd.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-DNVffIXa.js → YamlWorkflowDetailPage-DLAlEzwT.js} +10 -10
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-DNVffIXa.js.map → YamlWorkflowDetailPage-DLAlEzwT.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-BGP8wuos.js → YamlWorkflowsPage-DQhenKFT.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-BGP8wuos.js.map → YamlWorkflowsPage-DQhenKFT.js.map} +1 -1
- package/dashboard/dist/assets/{agents-BZJLIJ4h.js → agents-s3feet3W.js} +2 -2
- package/dashboard/dist/assets/{agents-BZJLIJ4h.js.map → agents-s3feet3W.js.map} +1 -1
- package/dashboard/dist/assets/{bots-ClLcDGJb.js → bots-CkSd2rn9.js} +2 -2
- package/dashboard/dist/assets/{bots-ClLcDGJb.js.map → bots-CkSd2rn9.js.map} +1 -1
- package/dashboard/dist/assets/capabilities-DA_r09tM.js +2 -0
- package/dashboard/dist/assets/{capabilities-IaCcS7ge.js.map → capabilities-DA_r09tM.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-Zi4m_MSx.js → controlplane-C9c25q21.js} +2 -2
- package/dashboard/dist/assets/{controlplane-Zi4m_MSx.js.map → controlplane-C9c25q21.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-columns-BY2mg9DY.js → escalation-columns-Cp3UrT48.js} +2 -2
- package/dashboard/dist/assets/{escalation-columns-BY2mg9DY.js.map → escalation-columns-Cp3UrT48.js.map} +1 -1
- package/dashboard/dist/assets/{index-CJu2PBNx.js → index--7Vdkzwd.js} +2 -2
- package/dashboard/dist/assets/{index-CJu2PBNx.js.map → index--7Vdkzwd.js.map} +1 -1
- package/dashboard/dist/assets/{index-CfAi1OsI.js → index--DG-qQBT.js} +26 -26
- package/dashboard/dist/assets/index--DG-qQBT.js.map +1 -0
- package/dashboard/dist/assets/{index-CmnNqpWg.js → index-BIcYbDVf.js} +2 -2
- package/dashboard/dist/assets/{index-CmnNqpWg.js.map → index-BIcYbDVf.js.map} +1 -1
- package/dashboard/dist/assets/index-BU5FFAJo.js +2 -0
- package/dashboard/dist/assets/{index-CLmZaNTK.js.map → index-BU5FFAJo.js.map} +1 -1
- package/dashboard/dist/assets/{index-yGNt29V9.js → index-Bo5TtX9l.js} +2 -2
- package/dashboard/dist/assets/{index-yGNt29V9.js.map → index-Bo5TtX9l.js.map} +1 -1
- package/dashboard/dist/assets/{index-BqGnhkh0.js → index-C-MmR-jf.js} +2 -2
- package/dashboard/dist/assets/{index-BqGnhkh0.js.map → index-C-MmR-jf.js.map} +1 -1
- package/dashboard/dist/assets/{index-BzkE48xJ.js → index-C7ABSOU2.js} +2 -2
- package/dashboard/dist/assets/{index-BzkE48xJ.js.map → index-C7ABSOU2.js.map} +1 -1
- package/dashboard/dist/assets/index-Cmxzk4ay.js +5 -0
- package/dashboard/dist/assets/{index-CvNBdkB1.js.map → index-Cmxzk4ay.js.map} +1 -1
- package/dashboard/dist/assets/{index-C3o4OisO.js → index-Cw9poaez.js} +2 -2
- package/dashboard/dist/assets/{index-C3o4OisO.js.map → index-Cw9poaez.js.map} +1 -1
- package/dashboard/dist/assets/index-DEbY57_c.js +3 -0
- package/dashboard/dist/assets/index-DEbY57_c.js.map +1 -0
- package/dashboard/dist/assets/index-DnV6LSeY.css +1 -0
- package/dashboard/dist/assets/{index-D0zFReGL.js → index-DvoMXQqO.js} +2 -2
- package/dashboard/dist/assets/{index-D0zFReGL.js.map → index-DvoMXQqO.js.map} +1 -1
- package/dashboard/dist/assets/{index-kiKZresb.js → index-S13oPvuS.js} +2 -2
- package/dashboard/dist/assets/{index-kiKZresb.js.map → index-S13oPvuS.js.map} +1 -1
- package/dashboard/dist/assets/index-WxE3ONia.js +2 -0
- package/dashboard/dist/assets/{index-Dldi3Q3M.js.map → index-WxE3ONia.js.map} +1 -1
- package/dashboard/dist/assets/{knowledge-DWLxGTib.js → knowledge-Bpln0zy_.js} +2 -2
- package/dashboard/dist/assets/{knowledge-DWLxGTib.js.map → knowledge-Bpln0zy_.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-B6AARZ2I.js → mcp-BqDq3RZH.js} +2 -2
- package/dashboard/dist/assets/{mcp-B6AARZ2I.js.map → mcp-BqDq3RZH.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-DrkvBU3a.js → mcp-query-DGue75R6.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-DrkvBU3a.js.map → mcp-query-DGue75R6.js.map} +1 -1
- package/dashboard/dist/assets/{personas-Cmz2SAEU.js → personas-B8z_sTiJ.js} +2 -2
- package/dashboard/dist/assets/{personas-Cmz2SAEU.js.map → personas-B8z_sTiJ.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-CSgfVCMy.js → pipelines-DYgNd9nB.js} +2 -2
- package/dashboard/dist/assets/{pipelines-CSgfVCMy.js.map → pipelines-DYgNd9nB.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-UOtUkDk-.js → tasks-CJdjjhgO.js} +2 -2
- package/dashboard/dist/assets/{tasks-UOtUkDk-.js.map → tasks-CJdjjhgO.js.map} +1 -1
- package/dashboard/dist/assets/{topics-Df5hGh6o.js → topics-DPrL8Dtq.js} +2 -2
- package/dashboard/dist/assets/{topics-Df5hGh6o.js.map → topics-DPrL8Dtq.js.map} +1 -1
- package/dashboard/dist/assets/{useEventHooks-PDbuSJ12.js → useEventHooks-DXCgDgiu.js} +2 -2
- package/dashboard/dist/assets/{useEventHooks-PDbuSJ12.js.map → useEventHooks-DXCgDgiu.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-tZSOlge3.js → useNamespace-DnFZfy7N.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-tZSOlge3.js.map → useNamespace-DnFZfy7N.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-CINLzE32.js → useYamlActivityEvents-kx5CLENv.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-CINLzE32.js.map → useYamlActivityEvents-kx5CLENv.js.map} +1 -1
- package/dashboard/dist/assets/{users-G8qwyZKS.js → users-DKng7vAG.js} +2 -2
- package/dashboard/dist/assets/{users-G8qwyZKS.js.map → users-DKng7vAG.js.map} +1 -1
- package/dashboard/dist/assets/{vendor-icons-BpZiWH2f.js → vendor-icons-CN-bAo9U.js} +138 -133
- package/dashboard/dist/assets/vendor-icons-CN-bAo9U.js.map +1 -0
- package/dashboard/dist/assets/{workflows-DbPqi1TW.js → workflows-C4V0rMkM.js} +2 -2
- package/dashboard/dist/assets/{workflows-DbPqi1TW.js.map → workflows-C4V0rMkM.js.map} +1 -1
- package/dashboard/dist/assets/{yaml-workflows-DozD8hpR.js → yaml-workflows-D3PAiJ9d.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-DozD8hpR.js.map → yaml-workflows-D3PAiJ9d.js.map} +1 -1
- package/dashboard/dist/index.html +3 -3
- package/docs/design-principles.md +9 -7
- package/docs/hitl/x-lt-embed.md +8 -4
- package/docs/hitl/x-lt-footer.md +68 -0
- package/docs/hitl/x-lt-list-schema.md +10 -3
- package/docs/hitl-guide.md +9 -0
- package/package.json +1 -1
- package/dashboard/dist/assets/AgentsPage-CToVu1qj.js +0 -2
- package/dashboard/dist/assets/AvailableEscalationsPage-DldboL4W.js +0 -2
- package/dashboard/dist/assets/CountdownTimer-DPjIkerB.js +0 -2
- package/dashboard/dist/assets/CountdownTimer-DPjIkerB.js.map +0 -1
- package/dashboard/dist/assets/EventTable-CwPWl163.js +0 -2
- package/dashboard/dist/assets/EventTable-CwPWl163.js.map +0 -1
- package/dashboard/dist/assets/FilterBar-D7GghUsU.js +0 -2
- package/dashboard/dist/assets/FilterBar-D7GghUsU.js.map +0 -1
- package/dashboard/dist/assets/McpQueryPage-CNsuiw_q.js +0 -2
- package/dashboard/dist/assets/McpRunDetailPage-BJguEMS0.js +0 -2
- package/dashboard/dist/assets/McpRunDetailPage-BJguEMS0.js.map +0 -1
- package/dashboard/dist/assets/OperationsPage-DvWrLuH6.js +0 -2
- package/dashboard/dist/assets/OperatorDashboard-C-jE0IRA.js +0 -2
- package/dashboard/dist/assets/RunAsSelector-CS3KQ-BF.js +0 -2
- package/dashboard/dist/assets/StickyPagination-hMrnLXde.js +0 -2
- package/dashboard/dist/assets/StickyPagination-hMrnLXde.js.map +0 -1
- package/dashboard/dist/assets/WorkflowExecutionPage-C15GSAoe.js +0 -2
- package/dashboard/dist/assets/WorkflowExecutionPage-C15GSAoe.js.map +0 -1
- package/dashboard/dist/assets/WorkflowsDashboard-BMQd_0tW.js +0 -2
- package/dashboard/dist/assets/capabilities-IaCcS7ge.js +0 -2
- package/dashboard/dist/assets/index-CLmZaNTK.js +0 -2
- package/dashboard/dist/assets/index-CfAi1OsI.js.map +0 -1
- package/dashboard/dist/assets/index-CvNBdkB1.js +0 -5
- package/dashboard/dist/assets/index-Dldi3Q3M.js +0 -2
- package/dashboard/dist/assets/index-mKcQGi2B.js +0 -3
- package/dashboard/dist/assets/index-mKcQGi2B.js.map +0 -1
- package/dashboard/dist/assets/index-zQiUPfxA.css +0 -1
- package/dashboard/dist/assets/vendor-icons-BpZiWH2f.js.map +0 -1
package/README.md
CHANGED
|
@@ -4,9 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
Durable platforms are built around determinism — that is their strength and their blind spot. They give you rich, first-class queues for deterministic work (retry, timeout, `backoffCoefficient`, exactly-once) and an `await condition()` to park a workflow until a signal arrives. All of it assumes the thing you are waiting on will, eventually, behave.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
Long Tail makes it a primitive. The same `condition()` wait — except the act of waiting mints a row that is searchable, claimable, deadlined, and role-gated on a shared metadata surface. Machines answer some rows, people answer others; the workflow resumes either way, exactly where it paused.
|
|
7
|
+
Long Tail makes non-determinism a primitive. The same `condition()` wait — except the act of waiting mints a row that is searchable, claimable, deadlined, and role-gated on a shared metadata surface. Machines answer some rows, people answer others; the workflow resumes either way, exactly where it paused.
|
|
10
8
|
|
|
11
9
|
```bash
|
|
12
10
|
npm install @hotmeshio/long-tail
|
|
@@ -14,7 +12,7 @@ npm install @hotmeshio/long-tail
|
|
|
14
12
|
|
|
15
13
|
## How it works
|
|
16
14
|
|
|
17
|
-
One workflow, both queues: `proxyActivities` for the deterministic one, `condition()` for
|
|
15
|
+
One workflow, both queues: `proxyActivities` for the deterministic one, `condition()` for non-determinism.
|
|
18
16
|
|
|
19
17
|
```typescript
|
|
20
18
|
import { Durable } from '@hotmeshio/hotmesh';
|
|
@@ -161,7 +161,7 @@ async function resolveByMetadata(input, auth) {
|
|
|
161
161
|
const enforcing = await (0, enforcement_cache_1.getEnforcingRoles)();
|
|
162
162
|
let result = await escalationService.resolveByMetadataAtomic(input.key, input.value, resolveUserId, input.resolverPayload, input.metadata, writeAllRoles, writeSelfRoles, enforcing.size > 0 ? [...enforcing] : null, null, input.extraFacets);
|
|
163
163
|
if (result.outcome === 'validation_required' && result.row) {
|
|
164
|
-
const report = await (0, resolver_validation_1.checkResolverPayload)(result.row, input.resolverPayload);
|
|
164
|
+
const report = await (0, resolver_validation_1.checkResolverPayload)(result.row, input.resolverPayload, undefined, resolveUserId);
|
|
165
165
|
if (report)
|
|
166
166
|
return (0, resolve_1.validationFailure)(report);
|
|
167
167
|
result = await escalationService.resolveByMetadataAtomic(input.key, input.value, resolveUserId, input.resolverPayload, input.metadata, writeAllRoles, writeSelfRoles, null, result.row.id, input.extraFacets);
|
|
@@ -98,7 +98,7 @@ async function resolveEscalation(input, auth) {
|
|
|
98
98
|
// the escalation's resolved form schema BEFORE any resolution path runs.
|
|
99
99
|
// Costs nothing when the role does not enforce (cached role set); the
|
|
100
100
|
// task-fallback envelope read only happens for enforcing roles.
|
|
101
|
-
const violation = await (0, resolver_validation_1.checkResolverPayload)(escalation, resolverPayload, () => reconstructEnvelope(escalation));
|
|
101
|
+
const violation = await (0, resolver_validation_1.checkResolverPayload)(escalation, resolverPayload, () => reconstructEnvelope(escalation), auth.userId);
|
|
102
102
|
if (violation)
|
|
103
103
|
return validationFailure(violation);
|
|
104
104
|
// The resolver payload is stored exactly as submitted — its shape is the
|
|
@@ -181,7 +181,7 @@ async function resolveBySignalKey(input, auth) {
|
|
|
181
181
|
return { status: 404, error: 'Escalation not found' };
|
|
182
182
|
// Schema enforcement — the row (envelope included) is already loaded, so
|
|
183
183
|
// this costs zero extra reads beyond the cached schema.
|
|
184
|
-
const violation = await (0, resolver_validation_1.checkResolverPayload)(escalation, resolverPayload);
|
|
184
|
+
const violation = await (0, resolver_validation_1.checkResolverPayload)(escalation, resolverPayload, undefined, auth.userId);
|
|
185
185
|
if (violation)
|
|
186
186
|
return validationFailure(violation);
|
|
187
187
|
// The payload is delivered as the signal the parked workflow's condition()
|
|
@@ -247,7 +247,7 @@ async function resolveByIds(input, auth) {
|
|
|
247
247
|
const fullRows = await escalationService.getEscalationsByIds(involved);
|
|
248
248
|
const failed = [];
|
|
249
249
|
for (const row of fullRows) {
|
|
250
|
-
const report = await (0, resolver_validation_1.checkResolverPayload)(row, resolverPayload);
|
|
250
|
+
const report = await (0, resolver_validation_1.checkResolverPayload)(row, resolverPayload, undefined, auth.userId);
|
|
251
251
|
if (report)
|
|
252
252
|
failed.push({ id: row.id, report });
|
|
253
253
|
}
|
|
@@ -346,7 +346,7 @@ async function resolveAllOrNone(input, auth) {
|
|
|
346
346
|
const row = rowById.get(item.id);
|
|
347
347
|
if (!row || !row.role || !enforcing.has(row.role))
|
|
348
348
|
continue;
|
|
349
|
-
const report = await (0, resolver_validation_1.checkResolverPayload)(row, item.resolverPayload);
|
|
349
|
+
const report = await (0, resolver_validation_1.checkResolverPayload)(row, item.resolverPayload, undefined, auth.userId);
|
|
350
350
|
if (report)
|
|
351
351
|
failed.push({ id: item.id, report });
|
|
352
352
|
}
|
|
@@ -23,6 +23,6 @@ export interface ResolverSchemaViolationReport {
|
|
|
23
23
|
* surface's task fallback); by default the row's own envelope column is used.
|
|
24
24
|
* It is only invoked when the role actually enforces.
|
|
25
25
|
*/
|
|
26
|
-
export declare function checkResolverPayload(escalation: ResolvableEscalationRow, resolverPayload: Record<string, any>, loadEnvelope?: () => Promise<Record<string, any
|
|
26
|
+
export declare function checkResolverPayload(escalation: ResolvableEscalationRow, resolverPayload: Record<string, any>, loadEnvelope?: () => Promise<Record<string, any>>, resolvingUserId?: string): Promise<ResolverSchemaViolationReport | null>;
|
|
27
27
|
/** The canonical 422 body for a violation report (types/validation.ts). */
|
|
28
28
|
export declare function toValidationErrorBody(report: ResolverSchemaViolationReport): LTValidationErrorBody;
|
|
@@ -22,6 +22,7 @@ exports.toValidationErrorBody = toValidationErrorBody;
|
|
|
22
22
|
* the gate passes.
|
|
23
23
|
*/
|
|
24
24
|
const form_validation_1 = require("../../shared/form-validation");
|
|
25
|
+
const submit_guard_1 = require("./submit-guard");
|
|
25
26
|
const enforcement_cache_1 = require("../role/enforcement-cache");
|
|
26
27
|
const escalation_1 = require("../../types/escalation");
|
|
27
28
|
const validation_1 = require("../../types/validation");
|
|
@@ -54,7 +55,7 @@ function pinnedVersionOf(metadata) {
|
|
|
54
55
|
* surface's task fallback); by default the row's own envelope column is used.
|
|
55
56
|
* It is only invoked when the role actually enforces.
|
|
56
57
|
*/
|
|
57
|
-
async function checkResolverPayload(escalation, resolverPayload, loadEnvelope) {
|
|
58
|
+
async function checkResolverPayload(escalation, resolverPayload, loadEnvelope, resolvingUserId) {
|
|
58
59
|
const role = escalation.role;
|
|
59
60
|
if (!role)
|
|
60
61
|
return null;
|
|
@@ -72,15 +73,21 @@ async function checkResolverPayload(escalation, resolverPayload, loadEnvelope) {
|
|
|
72
73
|
const envelope = loadEnvelope
|
|
73
74
|
? await loadEnvelope()
|
|
74
75
|
: parseJsonOrNull(escalation.envelope) ?? {};
|
|
75
|
-
const
|
|
76
|
+
const ctx = {
|
|
76
77
|
escalation: escalation,
|
|
77
78
|
metadata,
|
|
78
79
|
envelope,
|
|
79
80
|
payload: parseJsonOrNull(escalation.escalation_payload),
|
|
80
|
-
}
|
|
81
|
-
|
|
81
|
+
};
|
|
82
|
+
const violations = (0, form_validation_1.validateResolverPayload)(schema, resolverPayload, ctx);
|
|
83
|
+
// The query precondition (x-lt-submit-guard): reject while the embedded query
|
|
84
|
+
// still returns rows. Enforced on the same enforce_schema opt-in as the field
|
|
85
|
+
// contract, so a raw-API resolve honors the gate the dashboard shows.
|
|
86
|
+
const guardViolation = await (0, submit_guard_1.checkSubmitGuard)(schema, ctx, resolvingUserId);
|
|
87
|
+
const allViolations = guardViolation ? [...violations, guardViolation] : violations;
|
|
88
|
+
if (allViolations.length === 0)
|
|
82
89
|
return null;
|
|
83
|
-
return { role, schemaVersion: pin, violations };
|
|
90
|
+
return { role, schemaVersion: pin, violations: allViolations };
|
|
84
91
|
}
|
|
85
92
|
/** The canonical 422 body for a violation report (types/validation.ts). */
|
|
86
93
|
function toValidationErrorBody(report) {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-side enforcement of the `x-lt-submit-guard` query precondition — the
|
|
3
|
+
* API-first counterpart of the dashboard's `useSubmitGuard`. Before an
|
|
4
|
+
* escalation resolves, if its form schema declares a submit guard, the same
|
|
5
|
+
* embedded query runs and the resolve is REJECTED while it still returns rows.
|
|
6
|
+
*
|
|
7
|
+
* Isomorphism with the dashboard is exact: the guard reuses `resolveScopedQuery`
|
|
8
|
+
* (the mapping the escalation-list embed uses) and runs it through
|
|
9
|
+
* `searchEscalationsFaceted` — the same faceted query the list API composes.
|
|
10
|
+
*
|
|
11
|
+
* Two deliberate rules:
|
|
12
|
+
* - The count is taken with `global: true`, bypassing the resolver's read
|
|
13
|
+
* scope, so a role that cannot SEE the children can never falsely clear the
|
|
14
|
+
* gate. Only a real, empty result count clears it (the "403 ≠ empty" rule).
|
|
15
|
+
* - A guard whose scope cannot be evaluated (e.g. `assigned:'me'` on a surface
|
|
16
|
+
* with no resolving user, like an MCP resolve) is skipped here; the consuming
|
|
17
|
+
* workflow's own verification remains the durable backstop.
|
|
18
|
+
*/
|
|
19
|
+
import { type ShowIfContext } from '../../shared/form-validation';
|
|
20
|
+
import type { LTFieldViolation } from '../../types/validation';
|
|
21
|
+
/** The synthetic violation field for a guard rejection — not a form field. */
|
|
22
|
+
export declare const SUBMIT_GUARD_VIOLATION_FIELD = "_submitGuard";
|
|
23
|
+
/**
|
|
24
|
+
* Returns a violation when the escalation's submit guard still matches rows, or
|
|
25
|
+
* null when there is no guard, its scope is inert, or the query is confirmed
|
|
26
|
+
* empty. The context carries the escalation domains the query facets and the
|
|
27
|
+
* message interpolate against.
|
|
28
|
+
*/
|
|
29
|
+
export declare function checkSubmitGuard(schema: Record<string, any> | null | undefined, ctx: ShowIfContext, resolvingUserId: string | undefined): Promise<LTFieldViolation | null>;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SUBMIT_GUARD_VIOLATION_FIELD = void 0;
|
|
4
|
+
exports.checkSubmitGuard = checkSubmitGuard;
|
|
5
|
+
/**
|
|
6
|
+
* Server-side enforcement of the `x-lt-submit-guard` query precondition — the
|
|
7
|
+
* API-first counterpart of the dashboard's `useSubmitGuard`. Before an
|
|
8
|
+
* escalation resolves, if its form schema declares a submit guard, the same
|
|
9
|
+
* embedded query runs and the resolve is REJECTED while it still returns rows.
|
|
10
|
+
*
|
|
11
|
+
* Isomorphism with the dashboard is exact: the guard reuses `resolveScopedQuery`
|
|
12
|
+
* (the mapping the escalation-list embed uses) and runs it through
|
|
13
|
+
* `searchEscalationsFaceted` — the same faceted query the list API composes.
|
|
14
|
+
*
|
|
15
|
+
* Two deliberate rules:
|
|
16
|
+
* - The count is taken with `global: true`, bypassing the resolver's read
|
|
17
|
+
* scope, so a role that cannot SEE the children can never falsely clear the
|
|
18
|
+
* gate. Only a real, empty result count clears it (the "403 ≠ empty" rule).
|
|
19
|
+
* - A guard whose scope cannot be evaluated (e.g. `assigned:'me'` on a surface
|
|
20
|
+
* with no resolving user, like an MCP resolve) is skipped here; the consuming
|
|
21
|
+
* workflow's own verification remains the durable backstop.
|
|
22
|
+
*/
|
|
23
|
+
const form_validation_1 = require("../../shared/form-validation");
|
|
24
|
+
const queries_1 = require("./queries");
|
|
25
|
+
/** The synthetic violation field for a guard rejection — not a form field. */
|
|
26
|
+
exports.SUBMIT_GUARD_VIOLATION_FIELD = '_submitGuard';
|
|
27
|
+
/**
|
|
28
|
+
* Returns a violation when the escalation's submit guard still matches rows, or
|
|
29
|
+
* null when there is no guard, its scope is inert, or the query is confirmed
|
|
30
|
+
* empty. The context carries the escalation domains the query facets and the
|
|
31
|
+
* message interpolate against.
|
|
32
|
+
*/
|
|
33
|
+
async function checkSubmitGuard(schema, ctx, resolvingUserId) {
|
|
34
|
+
const guard = (0, form_validation_1.readSubmitGuard)(schema);
|
|
35
|
+
if (!guard || guard.mustBeEmpty === false)
|
|
36
|
+
return null;
|
|
37
|
+
const scoped = (0, form_validation_1.resolveScopedQuery)(guard.query, ctx, resolvingUserId);
|
|
38
|
+
if (!scoped.enabled)
|
|
39
|
+
return null;
|
|
40
|
+
const { total } = await (0, queries_1.searchEscalationsFaceted)({
|
|
41
|
+
global: true,
|
|
42
|
+
facet: {
|
|
43
|
+
role: scoped.role,
|
|
44
|
+
status: scoped.status,
|
|
45
|
+
available: scoped.available,
|
|
46
|
+
facets: scoped.facets,
|
|
47
|
+
},
|
|
48
|
+
assigned_to: scoped.assigned_to,
|
|
49
|
+
limit: 1,
|
|
50
|
+
offset: 0,
|
|
51
|
+
});
|
|
52
|
+
if (total <= 0)
|
|
53
|
+
return null;
|
|
54
|
+
const template = guard.message ?? form_validation_1.SUBMIT_GUARD_DEFAULT_MESSAGE;
|
|
55
|
+
const message = (0, form_validation_1.interpolateHelp)(template.replace(/\{\{count\}\}/g, String(total)), ctx);
|
|
56
|
+
return { field: exports.SUBMIT_GUARD_VIOLATION_FIELD, message };
|
|
57
|
+
}
|
|
@@ -8,6 +8,10 @@ export * from './derive-field-label';
|
|
|
8
8
|
export * from './x-lt-bind';
|
|
9
9
|
export * from './x-lt-help';
|
|
10
10
|
export * from './x-lt-transition';
|
|
11
|
+
export * from './x-lt-submit-on-claim';
|
|
12
|
+
export * from './x-lt-labels';
|
|
13
|
+
export * from './x-lt-query';
|
|
14
|
+
export * from './x-lt-submit-guard';
|
|
11
15
|
export * from './x-lt-show-if';
|
|
12
16
|
export * from './field-validator';
|
|
13
17
|
export * from './validate-resolver-payload';
|
|
@@ -24,6 +24,10 @@ __exportStar(require("./derive-field-label"), exports);
|
|
|
24
24
|
__exportStar(require("./x-lt-bind"), exports);
|
|
25
25
|
__exportStar(require("./x-lt-help"), exports);
|
|
26
26
|
__exportStar(require("./x-lt-transition"), exports);
|
|
27
|
+
__exportStar(require("./x-lt-submit-on-claim"), exports);
|
|
28
|
+
__exportStar(require("./x-lt-labels"), exports);
|
|
29
|
+
__exportStar(require("./x-lt-query"), exports);
|
|
30
|
+
__exportStar(require("./x-lt-submit-guard"), exports);
|
|
27
31
|
__exportStar(require("./x-lt-show-if"), exports);
|
|
28
32
|
__exportStar(require("./field-validator"), exports);
|
|
29
33
|
__exportStar(require("./validate-resolver-payload"), exports);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* x-lt-labels — configurable copy for the standard escalation footer. A
|
|
3
|
+
* form_schema may declare, at its schema root, an object that renames the
|
|
4
|
+
* footer's action controls. Each key is a standard target; its value is the
|
|
5
|
+
* label to render in place of the default.
|
|
6
|
+
*
|
|
7
|
+
* x-lt-labels object — { claim, cancel, submit, escalate, release }
|
|
8
|
+
*
|
|
9
|
+
* ```jsonc
|
|
10
|
+
* { "x-lt-labels": { "claim": "Claim and Submit", "submit": "Approve" } }
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* Only the five known targets are read; unknown keys and non-string values are
|
|
14
|
+
* ignored. Any target the schema omits keeps its default label, so a schema
|
|
15
|
+
* overrides just the controls it cares about.
|
|
16
|
+
*/
|
|
17
|
+
export declare const X_LT_LABELS = "x-lt-labels";
|
|
18
|
+
/** The footer controls a schema may rename. */
|
|
19
|
+
export declare const FOOTER_LABEL_TARGETS: readonly ["claim", "cancel", "submit", "escalate", "release"];
|
|
20
|
+
export type FooterLabelTarget = (typeof FOOTER_LABEL_TARGETS)[number];
|
|
21
|
+
/** A partial map of target → override label. Absent targets keep their default. */
|
|
22
|
+
export type FooterLabels = Partial<Record<FooterLabelTarget, string>>;
|
|
23
|
+
/**
|
|
24
|
+
* The schema's footer label overrides, or an empty map when none are declared.
|
|
25
|
+
* Reads only the known targets; a non-object `x-lt-labels`, unknown keys, and
|
|
26
|
+
* blank or non-string values are dropped.
|
|
27
|
+
*/
|
|
28
|
+
export declare function readFooterLabels(schema: Record<string, unknown> | null | undefined): FooterLabels;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* x-lt-labels — configurable copy for the standard escalation footer. A
|
|
4
|
+
* form_schema may declare, at its schema root, an object that renames the
|
|
5
|
+
* footer's action controls. Each key is a standard target; its value is the
|
|
6
|
+
* label to render in place of the default.
|
|
7
|
+
*
|
|
8
|
+
* x-lt-labels object — { claim, cancel, submit, escalate, release }
|
|
9
|
+
*
|
|
10
|
+
* ```jsonc
|
|
11
|
+
* { "x-lt-labels": { "claim": "Claim and Submit", "submit": "Approve" } }
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* Only the five known targets are read; unknown keys and non-string values are
|
|
15
|
+
* ignored. Any target the schema omits keeps its default label, so a schema
|
|
16
|
+
* overrides just the controls it cares about.
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.FOOTER_LABEL_TARGETS = exports.X_LT_LABELS = void 0;
|
|
20
|
+
exports.readFooterLabels = readFooterLabels;
|
|
21
|
+
exports.X_LT_LABELS = 'x-lt-labels';
|
|
22
|
+
/** The footer controls a schema may rename. */
|
|
23
|
+
exports.FOOTER_LABEL_TARGETS = ['claim', 'cancel', 'submit', 'escalate', 'release'];
|
|
24
|
+
/**
|
|
25
|
+
* The schema's footer label overrides, or an empty map when none are declared.
|
|
26
|
+
* Reads only the known targets; a non-object `x-lt-labels`, unknown keys, and
|
|
27
|
+
* blank or non-string values are dropped.
|
|
28
|
+
*/
|
|
29
|
+
function readFooterLabels(schema) {
|
|
30
|
+
const raw = schema?.[exports.X_LT_LABELS];
|
|
31
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw))
|
|
32
|
+
return {};
|
|
33
|
+
const source = raw;
|
|
34
|
+
const labels = {};
|
|
35
|
+
for (const target of exports.FOOTER_LABEL_TARGETS) {
|
|
36
|
+
const value = source[target];
|
|
37
|
+
if (typeof value === 'string' && value.trim().length > 0) {
|
|
38
|
+
labels[target] = value.trim();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return labels;
|
|
42
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { ShowIfContext } from './x-lt-show-if';
|
|
2
|
+
/**
|
|
3
|
+
* The embedded escalation query shape shared by `x-lt-query` (escalation-list
|
|
4
|
+
* widget) and `x-lt-submit-guard.query` (form-level submit gate). String
|
|
5
|
+
* values inside `facets` support `{{domain.path}}` token interpolation against
|
|
6
|
+
* the host escalation's context. Isomorphic: the dashboard renders embeds from
|
|
7
|
+
* it, and the API layer enforces the submit gate from the identical mapping.
|
|
8
|
+
*
|
|
9
|
+
* `assigned` is the ownership scope. Ownership is not a separate list — it is
|
|
10
|
+
* one more dimension of the same faceted query language the escalation API
|
|
11
|
+
* composes server-side ("claimed" is the implied status: pending, held, claim
|
|
12
|
+
* window live):
|
|
13
|
+
* - `"me"` — rows claimed by the viewing user (the walk case: I walk what I own)
|
|
14
|
+
* - `"any"` — all matching rows regardless of claim state
|
|
15
|
+
* - omitted — available rows only (unclaimed, or claim window lapsed)
|
|
16
|
+
*/
|
|
17
|
+
export interface EmbedQuery {
|
|
18
|
+
role?: string;
|
|
19
|
+
status?: string;
|
|
20
|
+
facets?: Record<string, string>;
|
|
21
|
+
limit?: number;
|
|
22
|
+
assigned?: 'me' | 'any';
|
|
23
|
+
/** Superseded by `assigned`; honored only when `assigned` is omitted. */
|
|
24
|
+
available?: boolean;
|
|
25
|
+
}
|
|
26
|
+
/** Interpolate `{{domain.path}}` tokens in every string value of the facets map. */
|
|
27
|
+
export declare function resolveQueryFacets(facets: Record<string, string> | undefined, ctx: ShowIfContext): Record<string, unknown>;
|
|
28
|
+
/** The escalation-query params an EmbedQuery resolves to — the exact input
|
|
29
|
+
* shape of `useEscalations`, so every embed surface queries identically. */
|
|
30
|
+
export interface ScopedQueryParams {
|
|
31
|
+
role?: string;
|
|
32
|
+
status: string;
|
|
33
|
+
facets: Record<string, unknown>;
|
|
34
|
+
assigned_to?: string;
|
|
35
|
+
available?: boolean;
|
|
36
|
+
limit?: number;
|
|
37
|
+
enabled: boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Resolve an EmbedQuery into concrete escalation-query params — the ONE
|
|
41
|
+
* mapping every embed surface (escalation-list, x-lt-actions, x-lt-submit-guard)
|
|
42
|
+
* consumes, so the visible rows and any count derived from the same query can
|
|
43
|
+
* never disagree.
|
|
44
|
+
*
|
|
45
|
+
* Ownership scope translates into the faceted query language:
|
|
46
|
+
* - `assigned: "me"` → `assigned_to = viewer AND available = false` — the
|
|
47
|
+
* implied "claimed" status (pending + live claim window held by the viewer)
|
|
48
|
+
* - `assigned: "any"` → no ownership constraint
|
|
49
|
+
* - omitted → `available = true` (the unclaimed pool; a declared
|
|
50
|
+
* legacy `available` value is honored)
|
|
51
|
+
*
|
|
52
|
+
* When `assigned: "me"` and no viewer id is supplied (a surface with no
|
|
53
|
+
* resolving user, e.g. an MCP resolve), the scope cannot be evaluated —
|
|
54
|
+
* `enabled` is false rather than silently widening to another scope.
|
|
55
|
+
*/
|
|
56
|
+
export declare function resolveScopedQuery(query: EmbedQuery, ctx: ShowIfContext, viewerId: string | undefined): ScopedQueryParams;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveQueryFacets = resolveQueryFacets;
|
|
4
|
+
exports.resolveScopedQuery = resolveScopedQuery;
|
|
5
|
+
const x_lt_help_1 = require("./x-lt-help");
|
|
6
|
+
/** Interpolate `{{domain.path}}` tokens in every string value of the facets map. */
|
|
7
|
+
function resolveQueryFacets(facets, ctx) {
|
|
8
|
+
if (!facets)
|
|
9
|
+
return {};
|
|
10
|
+
const resolved = {};
|
|
11
|
+
for (const [k, v] of Object.entries(facets)) {
|
|
12
|
+
resolved[k] = typeof v === 'string' ? (0, x_lt_help_1.interpolateHelp)(v, ctx) : v;
|
|
13
|
+
}
|
|
14
|
+
return resolved;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Resolve an EmbedQuery into concrete escalation-query params — the ONE
|
|
18
|
+
* mapping every embed surface (escalation-list, x-lt-actions, x-lt-submit-guard)
|
|
19
|
+
* consumes, so the visible rows and any count derived from the same query can
|
|
20
|
+
* never disagree.
|
|
21
|
+
*
|
|
22
|
+
* Ownership scope translates into the faceted query language:
|
|
23
|
+
* - `assigned: "me"` → `assigned_to = viewer AND available = false` — the
|
|
24
|
+
* implied "claimed" status (pending + live claim window held by the viewer)
|
|
25
|
+
* - `assigned: "any"` → no ownership constraint
|
|
26
|
+
* - omitted → `available = true` (the unclaimed pool; a declared
|
|
27
|
+
* legacy `available` value is honored)
|
|
28
|
+
*
|
|
29
|
+
* When `assigned: "me"` and no viewer id is supplied (a surface with no
|
|
30
|
+
* resolving user, e.g. an MCP resolve), the scope cannot be evaluated —
|
|
31
|
+
* `enabled` is false rather than silently widening to another scope.
|
|
32
|
+
*/
|
|
33
|
+
function resolveScopedQuery(query, ctx, viewerId) {
|
|
34
|
+
const facets = resolveQueryFacets(query.facets, ctx);
|
|
35
|
+
const base = {
|
|
36
|
+
role: query.role,
|
|
37
|
+
status: query.status ?? 'pending',
|
|
38
|
+
facets,
|
|
39
|
+
limit: query.limit,
|
|
40
|
+
enabled: !!(query.role || Object.keys(facets).length),
|
|
41
|
+
};
|
|
42
|
+
if (query.assigned === 'me') {
|
|
43
|
+
return { ...base, assigned_to: viewerId, available: false, enabled: base.enabled && !!viewerId };
|
|
44
|
+
}
|
|
45
|
+
if (query.assigned === 'any') {
|
|
46
|
+
return base;
|
|
47
|
+
}
|
|
48
|
+
return { ...base, available: query.available ?? true };
|
|
49
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* x-lt-submit-guard — a query precondition on the resolve. A form_schema may
|
|
3
|
+
* declare, at its root, that the escalation cannot be resolved while an embedded
|
|
4
|
+
* escalation query still returns rows: the parent references a set of children
|
|
5
|
+
* (commonly claimed by the same person) that must all be completed first, a
|
|
6
|
+
* to-do list that empties as children resolve.
|
|
7
|
+
*
|
|
8
|
+
* "x-lt-submit-guard": {
|
|
9
|
+
* "query": { "role": "print-harvest", "status": "pending",
|
|
10
|
+
* "assigned": "me",
|
|
11
|
+
* "facets": { "walkId": "{{metadata.walkId}}" } },
|
|
12
|
+
* "mustBeEmpty": true, // the only mode today; defaults true
|
|
13
|
+
* "message": "{{count}} plates still pending — bag them before closing.",
|
|
14
|
+
* "autoResolveWhenEmpty": true // auto-submit the parent once empty
|
|
15
|
+
* }
|
|
16
|
+
*
|
|
17
|
+
* The gate is isomorphic. The dashboard disables the submit while the query
|
|
18
|
+
* returns rows (UI honesty), and the API layer enforces the same precondition
|
|
19
|
+
* for `enforce_schema` roles so a raw-API resolve is rejected too. Only a
|
|
20
|
+
* confirmed empty result (a successful read with zero rows) clears the gate — a
|
|
21
|
+
* 403 or any error never does.
|
|
22
|
+
*
|
|
23
|
+
* `autoResolveWhenEmpty` closes the loop: the moment the query is confirmed
|
|
24
|
+
* empty, the claimed parent auto-submits — checked on page-load and after each
|
|
25
|
+
* inline child-resolve — so a set of escalations completes with no extra click.
|
|
26
|
+
*/
|
|
27
|
+
import type { EmbedQuery } from './x-lt-query';
|
|
28
|
+
export declare const X_LT_SUBMIT_GUARD = "x-lt-submit-guard";
|
|
29
|
+
export interface SubmitGuardDef {
|
|
30
|
+
query: EmbedQuery;
|
|
31
|
+
/** The gate condition; defaults to true (the only supported mode today). */
|
|
32
|
+
mustBeEmpty?: boolean;
|
|
33
|
+
/** Shown beside the disabled submit. `{{count}}` and `{{domain.path}}` tokens interpolate. */
|
|
34
|
+
message?: string;
|
|
35
|
+
/** When true, auto-submit the claimed parent the moment the query is confirmed empty. */
|
|
36
|
+
autoResolveWhenEmpty?: boolean;
|
|
37
|
+
}
|
|
38
|
+
export declare const SUBMIT_GUARD_DEFAULT_MESSAGE = "{{count}} related items are still pending";
|
|
39
|
+
/** The schema's submit-guard, or undefined when it declares none. */
|
|
40
|
+
export declare function readSubmitGuard(schema: Record<string, unknown> | null | undefined): SubmitGuardDef | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Whether a guard blocks the resolve given the query's row count. `mustBeEmpty`
|
|
43
|
+
* defaults to true, so any matching row blocks. A pure decision — the caller
|
|
44
|
+
* supplies the count from a confirmed read (never an error/loading state).
|
|
45
|
+
*/
|
|
46
|
+
export declare function guardBlocks(count: number, guard: SubmitGuardDef | undefined): boolean;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SUBMIT_GUARD_DEFAULT_MESSAGE = exports.X_LT_SUBMIT_GUARD = void 0;
|
|
4
|
+
exports.readSubmitGuard = readSubmitGuard;
|
|
5
|
+
exports.guardBlocks = guardBlocks;
|
|
6
|
+
exports.X_LT_SUBMIT_GUARD = 'x-lt-submit-guard';
|
|
7
|
+
exports.SUBMIT_GUARD_DEFAULT_MESSAGE = '{{count}} related items are still pending';
|
|
8
|
+
/** The schema's submit-guard, or undefined when it declares none. */
|
|
9
|
+
function readSubmitGuard(schema) {
|
|
10
|
+
const raw = schema?.[exports.X_LT_SUBMIT_GUARD];
|
|
11
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw))
|
|
12
|
+
return undefined;
|
|
13
|
+
const guard = raw;
|
|
14
|
+
if (!guard.query || typeof guard.query !== 'object')
|
|
15
|
+
return undefined;
|
|
16
|
+
return guard;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Whether a guard blocks the resolve given the query's row count. `mustBeEmpty`
|
|
20
|
+
* defaults to true, so any matching row blocks. A pure decision — the caller
|
|
21
|
+
* supplies the count from a confirmed read (never an error/loading state).
|
|
22
|
+
*/
|
|
23
|
+
function guardBlocks(count, guard) {
|
|
24
|
+
return !!guard && guard.mustBeEmpty !== false && count > 0;
|
|
25
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* x-lt-submit-on-claim — a one-gesture claim. A form_schema may declare, at its
|
|
3
|
+
* schema root, that claiming one of its escalations should also resolve it in
|
|
4
|
+
* the same gesture, submitting whatever the form currently holds (its seeded
|
|
5
|
+
* defaults). The person clicks Claim once and the work item advances — no
|
|
6
|
+
* second Submit step.
|
|
7
|
+
*
|
|
8
|
+
* x-lt-submit-on-claim boolean — opt in to claim-and-submit
|
|
9
|
+
*
|
|
10
|
+
* It is opt-in and defaults off. Pair it with `x-lt-labels` to rename the Claim
|
|
11
|
+
* button ("Claim and Submit") so the single gesture reads honestly. When the
|
|
12
|
+
* seeded defaults fail validation the claim still lands; the page drops into the
|
|
13
|
+
* normal claimed state with the field errors surfaced, so the person finishes
|
|
14
|
+
* the form by hand.
|
|
15
|
+
*/
|
|
16
|
+
export declare const X_LT_SUBMIT_ON_CLAIM = "x-lt-submit-on-claim";
|
|
17
|
+
/**
|
|
18
|
+
* Whether the schema opts into claim-and-submit. Truthy `x-lt-submit-on-claim`
|
|
19
|
+
* turns it on; anything else (absent, false) leaves the standard two-step claim
|
|
20
|
+
* then submit.
|
|
21
|
+
*/
|
|
22
|
+
export declare function readSubmitOnClaim(schema: Record<string, unknown> | null | undefined): boolean;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* x-lt-submit-on-claim — a one-gesture claim. A form_schema may declare, at its
|
|
4
|
+
* schema root, that claiming one of its escalations should also resolve it in
|
|
5
|
+
* the same gesture, submitting whatever the form currently holds (its seeded
|
|
6
|
+
* defaults). The person clicks Claim once and the work item advances — no
|
|
7
|
+
* second Submit step.
|
|
8
|
+
*
|
|
9
|
+
* x-lt-submit-on-claim boolean — opt in to claim-and-submit
|
|
10
|
+
*
|
|
11
|
+
* It is opt-in and defaults off. Pair it with `x-lt-labels` to rename the Claim
|
|
12
|
+
* button ("Claim and Submit") so the single gesture reads honestly. When the
|
|
13
|
+
* seeded defaults fail validation the claim still lands; the page drops into the
|
|
14
|
+
* normal claimed state with the field errors surfaced, so the person finishes
|
|
15
|
+
* the form by hand.
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.X_LT_SUBMIT_ON_CLAIM = void 0;
|
|
19
|
+
exports.readSubmitOnClaim = readSubmitOnClaim;
|
|
20
|
+
exports.X_LT_SUBMIT_ON_CLAIM = 'x-lt-submit-on-claim';
|
|
21
|
+
/**
|
|
22
|
+
* Whether the schema opts into claim-and-submit. Truthy `x-lt-submit-on-claim`
|
|
23
|
+
* turns it on; anything else (absent, false) leaves the standard two-step claim
|
|
24
|
+
* then submit.
|
|
25
|
+
*/
|
|
26
|
+
function readSubmitOnClaim(schema) {
|
|
27
|
+
return !!schema?.[exports.X_LT_SUBMIT_ON_CLAIM];
|
|
28
|
+
}
|