@hotmeshio/long-tail 0.28.1 → 0.28.3

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.
Files changed (222) hide show
  1. package/build/lib/events/publish.js +3 -2
  2. package/build/lib/machines/transport/nats-bus.d.ts +2 -0
  3. package/build/lib/machines/transport/stream-bus.d.ts +2 -0
  4. package/build/lib/machines/transport/stream-bus.js +8 -2
  5. package/build/lib/machines/transport/streams.d.ts +2 -1
  6. package/build/lib/machines/transport/streams.js +3 -2
  7. package/build/lib/messaging/memory.js +7 -3
  8. package/build/lib/messaging/nats/permissions.js +1 -0
  9. package/build/lib/messaging/nats/streams.d.ts +18 -4
  10. package/build/lib/messaging/nats/streams.js +55 -10
  11. package/build/services/machines/gateway/dispatcher.js +18 -6
  12. package/build/services/machines/gateway/executor.d.ts +6 -1
  13. package/build/services/machines/gateway/executor.js +19 -2
  14. package/build/services/machines/gateway/log.d.ts +1 -0
  15. package/build/services/machines/gateway/log.js +1 -0
  16. package/build/services/machines/gateway/plan-escalation.js +21 -3
  17. package/build/services/machines/gateway/state.d.ts +4 -0
  18. package/build/services/machines/gateway/state.js +1 -1
  19. package/build/services/machines/leadership.d.ts +2 -0
  20. package/build/services/machines/leadership.js +7 -1
  21. package/build/services/machines/select.d.ts +1 -1
  22. package/build/services/machines/select.js +2 -2
  23. package/build/services/machines/surface.js +8 -2
  24. package/build/types/messaging.d.ts +5 -1
  25. package/dashboard/dist/assets/{AdminDashboard-Bm7VG65H.js → AdminDashboard-DRE0hSDS.js} +2 -2
  26. package/dashboard/dist/assets/{AdminDashboard-Bm7VG65H.js.map → AdminDashboard-DRE0hSDS.js.map} +1 -1
  27. package/dashboard/dist/assets/{AgentConfigPage-aJF7Sdbc.js → AgentConfigPage-BuflQGgy.js} +2 -2
  28. package/dashboard/dist/assets/{AgentConfigPage-aJF7Sdbc.js.map → AgentConfigPage-BuflQGgy.js.map} +1 -1
  29. package/dashboard/dist/assets/{AgentDetailPage-GwwghhxT.js → AgentDetailPage-BiL9FB7i.js} +2 -2
  30. package/dashboard/dist/assets/{AgentDetailPage-GwwghhxT.js.map → AgentDetailPage-BiL9FB7i.js.map} +1 -1
  31. package/dashboard/dist/assets/{AgentsPage-DVvCzZyg.js → AgentsPage-C4ZxCNxt.js} +2 -2
  32. package/dashboard/dist/assets/{AgentsPage-DVvCzZyg.js.map → AgentsPage-C4ZxCNxt.js.map} +1 -1
  33. package/dashboard/dist/assets/{AvailableEscalationsPage-Cxmcji_K.js → AvailableEscalationsPage-B5p8QJvI.js} +2 -2
  34. package/dashboard/dist/assets/{AvailableEscalationsPage-Cxmcji_K.js.map → AvailableEscalationsPage-B5p8QJvI.js.map} +1 -1
  35. package/dashboard/dist/assets/{BotPicker-CofRxk4L.js → BotPicker-B7V77PnY.js} +2 -2
  36. package/dashboard/dist/assets/{BotPicker-CofRxk4L.js.map → BotPicker-B7V77PnY.js.map} +1 -1
  37. package/dashboard/dist/assets/{BulkAssignModal-BARWuz4L.js → BulkAssignModal-DcGVMQqm.js} +2 -2
  38. package/dashboard/dist/assets/{BulkAssignModal-BARWuz4L.js.map → BulkAssignModal-DcGVMQqm.js.map} +1 -1
  39. package/dashboard/dist/assets/{CapabilitiesPage-BJAWVNEx.js → CapabilitiesPage-DmbC1pEs.js} +2 -2
  40. package/dashboard/dist/assets/{CapabilitiesPage-BJAWVNEx.js.map → CapabilitiesPage-DmbC1pEs.js.map} +1 -1
  41. package/dashboard/dist/assets/{CollapsibleSection-CtgoaG75.js → CollapsibleSection-C81S1qic.js} +2 -2
  42. package/dashboard/dist/assets/{CollapsibleSection-CtgoaG75.js.map → CollapsibleSection-C81S1qic.js.map} +1 -1
  43. package/dashboard/dist/assets/{ConfirmDeleteModal-BYXXBWs6.js → ConfirmDeleteModal-3RFyWN9Q.js} +2 -2
  44. package/dashboard/dist/assets/{ConfirmDeleteModal-BYXXBWs6.js.map → ConfirmDeleteModal-3RFyWN9Q.js.map} +1 -1
  45. package/dashboard/dist/assets/{ConnectedAppsPage-D0JkzWa7.js → ConnectedAppsPage-B0D2OvTD.js} +2 -2
  46. package/dashboard/dist/assets/{ConnectedAppsPage-D0JkzWa7.js.map → ConnectedAppsPage-B0D2OvTD.js.map} +1 -1
  47. package/dashboard/dist/assets/{CountdownTimer-BcFxdZYN.js → CountdownTimer-iAG28fzG.js} +2 -2
  48. package/dashboard/dist/assets/{CountdownTimer-BcFxdZYN.js.map → CountdownTimer-iAG28fzG.js.map} +1 -1
  49. package/dashboard/dist/assets/{CredentialsPage-DPSY20rV.js → CredentialsPage-DoFwNvFv.js} +2 -2
  50. package/dashboard/dist/assets/{CredentialsPage-DPSY20rV.js.map → CredentialsPage-DoFwNvFv.js.map} +1 -1
  51. package/dashboard/dist/assets/{CronLabel-Dg_Oew_Y.js → CronLabel-C1Bb2wo4.js} +2 -2
  52. package/dashboard/dist/assets/{CronLabel-Dg_Oew_Y.js.map → CronLabel-C1Bb2wo4.js.map} +1 -1
  53. package/dashboard/dist/assets/{ElapsedCell-Dm3G5fK2.js → ElapsedCell-DZs1I1JW.js} +2 -2
  54. package/dashboard/dist/assets/{ElapsedCell-Dm3G5fK2.js.map → ElapsedCell-DZs1I1JW.js.map} +1 -1
  55. package/dashboard/dist/assets/{EntityTimelinePanel-CrEEP04e.js → EntityTimelinePanel-Du1O6Oly.js} +2 -2
  56. package/dashboard/dist/assets/{EntityTimelinePanel-CrEEP04e.js.map → EntityTimelinePanel-Du1O6Oly.js.map} +1 -1
  57. package/dashboard/dist/assets/{EscalationListSchemaPage-wOInXcjs.js → EscalationListSchemaPage-CrpBhC0e.js} +2 -2
  58. package/dashboard/dist/assets/{EscalationListSchemaPage-wOInXcjs.js.map → EscalationListSchemaPage-CrpBhC0e.js.map} +1 -1
  59. package/dashboard/dist/assets/{EscalationSchemaPage-CrIj_g9d.js → EscalationSchemaPage-Co59lcuD.js} +2 -2
  60. package/dashboard/dist/assets/{EscalationSchemaPage-CrIj_g9d.js.map → EscalationSchemaPage-Co59lcuD.js.map} +1 -1
  61. package/dashboard/dist/assets/{EscalationTimeline-CeAsl5IT.js → EscalationTimeline-B_fzNsX5.js} +2 -2
  62. package/dashboard/dist/assets/{EscalationTimeline-CeAsl5IT.js.map → EscalationTimeline-B_fzNsX5.js.map} +1 -1
  63. package/dashboard/dist/assets/{EscalationTitleSelect-D8qpCYiy.js → EscalationTitleSelect-C2Goebjo.js} +2 -2
  64. package/dashboard/dist/assets/{EscalationTitleSelect-D8qpCYiy.js.map → EscalationTitleSelect-C2Goebjo.js.map} +1 -1
  65. package/dashboard/dist/assets/{EscalationsOverview-CvaqVPsr.js → EscalationsOverview-Cgmrl8Zc.js} +2 -2
  66. package/dashboard/dist/assets/{EscalationsOverview-CvaqVPsr.js.map → EscalationsOverview-Cgmrl8Zc.js.map} +1 -1
  67. package/dashboard/dist/assets/{EventTable-Be0JuEl6.js → EventTable-BdEiu3Fv.js} +2 -2
  68. package/dashboard/dist/assets/{EventTable-Be0JuEl6.js.map → EventTable-BdEiu3Fv.js.map} +1 -1
  69. package/dashboard/dist/assets/{FilterBar-BVyAjIgv.js → FilterBar-CzKYBOMC.js} +2 -2
  70. package/dashboard/dist/assets/{FilterBar-BVyAjIgv.js.map → FilterBar-CzKYBOMC.js.map} +1 -1
  71. package/dashboard/dist/assets/{GraphInvokePage-D_QigJeD.js → GraphInvokePage-CcDFhY53.js} +2 -2
  72. package/dashboard/dist/assets/{GraphInvokePage-D_QigJeD.js.map → GraphInvokePage-CcDFhY53.js.map} +1 -1
  73. package/dashboard/dist/assets/{HomePage-C1haeuNy.js → HomePage-Xahqcdu9.js} +2 -2
  74. package/dashboard/dist/assets/{HomePage-C1haeuNy.js.map → HomePage-Xahqcdu9.js.map} +1 -1
  75. package/dashboard/dist/assets/{LinePage-CWD5pv1g.js → LinePage-DKwhGunp.js} +2 -2
  76. package/dashboard/dist/assets/{LinePage-CWD5pv1g.js.map → LinePage-DKwhGunp.js.map} +1 -1
  77. package/dashboard/dist/assets/{LinesPage-NqChsKcO.js → LinesPage-BXZVO4MC.js} +2 -2
  78. package/dashboard/dist/assets/{LinesPage-NqChsKcO.js.map → LinesPage-BXZVO4MC.js.map} +1 -1
  79. package/dashboard/dist/assets/{ListToolbar-BZCNrTh6.js → ListToolbar-orQsOdl_.js} +2 -2
  80. package/dashboard/dist/assets/{ListToolbar-BZCNrTh6.js.map → ListToolbar-orQsOdl_.js.map} +1 -1
  81. package/dashboard/dist/assets/{McpOverview-yJTYnh1z.js → McpOverview-pSnadtSM.js} +2 -2
  82. package/dashboard/dist/assets/{McpOverview-yJTYnh1z.js.map → McpOverview-pSnadtSM.js.map} +1 -1
  83. package/dashboard/dist/assets/{McpQueryDetailPage-ChuLpJ4u.js → McpQueryDetailPage-BCAJ3rKO.js} +2 -2
  84. package/dashboard/dist/assets/{McpQueryDetailPage-ChuLpJ4u.js.map → McpQueryDetailPage-BCAJ3rKO.js.map} +1 -1
  85. package/dashboard/dist/assets/{McpQueryPage-9S-v9soF.js → McpQueryPage-CRyXeRp5.js} +2 -2
  86. package/dashboard/dist/assets/{McpQueryPage-9S-v9soF.js.map → McpQueryPage-CRyXeRp5.js.map} +1 -1
  87. package/dashboard/dist/assets/{McpRunDetailPage-BhrcfxD5.js → McpRunDetailPage-BHppCztI.js} +2 -2
  88. package/dashboard/dist/assets/{McpRunDetailPage-BhrcfxD5.js.map → McpRunDetailPage-BHppCztI.js.map} +1 -1
  89. package/dashboard/dist/assets/{McpRunsPage-C5_i8_Zx.js → McpRunsPage-Cd9yCT-_.js} +2 -2
  90. package/dashboard/dist/assets/{McpRunsPage-C5_i8_Zx.js.map → McpRunsPage-Cd9yCT-_.js.map} +1 -1
  91. package/dashboard/dist/assets/{OperationsPage-C03CeU5P.js → OperationsPage-BtnthZgj.js} +2 -2
  92. package/dashboard/dist/assets/{OperationsPage-C03CeU5P.js.map → OperationsPage-BtnthZgj.js.map} +1 -1
  93. package/dashboard/dist/assets/{OperatorDashboard-BzC134Jt.js → OperatorDashboard-B4_OBhYh.js} +2 -2
  94. package/dashboard/dist/assets/{OperatorDashboard-BzC134Jt.js.map → OperatorDashboard-B4_OBhYh.js.map} +1 -1
  95. package/dashboard/dist/assets/{PersonaDetailPage-D0mY9L6j.js → PersonaDetailPage-BAYjM9qf.js} +2 -2
  96. package/dashboard/dist/assets/{PersonaDetailPage-D0mY9L6j.js.map → PersonaDetailPage-BAYjM9qf.js.map} +1 -1
  97. package/dashboard/dist/assets/{PersonasPage-FFlm5Eug.js → PersonasPage-6HsOp-1y.js} +2 -2
  98. package/dashboard/dist/assets/{PersonasPage-FFlm5Eug.js.map → PersonasPage-6HsOp-1y.js.map} +1 -1
  99. package/dashboard/dist/assets/{PortalPage-Cpc25uO-.js → PortalPage-6OMr7KtJ.js} +2 -2
  100. package/dashboard/dist/assets/{PortalPage-Cpc25uO-.js.map → PortalPage-6OMr7KtJ.js.map} +1 -1
  101. package/dashboard/dist/assets/{ProcessDetailPage-Di2J7KwY.js → ProcessDetailPage-AidH_h7z.js} +2 -2
  102. package/dashboard/dist/assets/{ProcessDetailPage-Di2J7KwY.js.map → ProcessDetailPage-AidH_h7z.js.map} +1 -1
  103. package/dashboard/dist/assets/{ProcessesListPage-BEXwU3Z0.js → ProcessesListPage-BWKoKbXk.js} +2 -2
  104. package/dashboard/dist/assets/{ProcessesListPage-BEXwU3Z0.js.map → ProcessesListPage-BWKoKbXk.js.map} +1 -1
  105. package/dashboard/dist/assets/{ResolverForm-2ks-3jXC.js → ResolverForm-BaSvhLoT.js} +2 -2
  106. package/dashboard/dist/assets/ResolverForm-BaSvhLoT.js.map +1 -0
  107. package/dashboard/dist/assets/{RoleDetailPage-DqoOk0xc.js → RoleDetailPage-D_30TDVh.js} +2 -2
  108. package/dashboard/dist/assets/{RoleDetailPage-DqoOk0xc.js.map → RoleDetailPage-D_30TDVh.js.map} +1 -1
  109. package/dashboard/dist/assets/{RolesPage-CPmo8Srr.js → RolesPage-T2hH_MV5.js} +2 -2
  110. package/dashboard/dist/assets/{RolesPage-CPmo8Srr.js.map → RolesPage-T2hH_MV5.js.map} +1 -1
  111. package/dashboard/dist/assets/{RosterWidget-D2yovCKw.js → RosterWidget-DG6Rcx4P.js} +2 -2
  112. package/dashboard/dist/assets/{RosterWidget-D2yovCKw.js.map → RosterWidget-DG6Rcx4P.js.map} +1 -1
  113. package/dashboard/dist/assets/{RunAsSelector-CMv96On6.js → RunAsSelector-M2h9U6PP.js} +2 -2
  114. package/dashboard/dist/assets/{RunAsSelector-CMv96On6.js.map → RunAsSelector-M2h9U6PP.js.map} +1 -1
  115. package/dashboard/dist/assets/{ScanCodesPage-CA6cTT-M.js → ScanCodesPage-lB_WxoZw.js} +2 -2
  116. package/dashboard/dist/assets/{ScanCodesPage-CA6cTT-M.js.map → ScanCodesPage-lB_WxoZw.js.map} +1 -1
  117. package/dashboard/dist/assets/{ScanSchemeDetailPage-DnctN5-H.js → ScanSchemeDetailPage-C3VLg61H.js} +2 -2
  118. package/dashboard/dist/assets/{ScanSchemeDetailPage-DnctN5-H.js.map → ScanSchemeDetailPage-C3VLg61H.js.map} +1 -1
  119. package/dashboard/dist/assets/{ScanStationPage-Bk8RwkKL.js → ScanStationPage-CVET1_4r.js} +2 -2
  120. package/dashboard/dist/assets/{ScanStationPage-Bk8RwkKL.js.map → ScanStationPage-CVET1_4r.js.map} +1 -1
  121. package/dashboard/dist/assets/{StickyPagination-B0FSuUgs.js → StickyPagination-BdjseWXr.js} +2 -2
  122. package/dashboard/dist/assets/{StickyPagination-B0FSuUgs.js.map → StickyPagination-BdjseWXr.js.map} +1 -1
  123. package/dashboard/dist/assets/{StreamMessageDetail-BwZEvMpP.js → StreamMessageDetail-DJCBxETh.js} +2 -2
  124. package/dashboard/dist/assets/{StreamMessageDetail-BwZEvMpP.js.map → StreamMessageDetail-DJCBxETh.js.map} +1 -1
  125. package/dashboard/dist/assets/{SwimlaneTimeline-BDVQEaMw.js → SwimlaneTimeline-DiXm9jIk.js} +2 -2
  126. package/dashboard/dist/assets/{SwimlaneTimeline-BDVQEaMw.js.map → SwimlaneTimeline-DiXm9jIk.js.map} +1 -1
  127. package/dashboard/dist/assets/{TaskDetailPage-BOlv3iGB.js → TaskDetailPage-m8CQFN4w.js} +2 -2
  128. package/dashboard/dist/assets/{TaskDetailPage-BOlv3iGB.js.map → TaskDetailPage-m8CQFN4w.js.map} +1 -1
  129. package/dashboard/dist/assets/{TasksListPage-e2teY0bD.js → TasksListPage-DHBSUhZC.js} +2 -2
  130. package/dashboard/dist/assets/{TasksListPage-e2teY0bD.js.map → TasksListPage-DHBSUhZC.js.map} +1 -1
  131. package/dashboard/dist/assets/{TimeAgo-Cvkpf_b3.js → TimeAgo-Cq3bKUd-.js} +2 -2
  132. package/dashboard/dist/assets/{TimeAgo-Cvkpf_b3.js.map → TimeAgo-Cq3bKUd-.js.map} +1 -1
  133. package/dashboard/dist/assets/{TimestampCell-B3btAV0N.js → TimestampCell-e5gRR_FY.js} +2 -2
  134. package/dashboard/dist/assets/{TimestampCell-B3btAV0N.js.map → TimestampCell-e5gRR_FY.js.map} +1 -1
  135. package/dashboard/dist/assets/{ToolTestPanel-B03nebR7.js → ToolTestPanel-Bg0ss9oN.js} +2 -2
  136. package/dashboard/dist/assets/{ToolTestPanel-B03nebR7.js.map → ToolTestPanel-Bg0ss9oN.js.map} +1 -1
  137. package/dashboard/dist/assets/{TopicDetailPage-DBRWne3O.js → TopicDetailPage-DhPiCfOO.js} +2 -2
  138. package/dashboard/dist/assets/{TopicDetailPage-DBRWne3O.js.map → TopicDetailPage-DhPiCfOO.js.map} +1 -1
  139. package/dashboard/dist/assets/{TopicsPage-CVe2M9HD.js → TopicsPage-BqZaVv3d.js} +2 -2
  140. package/dashboard/dist/assets/{TopicsPage-CVe2M9HD.js.map → TopicsPage-BqZaVv3d.js.map} +1 -1
  141. package/dashboard/dist/assets/{UserName-B_q_qp6V.js → UserName-C6ZNHHKN.js} +2 -2
  142. package/dashboard/dist/assets/{UserName-B_q_qp6V.js.map → UserName-C6ZNHHKN.js.map} +1 -1
  143. package/dashboard/dist/assets/{WorkflowExecutionPage-Bh_dr9tM.js → WorkflowExecutionPage-BUqIhtcr.js} +2 -2
  144. package/dashboard/dist/assets/{WorkflowExecutionPage-Bh_dr9tM.js.map → WorkflowExecutionPage-BUqIhtcr.js.map} +1 -1
  145. package/dashboard/dist/assets/{WorkflowsDashboard-DA6Mj7qH.js → WorkflowsDashboard-BKxhC_hT.js} +2 -2
  146. package/dashboard/dist/assets/{WorkflowsDashboard-DA6Mj7qH.js.map → WorkflowsDashboard-BKxhC_hT.js.map} +1 -1
  147. package/dashboard/dist/assets/{WorkflowsOverview-B1kBLj-a.js → WorkflowsOverview-018s2q_p.js} +2 -2
  148. package/dashboard/dist/assets/{WorkflowsOverview-B1kBLj-a.js.map → WorkflowsOverview-018s2q_p.js.map} +1 -1
  149. package/dashboard/dist/assets/{YamlWorkflowDetailPage-6GJM8QIX.js → YamlWorkflowDetailPage-C2zcXDr1.js} +2 -2
  150. package/dashboard/dist/assets/{YamlWorkflowDetailPage-6GJM8QIX.js.map → YamlWorkflowDetailPage-C2zcXDr1.js.map} +1 -1
  151. package/dashboard/dist/assets/{YamlWorkflowsPage-Bu811C7f.js → YamlWorkflowsPage-aVcNZNu6.js} +2 -2
  152. package/dashboard/dist/assets/{YamlWorkflowsPage-Bu811C7f.js.map → YamlWorkflowsPage-aVcNZNu6.js.map} +1 -1
  153. package/dashboard/dist/assets/{agents-MPk_GnYz.js → agents-DRaaJUue.js} +2 -2
  154. package/dashboard/dist/assets/{agents-MPk_GnYz.js.map → agents-DRaaJUue.js.map} +1 -1
  155. package/dashboard/dist/assets/{bots-2RihE2Tc.js → bots-C4N90NCj.js} +2 -2
  156. package/dashboard/dist/assets/{bots-2RihE2Tc.js.map → bots-C4N90NCj.js.map} +1 -1
  157. package/dashboard/dist/assets/{capabilities-CC4iwJ1P.js → capabilities-BoRWifSC.js} +2 -2
  158. package/dashboard/dist/assets/{capabilities-CC4iwJ1P.js.map → capabilities-BoRWifSC.js.map} +1 -1
  159. package/dashboard/dist/assets/{controlplane-Bmkic8BH.js → controlplane-DGZAxi7J.js} +2 -2
  160. package/dashboard/dist/assets/{controlplane-Bmkic8BH.js.map → controlplane-DGZAxi7J.js.map} +1 -1
  161. package/dashboard/dist/assets/{escalation-columns-B0lhUUrQ.js → escalation-columns-DJbfsH_m.js} +2 -2
  162. package/dashboard/dist/assets/{escalation-columns-B0lhUUrQ.js.map → escalation-columns-DJbfsH_m.js.map} +1 -1
  163. package/dashboard/dist/assets/{escalation-items-7WFpPo46.js → escalation-items-C8iJZEA8.js} +2 -2
  164. package/dashboard/dist/assets/{escalation-items-7WFpPo46.js.map → escalation-items-C8iJZEA8.js.map} +1 -1
  165. package/dashboard/dist/assets/{index-CvJsvqIc.js → index-3HaFP00M.js} +2 -2
  166. package/dashboard/dist/assets/{index-CvJsvqIc.js.map → index-3HaFP00M.js.map} +1 -1
  167. package/dashboard/dist/assets/{index-CmsmwCyv.js → index-BFxHIfQ_.js} +2 -2
  168. package/dashboard/dist/assets/{index-CmsmwCyv.js.map → index-BFxHIfQ_.js.map} +1 -1
  169. package/dashboard/dist/assets/{index-C2CLfGwL.js → index-BhS9XSy8.js} +2 -2
  170. package/dashboard/dist/assets/{index-C2CLfGwL.js.map → index-BhS9XSy8.js.map} +1 -1
  171. package/dashboard/dist/assets/{index-DSUtfDXx.js → index-BuSUevzO.js} +2 -2
  172. package/dashboard/dist/assets/{index-DSUtfDXx.js.map → index-BuSUevzO.js.map} +1 -1
  173. package/dashboard/dist/assets/{index-Da6ycKyf.js → index-CXXc9sUr.js} +2 -2
  174. package/dashboard/dist/assets/index-CXXc9sUr.js.map +1 -0
  175. package/dashboard/dist/assets/{index-D-ilRyfy.js → index-CeeSFnl-.js} +2 -2
  176. package/dashboard/dist/assets/{index-D-ilRyfy.js.map → index-CeeSFnl-.js.map} +1 -1
  177. package/dashboard/dist/assets/{index-CcArGkzI.js → index-CjjRxpVe.js} +2 -2
  178. package/dashboard/dist/assets/index-CjjRxpVe.js.map +1 -0
  179. package/dashboard/dist/assets/{index-CRWsB7ZC.js → index-CyL-6CAa.js} +2 -2
  180. package/dashboard/dist/assets/{index-CRWsB7ZC.js.map → index-CyL-6CAa.js.map} +1 -1
  181. package/dashboard/dist/assets/{index-C3AeFihz.js → index-DIU89TX3.js} +2 -2
  182. package/dashboard/dist/assets/{index-C3AeFihz.js.map → index-DIU89TX3.js.map} +1 -1
  183. package/dashboard/dist/assets/{index-B_XV1rwu.js → index-DMKLnxt8.js} +2 -2
  184. package/dashboard/dist/assets/{index-B_XV1rwu.js.map → index-DMKLnxt8.js.map} +1 -1
  185. package/dashboard/dist/assets/{index-CTOv3G7a.js → index-DeyA88jq.js} +2 -2
  186. package/dashboard/dist/assets/{index-CTOv3G7a.js.map → index-DeyA88jq.js.map} +1 -1
  187. package/dashboard/dist/assets/{index-CBri8fYM.js → index-DhKGp4QK.js} +2 -2
  188. package/dashboard/dist/assets/{index-CBri8fYM.js.map → index-DhKGp4QK.js.map} +1 -1
  189. package/dashboard/dist/assets/{index-CkMHS-hG.js → index-pzbGpihI.js} +3 -3
  190. package/dashboard/dist/assets/{index-CkMHS-hG.js.map → index-pzbGpihI.js.map} +1 -1
  191. package/dashboard/dist/assets/{knowledge-Bpbg20DC.js → knowledge-BWo3OCJc.js} +2 -2
  192. package/dashboard/dist/assets/{knowledge-Bpbg20DC.js.map → knowledge-BWo3OCJc.js.map} +1 -1
  193. package/dashboard/dist/assets/{machines-BqOZZU-3.js → machines-LEYY_yar.js} +2 -2
  194. package/dashboard/dist/assets/{machines-BqOZZU-3.js.map → machines-LEYY_yar.js.map} +1 -1
  195. package/dashboard/dist/assets/{mcp-CmcUXYce.js → mcp-_0kFRcyT.js} +2 -2
  196. package/dashboard/dist/assets/{mcp-CmcUXYce.js.map → mcp-_0kFRcyT.js.map} +1 -1
  197. package/dashboard/dist/assets/{mcp-query-C8buQxN9.js → mcp-query-BzmN0lc5.js} +2 -2
  198. package/dashboard/dist/assets/{mcp-query-C8buQxN9.js.map → mcp-query-BzmN0lc5.js.map} +1 -1
  199. package/dashboard/dist/assets/{personas-C2n5oDmY.js → personas-kE4PMrgo.js} +2 -2
  200. package/dashboard/dist/assets/{personas-C2n5oDmY.js.map → personas-kE4PMrgo.js.map} +1 -1
  201. package/dashboard/dist/assets/{pipelines-RKpSkFz7.js → pipelines-DYDNaypF.js} +2 -2
  202. package/dashboard/dist/assets/{pipelines-RKpSkFz7.js.map → pipelines-DYDNaypF.js.map} +1 -1
  203. package/dashboard/dist/assets/{tasks-Dab4hExW.js → tasks-ClJ-mbj9.js} +2 -2
  204. package/dashboard/dist/assets/{tasks-Dab4hExW.js.map → tasks-ClJ-mbj9.js.map} +1 -1
  205. package/dashboard/dist/assets/{topics-FTMNP7r3.js → topics-oHX4vbqe.js} +2 -2
  206. package/dashboard/dist/assets/{topics-FTMNP7r3.js.map → topics-oHX4vbqe.js.map} +1 -1
  207. package/dashboard/dist/assets/{useDebouncedValue-B_1u1YIk.js → useDebouncedValue-C97KADrj.js} +2 -2
  208. package/dashboard/dist/assets/{useDebouncedValue-B_1u1YIk.js.map → useDebouncedValue-C97KADrj.js.map} +1 -1
  209. package/dashboard/dist/assets/{useNamespace-HUeAI7Qb.js → useNamespace-Kje0Rn7j.js} +2 -2
  210. package/dashboard/dist/assets/{useNamespace-HUeAI7Qb.js.map → useNamespace-Kje0Rn7j.js.map} +1 -1
  211. package/dashboard/dist/assets/{useYamlActivityEvents-Cax54qHH.js → useYamlActivityEvents-DMz-HKFv.js} +2 -2
  212. package/dashboard/dist/assets/{useYamlActivityEvents-Cax54qHH.js.map → useYamlActivityEvents-DMz-HKFv.js.map} +1 -1
  213. package/dashboard/dist/assets/{validate-DxOaV7QS.js → validate-hUqjWN63.js} +2 -2
  214. package/dashboard/dist/assets/{validate-DxOaV7QS.js.map → validate-hUqjWN63.js.map} +1 -1
  215. package/dashboard/dist/assets/{yaml-workflows-BgY1XHJx.js → yaml-workflows-64vfmKJx.js} +2 -2
  216. package/dashboard/dist/assets/{yaml-workflows-BgY1XHJx.js.map → yaml-workflows-64vfmKJx.js.map} +1 -1
  217. package/dashboard/dist/index.html +1 -1
  218. package/docs/machines.md +3 -3
  219. package/package.json +1 -1
  220. package/dashboard/dist/assets/ResolverForm-2ks-3jXC.js.map +0 -1
  221. package/dashboard/dist/assets/index-CcArGkzI.js.map +0 -1
  222. package/dashboard/dist/assets/index-Da6ycKyf.js.map +0 -1
@@ -1,2 +1,2 @@
1
- import{j as p,a as U}from"./vendor-query-DvWWuNIB.js";import{a as j}from"./StatusBadge-DHVwxre2.js";import{r as k}from"./index-CkMHS-hG.js";import{b as P}from"./vendor-icons-fxBvvHBi.js";import{u as q,a as Y}from"./vendor-react-_9U4mKFr.js";function v(t){return!!(t.assigned_to&&t.assigned_until&&new Date(t.assigned_until)>new Date)}function ft(t){return!t.workflow_type}function W(t){return t.replace(/[_\-.]+/g," ").replace(/([a-z\d])([A-Z])/g,"$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1 $2").replace(/([a-zA-Z])(\d)/g,"$1 $2").trim().split(/\s+/).filter(Boolean).map(e=>e===e.toUpperCase()&&e.length>1?e:e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}function mt(t){return t.status==="pending"?v(t)?"bg-status-claimed-graphic":"bg-status-active":j[t.status]??"bg-status-active"}function At(t){const s=e=>{if(!e)return null;try{const o=JSON.parse(e);return o&&typeof o=="object"?o:null}catch{return null}};return{escalation:t,metadata:t.metadata??null,envelope:s(t.envelope),payload:s(t.escalation_payload),resolver:s(t.resolver_payload)}}const pt="200px";function gt(t){return`${Math.max(6,Math.round(t.length*.55+3.5))}rem`}const X=30;function K(t){return t.status==="pending"&&!v(t)}function yt({row:t,def:s,onView:e,prominent:o,forceView:i}){const r=(s==null?void 0:s.action)??"claim",a=i?"view":r,l=r===a&&(s!=null&&s.label)?s.label:a==="claim"?"Claim":"View",A=k(),R=q(),L=Y(),[T,h]=U.useState(""),$=a==="claim"&&!K(t),D=I=>{if(I.stopPropagation(),a==="view"){e==null||e();return}if(s!=null&&s.submitOnClaim){R(`/escalations/detail/${t.id}`,{state:{autoStart:!0,durationMinutes:s==null?void 0:s.durationMinutes,from:L.pathname}});return}h(""),A.mutate({id:t.id,durationMinutes:(s==null?void 0:s.durationMinutes)??X},{onSuccess:()=>e==null?void 0:e(),onError:N=>h(N.message)})},C=o?"btn-primary text-xs shrink-0 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-accent":"px-2 py-0.5 rounded text-2xs font-medium text-accent/70 border border-accent/30 enabled:hover:text-accent enabled:hover:border-accent/60 enabled:hover:bg-accent/5 transition-colors disabled:opacity-50 disabled:cursor-not-allowed whitespace-nowrap";return p.jsxs("span",{className:"inline-flex flex-col items-end gap-0.5",children:[p.jsx("button",{type:"button",onClick:D,disabled:A.isPending||$,title:$?t.status==="pending"?"claimed":t.status:void 0,className:C,"data-testid":"row-action-button",children:A.isPending?"Claiming…":l}),T&&p.jsx("span",{className:"text-2xs text-status-error","data-testid":"row-action-error",children:T})]})}const Z=/^\{\{\s*metadata\.([a-zA-Z0-9_]+)\s*\}\}$/;function x(t){return typeof t=="string"&&t!==""||typeof t=="number"||typeof t=="boolean"}function Et(t,s){var r;const e=[],o=new Set,i=t.metadata??{};for(const a of s){const l=typeof a.value=="string"?(r=a.value.match(Z))==null?void 0:r[1]:void 0;if(!l||o.has(l))continue;const A=i[l];x(A)&&(o.add(l),e.push({key:l,label:a.label,value:A,bound:!0}))}for(const[a,l]of Object.entries(i))o.has(a)||!x(l)||(o.add(a),e.push({key:a,label:W(a),value:l}));return e}function bt({onOpen:t,className:s=""}){return p.jsx("button",{type:"button",onClick:e=>{e.stopPropagation(),t()},className:`p-1.5 rounded text-text-quaternary/70 hover:text-accent hover:bg-surface-hover transition-colors ${s}`,title:"Refine — filter or search by this row's values","aria-label":"Refine — filter or search by this row's values","data-testid":"row-refine",children:p.jsx(P,{className:"w-3.5 h-3.5",strokeWidth:1.5})})}const g={RELATED:"x-lt-related",COLUMNS:"x-lt-columns",ROW_DETAIL:"x-lt-row-detail",GROUP_BY:"x-lt-group-by",LAYOUT:"x-lt-layout"},f={ITEMS:"items",QUERY:"query"},E={COUNT:"count",MIN:"min",MAX:"max"},z={FIRST:"first",MIN:"min",MAX:"max",SUM:"sum",COUNT:"count",DISTINCT:"distinct"},u={ROLE:"role",METADATA:"metadata.",PAYLOAD:"payload.",RECIPROCAL_METADATA:"reciprocal.metadata."},d={MAX_SETS:4,MAX_QUERY_ROLES:12,MAX_ROW_DETAIL_SECTIONS:4,ROWS_MAX:100},G="facet-table",M="default",F=/^\{\{\s*([^{}]+?)\s*\}\}$/,_="item.",Q=/^[a-zA-Z0-9_]+$/,B=/^[a-zA-Z0-9_]+$/,H=/\{n\}/g;function b(t){return t===E.MIN||t===E.MAX}function O(t,s){var i;if(typeof s!="string")return null;const e=(i=s.match(F))==null?void 0:i[1];if(!e)return null;if(t===f.ITEMS){if(!e.startsWith(`${_}${u.PAYLOAD}`))return null;const r=e.slice(_.length+u.PAYLOAD.length);return r&&r.split(".").every(a=>Q.test(a))?`${u.PAYLOAD}${r}`:null}if(!e.startsWith(u.METADATA))return null;const o=e.slice(u.METADATA.length);return B.test(o)?e:null}function Tt(t,s){return b(t.aggregate)?`${t.aggregate}:${O(s,t.value)??""}`:t.splitBy??""}function ht(t,s){if(!t)return null;const e=t[String(s)]??t[M];return e===void 0?null:e.replace(H,String(s))}function $t(t,s){if(!s.length)return;const e=t===E.MIN;if(s.every(i=>typeof i=="number"))return e?Math.min(...s):Math.max(...s);const o=s.map(String).sort((i,r)=>i<r?-1:i>r?1:0);return e?o[0]:o[o.length-1]}const y=/^[a-zA-Z0-9_]+$/,J=/^[a-zA-Z][a-zA-Z0-9_-]{0,47}$/,w=/^[a-zA-Z0-9_]+$/,V=/^(0|[1-9][0-9]*)$/;class tt extends Error{}function n(t){throw new tt(t)}function c(t){return!!t&&typeof t=="object"&&!Array.isArray(t)}function m(t){return typeof t=="string"&&t.trim().length>0}function et(t){return t.length>0&&t.split(".").every(s=>w.test(s))}function st(t,s){return t===f.QUERY?s===u.ROLE||s.startsWith(u.METADATA)&&y.test(s.slice(u.METADATA.length))?null:`splitBy "${s}" on a query set must be "role" or "metadata.<key>"`:s.startsWith(u.PAYLOAD)&&et(s.slice(u.PAYLOAD.length))||s.startsWith(u.RECIPROCAL_METADATA)&&y.test(s.slice(u.RECIPROCAL_METADATA.length))?null:`splitBy "${s}" on an items set must be "payload.<path>" or "reciprocal.metadata.<key>"`}function rt(t,s){if(J.test(t)||n(`x-lt-related name "${t}" must start with a letter (letters, digits, _ or -)`),c(s)||n(`x-lt-related.${t} must be an object`),s.source===f.ITEMS)return s.query!==void 0&&n(`x-lt-related.${t}: an items set takes no query`),{source:f.ITEMS};s.source!==f.QUERY&&n(`x-lt-related.${t}.source must be "items" or "query"`);const e=s.query;c(e)||n(`x-lt-related.${t}.query is required for a query set`);const o=e.roles!==void 0,i=e.segment!==void 0;if(o===i&&n(`x-lt-related.${t}.query takes exactly one of roles or segment`),o){const r=e.roles;(!Array.isArray(r)||r.length===0||r.length>d.MAX_QUERY_ROLES||!r.every(m))&&n(`x-lt-related.${t}.query.roles must be 1..${d.MAX_QUERY_ROLES} role names`)}else m(e.segment)||n(`x-lt-related.${t}.query.segment must be a role name`);(!c(e.facets)||Object.keys(e.facets).length===0)&&n(`x-lt-related.${t}.query.facets must name at least one facet`);for(const[r,a]of Object.entries(e.facets))y.test(r)||n(`x-lt-related.${t}.query.facets key "${r}" must be letters, digits or _`),(a===null||typeof a=="object")&&n(`x-lt-related.${t}.query.facets.${r} must be a scalar or template`);if(e.narrow!==void 0){(!c(e.narrow)||Object.keys(e.narrow).length===0)&&n(`x-lt-related.${t}.query.narrow must name at least one facet`);for(const[r,a]of Object.entries(e.narrow))y.test(r)||n(`x-lt-related.${t}.query.narrow key "${r}" must be letters, digits or _`),r in e.facets&&n(`x-lt-related.${t}.query.narrow.${r} is already a required facet`),(a===null||typeof a=="object")&&n(`x-lt-related.${t}.query.narrow.${r} must be a scalar or template`)}return e.status!==void 0&&!m(e.status)&&n(`x-lt-related.${t}.query.status must be a status`),{source:f.QUERY,query:{...o?{roles:[...e.roles]}:{segment:e.segment},facets:{...e.facets},...e.narrow!==void 0?{narrow:{...e.narrow}}:{},...e.status!==void 0?{status:e.status}:{}}}}function at(t,s,e){const o=t.related;(!m(o)||!s[o])&&n(`${e}.related must name a set declared in x-lt-related`),t.aggregate!==void 0&&t.aggregate!==E.COUNT&&!b(t.aggregate)&&n(`${e}.aggregate must be "count", "min" or "max"`);const i=s[o].source;if(b(t.aggregate)?(O(i,t.value)||n(i===f.ITEMS?`${e}.value must be "{{item.payload.<path>}}" on an items set`:`${e}.value must be "{{metadata.<key>}}" on a query set`),t.splitBy!==void 0&&n(`${e}: a ${t.aggregate} column takes no splitBy`),t.display!==void 0&&n(`${e}: display applies to a count column`)):t.value!==void 0&&n(`${e}.value applies to a min or max column`),t.format!==void 0&&typeof t.format!="string"&&n(`${e}.format must be a format name`),t.display!==void 0&&(!c(t.display)||Object.keys(t.display).length===0||!Object.entries(t.display).every(([r,a])=>(r===M||V.test(r))&&typeof a=="string"))&&n(`${e}.display must map counts (or "default") to display text`),t.splitBy!==void 0){m(t.splitBy)||n(`${e}.splitBy must be a path`);const r=st(s[o].source,t.splitBy);r&&n(`${e}: ${r}`)}return t.labels!==void 0&&(!c(t.labels)||!Object.values(t.labels).every(r=>typeof r=="string"))&&n(`${e}.labels must map values to display text`),t}function nt(t,s){return t===void 0?[]:((!Array.isArray(t)||t.length===0||t.length>d.MAX_ROW_DETAIL_SECTIONS)&&n(`x-lt-row-detail must be 1..${d.MAX_ROW_DETAIL_SECTIONS} sections`),t.map((e,o)=>{const i=`x-lt-row-detail[${o}]`;c(e)||n(`${i} must be an object`),(!m(e.related)||!s[e.related])&&n(`${i}.related must name a set declared in x-lt-related`),(!Array.isArray(e.columns)||e.columns.length===0)&&n(`${i}.columns must list at least one column`);for(const[r,a]of e.columns.entries())(!c(a)||!m(a.label)||typeof a.value!="string")&&n(`${i}.columns[${r}] needs a label and a value template`);return e.limit!==void 0&&(!Number.isInteger(e.limit)||e.limit<1||e.limit>d.ROWS_MAX)&&n(`${i}.limit must be 1..${d.ROWS_MAX}`),e}))}function ot(t){const s=t[g.GROUP_BY];if(s===void 0||t[g.LAYOUT]!==G)return null;const e=typeof s=="string"&&s.startsWith(u.METADATA)?s.slice(u.METADATA.length):"";return y.test(e)||n('x-lt-group-by on a facet-table must be "metadata.<key>"'),e}const S=new Set(Object.values(z));function xt(t){const s={sets:{},columns:[],rowDetail:[],groupKey:null};if(!c(t))return s;const e=t[g.RELATED],o={};if(e!==void 0){c(e)||n("x-lt-related must map set names to declarations");const a=Object.keys(e);(a.length===0||a.length>d.MAX_SETS)&&n(`x-lt-related must declare 1..${d.MAX_SETS} sets`);for(const l of a)o[l]=rt(l,e[l])}const i=[],r=t[g.COLUMNS];return Array.isArray(r)&&r.forEach((a,l)=>{c(a)&&(a.related!==void 0&&i.push(at(a,o,`x-lt-columns[${l}]`)),a.group!==void 0&&(typeof a.group!="string"||!S.has(a.group))&&n(`x-lt-columns[${l}].group must be one of ${[...S].join(", ")}`))}),{sets:o,columns:i,rowDetail:nt(t[g.ROW_DETAIL],o),groupKey:ot(t)}}export{z as G,pt as I,Z as M,bt as R,u as S,W as a,xt as b,b as c,ht as d,mt as e,$t as f,Et as g,yt as h,v as i,gt as j,Tt as k,ft as l,At as r};
2
- //# sourceMappingURL=validate-DxOaV7QS.js.map
1
+ import{j as p,a as U}from"./vendor-query-DvWWuNIB.js";import{a as j}from"./StatusBadge-DHVwxre2.js";import{r as k}from"./index-pzbGpihI.js";import{b as P}from"./vendor-icons-fxBvvHBi.js";import{u as q,a as Y}from"./vendor-react-_9U4mKFr.js";function v(t){return!!(t.assigned_to&&t.assigned_until&&new Date(t.assigned_until)>new Date)}function ft(t){return!t.workflow_type}function W(t){return t.replace(/[_\-.]+/g," ").replace(/([a-z\d])([A-Z])/g,"$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1 $2").replace(/([a-zA-Z])(\d)/g,"$1 $2").trim().split(/\s+/).filter(Boolean).map(e=>e===e.toUpperCase()&&e.length>1?e:e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}function mt(t){return t.status==="pending"?v(t)?"bg-status-claimed-graphic":"bg-status-active":j[t.status]??"bg-status-active"}function At(t){const s=e=>{if(!e)return null;try{const o=JSON.parse(e);return o&&typeof o=="object"?o:null}catch{return null}};return{escalation:t,metadata:t.metadata??null,envelope:s(t.envelope),payload:s(t.escalation_payload),resolver:s(t.resolver_payload)}}const pt="200px";function gt(t){return`${Math.max(6,Math.round(t.length*.55+3.5))}rem`}const X=30;function K(t){return t.status==="pending"&&!v(t)}function yt({row:t,def:s,onView:e,prominent:o,forceView:i}){const r=(s==null?void 0:s.action)??"claim",a=i?"view":r,l=r===a&&(s!=null&&s.label)?s.label:a==="claim"?"Claim":"View",A=k(),R=q(),L=Y(),[T,h]=U.useState(""),$=a==="claim"&&!K(t),D=I=>{if(I.stopPropagation(),a==="view"){e==null||e();return}if(s!=null&&s.submitOnClaim){R(`/escalations/detail/${t.id}`,{state:{autoStart:!0,durationMinutes:s==null?void 0:s.durationMinutes,from:L.pathname}});return}h(""),A.mutate({id:t.id,durationMinutes:(s==null?void 0:s.durationMinutes)??X},{onSuccess:()=>e==null?void 0:e(),onError:N=>h(N.message)})},C=o?"btn-primary text-xs shrink-0 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-accent":"px-2 py-0.5 rounded text-2xs font-medium text-accent/70 border border-accent/30 enabled:hover:text-accent enabled:hover:border-accent/60 enabled:hover:bg-accent/5 transition-colors disabled:opacity-50 disabled:cursor-not-allowed whitespace-nowrap";return p.jsxs("span",{className:"inline-flex flex-col items-end gap-0.5",children:[p.jsx("button",{type:"button",onClick:D,disabled:A.isPending||$,title:$?t.status==="pending"?"claimed":t.status:void 0,className:C,"data-testid":"row-action-button",children:A.isPending?"Claiming…":l}),T&&p.jsx("span",{className:"text-2xs text-status-error","data-testid":"row-action-error",children:T})]})}const Z=/^\{\{\s*metadata\.([a-zA-Z0-9_]+)\s*\}\}$/;function x(t){return typeof t=="string"&&t!==""||typeof t=="number"||typeof t=="boolean"}function Et(t,s){var r;const e=[],o=new Set,i=t.metadata??{};for(const a of s){const l=typeof a.value=="string"?(r=a.value.match(Z))==null?void 0:r[1]:void 0;if(!l||o.has(l))continue;const A=i[l];x(A)&&(o.add(l),e.push({key:l,label:a.label,value:A,bound:!0}))}for(const[a,l]of Object.entries(i))o.has(a)||!x(l)||(o.add(a),e.push({key:a,label:W(a),value:l}));return e}function bt({onOpen:t,className:s=""}){return p.jsx("button",{type:"button",onClick:e=>{e.stopPropagation(),t()},className:`p-1.5 rounded text-text-quaternary/70 hover:text-accent hover:bg-surface-hover transition-colors ${s}`,title:"Refine — filter or search by this row's values","aria-label":"Refine — filter or search by this row's values","data-testid":"row-refine",children:p.jsx(P,{className:"w-3.5 h-3.5",strokeWidth:1.5})})}const g={RELATED:"x-lt-related",COLUMNS:"x-lt-columns",ROW_DETAIL:"x-lt-row-detail",GROUP_BY:"x-lt-group-by",LAYOUT:"x-lt-layout"},f={ITEMS:"items",QUERY:"query"},E={COUNT:"count",MIN:"min",MAX:"max"},z={FIRST:"first",MIN:"min",MAX:"max",SUM:"sum",COUNT:"count",DISTINCT:"distinct"},u={ROLE:"role",METADATA:"metadata.",PAYLOAD:"payload.",RECIPROCAL_METADATA:"reciprocal.metadata."},d={MAX_SETS:4,MAX_QUERY_ROLES:12,MAX_ROW_DETAIL_SECTIONS:4,ROWS_MAX:100},G="facet-table",M="default",F=/^\{\{\s*([^{}]+?)\s*\}\}$/,_="item.",Q=/^[a-zA-Z0-9_]+$/,B=/^[a-zA-Z0-9_]+$/,H=/\{n\}/g;function b(t){return t===E.MIN||t===E.MAX}function O(t,s){var i;if(typeof s!="string")return null;const e=(i=s.match(F))==null?void 0:i[1];if(!e)return null;if(t===f.ITEMS){if(!e.startsWith(`${_}${u.PAYLOAD}`))return null;const r=e.slice(_.length+u.PAYLOAD.length);return r&&r.split(".").every(a=>Q.test(a))?`${u.PAYLOAD}${r}`:null}if(!e.startsWith(u.METADATA))return null;const o=e.slice(u.METADATA.length);return B.test(o)?e:null}function Tt(t,s){return b(t.aggregate)?`${t.aggregate}:${O(s,t.value)??""}`:t.splitBy??""}function ht(t,s){if(!t)return null;const e=t[String(s)]??t[M];return e===void 0?null:e.replace(H,String(s))}function $t(t,s){if(!s.length)return;const e=t===E.MIN;if(s.every(i=>typeof i=="number"))return e?Math.min(...s):Math.max(...s);const o=s.map(String).sort((i,r)=>i<r?-1:i>r?1:0);return e?o[0]:o[o.length-1]}const y=/^[a-zA-Z0-9_]+$/,J=/^[a-zA-Z][a-zA-Z0-9_-]{0,47}$/,w=/^[a-zA-Z0-9_]+$/,V=/^(0|[1-9][0-9]*)$/;class tt extends Error{}function n(t){throw new tt(t)}function c(t){return!!t&&typeof t=="object"&&!Array.isArray(t)}function m(t){return typeof t=="string"&&t.trim().length>0}function et(t){return t.length>0&&t.split(".").every(s=>w.test(s))}function st(t,s){return t===f.QUERY?s===u.ROLE||s.startsWith(u.METADATA)&&y.test(s.slice(u.METADATA.length))?null:`splitBy "${s}" on a query set must be "role" or "metadata.<key>"`:s.startsWith(u.PAYLOAD)&&et(s.slice(u.PAYLOAD.length))||s.startsWith(u.RECIPROCAL_METADATA)&&y.test(s.slice(u.RECIPROCAL_METADATA.length))?null:`splitBy "${s}" on an items set must be "payload.<path>" or "reciprocal.metadata.<key>"`}function rt(t,s){if(J.test(t)||n(`x-lt-related name "${t}" must start with a letter (letters, digits, _ or -)`),c(s)||n(`x-lt-related.${t} must be an object`),s.source===f.ITEMS)return s.query!==void 0&&n(`x-lt-related.${t}: an items set takes no query`),{source:f.ITEMS};s.source!==f.QUERY&&n(`x-lt-related.${t}.source must be "items" or "query"`);const e=s.query;c(e)||n(`x-lt-related.${t}.query is required for a query set`);const o=e.roles!==void 0,i=e.segment!==void 0;if(o===i&&n(`x-lt-related.${t}.query takes exactly one of roles or segment`),o){const r=e.roles;(!Array.isArray(r)||r.length===0||r.length>d.MAX_QUERY_ROLES||!r.every(m))&&n(`x-lt-related.${t}.query.roles must be 1..${d.MAX_QUERY_ROLES} role names`)}else m(e.segment)||n(`x-lt-related.${t}.query.segment must be a role name`);(!c(e.facets)||Object.keys(e.facets).length===0)&&n(`x-lt-related.${t}.query.facets must name at least one facet`);for(const[r,a]of Object.entries(e.facets))y.test(r)||n(`x-lt-related.${t}.query.facets key "${r}" must be letters, digits or _`),(a===null||typeof a=="object")&&n(`x-lt-related.${t}.query.facets.${r} must be a scalar or template`);if(e.narrow!==void 0){(!c(e.narrow)||Object.keys(e.narrow).length===0)&&n(`x-lt-related.${t}.query.narrow must name at least one facet`);for(const[r,a]of Object.entries(e.narrow))y.test(r)||n(`x-lt-related.${t}.query.narrow key "${r}" must be letters, digits or _`),r in e.facets&&n(`x-lt-related.${t}.query.narrow.${r} is already a required facet`),(a===null||typeof a=="object")&&n(`x-lt-related.${t}.query.narrow.${r} must be a scalar or template`)}return e.status!==void 0&&!m(e.status)&&n(`x-lt-related.${t}.query.status must be a status`),{source:f.QUERY,query:{...o?{roles:[...e.roles]}:{segment:e.segment},facets:{...e.facets},...e.narrow!==void 0?{narrow:{...e.narrow}}:{},...e.status!==void 0?{status:e.status}:{}}}}function at(t,s,e){const o=t.related;(!m(o)||!s[o])&&n(`${e}.related must name a set declared in x-lt-related`),t.aggregate!==void 0&&t.aggregate!==E.COUNT&&!b(t.aggregate)&&n(`${e}.aggregate must be "count", "min" or "max"`);const i=s[o].source;if(b(t.aggregate)?(O(i,t.value)||n(i===f.ITEMS?`${e}.value must be "{{item.payload.<path>}}" on an items set`:`${e}.value must be "{{metadata.<key>}}" on a query set`),t.splitBy!==void 0&&n(`${e}: a ${t.aggregate} column takes no splitBy`),t.display!==void 0&&n(`${e}: display applies to a count column`)):t.value!==void 0&&n(`${e}.value applies to a min or max column`),t.format!==void 0&&typeof t.format!="string"&&n(`${e}.format must be a format name`),t.display!==void 0&&(!c(t.display)||Object.keys(t.display).length===0||!Object.entries(t.display).every(([r,a])=>(r===M||V.test(r))&&typeof a=="string"))&&n(`${e}.display must map counts (or "default") to display text`),t.splitBy!==void 0){m(t.splitBy)||n(`${e}.splitBy must be a path`);const r=st(s[o].source,t.splitBy);r&&n(`${e}: ${r}`)}return t.labels!==void 0&&(!c(t.labels)||!Object.values(t.labels).every(r=>typeof r=="string"))&&n(`${e}.labels must map values to display text`),t}function nt(t,s){return t===void 0?[]:((!Array.isArray(t)||t.length===0||t.length>d.MAX_ROW_DETAIL_SECTIONS)&&n(`x-lt-row-detail must be 1..${d.MAX_ROW_DETAIL_SECTIONS} sections`),t.map((e,o)=>{const i=`x-lt-row-detail[${o}]`;c(e)||n(`${i} must be an object`),(!m(e.related)||!s[e.related])&&n(`${i}.related must name a set declared in x-lt-related`),(!Array.isArray(e.columns)||e.columns.length===0)&&n(`${i}.columns must list at least one column`);for(const[r,a]of e.columns.entries())(!c(a)||!m(a.label)||typeof a.value!="string")&&n(`${i}.columns[${r}] needs a label and a value template`);return e.limit!==void 0&&(!Number.isInteger(e.limit)||e.limit<1||e.limit>d.ROWS_MAX)&&n(`${i}.limit must be 1..${d.ROWS_MAX}`),e}))}function ot(t){const s=t[g.GROUP_BY];if(s===void 0||t[g.LAYOUT]!==G)return null;const e=typeof s=="string"&&s.startsWith(u.METADATA)?s.slice(u.METADATA.length):"";return y.test(e)||n('x-lt-group-by on a facet-table must be "metadata.<key>"'),e}const S=new Set(Object.values(z));function xt(t){const s={sets:{},columns:[],rowDetail:[],groupKey:null};if(!c(t))return s;const e=t[g.RELATED],o={};if(e!==void 0){c(e)||n("x-lt-related must map set names to declarations");const a=Object.keys(e);(a.length===0||a.length>d.MAX_SETS)&&n(`x-lt-related must declare 1..${d.MAX_SETS} sets`);for(const l of a)o[l]=rt(l,e[l])}const i=[],r=t[g.COLUMNS];return Array.isArray(r)&&r.forEach((a,l)=>{c(a)&&(a.related!==void 0&&i.push(at(a,o,`x-lt-columns[${l}]`)),a.group!==void 0&&(typeof a.group!="string"||!S.has(a.group))&&n(`x-lt-columns[${l}].group must be one of ${[...S].join(", ")}`))}),{sets:o,columns:i,rowDetail:nt(t[g.ROW_DETAIL],o),groupKey:ot(t)}}export{z as G,pt as I,Z as M,bt as R,u as S,W as a,xt as b,b as c,ht as d,mt as e,$t as f,Et as g,yt as h,v as i,gt as j,Tt as k,ft as l,At as r};
2
+ //# sourceMappingURL=validate-hUqjWN63.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"validate-DxOaV7QS.js","sources":["../../src/lib/escalation.ts","../../src/lib/identifier-label.ts","../../src/components/escalation/list-view/row-parts.tsx","../../../shared/list-schema/types.ts","../../../shared/list-schema/aggregate.ts","../../../shared/list-schema/validate.ts"],"sourcesContent":["import type { LTEscalationRecord } from '../api/types';\n\nexport function isEffectivelyClaimed(esc: LTEscalationRecord): boolean {\n return !!(\n esc.assigned_to &&\n esc.assigned_until &&\n new Date(esc.assigned_until) > new Date()\n );\n}\n\n/** An ACK escalation has no associated workflow — it's a notification, not a task. */\nexport function isAckEscalation(esc: LTEscalationRecord): boolean {\n return !esc.workflow_type;\n}\n\nexport function isAvailable(esc: LTEscalationRecord): boolean {\n return (\n esc.status === 'pending' &&\n (!esc.assigned_to ||\n !esc.assigned_until ||\n new Date(esc.assigned_until) <= new Date())\n );\n}\n","/**\n * A human label for a code identifier: camelCase, snake_case, kebab-case, and\n * digit runs become Title Case words. `fleetTools` → `Fleet Tools`,\n * `print_order2` → `Print Order 2`. Acronyms keep their capitals: `mcpQuery`\n * → `Mcp Query` is avoided by treating an all-caps run as one word.\n */\nexport function identifierToTitle(id: string): string {\n const words = id\n .replace(/[_\\-.]+/g, ' ')\n .replace(/([a-z\\d])([A-Z])/g, '$1 $2')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n .replace(/([a-zA-Z])(\\d)/g, '$1 $2')\n .trim()\n .split(/\\s+/)\n .filter(Boolean);\n return words\n .map((w) => (w === w.toUpperCase() && w.length > 1 ? w : w.charAt(0).toUpperCase() + w.slice(1)))\n .join(' ');\n}\n","import { useState } from 'react';\nimport { useNavigate, useLocation } from 'react-router-dom';\nimport { Search } from 'lucide-react';\nimport type { HelpTokenContext } from '../../../lib/x-lt-help';\nimport { STATUS_DOT_STYLES } from '../../common/display/StatusBadge';\nimport { useClaimEscalation } from '../../../api/escalations';\nimport { isEffectivelyClaimed } from '../../../lib/escalation';\nimport { identifierToTitle } from '../../../lib/identifier-label';\nimport type { RefinePair } from '../RefineDialog';\nimport type { LTEscalationRecord } from '../../../api/types';\n\n/** The row-level pieces every list layout shares: column and action\n * declarations, the row's token context, the row action, and refine. */\n\n/** Dot colour matches the standard table view: blue = pending unclaimed,\n * orange = under a live claim; other statuses follow the shared map. */\nexport function escalationDotClass(e: LTEscalationRecord): string {\n if (e.status === 'pending') {\n return isEffectivelyClaimed(e) ? 'bg-status-claimed-graphic' : 'bg-status-active';\n }\n return STATUS_DOT_STYLES[e.status] ?? 'bg-status-active';\n}\n\nexport interface ColumnDef {\n label: string;\n value: string;\n /** \"age\" renders an ISO timestamp as a compact age with an absolute tooltip. */\n format?: string;\n /**\n * Card-fold behavior when the table folds at narrow widths (same contract\n * as the engineer table): 1 = identity — always visible, forms the card's\n * title line; 2 = folds into the card body as a label/value pair; 3 =\n * dropped in card mode. Undeclared, the first column is the identity and\n * the rest fold.\n */\n priority?: 1 | 2 | 3;\n /** CSS column width (\"40%\", \"12rem\"). Unset columns share the remainder;\n * when no column declares one, the first column holds a fixed 200px so\n * the identity stays legible and every other value keeps its room. */\n width?: string;\n}\n\n/**\n * The per-row action button — the queue-working gesture, always available on\n * every layout. Template-driven: the schema author sets the action, its text,\n * and (for claim) the hold time.\n */\nexport interface RowActionDef {\n /** \"claim\" fires a one-click claim then opens the detail page already\n * claimed; \"view\" just opens it. Default \"claim\". */\n action?: 'claim' | 'view';\n /** Button text. Defaults \"Claim\" / \"View\" by action. */\n label?: string;\n /** Claim hold time in minutes. Default 30 (the platform claim default). */\n durationMinutes?: number;\n /**\n * Launch the detail page's claim-and-submit flow instead of a plain claim:\n * the row is claimed, the form's seeded defaults are resolved, and — when the\n * form declares `x-lt-transition` — the wait screen bridges to the born-assigned\n * follow-on. One list gesture (\"Start Harvesting\") starts the work and lands\n * the person on the next step. The behavior lives on the detail page (form\n * defaults, validation, transition); the list only points there with intent.\n */\n submitOnClaim?: boolean;\n}\n\n/** Build the token context for one escalation row (payloads are JSON strings). */\nexport function rowContext(e: LTEscalationRecord): HelpTokenContext {\n const parse = (s: string | null | undefined): Record<string, unknown> | null => {\n if (!s) return null;\n try {\n const v = JSON.parse(s);\n return v && typeof v === 'object' ? v : null;\n } catch {\n return null;\n }\n };\n return {\n escalation: e as unknown as Record<string, unknown>,\n metadata: e.metadata ?? null,\n envelope: parse(e.envelope),\n payload: parse(e.escalation_payload),\n resolver: parse(e.resolver_payload),\n };\n}\n\n/** The identity column's width when no column declares one: room for a label, no more. */\nexport const IDENTITY_COLUMN_WIDTH = '200px';\n\n/** The action column sizes to its label so the button never wraps or truncates. */\nexport function actionColumnWidth(label: string): string {\n return `${Math.max(6, Math.round(label.length * 0.55 + 3.5))}rem`;\n}\n\nconst DEFAULT_CLAIM_MINUTES = 30;\n\n/** Claim targets pending rows without a live claim window. */\nfunction isClaimable(row: LTEscalationRecord): boolean {\n return row.status === 'pending' && !isEffectivelyClaimed(row);\n}\n\n/**\n * The x-lt-row-action button. `claim` is one click: claim for the template's\n * duration, then open the detail page already claimed — the fast path for\n * working a queue. `view` opens the detail page. Persistent (light accent at\n * rest, saturating on hover); a rejected claim surfaces its message inline.\n */\nexport function RowActionButton({ row, def, onView, prominent, forceView }: {\n row: LTEscalationRecord;\n def?: RowActionDef;\n onView?: () => void;\n /** Hero treatment for the active-card CTA; default is the compact row button. */\n prominent?: boolean;\n /** Render claim templates as view actions (see EscalationListView). */\n forceView?: boolean;\n}) {\n const authored = def?.action ?? 'claim';\n const action = forceView ? 'view' : authored;\n // The authored label describes the authored gesture. When view is forced\n // over a claim template, claim wording would mislead — use the view default.\n const label = authored === action && def?.label\n ? def.label\n : action === 'claim' ? 'Claim' : 'View';\n const claim = useClaimEscalation();\n const navigate = useNavigate();\n const location = useLocation();\n const [error, setError] = useState('');\n\n // A spent gesture stays visible — the disabled button keeps every row's\n // layout uniform instead of leaving a hole on resolved/held rows.\n const spent = action === 'claim' && !isClaimable(row);\n\n const fire = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (action === 'view') {\n onView?.();\n return;\n }\n // Launch the detail page's claim → submit → transition flow. The detail\n // page owns the heavy lifting (seed defaults, validate, resolve, hand-off);\n // the list points there with the intent and the authored claim duration.\n if (def?.submitOnClaim) {\n navigate(`/escalations/detail/${row.id}`, {\n state: { autoStart: true, durationMinutes: def?.durationMinutes, from: location.pathname },\n });\n return;\n }\n setError('');\n claim.mutate(\n { id: row.id, durationMinutes: def?.durationMinutes ?? DEFAULT_CLAIM_MINUTES },\n {\n onSuccess: () => onView?.(),\n onError: (err) => setError((err as Error).message),\n },\n );\n };\n\n const classes = prominent\n ? 'btn-primary text-xs shrink-0 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-accent'\n : 'px-2 py-0.5 rounded text-2xs font-medium text-accent/70 border border-accent/30 enabled:hover:text-accent enabled:hover:border-accent/60 enabled:hover:bg-accent/5 transition-colors disabled:opacity-50 disabled:cursor-not-allowed whitespace-nowrap';\n\n return (\n <span className=\"inline-flex flex-col items-end gap-0.5\">\n <button\n type=\"button\"\n onClick={fire}\n disabled={claim.isPending || spent}\n title={spent ? (row.status === 'pending' ? 'claimed' : row.status) : undefined}\n className={classes}\n data-testid=\"row-action-button\"\n >\n {claim.isPending ? 'Claiming…' : label}\n </button>\n {error && <span className=\"text-2xs text-status-error\" data-testid=\"row-action-error\">{error}</span>}\n </span>\n );\n}\n\n/** A field value token that is a pure metadata binding — facet-linkable. */\nexport const METADATA_TOKEN = /^\\{\\{\\s*metadata\\.([a-zA-Z0-9_]+)\\s*\\}\\}$/;\n\n/** A metadata value the faceted query can match on: a scalar with something in it. */\nfunction isFacetValue(raw: unknown): raw is string | number | boolean {\n return (typeof raw === 'string' && raw !== '') || typeof raw === 'number' || typeof raw === 'boolean';\n}\n\n/**\n * The refinable facts one row offers: every metadata facet the row carries.\n * Columns the author bound to a metadata value lead, under their authored\n * labels; every other scalar facet follows under a label derived from its\n * key, so the dialog reaches the whole record, not only what the columns\n * show. Feeds the row's RefineDialog.\n */\nexport function rowRefinePairs(row: LTEscalationRecord, columnDefs: ColumnDef[]): RefinePair[] {\n const pairs: RefinePair[] = [];\n const seen = new Set<string>();\n const metadata = row.metadata ?? {};\n for (const col of columnDefs) {\n const bound = typeof col.value === 'string' ? col.value.match(METADATA_TOKEN)?.[1] : undefined;\n if (!bound || seen.has(bound)) continue;\n const raw = metadata[bound];\n if (!isFacetValue(raw)) continue;\n seen.add(bound);\n pairs.push({ key: bound, label: col.label, value: raw, bound: true });\n }\n for (const [key, raw] of Object.entries(metadata)) {\n if (seen.has(key) || !isFacetValue(raw)) continue;\n seen.add(key);\n pairs.push({ key, label: identifierToTitle(key), value: raw });\n }\n return pairs;\n}\n\n/** The always-tappable row/card refine trigger — one magnifier, dialog behind it. */\nexport function RefineTrigger({ onOpen, className = '' }: { onOpen: () => void; className?: string }) {\n return (\n <button\n type=\"button\"\n onClick={(e) => { e.stopPropagation(); onOpen(); }}\n className={`p-1.5 rounded text-text-quaternary/70 hover:text-accent hover:bg-surface-hover transition-colors ${className}`}\n title=\"Refine — filter or search by this row's values\"\n aria-label=\"Refine — filter or search by this row's values\"\n data-testid=\"row-refine\"\n >\n <Search className=\"w-3.5 h-3.5\" strokeWidth={1.5} />\n </button>\n );\n}\n","/**\n * Related sets on a role's list schema. A set is named once under\n * `x-lt-related`; columns (`related`) and row details (`x-lt-row-detail`)\n * reference it by name. The server reads the declaration from the stored\n * list schema, never from the caller.\n *\n * items the host row's accumulated or batch items, each read through its\n * payload or its reciprocal row\n * query rows in other roles that share facets with the host row; facet\n * values are `{{domain.path}}` templates over the host row\n */\n\nexport const LIST_SCHEMA_KEYS = {\n RELATED: 'x-lt-related',\n COLUMNS: 'x-lt-columns',\n ROW_DETAIL: 'x-lt-row-detail',\n GROUP_BY: 'x-lt-group-by',\n LAYOUT: 'x-lt-layout',\n} as const;\n\nexport const RELATED_SOURCES = {\n ITEMS: 'items',\n QUERY: 'query',\n} as const;\nexport type RelatedSource = (typeof RELATED_SOURCES)[keyof typeof RELATED_SOURCES];\n\nexport const RELATED_AGGREGATES = {\n COUNT: 'count',\n /** The least item or row value: numbers as numbers, everything else as text. */\n MIN: 'min',\n MAX: 'max',\n} as const;\nexport type RelatedAggregate = (typeof RELATED_AGGREGATES)[keyof typeof RELATED_AGGREGATES];\n\n/** How a grouped table folds a plain column across a group's rows. */\nexport const GROUP_FOLDS = {\n FIRST: 'first',\n MIN: 'min',\n MAX: 'max',\n SUM: 'sum',\n COUNT: 'count',\n /** The distinct values, in row order, joined: \"standard, express\". */\n DISTINCT: 'distinct',\n} as const;\nexport type GroupFold = (typeof GROUP_FOLDS)[keyof typeof GROUP_FOLDS];\n\n/** Split prefixes. `role` splits a query set by the related row's role. */\nexport const SPLIT_PATHS = {\n ROLE: 'role',\n METADATA: 'metadata.',\n PAYLOAD: 'payload.',\n RECIPROCAL_METADATA: 'reciprocal.metadata.',\n} as const;\n\nexport const RELATED_LIMITS = {\n MAX_SETS: 4,\n MAX_QUERY_ROLES: 12,\n MAX_ROW_DETAIL_SECTIONS: 4,\n MAX_HOSTS: 100,\n ROWS_DEFAULT: 25,\n ROWS_MAX: 100,\n} as const;\n\n/** The table layout that renders related columns, row details, and groups. */\nexport const FACET_TABLE_LAYOUT = 'facet-table';\n\nexport interface RelatedQueryDecl {\n /** Related roles, in display order. Exclusive with `segment`. */\n roles?: string[];\n /** A Pace Board sequence by its first role; resolves to the ordered chain. */\n segment?: string;\n /** Facet containment; string values may be `{{domain.path}}` templates. */\n facets?: Record<string, unknown>;\n /**\n * Facets that narrow the match when the host row carries a value, and\n * drop away when it does not: a lane narrows its tub's look-ahead to its\n * own service level, a tub without lanes keeps the whole destination.\n */\n narrow?: Record<string, unknown>;\n /** Default `pending`. */\n status?: string;\n}\n\nexport interface RelatedSetDecl {\n source: RelatedSource;\n query?: RelatedQueryDecl;\n}\n\n/** A count column's text keyed by count; `default` covers the rest, `{n}` reads the count. */\nexport const RELATED_DISPLAY_DEFAULT = 'default';\n\nexport interface RelatedColumnDecl {\n label: string;\n related: string;\n aggregate?: RelatedAggregate;\n /** min/max: `{{item.payload.<path>}}` on an items set, `{{metadata.<key>}}` on a query set. */\n value?: string;\n /** min/max: how the value renders, as on any facet-table column. */\n format?: string;\n /** count: text by count, e.g. `{ \"0\": \"Ready\", \"default\": \"Waiting on {n}\" }`. */\n display?: Record<string, string>;\n splitBy?: string;\n labels?: Record<string, string>;\n priority?: 1 | 2 | 3;\n /** CSS width, as on any facet-table column. */\n width?: string;\n}\n\nexport interface RowDetailColumnDecl {\n label: string;\n value: string;\n format?: string;\n priority?: 1 | 2 | 3;\n}\n\nexport interface RowDetailSectionDecl {\n related: string;\n label?: string;\n columns: RowDetailColumnDecl[];\n limit?: number;\n}\n\n/** The validated, normalized related declaration of one list schema. */\nexport interface ListSchemaRelations {\n sets: Record<string, RelatedSetDecl>;\n columns: RelatedColumnDecl[];\n rowDetail: RowDetailSectionDecl[];\n /** The metadata key a facet-table groups by, when declared. */\n groupKey: string | null;\n}\n\n/** Per-host aggregate for one (set, splitBy) pair, or one (set, min/max, value) triple. */\nexport interface RelatedHostAggregate {\n count: number;\n /** min/max: the extreme value among `count` values; absent when none carries one. */\n value?: string | number;\n /** Split value to count; a null value is keyed by the empty string. */\n splits?: Record<string, number>;\n /** Items whose reciprocal row the viewer cannot read. */\n hidden?: number;\n /** A host whose facet templates resolved to nothing; the set did not run. */\n unresolved?: boolean;\n}\n\nexport interface RelatedSetResult {\n source: RelatedSource;\n /**\n * The roles whose rows the set reads, which a list follows for live\n * changes: a query set's resolved roles in order, or the roles of an item\n * set's readable reciprocal rows when a column splits by them.\n */\n roles?: string[];\n /** Query sets: role titles, keyed by role. */\n roleLabels?: Record<string, string>;\n /** Query sets: declared roles outside the viewer's full read scope. */\n restricted?: string[];\n /** Keyed by relatedAggregateKey (the splitBy, '' when unsplit, or `min:<path>`), then host id. */\n aggregates: Record<string, Record<string, RelatedHostAggregate>>;\n}\n\nexport interface RelatedAggregatesResponse {\n version: number | null;\n sets: Record<string, RelatedSetResult>;\n}\n\nexport interface RelatedItemEntry {\n itemKey: string;\n payload?: unknown;\n at?: string;\n actor?: string;\n reciprocalId?: string;\n}\n\nexport interface RelatedRow {\n /** Items sets only. */\n item?: RelatedItemEntry;\n /** The reciprocal row (items) or the related row (query); null when unreadable. */\n escalation: Record<string, unknown> | null;\n}\n\nexport interface RelatedRowsResponse {\n source: RelatedSource;\n rows: RelatedRow[];\n total: number;\n restricted?: string[];\n roleLabels?: Record<string, string>;\n}\n","import {\n RELATED_AGGREGATES,\n RELATED_DISPLAY_DEFAULT,\n RELATED_SOURCES,\n SPLIT_PATHS,\n type RelatedAggregate,\n type RelatedColumnDecl,\n} from './types';\n\nconst VALUE_TOKEN = /^\\{\\{\\s*([^{}]+?)\\s*\\}\\}$/;\nconst ITEM_PREFIX = 'item.';\nconst PATH_SEGMENT = /^[a-zA-Z0-9_]+$/;\nconst METADATA_KEY = /^[a-zA-Z0-9_]+$/;\nconst COUNT_TOKEN = /\\{n\\}/g;\n\nexport type RelatedExtreme = typeof RELATED_AGGREGATES.MIN | typeof RELATED_AGGREGATES.MAX;\n\n/** True for the aggregates that pick one value rather than count. */\nexport function isExtremeAggregate(aggregate: unknown): aggregate is RelatedExtreme {\n return aggregate === RELATED_AGGREGATES.MIN || aggregate === RELATED_AGGREGATES.MAX;\n}\n\n/**\n * The stored path a min/max `value` template reads: `payload.<path>` for an\n * items set, `metadata.<key>` for a query set. Null when the template does\n * not fit the set's source.\n */\nexport function relatedValuePath(source: string, value: unknown): string | null {\n if (typeof value !== 'string') return null;\n const token = value.match(VALUE_TOKEN)?.[1];\n if (!token) return null;\n if (source === RELATED_SOURCES.ITEMS) {\n if (!token.startsWith(`${ITEM_PREFIX}${SPLIT_PATHS.PAYLOAD}`)) return null;\n const path = token.slice(ITEM_PREFIX.length + SPLIT_PATHS.PAYLOAD.length);\n return path && path.split('.').every((s) => PATH_SEGMENT.test(s)) ? `${SPLIT_PATHS.PAYLOAD}${path}` : null;\n }\n if (!token.startsWith(SPLIT_PATHS.METADATA)) return null;\n const key = token.slice(SPLIT_PATHS.METADATA.length);\n return METADATA_KEY.test(key) ? token : null;\n}\n\n/** The key a column's per-host aggregates are stored under in its set's result. */\nexport function relatedAggregateKey(col: Pick<RelatedColumnDecl, 'aggregate' | 'splitBy' | 'value'>, source: string): string {\n if (isExtremeAggregate(col.aggregate)) return `${col.aggregate}:${relatedValuePath(source, col.value) ?? ''}`;\n return col.splitBy ?? '';\n}\n\n/** A count column's display text, or null when the column declares none for this count. */\nexport function relatedCountText(display: Record<string, string> | undefined, count: number): string | null {\n if (!display) return null;\n const text = display[String(count)] ?? display[RELATED_DISPLAY_DEFAULT];\n return text === undefined ? null : text.replace(COUNT_TOKEN, String(count));\n}\n\n/**\n * The least or greatest of several values: numbers when every value is a\n * number, otherwise text in code-unit order (ISO instants order as text).\n */\nexport function foldExtreme(fold: RelatedAggregate, values: Array<string | number>): string | number | undefined {\n if (!values.length) return undefined;\n const pickMin = fold === RELATED_AGGREGATES.MIN;\n if (values.every((v) => typeof v === 'number')) {\n return pickMin ? Math.min(...(values as number[])) : Math.max(...(values as number[]));\n }\n const texts = values.map(String).sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));\n return pickMin ? texts[0] : texts[texts.length - 1];\n}\n","import {\n FACET_TABLE_LAYOUT,\n GROUP_FOLDS,\n LIST_SCHEMA_KEYS,\n RELATED_AGGREGATES,\n RELATED_DISPLAY_DEFAULT,\n RELATED_LIMITS,\n RELATED_SOURCES,\n SPLIT_PATHS,\n type ListSchemaRelations,\n type RelatedColumnDecl,\n type RelatedSetDecl,\n type RowDetailSectionDecl,\n} from './types';\nimport { isExtremeAggregate, relatedValuePath } from './aggregate';\n\n/** A metadata key: interpolated as a JSON path, so strictly validated. */\nexport const METADATA_KEY = /^[a-zA-Z0-9_]+$/;\nconst SET_NAME = /^[a-zA-Z][a-zA-Z0-9_-]{0,47}$/;\nconst PATH_SEGMENT = /^[a-zA-Z0-9_]+$/;\nconst COUNT_KEY = /^(0|[1-9][0-9]*)$/;\n\ntype Obj = Record<string, unknown>;\n\nclass ListSchemaError extends Error {}\n\nfunction fail(message: string): never {\n throw new ListSchemaError(message);\n}\n\nfunction isObj(value: unknown): value is Obj {\n return !!value && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0;\n}\n\n/** True when a dotted path has only plain segments. */\nfunction isPlainPath(path: string): boolean {\n return path.length > 0 && path.split('.').every((s) => PATH_SEGMENT.test(s));\n}\n\n/** The split paths a set's source accepts. */\nexport function splitPathError(source: string, splitBy: string): string | null {\n if (source === RELATED_SOURCES.QUERY) {\n if (splitBy === SPLIT_PATHS.ROLE) return null;\n if (splitBy.startsWith(SPLIT_PATHS.METADATA) && METADATA_KEY.test(splitBy.slice(SPLIT_PATHS.METADATA.length))) return null;\n return `splitBy \"${splitBy}\" on a query set must be \"role\" or \"metadata.<key>\"`;\n }\n if (splitBy.startsWith(SPLIT_PATHS.PAYLOAD) && isPlainPath(splitBy.slice(SPLIT_PATHS.PAYLOAD.length))) return null;\n if (splitBy.startsWith(SPLIT_PATHS.RECIPROCAL_METADATA)\n && METADATA_KEY.test(splitBy.slice(SPLIT_PATHS.RECIPROCAL_METADATA.length))) return null;\n return `splitBy \"${splitBy}\" on an items set must be \"payload.<path>\" or \"reciprocal.metadata.<key>\"`;\n}\n\nfunction readSet(name: string, raw: unknown): RelatedSetDecl {\n if (!SET_NAME.test(name)) fail(`x-lt-related name \"${name}\" must start with a letter (letters, digits, _ or -)`);\n if (!isObj(raw)) fail(`x-lt-related.${name} must be an object`);\n if (raw.source === RELATED_SOURCES.ITEMS) {\n if (raw.query !== undefined) fail(`x-lt-related.${name}: an items set takes no query`);\n return { source: RELATED_SOURCES.ITEMS };\n }\n if (raw.source !== RELATED_SOURCES.QUERY) fail(`x-lt-related.${name}.source must be \"items\" or \"query\"`);\n const q = raw.query;\n if (!isObj(q)) fail(`x-lt-related.${name}.query is required for a query set`);\n const hasRoles = q.roles !== undefined;\n const hasSegment = q.segment !== undefined;\n if (hasRoles === hasSegment) fail(`x-lt-related.${name}.query takes exactly one of roles or segment`);\n if (hasRoles) {\n const roles = q.roles;\n if (!Array.isArray(roles) || roles.length === 0 || roles.length > RELATED_LIMITS.MAX_QUERY_ROLES\n || !roles.every(isNonEmptyString)) {\n fail(`x-lt-related.${name}.query.roles must be 1..${RELATED_LIMITS.MAX_QUERY_ROLES} role names`);\n }\n } else if (!isNonEmptyString(q.segment)) {\n fail(`x-lt-related.${name}.query.segment must be a role name`);\n }\n if (!isObj(q.facets) || Object.keys(q.facets).length === 0) {\n fail(`x-lt-related.${name}.query.facets must name at least one facet`);\n }\n for (const [key, value] of Object.entries(q.facets)) {\n if (!METADATA_KEY.test(key)) fail(`x-lt-related.${name}.query.facets key \"${key}\" must be letters, digits or _`);\n if (value === null || typeof value === 'object') fail(`x-lt-related.${name}.query.facets.${key} must be a scalar or template`);\n }\n if (q.narrow !== undefined) {\n if (!isObj(q.narrow) || Object.keys(q.narrow).length === 0) fail(`x-lt-related.${name}.query.narrow must name at least one facet`);\n for (const [key, value] of Object.entries(q.narrow)) {\n if (!METADATA_KEY.test(key)) fail(`x-lt-related.${name}.query.narrow key \"${key}\" must be letters, digits or _`);\n if (key in q.facets) fail(`x-lt-related.${name}.query.narrow.${key} is already a required facet`);\n if (value === null || typeof value === 'object') fail(`x-lt-related.${name}.query.narrow.${key} must be a scalar or template`);\n }\n }\n if (q.status !== undefined && !isNonEmptyString(q.status)) fail(`x-lt-related.${name}.query.status must be a status`);\n return {\n source: RELATED_SOURCES.QUERY,\n query: {\n ...(hasRoles ? { roles: [...(q.roles as string[])] } : { segment: q.segment as string }),\n facets: { ...q.facets },\n ...(q.narrow !== undefined ? { narrow: { ...(q.narrow as Obj) } } : {}),\n ...(q.status !== undefined ? { status: q.status as string } : {}),\n },\n };\n}\n\nfunction readRelatedColumn(raw: Obj, sets: Record<string, RelatedSetDecl>, at: string): RelatedColumnDecl {\n const name = raw.related;\n if (!isNonEmptyString(name) || !sets[name]) fail(`${at}.related must name a set declared in x-lt-related`);\n if (raw.aggregate !== undefined && raw.aggregate !== RELATED_AGGREGATES.COUNT && !isExtremeAggregate(raw.aggregate)) {\n fail(`${at}.aggregate must be \"count\", \"min\" or \"max\"`);\n }\n const source = sets[name].source;\n if (isExtremeAggregate(raw.aggregate)) {\n if (!relatedValuePath(source, raw.value)) {\n fail(source === RELATED_SOURCES.ITEMS\n ? `${at}.value must be \"{{item.payload.<path>}}\" on an items set`\n : `${at}.value must be \"{{metadata.<key>}}\" on a query set`);\n }\n if (raw.splitBy !== undefined) fail(`${at}: a ${raw.aggregate} column takes no splitBy`);\n if (raw.display !== undefined) fail(`${at}: display applies to a count column`);\n } else if (raw.value !== undefined) {\n fail(`${at}.value applies to a min or max column`);\n }\n if (raw.format !== undefined && typeof raw.format !== 'string') fail(`${at}.format must be a format name`);\n if (raw.display !== undefined) {\n if (!isObj(raw.display) || Object.keys(raw.display).length === 0\n || !Object.entries(raw.display).every(([k, v]) => (k === RELATED_DISPLAY_DEFAULT || COUNT_KEY.test(k)) && typeof v === 'string')) {\n fail(`${at}.display must map counts (or \"default\") to display text`);\n }\n }\n if (raw.splitBy !== undefined) {\n if (!isNonEmptyString(raw.splitBy)) fail(`${at}.splitBy must be a path`);\n const err = splitPathError(sets[name].source, raw.splitBy);\n if (err) fail(`${at}: ${err}`);\n }\n if (raw.labels !== undefined && (!isObj(raw.labels) || !Object.values(raw.labels).every((v) => typeof v === 'string'))) {\n fail(`${at}.labels must map values to display text`);\n }\n return raw as unknown as RelatedColumnDecl;\n}\n\nfunction readRowDetail(raw: unknown, sets: Record<string, RelatedSetDecl>): RowDetailSectionDecl[] {\n if (raw === undefined) return [];\n if (!Array.isArray(raw) || raw.length === 0 || raw.length > RELATED_LIMITS.MAX_ROW_DETAIL_SECTIONS) {\n fail(`x-lt-row-detail must be 1..${RELATED_LIMITS.MAX_ROW_DETAIL_SECTIONS} sections`);\n }\n return raw.map((section, i) => {\n const at = `x-lt-row-detail[${i}]`;\n if (!isObj(section)) fail(`${at} must be an object`);\n if (!isNonEmptyString(section.related) || !sets[section.related]) fail(`${at}.related must name a set declared in x-lt-related`);\n if (!Array.isArray(section.columns) || section.columns.length === 0) fail(`${at}.columns must list at least one column`);\n for (const [j, col] of section.columns.entries()) {\n if (!isObj(col) || !isNonEmptyString(col.label) || typeof col.value !== 'string') {\n fail(`${at}.columns[${j}] needs a label and a value template`);\n }\n }\n if (section.limit !== undefined && (!Number.isInteger(section.limit) || (section.limit as number) < 1\n || (section.limit as number) > RELATED_LIMITS.ROWS_MAX)) {\n fail(`${at}.limit must be 1..${RELATED_LIMITS.ROWS_MAX}`);\n }\n return section as unknown as RowDetailSectionDecl;\n });\n}\n\nfunction readGroupKey(schema: Obj): string | null {\n const raw = schema[LIST_SCHEMA_KEYS.GROUP_BY];\n if (raw === undefined || schema[LIST_SCHEMA_KEYS.LAYOUT] !== FACET_TABLE_LAYOUT) return null;\n const key = typeof raw === 'string' && raw.startsWith(SPLIT_PATHS.METADATA) ? raw.slice(SPLIT_PATHS.METADATA.length) : '';\n if (!METADATA_KEY.test(key)) fail('x-lt-group-by on a facet-table must be \"metadata.<key>\"');\n return key;\n}\n\nconst FOLDS = new Set<string>(Object.values(GROUP_FOLDS));\n\n/**\n * Validate and normalize the related declaration of a list schema. Throws on\n * an invalid declaration; keys outside this vocabulary stay opaque.\n */\nexport function readListSchemaRelations(schema: unknown): ListSchemaRelations {\n const empty: ListSchemaRelations = { sets: {}, columns: [], rowDetail: [], groupKey: null };\n if (!isObj(schema)) return empty;\n const rawSets = schema[LIST_SCHEMA_KEYS.RELATED];\n const sets: Record<string, RelatedSetDecl> = {};\n if (rawSets !== undefined) {\n if (!isObj(rawSets)) fail('x-lt-related must map set names to declarations');\n const names = Object.keys(rawSets);\n if (names.length === 0 || names.length > RELATED_LIMITS.MAX_SETS) fail(`x-lt-related must declare 1..${RELATED_LIMITS.MAX_SETS} sets`);\n for (const name of names) sets[name] = readSet(name, rawSets[name]);\n }\n const columns: RelatedColumnDecl[] = [];\n const rawColumns = schema[LIST_SCHEMA_KEYS.COLUMNS];\n if (Array.isArray(rawColumns)) {\n rawColumns.forEach((col, i) => {\n if (!isObj(col)) return;\n if (col.related !== undefined) columns.push(readRelatedColumn(col, sets, `x-lt-columns[${i}]`));\n if (col.group !== undefined && (typeof col.group !== 'string' || !FOLDS.has(col.group))) {\n fail(`x-lt-columns[${i}].group must be one of ${[...FOLDS].join(', ')}`);\n }\n });\n }\n return { sets, columns, rowDetail: readRowDetail(schema[LIST_SCHEMA_KEYS.ROW_DETAIL], sets), groupKey: readGroupKey(schema) };\n}\n\n/** The declaration's first error, or null when valid. */\nexport function listSchemaRelationsError(schema: unknown): string | null {\n try {\n readListSchemaRelations(schema);\n return null;\n } catch (err) {\n if (err instanceof ListSchemaError) return err.message;\n throw err;\n }\n}\n"],"names":["isEffectivelyClaimed","esc","isAckEscalation","identifierToTitle","id","w","escalationDotClass","e","STATUS_DOT_STYLES","rowContext","parse","s","v","IDENTITY_COLUMN_WIDTH","actionColumnWidth","label","DEFAULT_CLAIM_MINUTES","isClaimable","row","RowActionButton","def","onView","prominent","forceView","authored","action","claim","useClaimEscalation","navigate","useNavigate","location","useLocation","error","setError","useState","spent","fire","err","classes","jsxs","jsx","METADATA_TOKEN","isFacetValue","raw","rowRefinePairs","columnDefs","pairs","seen","metadata","col","bound","_a","key","RefineTrigger","onOpen","className","Search","LIST_SCHEMA_KEYS","RELATED_SOURCES","RELATED_AGGREGATES","GROUP_FOLDS","SPLIT_PATHS","RELATED_LIMITS","FACET_TABLE_LAYOUT","RELATED_DISPLAY_DEFAULT","VALUE_TOKEN","ITEM_PREFIX","PATH_SEGMENT","METADATA_KEY","COUNT_TOKEN","isExtremeAggregate","aggregate","relatedValuePath","source","value","token","path","relatedAggregateKey","relatedCountText","display","count","text","foldExtreme","fold","values","pickMin","texts","a","b","SET_NAME","COUNT_KEY","ListSchemaError","fail","message","isObj","isNonEmptyString","isPlainPath","splitPathError","splitBy","readSet","name","q","hasRoles","hasSegment","roles","readRelatedColumn","sets","at","k","readRowDetail","section","i","j","readGroupKey","schema","FOLDS","readListSchemaRelations","empty","rawSets","names","columns","rawColumns"],"mappings":"iPAEO,SAASA,EAAqBC,EAAkC,CACrE,MAAO,CAAC,EACNA,EAAI,aACJA,EAAI,gBACJ,IAAI,KAAKA,EAAI,cAAc,EAAI,IAAI,KAEvC,CAGO,SAASC,GAAgBD,EAAkC,CAChE,MAAO,CAACA,EAAI,aACd,CCPO,SAASE,EAAkBC,EAAoB,CASpD,OARcA,EACX,QAAQ,WAAY,GAAG,EACvB,QAAQ,oBAAqB,OAAO,EACpC,QAAQ,wBAAyB,OAAO,EACxC,QAAQ,kBAAmB,OAAO,EAClC,OACA,MAAM,KAAK,EACX,OAAO,OAAO,EAEd,IAAKC,GAAOA,IAAMA,EAAE,eAAiBA,EAAE,OAAS,EAAIA,EAAIA,EAAE,OAAO,CAAC,EAAE,cAAgBA,EAAE,MAAM,CAAC,CAAE,EAC/F,KAAK,GAAG,CACb,CCFO,SAASC,GAAmBC,EAA+B,CAChE,OAAIA,EAAE,SAAW,UACRP,EAAqBO,CAAC,EAAI,4BAA8B,mBAE1DC,EAAkBD,EAAE,MAAM,GAAK,kBACxC,CA8CO,SAASE,GAAWF,EAAyC,CAClE,MAAMG,EAASC,GAAiE,CAC9E,GAAI,CAACA,EAAG,OAAO,KACf,GAAI,CACF,MAAMC,EAAI,KAAK,MAAMD,CAAC,EACtB,OAAOC,GAAK,OAAOA,GAAM,SAAWA,EAAI,IAC1C,MAAQ,CACN,OAAO,IACT,CACF,EACA,MAAO,CACL,WAAYL,EACZ,SAAUA,EAAE,UAAY,KACxB,SAAUG,EAAMH,EAAE,QAAQ,EAC1B,QAASG,EAAMH,EAAE,kBAAkB,EACnC,SAAUG,EAAMH,EAAE,gBAAgB,CAAA,CAEtC,CAGO,MAAMM,GAAwB,QAG9B,SAASC,GAAkBC,EAAuB,CACvD,MAAO,GAAG,KAAK,IAAI,EAAG,KAAK,MAAMA,EAAM,OAAS,IAAO,GAAG,CAAC,CAAC,KAC9D,CAEA,MAAMC,EAAwB,GAG9B,SAASC,EAAYC,EAAkC,CACrD,OAAOA,EAAI,SAAW,WAAa,CAAClB,EAAqBkB,CAAG,CAC9D,CAQO,SAASC,GAAgB,CAAE,IAAAD,EAAK,IAAAE,EAAK,OAAAC,EAAQ,UAAAC,EAAW,UAAAC,GAQ5D,CACD,MAAMC,GAAWJ,GAAA,YAAAA,EAAK,SAAU,QAC1BK,EAASF,EAAY,OAASC,EAG9BT,EAAQS,IAAaC,IAAUL,GAAA,MAAAA,EAAK,OACtCA,EAAI,MACJK,IAAW,QAAU,QAAU,OAC7BC,EAAQC,EAAA,EACRC,EAAWC,EAAA,EACXC,EAAWC,EAAA,EACX,CAACC,EAAOC,CAAQ,EAAIC,EAAAA,SAAS,EAAE,EAI/BC,EAAQV,IAAW,SAAW,CAACR,EAAYC,CAAG,EAE9CkB,EAAQ7B,GAAwB,CAEpC,GADAA,EAAE,gBAAA,EACEkB,IAAW,OAAQ,CACrBJ,GAAA,MAAAA,IACA,MACF,CAIA,GAAID,GAAA,MAAAA,EAAK,cAAe,CACtBQ,EAAS,uBAAuBV,EAAI,EAAE,GAAI,CACxC,MAAO,CAAE,UAAW,GAAM,gBAAiBE,GAAA,YAAAA,EAAK,gBAAiB,KAAMU,EAAS,QAAA,CAAS,CAC1F,EACD,MACF,CACAG,EAAS,EAAE,EACXP,EAAM,OACJ,CAAE,GAAIR,EAAI,GAAI,iBAAiBE,GAAA,YAAAA,EAAK,kBAAmBJ,CAAA,EACvD,CACE,UAAW,IAAMK,GAAA,YAAAA,IACjB,QAAUgB,GAAQJ,EAAUI,EAAc,OAAO,CAAA,CACnD,CAEJ,EAEMC,EAAUhB,EACZ,wGACA,yPAEJ,OACEiB,EAAAA,KAAC,OAAA,CAAK,UAAU,yCACd,SAAA,CAAAC,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,QAASJ,EACT,SAAUV,EAAM,WAAaS,EAC7B,MAAOA,EAASjB,EAAI,SAAW,UAAY,UAAYA,EAAI,OAAU,OACrE,UAAWoB,EACX,cAAY,oBAEX,SAAAZ,EAAM,UAAY,YAAcX,CAAA,CAAA,EAElCiB,GAASQ,EAAAA,IAAC,OAAA,CAAK,UAAU,6BAA6B,cAAY,mBAAoB,SAAAR,CAAA,CAAM,CAAA,EAC/F,CAEJ,CAGO,MAAMS,EAAiB,4CAG9B,SAASC,EAAaC,EAAgD,CACpE,OAAQ,OAAOA,GAAQ,UAAYA,IAAQ,IAAO,OAAOA,GAAQ,UAAY,OAAOA,GAAQ,SAC9F,CASO,SAASC,GAAe1B,EAAyB2B,EAAuC,OAC7F,MAAMC,EAAsB,CAAA,EACtBC,MAAW,IACXC,EAAW9B,EAAI,UAAY,CAAA,EACjC,UAAW+B,KAAOJ,EAAY,CAC5B,MAAMK,EAAQ,OAAOD,EAAI,OAAU,UAAWE,EAAAF,EAAI,MAAM,MAAMR,CAAc,IAA9B,YAAAU,EAAkC,GAAK,OACrF,GAAI,CAACD,GAASH,EAAK,IAAIG,CAAK,EAAG,SAC/B,MAAMP,EAAMK,EAASE,CAAK,EACrBR,EAAaC,CAAG,IACrBI,EAAK,IAAIG,CAAK,EACdJ,EAAM,KAAK,CAAE,IAAKI,EAAO,MAAOD,EAAI,MAAO,MAAON,EAAK,MAAO,EAAA,CAAM,EACtE,CACA,SAAW,CAACS,EAAKT,CAAG,IAAK,OAAO,QAAQK,CAAQ,EAC1CD,EAAK,IAAIK,CAAG,GAAK,CAACV,EAAaC,CAAG,IACtCI,EAAK,IAAIK,CAAG,EACZN,EAAM,KAAK,CAAE,IAAAM,EAAK,MAAOjD,EAAkBiD,CAAG,EAAG,MAAOT,EAAK,GAE/D,OAAOG,CACT,CAGO,SAASO,GAAc,CAAE,OAAAC,EAAQ,UAAAC,EAAY,IAAkD,CACpG,OACEf,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,QAAU,GAAM,CAAE,EAAE,gBAAA,EAAmBc,EAAA,CAAU,EACjD,UAAW,oGAAoGC,CAAS,GACxH,MAAM,iDACN,aAAW,iDACX,cAAY,aAEZ,SAAAf,EAAAA,IAACgB,EAAA,CAAO,UAAU,cAAc,YAAa,GAAA,CAAK,CAAA,CAAA,CAGxD,CCvNO,MAAMC,EAAmB,CAC9B,QAAS,eACT,QAAS,eACT,WAAY,kBACZ,SAAU,gBACV,OAAQ,aACV,EAEaC,EAAkB,CAC7B,MAAO,QACP,MAAO,OACT,EAGaC,EAAqB,CAChC,MAAO,QAEP,IAAK,MACL,IAAK,KACP,EAIaC,EAAc,CACzB,MAAO,QACP,IAAK,MACL,IAAK,MACL,IAAK,MACL,MAAO,QAEP,SAAU,UACZ,EAIaC,EAAc,CACzB,KAAM,OACN,SAAU,YACV,QAAS,WACT,oBAAqB,sBACvB,EAEaC,EAAiB,CAC5B,SAAU,EACV,gBAAiB,GACjB,wBAAyB,EAGzB,SAAU,GACZ,EAGaC,EAAqB,cAyBrBC,EAA0B,UChFjCC,EAAc,4BACdC,EAAc,QACdC,EAAe,kBACfC,EAAe,kBACfC,EAAc,SAKb,SAASC,EAAmBC,EAAiD,CAClF,OAAOA,IAAcZ,EAAmB,KAAOY,IAAcZ,EAAmB,GAClF,CAOO,SAASa,EAAiBC,EAAgBC,EAA+B,OAC9E,GAAI,OAAOA,GAAU,SAAU,OAAO,KACtC,MAAMC,GAAQxB,EAAAuB,EAAM,MAAMT,CAAW,IAAvB,YAAAd,EAA2B,GACzC,GAAI,CAACwB,EAAO,OAAO,KACnB,GAAIF,IAAWf,EAAgB,MAAO,CACpC,GAAI,CAACiB,EAAM,WAAW,GAAGT,CAAW,GAAGL,EAAY,OAAO,EAAE,EAAG,OAAO,KACtE,MAAMe,EAAOD,EAAM,MAAMT,EAAY,OAASL,EAAY,QAAQ,MAAM,EACxE,OAAOe,GAAQA,EAAK,MAAM,GAAG,EAAE,MAAOjE,GAAMwD,EAAa,KAAKxD,CAAC,CAAC,EAAI,GAAGkD,EAAY,OAAO,GAAGe,CAAI,GAAK,IACxG,CACA,GAAI,CAACD,EAAM,WAAWd,EAAY,QAAQ,EAAG,OAAO,KACpD,MAAMT,EAAMuB,EAAM,MAAMd,EAAY,SAAS,MAAM,EACnD,OAAOO,EAAa,KAAKhB,CAAG,EAAIuB,EAAQ,IAC1C,CAGO,SAASE,GAAoB5B,EAAiEwB,EAAwB,CAC3H,OAAIH,EAAmBrB,EAAI,SAAS,EAAU,GAAGA,EAAI,SAAS,IAAIuB,EAAiBC,EAAQxB,EAAI,KAAK,GAAK,EAAE,GACpGA,EAAI,SAAW,EACxB,CAGO,SAAS6B,GAAiBC,EAA6CC,EAA8B,CAC1G,GAAI,CAACD,EAAS,OAAO,KACrB,MAAME,EAAOF,EAAQ,OAAOC,CAAK,CAAC,GAAKD,EAAQf,CAAuB,EACtE,OAAOiB,IAAS,OAAY,KAAOA,EAAK,QAAQZ,EAAa,OAAOW,CAAK,CAAC,CAC5E,CAMO,SAASE,GAAYC,EAAwBC,EAA6D,CAC/G,GAAI,CAACA,EAAO,OAAQ,OACpB,MAAMC,EAAUF,IAASxB,EAAmB,IAC5C,GAAIyB,EAAO,MAAOxE,GAAM,OAAOA,GAAM,QAAQ,EAC3C,OAAOyE,EAAU,KAAK,IAAI,GAAID,CAAmB,EAAI,KAAK,IAAI,GAAIA,CAAmB,EAEvF,MAAME,EAAQF,EAAO,IAAI,MAAM,EAAE,KAAK,CAACG,EAAGC,IAAOD,EAAIC,EAAI,GAAKD,EAAIC,EAAI,EAAI,CAAE,EAC5E,OAAOH,EAAUC,EAAM,CAAC,EAAIA,EAAMA,EAAM,OAAS,CAAC,CACpD,CCjDO,MAAMlB,EAAe,kBACtBqB,EAAW,gCACXtB,EAAe,kBACfuB,EAAY,oBAIlB,MAAMC,WAAwB,KAAM,CAAC,CAErC,SAASC,EAAKC,EAAwB,CACpC,MAAM,IAAIF,GAAgBE,CAAO,CACnC,CAEA,SAASC,EAAMpB,EAA8B,CAC3C,MAAO,CAAC,CAACA,GAAS,OAAOA,GAAU,UAAY,CAAC,MAAM,QAAQA,CAAK,CACrE,CAEA,SAASqB,EAAiBrB,EAAiC,CACzD,OAAO,OAAOA,GAAU,UAAYA,EAAM,KAAA,EAAO,OAAS,CAC5D,CAGA,SAASsB,GAAYpB,EAAuB,CAC1C,OAAOA,EAAK,OAAS,GAAKA,EAAK,MAAM,GAAG,EAAE,MAAO,GAAMT,EAAa,KAAK,CAAC,CAAC,CAC7E,CAGO,SAAS8B,GAAexB,EAAgByB,EAAgC,CAC7E,OAAIzB,IAAWf,EAAgB,MACzBwC,IAAYrC,EAAY,MACxBqC,EAAQ,WAAWrC,EAAY,QAAQ,GAAKO,EAAa,KAAK8B,EAAQ,MAAMrC,EAAY,SAAS,MAAM,CAAC,EAAU,KAC/G,YAAYqC,CAAO,sDAExBA,EAAQ,WAAWrC,EAAY,OAAO,GAAKmC,GAAYE,EAAQ,MAAMrC,EAAY,QAAQ,MAAM,CAAC,GAChGqC,EAAQ,WAAWrC,EAAY,mBAAmB,GACjDO,EAAa,KAAK8B,EAAQ,MAAMrC,EAAY,oBAAoB,MAAM,CAAC,EAAU,KAC/E,YAAYqC,CAAO,2EAC5B,CAEA,SAASC,GAAQC,EAAczD,EAA8B,CAG3D,GAFK8C,EAAS,KAAKW,CAAI,GAAGR,EAAK,sBAAsBQ,CAAI,sDAAsD,EAC1GN,EAAMnD,CAAG,GAAGiD,EAAK,gBAAgBQ,CAAI,oBAAoB,EAC1DzD,EAAI,SAAWe,EAAgB,MACjC,OAAIf,EAAI,QAAU,QAAWiD,EAAK,gBAAgBQ,CAAI,+BAA+B,EAC9E,CAAE,OAAQ1C,EAAgB,KAAA,EAE/Bf,EAAI,SAAWe,EAAgB,OAAOkC,EAAK,gBAAgBQ,CAAI,oCAAoC,EACvG,MAAMC,EAAI1D,EAAI,MACTmD,EAAMO,CAAC,GAAGT,EAAK,gBAAgBQ,CAAI,oCAAoC,EAC5E,MAAME,EAAWD,EAAE,QAAU,OACvBE,EAAaF,EAAE,UAAY,OAEjC,GADIC,IAAaC,GAAYX,EAAK,gBAAgBQ,CAAI,8CAA8C,EAChGE,EAAU,CACZ,MAAME,EAAQH,EAAE,OACZ,CAAC,MAAM,QAAQG,CAAK,GAAKA,EAAM,SAAW,GAAKA,EAAM,OAAS1C,EAAe,iBAC5E,CAAC0C,EAAM,MAAMT,CAAgB,IAChCH,EAAK,gBAAgBQ,CAAI,2BAA2BtC,EAAe,eAAe,aAAa,CAEnG,MAAYiC,EAAiBM,EAAE,OAAO,GACpCT,EAAK,gBAAgBQ,CAAI,oCAAoC,GAE3D,CAACN,EAAMO,EAAE,MAAM,GAAK,OAAO,KAAKA,EAAE,MAAM,EAAE,SAAW,IACvDT,EAAK,gBAAgBQ,CAAI,4CAA4C,EAEvE,SAAW,CAAChD,EAAKsB,CAAK,IAAK,OAAO,QAAQ2B,EAAE,MAAM,EAC3CjC,EAAa,KAAKhB,CAAG,KAAQ,gBAAgBgD,CAAI,sBAAsBhD,CAAG,gCAAgC,GAC3GsB,IAAU,MAAQ,OAAOA,GAAU,aAAe,gBAAgB0B,CAAI,iBAAiBhD,CAAG,+BAA+B,EAE/H,GAAIiD,EAAE,SAAW,OAAW,EACtB,CAACP,EAAMO,EAAE,MAAM,GAAK,OAAO,KAAKA,EAAE,MAAM,EAAE,SAAW,IAAGT,EAAK,gBAAgBQ,CAAI,4CAA4C,EACjI,SAAW,CAAChD,EAAKsB,CAAK,IAAK,OAAO,QAAQ2B,EAAE,MAAM,EAC3CjC,EAAa,KAAKhB,CAAG,KAAQ,gBAAgBgD,CAAI,sBAAsBhD,CAAG,gCAAgC,EAC3GA,KAAOiD,EAAE,QAAQT,EAAK,gBAAgBQ,CAAI,iBAAiBhD,CAAG,8BAA8B,GAC5FsB,IAAU,MAAQ,OAAOA,GAAU,aAAe,gBAAgB0B,CAAI,iBAAiBhD,CAAG,+BAA+B,CAEjI,CACA,OAAIiD,EAAE,SAAW,QAAa,CAACN,EAAiBM,EAAE,MAAM,GAAGT,EAAK,gBAAgBQ,CAAI,gCAAgC,EAC7G,CACL,OAAQ1C,EAAgB,MACxB,MAAO,CACL,GAAI4C,EAAW,CAAE,MAAO,CAAC,GAAID,EAAE,KAAkB,CAAA,EAAM,CAAE,QAASA,EAAE,OAAA,EACpE,OAAQ,CAAE,GAAGA,EAAE,MAAA,EACf,GAAIA,EAAE,SAAW,OAAY,CAAE,OAAQ,CAAE,GAAIA,EAAE,MAAA,CAAe,EAAM,CAAA,EACpE,GAAIA,EAAE,SAAW,OAAY,CAAE,OAAQA,EAAE,QAAqB,CAAA,CAAC,CACjE,CAEJ,CAEA,SAASI,GAAkB9D,EAAU+D,EAAsCC,EAA+B,CACxG,MAAMP,EAAOzD,EAAI,SACb,CAACoD,EAAiBK,CAAI,GAAK,CAACM,EAAKN,CAAI,IAAGR,EAAK,GAAGe,CAAE,mDAAmD,EACrGhE,EAAI,YAAc,QAAaA,EAAI,YAAcgB,EAAmB,OAAS,CAACW,EAAmB3B,EAAI,SAAS,GAChHiD,EAAK,GAAGe,CAAE,4CAA4C,EAExD,MAAMlC,EAASiC,EAAKN,CAAI,EAAE,OAmB1B,GAlBI9B,EAAmB3B,EAAI,SAAS,GAC7B6B,EAAiBC,EAAQ9B,EAAI,KAAK,GACrCiD,EAAKnB,IAAWf,EAAgB,MAC5B,GAAGiD,CAAE,2DACL,GAAGA,CAAE,oDAAoD,EAE3DhE,EAAI,UAAY,QAAWiD,EAAK,GAAGe,CAAE,OAAOhE,EAAI,SAAS,0BAA0B,EACnFA,EAAI,UAAY,QAAWiD,EAAK,GAAGe,CAAE,qCAAqC,GACrEhE,EAAI,QAAU,QACvBiD,EAAK,GAAGe,CAAE,uCAAuC,EAE/ChE,EAAI,SAAW,QAAa,OAAOA,EAAI,QAAW,UAAUiD,EAAK,GAAGe,CAAE,+BAA+B,EACrGhE,EAAI,UAAY,SACd,CAACmD,EAAMnD,EAAI,OAAO,GAAK,OAAO,KAAKA,EAAI,OAAO,EAAE,SAAW,GAC1D,CAAC,OAAO,QAAQA,EAAI,OAAO,EAAE,MAAM,CAAC,CAACiE,EAAGhG,CAAC,KAAOgG,IAAM5C,GAA2B0B,EAAU,KAAKkB,CAAC,IAAM,OAAOhG,GAAM,QAAQ,IAC/HgF,EAAK,GAAGe,CAAE,yDAAyD,EAGnEhE,EAAI,UAAY,OAAW,CACxBoD,EAAiBpD,EAAI,OAAO,GAAGiD,EAAK,GAAGe,CAAE,yBAAyB,EACvE,MAAMtE,EAAM4D,GAAeS,EAAKN,CAAI,EAAE,OAAQzD,EAAI,OAAO,EACrDN,GAAKuD,EAAK,GAAGe,CAAE,KAAKtE,CAAG,EAAE,CAC/B,CACA,OAAIM,EAAI,SAAW,SAAc,CAACmD,EAAMnD,EAAI,MAAM,GAAK,CAAC,OAAO,OAAOA,EAAI,MAAM,EAAE,MAAO/B,GAAM,OAAOA,GAAM,QAAQ,IAClHgF,EAAK,GAAGe,CAAE,yCAAyC,EAE9ChE,CACT,CAEA,SAASkE,GAAclE,EAAc+D,EAA8D,CACjG,OAAI/D,IAAQ,OAAkB,CAAA,IAC1B,CAAC,MAAM,QAAQA,CAAG,GAAKA,EAAI,SAAW,GAAKA,EAAI,OAASmB,EAAe,0BACzE8B,EAAK,8BAA8B9B,EAAe,uBAAuB,WAAW,EAE/EnB,EAAI,IAAI,CAACmE,EAASC,IAAM,CAC7B,MAAMJ,EAAK,mBAAmBI,CAAC,IAC1BjB,EAAMgB,CAAO,GAAGlB,EAAK,GAAGe,CAAE,oBAAoB,GAC/C,CAACZ,EAAiBe,EAAQ,OAAO,GAAK,CAACJ,EAAKI,EAAQ,OAAO,IAAGlB,EAAK,GAAGe,CAAE,mDAAmD,GAC3H,CAAC,MAAM,QAAQG,EAAQ,OAAO,GAAKA,EAAQ,QAAQ,SAAW,IAAGlB,EAAK,GAAGe,CAAE,wCAAwC,EACvH,SAAW,CAACK,EAAG/D,CAAG,IAAK6D,EAAQ,QAAQ,WACjC,CAAChB,EAAM7C,CAAG,GAAK,CAAC8C,EAAiB9C,EAAI,KAAK,GAAK,OAAOA,EAAI,OAAU,WACtE2C,EAAK,GAAGe,CAAE,YAAYK,CAAC,sCAAsC,EAGjE,OAAIF,EAAQ,QAAU,SAAc,CAAC,OAAO,UAAUA,EAAQ,KAAK,GAAMA,EAAQ,MAAmB,GAC9FA,EAAQ,MAAmBhD,EAAe,WAC9C8B,EAAK,GAAGe,CAAE,qBAAqB7C,EAAe,QAAQ,EAAE,EAEnDgD,CACT,CAAC,EACH,CAEA,SAASG,GAAaC,EAA4B,CAChD,MAAMvE,EAAMuE,EAAOzD,EAAiB,QAAQ,EAC5C,GAAId,IAAQ,QAAauE,EAAOzD,EAAiB,MAAM,IAAMM,EAAoB,OAAO,KACxF,MAAMX,EAAM,OAAOT,GAAQ,UAAYA,EAAI,WAAWkB,EAAY,QAAQ,EAAIlB,EAAI,MAAMkB,EAAY,SAAS,MAAM,EAAI,GACvH,OAAKO,EAAa,KAAKhB,CAAG,KAAQ,yDAAyD,EACpFA,CACT,CAEA,MAAM+D,EAAQ,IAAI,IAAY,OAAO,OAAOvD,CAAW,CAAC,EAMjD,SAASwD,GAAwBF,EAAsC,CAC5E,MAAMG,EAA6B,CAAE,KAAM,GAAI,QAAS,CAAA,EAAI,UAAW,CAAA,EAAI,SAAU,IAAA,EACrF,GAAI,CAACvB,EAAMoB,CAAM,EAAG,OAAOG,EAC3B,MAAMC,EAAUJ,EAAOzD,EAAiB,OAAO,EACzCiD,EAAuC,CAAA,EAC7C,GAAIY,IAAY,OAAW,CACpBxB,EAAMwB,CAAO,KAAQ,iDAAiD,EAC3E,MAAMC,EAAQ,OAAO,KAAKD,CAAO,GAC7BC,EAAM,SAAW,GAAKA,EAAM,OAASzD,EAAe,WAAU8B,EAAK,gCAAgC9B,EAAe,QAAQ,OAAO,EACrI,UAAWsC,KAAQmB,EAAOb,EAAKN,CAAI,EAAID,GAAQC,EAAMkB,EAAQlB,CAAI,CAAC,CACpE,CACA,MAAMoB,EAA+B,CAAA,EAC/BC,EAAaP,EAAOzD,EAAiB,OAAO,EAClD,OAAI,MAAM,QAAQgE,CAAU,GAC1BA,EAAW,QAAQ,CAACxE,EAAK8D,IAAM,CACxBjB,EAAM7C,CAAG,IACVA,EAAI,UAAY,QAAWuE,EAAQ,KAAKf,GAAkBxD,EAAKyD,EAAM,gBAAgBK,CAAC,GAAG,CAAC,EAC1F9D,EAAI,QAAU,SAAc,OAAOA,EAAI,OAAU,UAAY,CAACkE,EAAM,IAAIlE,EAAI,KAAK,IACnF2C,EAAK,gBAAgBmB,CAAC,0BAA0B,CAAC,GAAGI,CAAK,EAAE,KAAK,IAAI,CAAC,EAAE,EAE3E,CAAC,EAEI,CAAE,KAAAT,EAAM,QAAAc,EAAS,UAAWX,GAAcK,EAAOzD,EAAiB,UAAU,EAAGiD,CAAI,EAAG,SAAUO,GAAaC,CAAM,CAAA,CAC5H"}
1
+ {"version":3,"file":"validate-hUqjWN63.js","sources":["../../src/lib/escalation.ts","../../src/lib/identifier-label.ts","../../src/components/escalation/list-view/row-parts.tsx","../../../shared/list-schema/types.ts","../../../shared/list-schema/aggregate.ts","../../../shared/list-schema/validate.ts"],"sourcesContent":["import type { LTEscalationRecord } from '../api/types';\n\nexport function isEffectivelyClaimed(esc: LTEscalationRecord): boolean {\n return !!(\n esc.assigned_to &&\n esc.assigned_until &&\n new Date(esc.assigned_until) > new Date()\n );\n}\n\n/** An ACK escalation has no associated workflow — it's a notification, not a task. */\nexport function isAckEscalation(esc: LTEscalationRecord): boolean {\n return !esc.workflow_type;\n}\n\nexport function isAvailable(esc: LTEscalationRecord): boolean {\n return (\n esc.status === 'pending' &&\n (!esc.assigned_to ||\n !esc.assigned_until ||\n new Date(esc.assigned_until) <= new Date())\n );\n}\n","/**\n * A human label for a code identifier: camelCase, snake_case, kebab-case, and\n * digit runs become Title Case words. `fleetTools` → `Fleet Tools`,\n * `print_order2` → `Print Order 2`. Acronyms keep their capitals: `mcpQuery`\n * → `Mcp Query` is avoided by treating an all-caps run as one word.\n */\nexport function identifierToTitle(id: string): string {\n const words = id\n .replace(/[_\\-.]+/g, ' ')\n .replace(/([a-z\\d])([A-Z])/g, '$1 $2')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n .replace(/([a-zA-Z])(\\d)/g, '$1 $2')\n .trim()\n .split(/\\s+/)\n .filter(Boolean);\n return words\n .map((w) => (w === w.toUpperCase() && w.length > 1 ? w : w.charAt(0).toUpperCase() + w.slice(1)))\n .join(' ');\n}\n","import { useState } from 'react';\nimport { useNavigate, useLocation } from 'react-router-dom';\nimport { Search } from 'lucide-react';\nimport type { HelpTokenContext } from '../../../lib/x-lt-help';\nimport { STATUS_DOT_STYLES } from '../../common/display/StatusBadge';\nimport { useClaimEscalation } from '../../../api/escalations';\nimport { isEffectivelyClaimed } from '../../../lib/escalation';\nimport { identifierToTitle } from '../../../lib/identifier-label';\nimport type { RefinePair } from '../RefineDialog';\nimport type { LTEscalationRecord } from '../../../api/types';\n\n/** The row-level pieces every list layout shares: column and action\n * declarations, the row's token context, the row action, and refine. */\n\n/** Dot colour matches the standard table view: blue = pending unclaimed,\n * orange = under a live claim; other statuses follow the shared map. */\nexport function escalationDotClass(e: LTEscalationRecord): string {\n if (e.status === 'pending') {\n return isEffectivelyClaimed(e) ? 'bg-status-claimed-graphic' : 'bg-status-active';\n }\n return STATUS_DOT_STYLES[e.status] ?? 'bg-status-active';\n}\n\nexport interface ColumnDef {\n label: string;\n value: string;\n /** \"age\" renders an ISO timestamp as a compact age with an absolute tooltip. */\n format?: string;\n /**\n * Card-fold behavior when the table folds at narrow widths (same contract\n * as the engineer table): 1 = identity — always visible, forms the card's\n * title line; 2 = folds into the card body as a label/value pair; 3 =\n * dropped in card mode. Undeclared, the first column is the identity and\n * the rest fold.\n */\n priority?: 1 | 2 | 3;\n /** CSS column width (\"40%\", \"12rem\"). Unset columns share the remainder;\n * when no column declares one, the first column holds a fixed 200px so\n * the identity stays legible and every other value keeps its room. */\n width?: string;\n}\n\n/**\n * The per-row action button — the queue-working gesture, always available on\n * every layout. Template-driven: the schema author sets the action, its text,\n * and (for claim) the hold time.\n */\nexport interface RowActionDef {\n /** \"claim\" fires a one-click claim then opens the detail page already\n * claimed; \"view\" just opens it. Default \"claim\". */\n action?: 'claim' | 'view';\n /** Button text. Defaults \"Claim\" / \"View\" by action. */\n label?: string;\n /** Claim hold time in minutes. Default 30 (the platform claim default). */\n durationMinutes?: number;\n /**\n * Launch the detail page's claim-and-submit flow instead of a plain claim:\n * the row is claimed, the form's seeded defaults are resolved, and — when the\n * form declares `x-lt-transition` — the wait screen bridges to the born-assigned\n * follow-on. One list gesture (\"Start Harvesting\") starts the work and lands\n * the person on the next step. The behavior lives on the detail page (form\n * defaults, validation, transition); the list only points there with intent.\n */\n submitOnClaim?: boolean;\n}\n\n/** Build the token context for one escalation row (payloads are JSON strings). */\nexport function rowContext(e: LTEscalationRecord): HelpTokenContext {\n const parse = (s: string | null | undefined): Record<string, unknown> | null => {\n if (!s) return null;\n try {\n const v = JSON.parse(s);\n return v && typeof v === 'object' ? v : null;\n } catch {\n return null;\n }\n };\n return {\n escalation: e as unknown as Record<string, unknown>,\n metadata: e.metadata ?? null,\n envelope: parse(e.envelope),\n payload: parse(e.escalation_payload),\n resolver: parse(e.resolver_payload),\n };\n}\n\n/** The identity column's width when no column declares one: room for a label, no more. */\nexport const IDENTITY_COLUMN_WIDTH = '200px';\n\n/** The action column sizes to its label so the button never wraps or truncates. */\nexport function actionColumnWidth(label: string): string {\n return `${Math.max(6, Math.round(label.length * 0.55 + 3.5))}rem`;\n}\n\nconst DEFAULT_CLAIM_MINUTES = 30;\n\n/** Claim targets pending rows without a live claim window. */\nfunction isClaimable(row: LTEscalationRecord): boolean {\n return row.status === 'pending' && !isEffectivelyClaimed(row);\n}\n\n/**\n * The x-lt-row-action button. `claim` is one click: claim for the template's\n * duration, then open the detail page already claimed — the fast path for\n * working a queue. `view` opens the detail page. Persistent (light accent at\n * rest, saturating on hover); a rejected claim surfaces its message inline.\n */\nexport function RowActionButton({ row, def, onView, prominent, forceView }: {\n row: LTEscalationRecord;\n def?: RowActionDef;\n onView?: () => void;\n /** Hero treatment for the active-card CTA; default is the compact row button. */\n prominent?: boolean;\n /** Render claim templates as view actions (see EscalationListView). */\n forceView?: boolean;\n}) {\n const authored = def?.action ?? 'claim';\n const action = forceView ? 'view' : authored;\n // The authored label describes the authored gesture. When view is forced\n // over a claim template, claim wording would mislead — use the view default.\n const label = authored === action && def?.label\n ? def.label\n : action === 'claim' ? 'Claim' : 'View';\n const claim = useClaimEscalation();\n const navigate = useNavigate();\n const location = useLocation();\n const [error, setError] = useState('');\n\n // A spent gesture stays visible — the disabled button keeps every row's\n // layout uniform instead of leaving a hole on resolved/held rows.\n const spent = action === 'claim' && !isClaimable(row);\n\n const fire = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (action === 'view') {\n onView?.();\n return;\n }\n // Launch the detail page's claim → submit → transition flow. The detail\n // page owns the heavy lifting (seed defaults, validate, resolve, hand-off);\n // the list points there with the intent and the authored claim duration.\n if (def?.submitOnClaim) {\n navigate(`/escalations/detail/${row.id}`, {\n state: { autoStart: true, durationMinutes: def?.durationMinutes, from: location.pathname },\n });\n return;\n }\n setError('');\n claim.mutate(\n { id: row.id, durationMinutes: def?.durationMinutes ?? DEFAULT_CLAIM_MINUTES },\n {\n onSuccess: () => onView?.(),\n onError: (err) => setError((err as Error).message),\n },\n );\n };\n\n const classes = prominent\n ? 'btn-primary text-xs shrink-0 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-accent'\n : 'px-2 py-0.5 rounded text-2xs font-medium text-accent/70 border border-accent/30 enabled:hover:text-accent enabled:hover:border-accent/60 enabled:hover:bg-accent/5 transition-colors disabled:opacity-50 disabled:cursor-not-allowed whitespace-nowrap';\n\n return (\n <span className=\"inline-flex flex-col items-end gap-0.5\">\n <button\n type=\"button\"\n onClick={fire}\n disabled={claim.isPending || spent}\n title={spent ? (row.status === 'pending' ? 'claimed' : row.status) : undefined}\n className={classes}\n data-testid=\"row-action-button\"\n >\n {claim.isPending ? 'Claiming…' : label}\n </button>\n {error && <span className=\"text-2xs text-status-error\" data-testid=\"row-action-error\">{error}</span>}\n </span>\n );\n}\n\n/** A field value token that is a pure metadata binding — facet-linkable. */\nexport const METADATA_TOKEN = /^\\{\\{\\s*metadata\\.([a-zA-Z0-9_]+)\\s*\\}\\}$/;\n\n/** A metadata value the faceted query can match on: a scalar with something in it. */\nfunction isFacetValue(raw: unknown): raw is string | number | boolean {\n return (typeof raw === 'string' && raw !== '') || typeof raw === 'number' || typeof raw === 'boolean';\n}\n\n/**\n * The refinable facts one row offers: every metadata facet the row carries.\n * Columns the author bound to a metadata value lead, under their authored\n * labels; every other scalar facet follows under a label derived from its\n * key, so the dialog reaches the whole record, not only what the columns\n * show. Feeds the row's RefineDialog.\n */\nexport function rowRefinePairs(row: LTEscalationRecord, columnDefs: ColumnDef[]): RefinePair[] {\n const pairs: RefinePair[] = [];\n const seen = new Set<string>();\n const metadata = row.metadata ?? {};\n for (const col of columnDefs) {\n const bound = typeof col.value === 'string' ? col.value.match(METADATA_TOKEN)?.[1] : undefined;\n if (!bound || seen.has(bound)) continue;\n const raw = metadata[bound];\n if (!isFacetValue(raw)) continue;\n seen.add(bound);\n pairs.push({ key: bound, label: col.label, value: raw, bound: true });\n }\n for (const [key, raw] of Object.entries(metadata)) {\n if (seen.has(key) || !isFacetValue(raw)) continue;\n seen.add(key);\n pairs.push({ key, label: identifierToTitle(key), value: raw });\n }\n return pairs;\n}\n\n/** The always-tappable row/card refine trigger — one magnifier, dialog behind it. */\nexport function RefineTrigger({ onOpen, className = '' }: { onOpen: () => void; className?: string }) {\n return (\n <button\n type=\"button\"\n onClick={(e) => { e.stopPropagation(); onOpen(); }}\n className={`p-1.5 rounded text-text-quaternary/70 hover:text-accent hover:bg-surface-hover transition-colors ${className}`}\n title=\"Refine — filter or search by this row's values\"\n aria-label=\"Refine — filter or search by this row's values\"\n data-testid=\"row-refine\"\n >\n <Search className=\"w-3.5 h-3.5\" strokeWidth={1.5} />\n </button>\n );\n}\n","/**\n * Related sets on a role's list schema. A set is named once under\n * `x-lt-related`; columns (`related`) and row details (`x-lt-row-detail`)\n * reference it by name. The server reads the declaration from the stored\n * list schema, never from the caller.\n *\n * items the host row's accumulated or batch items, each read through its\n * payload or its reciprocal row\n * query rows in other roles that share facets with the host row; facet\n * values are `{{domain.path}}` templates over the host row\n */\n\nexport const LIST_SCHEMA_KEYS = {\n RELATED: 'x-lt-related',\n COLUMNS: 'x-lt-columns',\n ROW_DETAIL: 'x-lt-row-detail',\n GROUP_BY: 'x-lt-group-by',\n LAYOUT: 'x-lt-layout',\n} as const;\n\nexport const RELATED_SOURCES = {\n ITEMS: 'items',\n QUERY: 'query',\n} as const;\nexport type RelatedSource = (typeof RELATED_SOURCES)[keyof typeof RELATED_SOURCES];\n\nexport const RELATED_AGGREGATES = {\n COUNT: 'count',\n /** The least item or row value: numbers as numbers, everything else as text. */\n MIN: 'min',\n MAX: 'max',\n} as const;\nexport type RelatedAggregate = (typeof RELATED_AGGREGATES)[keyof typeof RELATED_AGGREGATES];\n\n/** How a grouped table folds a plain column across a group's rows. */\nexport const GROUP_FOLDS = {\n FIRST: 'first',\n MIN: 'min',\n MAX: 'max',\n SUM: 'sum',\n COUNT: 'count',\n /** The distinct values, in row order, joined: \"standard, express\". */\n DISTINCT: 'distinct',\n} as const;\nexport type GroupFold = (typeof GROUP_FOLDS)[keyof typeof GROUP_FOLDS];\n\n/** Split prefixes. `role` splits a query set by the related row's role. */\nexport const SPLIT_PATHS = {\n ROLE: 'role',\n METADATA: 'metadata.',\n PAYLOAD: 'payload.',\n RECIPROCAL_METADATA: 'reciprocal.metadata.',\n} as const;\n\nexport const RELATED_LIMITS = {\n MAX_SETS: 4,\n MAX_QUERY_ROLES: 12,\n MAX_ROW_DETAIL_SECTIONS: 4,\n MAX_HOSTS: 100,\n ROWS_DEFAULT: 25,\n ROWS_MAX: 100,\n} as const;\n\n/** The table layout that renders related columns, row details, and groups. */\nexport const FACET_TABLE_LAYOUT = 'facet-table';\n\nexport interface RelatedQueryDecl {\n /** Related roles, in display order. Exclusive with `segment`. */\n roles?: string[];\n /** A Pace Board sequence by its first role; resolves to the ordered chain. */\n segment?: string;\n /** Facet containment; string values may be `{{domain.path}}` templates. */\n facets?: Record<string, unknown>;\n /**\n * Facets that narrow the match when the host row carries a value, and\n * drop away when it does not: a lane narrows its tub's look-ahead to its\n * own service level, a tub without lanes keeps the whole destination.\n */\n narrow?: Record<string, unknown>;\n /** Default `pending`. */\n status?: string;\n}\n\nexport interface RelatedSetDecl {\n source: RelatedSource;\n query?: RelatedQueryDecl;\n}\n\n/** A count column's text keyed by count; `default` covers the rest, `{n}` reads the count. */\nexport const RELATED_DISPLAY_DEFAULT = 'default';\n\nexport interface RelatedColumnDecl {\n label: string;\n related: string;\n aggregate?: RelatedAggregate;\n /** min/max: `{{item.payload.<path>}}` on an items set, `{{metadata.<key>}}` on a query set. */\n value?: string;\n /** min/max: how the value renders, as on any facet-table column. */\n format?: string;\n /** count: text by count, e.g. `{ \"0\": \"Ready\", \"default\": \"Waiting on {n}\" }`. */\n display?: Record<string, string>;\n splitBy?: string;\n labels?: Record<string, string>;\n priority?: 1 | 2 | 3;\n /** CSS width, as on any facet-table column. */\n width?: string;\n}\n\nexport interface RowDetailColumnDecl {\n label: string;\n value: string;\n format?: string;\n priority?: 1 | 2 | 3;\n}\n\nexport interface RowDetailSectionDecl {\n related: string;\n label?: string;\n columns: RowDetailColumnDecl[];\n limit?: number;\n}\n\n/** The validated, normalized related declaration of one list schema. */\nexport interface ListSchemaRelations {\n sets: Record<string, RelatedSetDecl>;\n columns: RelatedColumnDecl[];\n rowDetail: RowDetailSectionDecl[];\n /** The metadata key a facet-table groups by, when declared. */\n groupKey: string | null;\n}\n\n/** Per-host aggregate for one (set, splitBy) pair, or one (set, min/max, value) triple. */\nexport interface RelatedHostAggregate {\n count: number;\n /** min/max: the extreme value among `count` values; absent when none carries one. */\n value?: string | number;\n /** Split value to count; a null value is keyed by the empty string. */\n splits?: Record<string, number>;\n /** Items whose reciprocal row the viewer cannot read. */\n hidden?: number;\n /** A host whose facet templates resolved to nothing; the set did not run. */\n unresolved?: boolean;\n}\n\nexport interface RelatedSetResult {\n source: RelatedSource;\n /**\n * The roles whose rows the set reads, which a list follows for live\n * changes: a query set's resolved roles in order, or the roles of an item\n * set's readable reciprocal rows when a column splits by them.\n */\n roles?: string[];\n /** Query sets: role titles, keyed by role. */\n roleLabels?: Record<string, string>;\n /** Query sets: declared roles outside the viewer's full read scope. */\n restricted?: string[];\n /** Keyed by relatedAggregateKey (the splitBy, '' when unsplit, or `min:<path>`), then host id. */\n aggregates: Record<string, Record<string, RelatedHostAggregate>>;\n}\n\nexport interface RelatedAggregatesResponse {\n version: number | null;\n sets: Record<string, RelatedSetResult>;\n}\n\nexport interface RelatedItemEntry {\n itemKey: string;\n payload?: unknown;\n at?: string;\n actor?: string;\n reciprocalId?: string;\n}\n\nexport interface RelatedRow {\n /** Items sets only. */\n item?: RelatedItemEntry;\n /** The reciprocal row (items) or the related row (query); null when unreadable. */\n escalation: Record<string, unknown> | null;\n}\n\nexport interface RelatedRowsResponse {\n source: RelatedSource;\n rows: RelatedRow[];\n total: number;\n restricted?: string[];\n roleLabels?: Record<string, string>;\n}\n","import {\n RELATED_AGGREGATES,\n RELATED_DISPLAY_DEFAULT,\n RELATED_SOURCES,\n SPLIT_PATHS,\n type RelatedAggregate,\n type RelatedColumnDecl,\n} from './types';\n\nconst VALUE_TOKEN = /^\\{\\{\\s*([^{}]+?)\\s*\\}\\}$/;\nconst ITEM_PREFIX = 'item.';\nconst PATH_SEGMENT = /^[a-zA-Z0-9_]+$/;\nconst METADATA_KEY = /^[a-zA-Z0-9_]+$/;\nconst COUNT_TOKEN = /\\{n\\}/g;\n\nexport type RelatedExtreme = typeof RELATED_AGGREGATES.MIN | typeof RELATED_AGGREGATES.MAX;\n\n/** True for the aggregates that pick one value rather than count. */\nexport function isExtremeAggregate(aggregate: unknown): aggregate is RelatedExtreme {\n return aggregate === RELATED_AGGREGATES.MIN || aggregate === RELATED_AGGREGATES.MAX;\n}\n\n/**\n * The stored path a min/max `value` template reads: `payload.<path>` for an\n * items set, `metadata.<key>` for a query set. Null when the template does\n * not fit the set's source.\n */\nexport function relatedValuePath(source: string, value: unknown): string | null {\n if (typeof value !== 'string') return null;\n const token = value.match(VALUE_TOKEN)?.[1];\n if (!token) return null;\n if (source === RELATED_SOURCES.ITEMS) {\n if (!token.startsWith(`${ITEM_PREFIX}${SPLIT_PATHS.PAYLOAD}`)) return null;\n const path = token.slice(ITEM_PREFIX.length + SPLIT_PATHS.PAYLOAD.length);\n return path && path.split('.').every((s) => PATH_SEGMENT.test(s)) ? `${SPLIT_PATHS.PAYLOAD}${path}` : null;\n }\n if (!token.startsWith(SPLIT_PATHS.METADATA)) return null;\n const key = token.slice(SPLIT_PATHS.METADATA.length);\n return METADATA_KEY.test(key) ? token : null;\n}\n\n/** The key a column's per-host aggregates are stored under in its set's result. */\nexport function relatedAggregateKey(col: Pick<RelatedColumnDecl, 'aggregate' | 'splitBy' | 'value'>, source: string): string {\n if (isExtremeAggregate(col.aggregate)) return `${col.aggregate}:${relatedValuePath(source, col.value) ?? ''}`;\n return col.splitBy ?? '';\n}\n\n/** A count column's display text, or null when the column declares none for this count. */\nexport function relatedCountText(display: Record<string, string> | undefined, count: number): string | null {\n if (!display) return null;\n const text = display[String(count)] ?? display[RELATED_DISPLAY_DEFAULT];\n return text === undefined ? null : text.replace(COUNT_TOKEN, String(count));\n}\n\n/**\n * The least or greatest of several values: numbers when every value is a\n * number, otherwise text in code-unit order (ISO instants order as text).\n */\nexport function foldExtreme(fold: RelatedAggregate, values: Array<string | number>): string | number | undefined {\n if (!values.length) return undefined;\n const pickMin = fold === RELATED_AGGREGATES.MIN;\n if (values.every((v) => typeof v === 'number')) {\n return pickMin ? Math.min(...(values as number[])) : Math.max(...(values as number[]));\n }\n const texts = values.map(String).sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));\n return pickMin ? texts[0] : texts[texts.length - 1];\n}\n","import {\n FACET_TABLE_LAYOUT,\n GROUP_FOLDS,\n LIST_SCHEMA_KEYS,\n RELATED_AGGREGATES,\n RELATED_DISPLAY_DEFAULT,\n RELATED_LIMITS,\n RELATED_SOURCES,\n SPLIT_PATHS,\n type ListSchemaRelations,\n type RelatedColumnDecl,\n type RelatedSetDecl,\n type RowDetailSectionDecl,\n} from './types';\nimport { isExtremeAggregate, relatedValuePath } from './aggregate';\n\n/** A metadata key: interpolated as a JSON path, so strictly validated. */\nexport const METADATA_KEY = /^[a-zA-Z0-9_]+$/;\nconst SET_NAME = /^[a-zA-Z][a-zA-Z0-9_-]{0,47}$/;\nconst PATH_SEGMENT = /^[a-zA-Z0-9_]+$/;\nconst COUNT_KEY = /^(0|[1-9][0-9]*)$/;\n\ntype Obj = Record<string, unknown>;\n\nclass ListSchemaError extends Error {}\n\nfunction fail(message: string): never {\n throw new ListSchemaError(message);\n}\n\nfunction isObj(value: unknown): value is Obj {\n return !!value && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0;\n}\n\n/** True when a dotted path has only plain segments. */\nfunction isPlainPath(path: string): boolean {\n return path.length > 0 && path.split('.').every((s) => PATH_SEGMENT.test(s));\n}\n\n/** The split paths a set's source accepts. */\nexport function splitPathError(source: string, splitBy: string): string | null {\n if (source === RELATED_SOURCES.QUERY) {\n if (splitBy === SPLIT_PATHS.ROLE) return null;\n if (splitBy.startsWith(SPLIT_PATHS.METADATA) && METADATA_KEY.test(splitBy.slice(SPLIT_PATHS.METADATA.length))) return null;\n return `splitBy \"${splitBy}\" on a query set must be \"role\" or \"metadata.<key>\"`;\n }\n if (splitBy.startsWith(SPLIT_PATHS.PAYLOAD) && isPlainPath(splitBy.slice(SPLIT_PATHS.PAYLOAD.length))) return null;\n if (splitBy.startsWith(SPLIT_PATHS.RECIPROCAL_METADATA)\n && METADATA_KEY.test(splitBy.slice(SPLIT_PATHS.RECIPROCAL_METADATA.length))) return null;\n return `splitBy \"${splitBy}\" on an items set must be \"payload.<path>\" or \"reciprocal.metadata.<key>\"`;\n}\n\nfunction readSet(name: string, raw: unknown): RelatedSetDecl {\n if (!SET_NAME.test(name)) fail(`x-lt-related name \"${name}\" must start with a letter (letters, digits, _ or -)`);\n if (!isObj(raw)) fail(`x-lt-related.${name} must be an object`);\n if (raw.source === RELATED_SOURCES.ITEMS) {\n if (raw.query !== undefined) fail(`x-lt-related.${name}: an items set takes no query`);\n return { source: RELATED_SOURCES.ITEMS };\n }\n if (raw.source !== RELATED_SOURCES.QUERY) fail(`x-lt-related.${name}.source must be \"items\" or \"query\"`);\n const q = raw.query;\n if (!isObj(q)) fail(`x-lt-related.${name}.query is required for a query set`);\n const hasRoles = q.roles !== undefined;\n const hasSegment = q.segment !== undefined;\n if (hasRoles === hasSegment) fail(`x-lt-related.${name}.query takes exactly one of roles or segment`);\n if (hasRoles) {\n const roles = q.roles;\n if (!Array.isArray(roles) || roles.length === 0 || roles.length > RELATED_LIMITS.MAX_QUERY_ROLES\n || !roles.every(isNonEmptyString)) {\n fail(`x-lt-related.${name}.query.roles must be 1..${RELATED_LIMITS.MAX_QUERY_ROLES} role names`);\n }\n } else if (!isNonEmptyString(q.segment)) {\n fail(`x-lt-related.${name}.query.segment must be a role name`);\n }\n if (!isObj(q.facets) || Object.keys(q.facets).length === 0) {\n fail(`x-lt-related.${name}.query.facets must name at least one facet`);\n }\n for (const [key, value] of Object.entries(q.facets)) {\n if (!METADATA_KEY.test(key)) fail(`x-lt-related.${name}.query.facets key \"${key}\" must be letters, digits or _`);\n if (value === null || typeof value === 'object') fail(`x-lt-related.${name}.query.facets.${key} must be a scalar or template`);\n }\n if (q.narrow !== undefined) {\n if (!isObj(q.narrow) || Object.keys(q.narrow).length === 0) fail(`x-lt-related.${name}.query.narrow must name at least one facet`);\n for (const [key, value] of Object.entries(q.narrow)) {\n if (!METADATA_KEY.test(key)) fail(`x-lt-related.${name}.query.narrow key \"${key}\" must be letters, digits or _`);\n if (key in q.facets) fail(`x-lt-related.${name}.query.narrow.${key} is already a required facet`);\n if (value === null || typeof value === 'object') fail(`x-lt-related.${name}.query.narrow.${key} must be a scalar or template`);\n }\n }\n if (q.status !== undefined && !isNonEmptyString(q.status)) fail(`x-lt-related.${name}.query.status must be a status`);\n return {\n source: RELATED_SOURCES.QUERY,\n query: {\n ...(hasRoles ? { roles: [...(q.roles as string[])] } : { segment: q.segment as string }),\n facets: { ...q.facets },\n ...(q.narrow !== undefined ? { narrow: { ...(q.narrow as Obj) } } : {}),\n ...(q.status !== undefined ? { status: q.status as string } : {}),\n },\n };\n}\n\nfunction readRelatedColumn(raw: Obj, sets: Record<string, RelatedSetDecl>, at: string): RelatedColumnDecl {\n const name = raw.related;\n if (!isNonEmptyString(name) || !sets[name]) fail(`${at}.related must name a set declared in x-lt-related`);\n if (raw.aggregate !== undefined && raw.aggregate !== RELATED_AGGREGATES.COUNT && !isExtremeAggregate(raw.aggregate)) {\n fail(`${at}.aggregate must be \"count\", \"min\" or \"max\"`);\n }\n const source = sets[name].source;\n if (isExtremeAggregate(raw.aggregate)) {\n if (!relatedValuePath(source, raw.value)) {\n fail(source === RELATED_SOURCES.ITEMS\n ? `${at}.value must be \"{{item.payload.<path>}}\" on an items set`\n : `${at}.value must be \"{{metadata.<key>}}\" on a query set`);\n }\n if (raw.splitBy !== undefined) fail(`${at}: a ${raw.aggregate} column takes no splitBy`);\n if (raw.display !== undefined) fail(`${at}: display applies to a count column`);\n } else if (raw.value !== undefined) {\n fail(`${at}.value applies to a min or max column`);\n }\n if (raw.format !== undefined && typeof raw.format !== 'string') fail(`${at}.format must be a format name`);\n if (raw.display !== undefined) {\n if (!isObj(raw.display) || Object.keys(raw.display).length === 0\n || !Object.entries(raw.display).every(([k, v]) => (k === RELATED_DISPLAY_DEFAULT || COUNT_KEY.test(k)) && typeof v === 'string')) {\n fail(`${at}.display must map counts (or \"default\") to display text`);\n }\n }\n if (raw.splitBy !== undefined) {\n if (!isNonEmptyString(raw.splitBy)) fail(`${at}.splitBy must be a path`);\n const err = splitPathError(sets[name].source, raw.splitBy);\n if (err) fail(`${at}: ${err}`);\n }\n if (raw.labels !== undefined && (!isObj(raw.labels) || !Object.values(raw.labels).every((v) => typeof v === 'string'))) {\n fail(`${at}.labels must map values to display text`);\n }\n return raw as unknown as RelatedColumnDecl;\n}\n\nfunction readRowDetail(raw: unknown, sets: Record<string, RelatedSetDecl>): RowDetailSectionDecl[] {\n if (raw === undefined) return [];\n if (!Array.isArray(raw) || raw.length === 0 || raw.length > RELATED_LIMITS.MAX_ROW_DETAIL_SECTIONS) {\n fail(`x-lt-row-detail must be 1..${RELATED_LIMITS.MAX_ROW_DETAIL_SECTIONS} sections`);\n }\n return raw.map((section, i) => {\n const at = `x-lt-row-detail[${i}]`;\n if (!isObj(section)) fail(`${at} must be an object`);\n if (!isNonEmptyString(section.related) || !sets[section.related]) fail(`${at}.related must name a set declared in x-lt-related`);\n if (!Array.isArray(section.columns) || section.columns.length === 0) fail(`${at}.columns must list at least one column`);\n for (const [j, col] of section.columns.entries()) {\n if (!isObj(col) || !isNonEmptyString(col.label) || typeof col.value !== 'string') {\n fail(`${at}.columns[${j}] needs a label and a value template`);\n }\n }\n if (section.limit !== undefined && (!Number.isInteger(section.limit) || (section.limit as number) < 1\n || (section.limit as number) > RELATED_LIMITS.ROWS_MAX)) {\n fail(`${at}.limit must be 1..${RELATED_LIMITS.ROWS_MAX}`);\n }\n return section as unknown as RowDetailSectionDecl;\n });\n}\n\nfunction readGroupKey(schema: Obj): string | null {\n const raw = schema[LIST_SCHEMA_KEYS.GROUP_BY];\n if (raw === undefined || schema[LIST_SCHEMA_KEYS.LAYOUT] !== FACET_TABLE_LAYOUT) return null;\n const key = typeof raw === 'string' && raw.startsWith(SPLIT_PATHS.METADATA) ? raw.slice(SPLIT_PATHS.METADATA.length) : '';\n if (!METADATA_KEY.test(key)) fail('x-lt-group-by on a facet-table must be \"metadata.<key>\"');\n return key;\n}\n\nconst FOLDS = new Set<string>(Object.values(GROUP_FOLDS));\n\n/**\n * Validate and normalize the related declaration of a list schema. Throws on\n * an invalid declaration; keys outside this vocabulary stay opaque.\n */\nexport function readListSchemaRelations(schema: unknown): ListSchemaRelations {\n const empty: ListSchemaRelations = { sets: {}, columns: [], rowDetail: [], groupKey: null };\n if (!isObj(schema)) return empty;\n const rawSets = schema[LIST_SCHEMA_KEYS.RELATED];\n const sets: Record<string, RelatedSetDecl> = {};\n if (rawSets !== undefined) {\n if (!isObj(rawSets)) fail('x-lt-related must map set names to declarations');\n const names = Object.keys(rawSets);\n if (names.length === 0 || names.length > RELATED_LIMITS.MAX_SETS) fail(`x-lt-related must declare 1..${RELATED_LIMITS.MAX_SETS} sets`);\n for (const name of names) sets[name] = readSet(name, rawSets[name]);\n }\n const columns: RelatedColumnDecl[] = [];\n const rawColumns = schema[LIST_SCHEMA_KEYS.COLUMNS];\n if (Array.isArray(rawColumns)) {\n rawColumns.forEach((col, i) => {\n if (!isObj(col)) return;\n if (col.related !== undefined) columns.push(readRelatedColumn(col, sets, `x-lt-columns[${i}]`));\n if (col.group !== undefined && (typeof col.group !== 'string' || !FOLDS.has(col.group))) {\n fail(`x-lt-columns[${i}].group must be one of ${[...FOLDS].join(', ')}`);\n }\n });\n }\n return { sets, columns, rowDetail: readRowDetail(schema[LIST_SCHEMA_KEYS.ROW_DETAIL], sets), groupKey: readGroupKey(schema) };\n}\n\n/** The declaration's first error, or null when valid. */\nexport function listSchemaRelationsError(schema: unknown): string | null {\n try {\n readListSchemaRelations(schema);\n return null;\n } catch (err) {\n if (err instanceof ListSchemaError) return err.message;\n throw err;\n }\n}\n"],"names":["isEffectivelyClaimed","esc","isAckEscalation","identifierToTitle","id","w","escalationDotClass","e","STATUS_DOT_STYLES","rowContext","parse","s","v","IDENTITY_COLUMN_WIDTH","actionColumnWidth","label","DEFAULT_CLAIM_MINUTES","isClaimable","row","RowActionButton","def","onView","prominent","forceView","authored","action","claim","useClaimEscalation","navigate","useNavigate","location","useLocation","error","setError","useState","spent","fire","err","classes","jsxs","jsx","METADATA_TOKEN","isFacetValue","raw","rowRefinePairs","columnDefs","pairs","seen","metadata","col","bound","_a","key","RefineTrigger","onOpen","className","Search","LIST_SCHEMA_KEYS","RELATED_SOURCES","RELATED_AGGREGATES","GROUP_FOLDS","SPLIT_PATHS","RELATED_LIMITS","FACET_TABLE_LAYOUT","RELATED_DISPLAY_DEFAULT","VALUE_TOKEN","ITEM_PREFIX","PATH_SEGMENT","METADATA_KEY","COUNT_TOKEN","isExtremeAggregate","aggregate","relatedValuePath","source","value","token","path","relatedAggregateKey","relatedCountText","display","count","text","foldExtreme","fold","values","pickMin","texts","a","b","SET_NAME","COUNT_KEY","ListSchemaError","fail","message","isObj","isNonEmptyString","isPlainPath","splitPathError","splitBy","readSet","name","q","hasRoles","hasSegment","roles","readRelatedColumn","sets","at","k","readRowDetail","section","i","j","readGroupKey","schema","FOLDS","readListSchemaRelations","empty","rawSets","names","columns","rawColumns"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{u as l,b as a,c as s}from"./vendor-query-DvWWuNIB.js";import{m as r}from"./index-CkMHS-hG.js";function f(e={}){const o=new URLSearchParams;return e.status&&o.set("status",e.status),e.graph_topic&&o.set("graph_topic",e.graph_topic),e.app_id&&o.set("app_id",e.app_id),e.search&&o.set("search",e.search),e.set_id&&o.set("set_id",e.set_id),e.limit&&o.set("limit",String(e.limit)),e.offset!==void 0&&o.set("offset",String(e.offset)),l({queryKey:["yamlWorkflows",e],queryFn:()=>r(`/yaml-workflows?${o}`)})}function m(){return l({queryKey:["yamlWorkflowAppIds"],queryFn:()=>r("/yaml-workflows/app-ids")})}function c(e){return l({queryKey:["yamlWorkflows",e],queryFn:()=>r(`/yaml-workflows/${e}`),enabled:!!e})}function w(){const e=a();return s({mutationFn:o=>r("/yaml-workflows",{method:"POST",body:JSON.stringify(o)}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function k(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/deploy`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function p(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/activate`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function d(){const e=a();return s({mutationFn:({id:o,data:t,sync:n,execute_as:u})=>r(`/yaml-workflows/${o}/invoke`,{method:"POST",body:JSON.stringify({data:t,sync:n,...u?{execute_as:u}:{}})}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function h(){const e=a();return s({mutationFn:({id:o,task_queue:t,compilation_feedback:n})=>r(`/yaml-workflows/${o}/regenerate`,{method:"POST",body:JSON.stringify({task_queue:t,compilation_feedback:n})}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function q(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/archive`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function W(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/restore`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"}),e.invalidateQueries({queryKey:["yamlWorkflow"],refetchType:"all"})}})}function S(){const e=a();return s({mutationFn:({id:o,...t})=>r(`/yaml-workflows/${o}`,{method:"PUT",body:JSON.stringify(t)}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function v(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}`,{method:"DELETE"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function T(e){return l({queryKey:["yamlWorkflows",e,"versions"],queryFn:()=>r(`/yaml-workflows/${e}/versions`),enabled:!!e})}function F(e,o){return l({queryKey:["yamlWorkflows",e,"versions",o],queryFn:()=>r(`/yaml-workflows/${e}/versions/${o}`),enabled:!!e&&o!==null})}export{m as a,S as b,c,T as d,k as e,p as f,q as g,W as h,v as i,h as j,F as k,d as l,w as m,f as u};
2
- //# sourceMappingURL=yaml-workflows-BgY1XHJx.js.map
1
+ import{u as l,b as a,c as s}from"./vendor-query-DvWWuNIB.js";import{m as r}from"./index-pzbGpihI.js";function f(e={}){const o=new URLSearchParams;return e.status&&o.set("status",e.status),e.graph_topic&&o.set("graph_topic",e.graph_topic),e.app_id&&o.set("app_id",e.app_id),e.search&&o.set("search",e.search),e.set_id&&o.set("set_id",e.set_id),e.limit&&o.set("limit",String(e.limit)),e.offset!==void 0&&o.set("offset",String(e.offset)),l({queryKey:["yamlWorkflows",e],queryFn:()=>r(`/yaml-workflows?${o}`)})}function m(){return l({queryKey:["yamlWorkflowAppIds"],queryFn:()=>r("/yaml-workflows/app-ids")})}function c(e){return l({queryKey:["yamlWorkflows",e],queryFn:()=>r(`/yaml-workflows/${e}`),enabled:!!e})}function w(){const e=a();return s({mutationFn:o=>r("/yaml-workflows",{method:"POST",body:JSON.stringify(o)}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function k(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/deploy`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function p(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/activate`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function d(){const e=a();return s({mutationFn:({id:o,data:t,sync:n,execute_as:u})=>r(`/yaml-workflows/${o}/invoke`,{method:"POST",body:JSON.stringify({data:t,sync:n,...u?{execute_as:u}:{}})}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function h(){const e=a();return s({mutationFn:({id:o,task_queue:t,compilation_feedback:n})=>r(`/yaml-workflows/${o}/regenerate`,{method:"POST",body:JSON.stringify({task_queue:t,compilation_feedback:n})}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function q(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/archive`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function W(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/restore`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"}),e.invalidateQueries({queryKey:["yamlWorkflow"],refetchType:"all"})}})}function S(){const e=a();return s({mutationFn:({id:o,...t})=>r(`/yaml-workflows/${o}`,{method:"PUT",body:JSON.stringify(t)}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function v(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}`,{method:"DELETE"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function T(e){return l({queryKey:["yamlWorkflows",e,"versions"],queryFn:()=>r(`/yaml-workflows/${e}/versions`),enabled:!!e})}function F(e,o){return l({queryKey:["yamlWorkflows",e,"versions",o],queryFn:()=>r(`/yaml-workflows/${e}/versions/${o}`),enabled:!!e&&o!==null})}export{m as a,S as b,c,T as d,k as e,p as f,q as g,W as h,v as i,h as j,F as k,d as l,w as m,f as u};
2
+ //# sourceMappingURL=yaml-workflows-64vfmKJx.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"yaml-workflows-BgY1XHJx.js","sources":["../../src/api/yaml-workflows.ts"],"sourcesContent":["import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';\nimport { apiFetch } from './client';\nimport type { LTYamlWorkflowRecord, LTYamlWorkflowStatus, LTYamlWorkflowVersion } from './types';\n\ninterface YamlWorkflowListResponse {\n workflows: LTYamlWorkflowRecord[];\n total: number;\n}\n\ninterface YamlWorkflowFilters {\n status?: LTYamlWorkflowStatus;\n graph_topic?: string;\n app_id?: string;\n search?: string;\n set_id?: string;\n limit?: number;\n offset?: number;\n}\n\nexport function useYamlWorkflows(filters: YamlWorkflowFilters = {}) {\n const params = new URLSearchParams();\n if (filters.status) params.set('status', filters.status);\n if (filters.graph_topic) params.set('graph_topic', filters.graph_topic);\n if (filters.app_id) params.set('app_id', filters.app_id);\n if (filters.search) params.set('search', filters.search);\n if (filters.set_id) params.set('set_id', filters.set_id);\n if (filters.limit) params.set('limit', String(filters.limit));\n if (filters.offset !== undefined) params.set('offset', String(filters.offset));\n\n return useQuery<YamlWorkflowListResponse>({\n queryKey: ['yamlWorkflows', filters],\n queryFn: () => apiFetch(`/yaml-workflows?${params}`),\n });\n}\n\nexport function useYamlWorkflowAppIds() {\n return useQuery<{ app_ids: string[] }>({\n queryKey: ['yamlWorkflowAppIds'],\n queryFn: () => apiFetch('/yaml-workflows/app-ids'),\n });\n}\n\nexport function useYamlWorkflowByTopic(graphTopic: string | undefined, appId?: string) {\n return useQuery<YamlWorkflowListResponse>({\n queryKey: ['yamlWorkflows', 'byTopic', graphTopic, appId],\n queryFn: () => {\n const params = new URLSearchParams({ graph_topic: graphTopic!, limit: '1' });\n if (appId) params.set('app_id', appId);\n return apiFetch(`/yaml-workflows?${params}`);\n },\n enabled: !!graphTopic,\n });\n}\n\nexport function useYamlWorkflow(id: string) {\n return useQuery<LTYamlWorkflowRecord>({\n queryKey: ['yamlWorkflows', id],\n queryFn: () => apiFetch(`/yaml-workflows/${id}`),\n enabled: !!id,\n });\n}\n\nexport function useCreateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (input: {\n workflow_id: string;\n task_queue: string;\n workflow_name: string;\n name: string;\n description?: string;\n app_id?: string;\n subscribes?: string;\n tags?: string[];\n compilation_feedback?: string;\n }) =>\n apiFetch<LTYamlWorkflowRecord>('/yaml-workflows', {\n method: 'POST',\n body: JSON.stringify(input),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useDeployYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/deploy`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useActivateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/activate`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useInvokeYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, data, sync, execute_as }: { id: string; data: Record<string, unknown>; sync?: boolean; execute_as?: string }) =>\n apiFetch<{ result?: unknown; job_id?: string }>(`/yaml-workflows/${id}/invoke`, {\n method: 'POST',\n body: JSON.stringify({ data, sync, ...(execute_as ? { execute_as } : {}) }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useRegenerateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, task_queue, compilation_feedback }: { id: string; task_queue?: string; compilation_feedback?: string }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/regenerate`, {\n method: 'POST',\n body: JSON.stringify({ task_queue, compilation_feedback }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useArchiveYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/archive`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useRestoreYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/restore`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflow'], refetchType: 'all' });\n },\n });\n}\n\nexport function useUpdateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, ...updates }: { id: string; yaml_content?: string; name?: string; description?: string; input_schema?: Record<string, unknown>; output_schema?: Record<string, unknown>; tags?: string[]; app_id?: string; graph_topic?: string }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}`, {\n method: 'PUT',\n body: JSON.stringify(updates),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useDeleteYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<{ deleted: boolean }>(`/yaml-workflows/${id}`, {\n method: 'DELETE',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\n// ── Cron scheduling ─────────────────────────────────────────────\n\nexport function useSetYamlCron() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, cron_schedule, cron_envelope, execute_as }: {\n id: string;\n cron_schedule: string;\n cron_envelope?: Record<string, unknown> | null;\n execute_as?: string | null;\n }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/cron`, {\n method: 'PUT',\n body: JSON.stringify({ cron_schedule, cron_envelope, execute_as }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useClearYamlCron() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/cron`, {\n method: 'DELETE',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\n// ── Version history ─────────────────────────────────────────────\n\nexport function useYamlWorkflowVersions(id: string) {\n return useQuery<{ versions: LTYamlWorkflowVersion[]; total: number }>({\n queryKey: ['yamlWorkflows', id, 'versions'],\n queryFn: () => apiFetch(`/yaml-workflows/${id}/versions`),\n enabled: !!id,\n });\n}\n\nexport function useYamlWorkflowVersion(id: string, version: number | null) {\n return useQuery<LTYamlWorkflowVersion>({\n queryKey: ['yamlWorkflows', id, 'versions', version],\n queryFn: () => apiFetch(`/yaml-workflows/${id}/versions/${version}`),\n enabled: !!id && version !== null,\n });\n}\n"],"names":["useYamlWorkflows","filters","params","useQuery","apiFetch","useYamlWorkflowAppIds","useYamlWorkflow","id","useCreateYamlWorkflow","queryClient","useQueryClient","useMutation","input","useDeployYamlWorkflow","useActivateYamlWorkflow","useInvokeYamlWorkflow","data","sync","execute_as","useRegenerateYamlWorkflow","task_queue","compilation_feedback","useArchiveYamlWorkflow","useRestoreYamlWorkflow","useUpdateYamlWorkflow","updates","useDeleteYamlWorkflow","useYamlWorkflowVersions","useYamlWorkflowVersion","version"],"mappings":"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"}
1
+ {"version":3,"file":"yaml-workflows-64vfmKJx.js","sources":["../../src/api/yaml-workflows.ts"],"sourcesContent":["import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';\nimport { apiFetch } from './client';\nimport type { LTYamlWorkflowRecord, LTYamlWorkflowStatus, LTYamlWorkflowVersion } from './types';\n\ninterface YamlWorkflowListResponse {\n workflows: LTYamlWorkflowRecord[];\n total: number;\n}\n\ninterface YamlWorkflowFilters {\n status?: LTYamlWorkflowStatus;\n graph_topic?: string;\n app_id?: string;\n search?: string;\n set_id?: string;\n limit?: number;\n offset?: number;\n}\n\nexport function useYamlWorkflows(filters: YamlWorkflowFilters = {}) {\n const params = new URLSearchParams();\n if (filters.status) params.set('status', filters.status);\n if (filters.graph_topic) params.set('graph_topic', filters.graph_topic);\n if (filters.app_id) params.set('app_id', filters.app_id);\n if (filters.search) params.set('search', filters.search);\n if (filters.set_id) params.set('set_id', filters.set_id);\n if (filters.limit) params.set('limit', String(filters.limit));\n if (filters.offset !== undefined) params.set('offset', String(filters.offset));\n\n return useQuery<YamlWorkflowListResponse>({\n queryKey: ['yamlWorkflows', filters],\n queryFn: () => apiFetch(`/yaml-workflows?${params}`),\n });\n}\n\nexport function useYamlWorkflowAppIds() {\n return useQuery<{ app_ids: string[] }>({\n queryKey: ['yamlWorkflowAppIds'],\n queryFn: () => apiFetch('/yaml-workflows/app-ids'),\n });\n}\n\nexport function useYamlWorkflowByTopic(graphTopic: string | undefined, appId?: string) {\n return useQuery<YamlWorkflowListResponse>({\n queryKey: ['yamlWorkflows', 'byTopic', graphTopic, appId],\n queryFn: () => {\n const params = new URLSearchParams({ graph_topic: graphTopic!, limit: '1' });\n if (appId) params.set('app_id', appId);\n return apiFetch(`/yaml-workflows?${params}`);\n },\n enabled: !!graphTopic,\n });\n}\n\nexport function useYamlWorkflow(id: string) {\n return useQuery<LTYamlWorkflowRecord>({\n queryKey: ['yamlWorkflows', id],\n queryFn: () => apiFetch(`/yaml-workflows/${id}`),\n enabled: !!id,\n });\n}\n\nexport function useCreateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (input: {\n workflow_id: string;\n task_queue: string;\n workflow_name: string;\n name: string;\n description?: string;\n app_id?: string;\n subscribes?: string;\n tags?: string[];\n compilation_feedback?: string;\n }) =>\n apiFetch<LTYamlWorkflowRecord>('/yaml-workflows', {\n method: 'POST',\n body: JSON.stringify(input),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useDeployYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/deploy`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useActivateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/activate`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useInvokeYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, data, sync, execute_as }: { id: string; data: Record<string, unknown>; sync?: boolean; execute_as?: string }) =>\n apiFetch<{ result?: unknown; job_id?: string }>(`/yaml-workflows/${id}/invoke`, {\n method: 'POST',\n body: JSON.stringify({ data, sync, ...(execute_as ? { execute_as } : {}) }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useRegenerateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, task_queue, compilation_feedback }: { id: string; task_queue?: string; compilation_feedback?: string }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/regenerate`, {\n method: 'POST',\n body: JSON.stringify({ task_queue, compilation_feedback }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useArchiveYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/archive`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useRestoreYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/restore`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflow'], refetchType: 'all' });\n },\n });\n}\n\nexport function useUpdateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, ...updates }: { id: string; yaml_content?: string; name?: string; description?: string; input_schema?: Record<string, unknown>; output_schema?: Record<string, unknown>; tags?: string[]; app_id?: string; graph_topic?: string }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}`, {\n method: 'PUT',\n body: JSON.stringify(updates),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useDeleteYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<{ deleted: boolean }>(`/yaml-workflows/${id}`, {\n method: 'DELETE',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\n// ── Cron scheduling ─────────────────────────────────────────────\n\nexport function useSetYamlCron() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, cron_schedule, cron_envelope, execute_as }: {\n id: string;\n cron_schedule: string;\n cron_envelope?: Record<string, unknown> | null;\n execute_as?: string | null;\n }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/cron`, {\n method: 'PUT',\n body: JSON.stringify({ cron_schedule, cron_envelope, execute_as }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useClearYamlCron() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/cron`, {\n method: 'DELETE',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\n// ── Version history ─────────────────────────────────────────────\n\nexport function useYamlWorkflowVersions(id: string) {\n return useQuery<{ versions: LTYamlWorkflowVersion[]; total: number }>({\n queryKey: ['yamlWorkflows', id, 'versions'],\n queryFn: () => apiFetch(`/yaml-workflows/${id}/versions`),\n enabled: !!id,\n });\n}\n\nexport function useYamlWorkflowVersion(id: string, version: number | null) {\n return useQuery<LTYamlWorkflowVersion>({\n queryKey: ['yamlWorkflows', id, 'versions', version],\n queryFn: () => apiFetch(`/yaml-workflows/${id}/versions/${version}`),\n enabled: !!id && version !== null,\n });\n}\n"],"names":["useYamlWorkflows","filters","params","useQuery","apiFetch","useYamlWorkflowAppIds","useYamlWorkflow","id","useCreateYamlWorkflow","queryClient","useQueryClient","useMutation","input","useDeployYamlWorkflow","useActivateYamlWorkflow","useInvokeYamlWorkflow","data","sync","execute_as","useRegenerateYamlWorkflow","task_queue","compilation_feedback","useArchiveYamlWorkflow","useRestoreYamlWorkflow","useUpdateYamlWorkflow","updates","useDeleteYamlWorkflow","useYamlWorkflowVersions","useYamlWorkflowVersion","version"],"mappings":"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"}
@@ -8,7 +8,7 @@
8
8
  <link rel="preconnect" href="https://fonts.googleapis.com" />
9
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
10
10
  <link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
11
- <script type="module" crossorigin src="./assets/index-CkMHS-hG.js"></script>
11
+ <script type="module" crossorigin src="./assets/index-pzbGpihI.js"></script>
12
12
  <link rel="modulepreload" crossorigin href="./assets/vendor-query-DvWWuNIB.js">
13
13
  <link rel="modulepreload" crossorigin href="./assets/vendor-react-_9U4mKFr.js">
14
14
  <link rel="modulepreload" crossorigin href="./assets/vendor-icons-fxBvvHBi.js">
package/docs/machines.md CHANGED
@@ -90,7 +90,7 @@ When a handoff ends without every unit (a failure, a timeout, a cancel), the gat
90
90
 
91
91
  `Machines.handoffProgress(units, items)` reads where a handoff's units stand from its items (a row's items, or `$accumulated` on a finished wait): `{ released, arrived, missing }`. A workflow reads it to decide what a split means for its own process.
92
92
 
93
- On arrival dispatch, the units are already at the receiver, so the row resolves `received` once the machine has the job: at its acceptance, or, when the acceptance says `preparing: true`, at the `completed` reply that follows; a `failed` reply meanwhile ends the row `dispatch-failed`. A gateway taking the line over resolves such a row at once if the machine's snapshot holds the job, since the reply it waited for may have passed. The job then runs with its row ended; the gateway that sent it remembers the row for as long as the machine holds the job's units, so a machine that restarts with the job unfinished is sent it again from that row (the same command id and issue time while the validity round lasts, flagged as a retry), with no verb on the row. A gateway that took the line after the row ended remembers nothing of the job: a restart then logs `machine_gateway.dispatch.unrecoverable` with the jobs the machine lost, and the next hop's row times out as its route decides.
93
+ On arrival dispatch, the units are already at the receiver, so the row resolves `received` once the machine has the job: at its acceptance, or, when the acceptance says `preparing: true`, at the `completed` reply that follows, however soon after the acceptance it comes; a `failed` reply meanwhile ends the row `dispatch-failed`. A gateway taking the line over resolves such a row at once if the machine's snapshot holds the job, since the reply it waited for may have passed. A new row for units the machine already holds from an earlier attempt (a job it failed to prepare, then the operator's retry) is dispatched at once with the arrivals the gateway kept, so the units are not scanned in twice. The job then runs with its row ended; the gateway that sent it remembers the row for as long as the machine holds the job's units, so a machine that restarts with the job unfinished is sent it again from that row (the same command id and issue time while the validity round lasts, flagged as a retry), with no verb on the row. A gateway that took the line after the row ended remembers nothing of the job: a restart then logs `machine_gateway.dispatch.unrecoverable` with the jobs the machine lost, and the next hop's row times out as its route decides.
94
94
 
95
95
  When the handoff ends without a receipt, the row resolves `{ received: false, errorCode, unitId?, result?, reason?, detail, code? }`. `detail` is text for a person; `code` is the machine's structured code when its reply carried one, so a workflow can branch on it:
96
96
 
@@ -327,8 +327,8 @@ The built-in `long-tail-machines` server offers the same surface to agents, gate
327
327
  ```
328
328
 
329
329
  - **Machines:** each machine logs in over MQTT 3.1.1 or 5 with its own certificate; the CN (`{site}-{line}-{address}`) is its username. The broker ACL lets it write only its own channels and read only its own commands. The line controller may command every machine on the line.
330
- - **Durable streams:** the bridge carries the line's topics one way into NATS, where only the bridge may publish them. JetStream keeps `LINE_EVENTS` (30 days) and `LINE_TELEMETRY` (3 days). The gateway reads through a durable consumer, `<controller>-events`, and may publish only JetStream requests and acks for its own streams and consumer; it cannot delete or purge them.
331
- - **One site, several codecs:** the streams are ensured with the subjects of every codec the surface runs on the site, so lines on different roots share `LINE_EVENTS` and `LINE_TELEMETRY` whichever line starts last; a gateway whose consumer the stream would feed nothing refuses to start and says which subjects are missing.
330
+ - **Durable streams:** the bridge carries the line's topics one way into NATS, where only the bridge may publish them. JetStream keeps `LINE_EVENTS` (30 days) and `LINE_TELEMETRY` (3 days). The gateway reads through a durable consumer, `<controller>-events`, and may publish only JetStream requests and acks for its own streams and consumer, and delete that one consumer; it cannot delete or purge a stream. A consumer whose subjects no longer match the line (the line changed protocol) is made again at the stream's newest message rather than moved, so a position in another protocol's messages is never carried over. A consumer that can deliver nothing more (its stream or itself gone, the server silent) ends the leader's turn: the gateway stops, the line contends again and ensures its streams anew, so no line leads a wire it cannot read.
331
+ - **One site, several codecs:** the streams are ensured with the subjects of every codec the surface runs on the site, sorted, so lines on different roots share `LINE_EVENTS` and `LINE_TELEMETRY` whichever line starts first or last, and two lines starting together on an empty JetStream agree on the stream (the create that loses the race updates instead); a gateway whose consumer the stream would feed nothing, or whose consumer did not follow its line, refuses to start and says which subjects are missing.
332
332
  - **Where the streams live:** by default in Long Tail's messaging ([events](events.md#messaging)), whose NATS server must run JetStream. The bridge then logs in to that server's edge account for the line (`Machines.edgeAccountFor`), which may publish only the line's subjects, so the edge reaches nothing of Long Tail's. With `MACHINE_SITE_NATS_URL`, the streams live instead in a NATS server of the site's own (`Machines.renderSiteConf`), and Long Tail's NATS stays inside Long Tail. Either way the gateway reads the same streams under the same consumer name.
333
333
  - **Escalation events:** the gateway inside Long Tail reads them in process. A standalone gateway subscribes to them over Long Tail's messaging.
334
334
  - **Commands:** the gateway publishes commands to the machine broker at QoS 1, so they queue for a machine that is away.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hotmeshio/long-tail",
3
- "version": "0.28.1",
3
+ "version": "0.28.3",
4
4
  "description": "Long Tail Workflows — Durable AI workflows with human-in-the-loop escalation. Powered by PostgreSQL.",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",