@hotmeshio/long-tail 0.10.11 → 0.10.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (336) hide show
  1. package/README.md +2 -4
  2. package/build/api/escalations/list.d.ts +1 -0
  3. package/build/api/escalations/list.js +1 -0
  4. package/build/api/escalations/metadata.d.ts +11 -0
  5. package/build/api/escalations/metadata.js +28 -8
  6. package/build/api/escalations/resolve.js +4 -4
  7. package/build/api/scan-codes/config.d.ts +22 -0
  8. package/build/api/scan-codes/config.js +136 -0
  9. package/build/api/scan-codes/execute.d.ts +9 -0
  10. package/build/api/scan-codes/execute.js +372 -0
  11. package/build/api/scan-codes/index.d.ts +2 -0
  12. package/build/api/scan-codes/index.js +14 -0
  13. package/build/lib/db/schemas/026_scan_codes.sql +51 -0
  14. package/build/lib/db/schemas/027_scan_codes_reindex.sql +23 -0
  15. package/build/lib/events/system-events.js +4 -0
  16. package/build/modules/features.d.ts +8 -0
  17. package/build/modules/features.js +1 -0
  18. package/build/routes/escalations/list.js +1 -0
  19. package/build/routes/index.js +2 -0
  20. package/build/routes/scan-codes.d.ts +2 -0
  21. package/build/routes/scan-codes.js +138 -0
  22. package/build/sdk/index.d.ts +4 -0
  23. package/build/services/escalation/crud.d.ts +1 -1
  24. package/build/services/escalation/crud.js +4 -2
  25. package/build/services/escalation/queries.d.ts +1 -0
  26. package/build/services/escalation/queries.js +2 -0
  27. package/build/services/escalation/resolver-validation.d.ts +1 -1
  28. package/build/services/escalation/resolver-validation.js +12 -5
  29. package/build/services/escalation/sql.d.ts +11 -6
  30. package/build/services/escalation/sql.js +20 -20
  31. package/build/services/escalation/submit-guard.d.ts +29 -0
  32. package/build/services/escalation/submit-guard.js +57 -0
  33. package/build/services/scan-code/index.d.ts +4 -0
  34. package/build/services/scan-code/index.js +21 -0
  35. package/build/services/scan-code/parse.d.ts +35 -0
  36. package/build/services/scan-code/parse.js +108 -0
  37. package/build/services/scan-code/read.d.ts +5 -0
  38. package/build/services/scan-code/read.js +50 -0
  39. package/build/services/scan-code/sql.d.ts +10 -0
  40. package/build/services/scan-code/sql.js +57 -0
  41. package/build/services/scan-code/validate.d.ts +12 -0
  42. package/build/services/scan-code/validate.js +78 -0
  43. package/build/services/scan-code/write.d.ts +26 -0
  44. package/build/services/scan-code/write.js +71 -0
  45. package/build/shared/form-validation/index.d.ts +5 -0
  46. package/build/shared/form-validation/index.js +5 -0
  47. package/build/shared/form-validation/x-lt-labels.d.ts +28 -0
  48. package/build/shared/form-validation/x-lt-labels.js +42 -0
  49. package/build/shared/form-validation/x-lt-query.d.ts +56 -0
  50. package/build/shared/form-validation/x-lt-query.js +49 -0
  51. package/build/shared/form-validation/x-lt-submit-guard.d.ts +46 -0
  52. package/build/shared/form-validation/x-lt-submit-guard.js +25 -0
  53. package/build/shared/form-validation/x-lt-submit-on-claim.d.ts +22 -0
  54. package/build/shared/form-validation/x-lt-submit-on-claim.js +28 -0
  55. package/build/shared/form-validation/x-lt-transition.d.ts +47 -0
  56. package/build/shared/form-validation/x-lt-transition.js +65 -0
  57. package/build/system/mcp-servers/admin/index.d.ts +1 -0
  58. package/build/system/mcp-servers/admin/index.js +5 -2
  59. package/build/system/mcp-servers/admin/scan-codes.d.ts +10 -0
  60. package/build/system/mcp-servers/admin/scan-codes.js +111 -0
  61. package/build/system/mcp-servers/admin/schemas.d.ts +232 -14
  62. package/build/system/mcp-servers/admin/schemas.js +50 -0
  63. package/build/system/seed/tool-manifests-admin.d.ts +1380 -0
  64. package/build/system/seed/tool-manifests-admin.js +6 -0
  65. package/build/tsconfig.tsbuildinfo +1 -1
  66. package/build/types/events.d.ts +9 -0
  67. package/build/types/index.d.ts +2 -0
  68. package/build/types/index.js +10 -1
  69. package/build/types/scan-code.d.ts +183 -0
  70. package/build/types/scan-code.js +80 -0
  71. package/build/types/startup.d.ts +6 -0
  72. package/dashboard/dist/assets/{AdminDashboard-CkTbRfY9.js → AdminDashboard-Chg69wlx.js} +2 -2
  73. package/dashboard/dist/assets/{AdminDashboard-CkTbRfY9.js.map → AdminDashboard-Chg69wlx.js.map} +1 -1
  74. package/dashboard/dist/assets/{AgentConfigPage-Cm8FRpXi.js → AgentConfigPage-DRTFwbfC.js} +6 -6
  75. package/dashboard/dist/assets/{AgentConfigPage-Cm8FRpXi.js.map → AgentConfigPage-DRTFwbfC.js.map} +1 -1
  76. package/dashboard/dist/assets/{AgentDetailPage-sQ1-UT46.js → AgentDetailPage-JKByfFIi.js} +3 -3
  77. package/dashboard/dist/assets/{AgentDetailPage-sQ1-UT46.js.map → AgentDetailPage-JKByfFIi.js.map} +1 -1
  78. package/dashboard/dist/assets/AgentsPage-BlgEmKhA.js +2 -0
  79. package/dashboard/dist/assets/{AgentsPage-bSx_mdae.js.map → AgentsPage-BlgEmKhA.js.map} +1 -1
  80. package/dashboard/dist/assets/{AutoGrowTextarea-y-oNY51_.js → AutoGrowTextarea-DgEQeRQw.js} +2 -2
  81. package/dashboard/dist/assets/{AutoGrowTextarea-y-oNY51_.js.map → AutoGrowTextarea-DgEQeRQw.js.map} +1 -1
  82. package/dashboard/dist/assets/AvailableEscalationsPage-C_7y692Q.js +2 -0
  83. package/dashboard/dist/assets/{AvailableEscalationsPage-8pMC7Xv6.js.map → AvailableEscalationsPage-C_7y692Q.js.map} +1 -1
  84. package/dashboard/dist/assets/BotPicker-CCVcz4Cq.js +2 -0
  85. package/dashboard/dist/assets/{BotPicker-C4uGH2x9.js.map → BotPicker-CCVcz4Cq.js.map} +1 -1
  86. package/dashboard/dist/assets/{CapabilitiesPage-BRoOeKcc.js → CapabilitiesPage-Czi9jUwD.js} +2 -2
  87. package/dashboard/dist/assets/{CapabilitiesPage-BRoOeKcc.js.map → CapabilitiesPage-Czi9jUwD.js.map} +1 -1
  88. package/dashboard/dist/assets/{CollapsibleSection-CIj8Adc9.js → CollapsibleSection-8YE965QX.js} +2 -2
  89. package/dashboard/dist/assets/{CollapsibleSection-CIj8Adc9.js.map → CollapsibleSection-8YE965QX.js.map} +1 -1
  90. package/dashboard/dist/assets/{ConfirmDeleteModal-Ugi_9Ukq.js → ConfirmDeleteModal-CQsJUzEa.js} +2 -2
  91. package/dashboard/dist/assets/{ConfirmDeleteModal-Ugi_9Ukq.js.map → ConfirmDeleteModal-CQsJUzEa.js.map} +1 -1
  92. package/dashboard/dist/assets/{CopyableId-GUEdiiL5.js → CopyableId-4Lqlc5cU.js} +2 -2
  93. package/dashboard/dist/assets/{CopyableId-GUEdiiL5.js.map → CopyableId-4Lqlc5cU.js.map} +1 -1
  94. package/dashboard/dist/assets/CountdownTimer-Bxvq3D7j.js +2 -0
  95. package/dashboard/dist/assets/CountdownTimer-Bxvq3D7j.js.map +1 -0
  96. package/dashboard/dist/assets/{CredentialsPage-B73Si6K1.js → CredentialsPage-Bn7_SX6-.js} +2 -2
  97. package/dashboard/dist/assets/{CredentialsPage-B73Si6K1.js.map → CredentialsPage-Bn7_SX6-.js.map} +1 -1
  98. package/dashboard/dist/assets/{CronLabel-Ca1aHolt.js → CronLabel-Bn4mX_Yn.js} +2 -2
  99. package/dashboard/dist/assets/{CronLabel-Ca1aHolt.js.map → CronLabel-Bn4mX_Yn.js.map} +1 -1
  100. package/dashboard/dist/assets/{CustomDurationPicker-_9E9x1YN.js → CustomDurationPicker-pMcrFyW6.js} +2 -2
  101. package/dashboard/dist/assets/{CustomDurationPicker-_9E9x1YN.js.map → CustomDurationPicker-pMcrFyW6.js.map} +1 -1
  102. package/dashboard/dist/assets/{DataTable-BTu2AaEl.js → DataTable-Bir0Xs1p.js} +2 -2
  103. package/dashboard/dist/assets/{DataTable-BTu2AaEl.js.map → DataTable-Bir0Xs1p.js.map} +1 -1
  104. package/dashboard/dist/assets/{DropZone-NYn6TWHz.js → DropZone-zCEGjjk-.js} +2 -2
  105. package/dashboard/dist/assets/{DropZone-NYn6TWHz.js.map → DropZone-zCEGjjk-.js.map} +1 -1
  106. package/dashboard/dist/assets/{ElapsedCell-karxia93.js → ElapsedCell-BGO7IXEg.js} +2 -2
  107. package/dashboard/dist/assets/{ElapsedCell-karxia93.js.map → ElapsedCell-BGO7IXEg.js.map} +1 -1
  108. package/dashboard/dist/assets/{EmptyState-BcsfPq9T.js → EmptyState-lpUFYfun.js} +2 -2
  109. package/dashboard/dist/assets/{EmptyState-BcsfPq9T.js.map → EmptyState-lpUFYfun.js.map} +1 -1
  110. package/dashboard/dist/assets/{EscalationListSchemaPage-CDaNmbUA.js → EscalationListSchemaPage-CFDxbd50.js} +3 -3
  111. package/dashboard/dist/assets/{EscalationListSchemaPage-CDaNmbUA.js.map → EscalationListSchemaPage-CFDxbd50.js.map} +1 -1
  112. package/dashboard/dist/assets/{EscalationSchemaPage-k-2hFT2t.js → EscalationSchemaPage-DnXPnDkz.js} +3 -3
  113. package/dashboard/dist/assets/{EscalationSchemaPage-k-2hFT2t.js.map → EscalationSchemaPage-DnXPnDkz.js.map} +1 -1
  114. package/dashboard/dist/assets/{EscalationsOverview-C1e7IPn_.js → EscalationsOverview-BZMVXrkK.js} +2 -2
  115. package/dashboard/dist/assets/{EscalationsOverview-C1e7IPn_.js.map → EscalationsOverview-BZMVXrkK.js.map} +1 -1
  116. package/dashboard/dist/assets/EventTable-Bfi-f8as.js +2 -0
  117. package/dashboard/dist/assets/EventTable-Bfi-f8as.js.map +1 -0
  118. package/dashboard/dist/assets/FilterBar-Do7yR4xM.js +2 -0
  119. package/dashboard/dist/assets/FilterBar-Do7yR4xM.js.map +1 -0
  120. package/dashboard/dist/assets/{GraphInvokePage-LMpWw8z1.js → GraphInvokePage-d1ie4T7f.js} +2 -2
  121. package/dashboard/dist/assets/{GraphInvokePage-LMpWw8z1.js.map → GraphInvokePage-d1ie4T7f.js.map} +1 -1
  122. package/dashboard/dist/assets/{HomePage-Kl2DBG6l.js → HomePage-BEeodImU.js} +2 -2
  123. package/dashboard/dist/assets/{HomePage-Kl2DBG6l.js.map → HomePage-BEeodImU.js.map} +1 -1
  124. package/dashboard/dist/assets/ListToolbar-CLtw-1QN.js +2 -0
  125. package/dashboard/dist/assets/{ListToolbar-B2fub0DY.js.map → ListToolbar-CLtw-1QN.js.map} +1 -1
  126. package/dashboard/dist/assets/{McpOverview-odYnCZCC.js → McpOverview-DIsy9TB3.js} +2 -2
  127. package/dashboard/dist/assets/{McpOverview-odYnCZCC.js.map → McpOverview-DIsy9TB3.js.map} +1 -1
  128. package/dashboard/dist/assets/{McpQueryDetailPage-BtqwHUAg.js → McpQueryDetailPage-6PomdsyD.js} +3 -3
  129. package/dashboard/dist/assets/{McpQueryDetailPage-BtqwHUAg.js.map → McpQueryDetailPage-6PomdsyD.js.map} +1 -1
  130. package/dashboard/dist/assets/McpQueryPage-YMdQCXm9.js +2 -0
  131. package/dashboard/dist/assets/{McpQueryPage-CPkVwNIK.js.map → McpQueryPage-YMdQCXm9.js.map} +1 -1
  132. package/dashboard/dist/assets/McpRunDetailPage-DsD1Gm2o.js +2 -0
  133. package/dashboard/dist/assets/McpRunDetailPage-DsD1Gm2o.js.map +1 -0
  134. package/dashboard/dist/assets/{McpRunsPage-rdpZ2yMh.js → McpRunsPage--a5Jgb33.js} +2 -2
  135. package/dashboard/dist/assets/{McpRunsPage-rdpZ2yMh.js.map → McpRunsPage--a5Jgb33.js.map} +1 -1
  136. package/dashboard/dist/assets/{Modal-Dr1Xy0j0.js → Modal-BU7No9NH.js} +2 -2
  137. package/dashboard/dist/assets/{Modal-Dr1Xy0j0.js.map → Modal-BU7No9NH.js.map} +1 -1
  138. package/dashboard/dist/assets/{NamespacePill-GwO-WfhX.js → NamespacePill-wV6L4VW1.js} +2 -2
  139. package/dashboard/dist/assets/{NamespacePill-GwO-WfhX.js.map → NamespacePill-wV6L4VW1.js.map} +1 -1
  140. package/dashboard/dist/assets/OperationsPage-B2v9k3DT.js +2 -0
  141. package/dashboard/dist/assets/{OperationsPage-DlyGLPAs.js.map → OperationsPage-B2v9k3DT.js.map} +1 -1
  142. package/dashboard/dist/assets/{OperatorDashboard-Csei5vj-.js → OperatorDashboard-CkLfbxEh.js} +2 -2
  143. package/dashboard/dist/assets/{OperatorDashboard-Csei5vj-.js.map → OperatorDashboard-CkLfbxEh.js.map} +1 -1
  144. package/dashboard/dist/assets/{PageHeader-Bo9BU9pK.js → PageHeader-BtIr6r-8.js} +2 -2
  145. package/dashboard/dist/assets/{PageHeader-Bo9BU9pK.js.map → PageHeader-BtIr6r-8.js.map} +1 -1
  146. package/dashboard/dist/assets/{PageHeaderWithStats-8_5cOSKL.js → PageHeaderWithStats-C2sGqFQG.js} +2 -2
  147. package/dashboard/dist/assets/{PageHeaderWithStats-8_5cOSKL.js.map → PageHeaderWithStats-C2sGqFQG.js.map} +1 -1
  148. package/dashboard/dist/assets/{PersonaDetailPage--ZL6Or6v.js → PersonaDetailPage-CCmOgKQb.js} +2 -2
  149. package/dashboard/dist/assets/{PersonaDetailPage--ZL6Or6v.js.map → PersonaDetailPage-CCmOgKQb.js.map} +1 -1
  150. package/dashboard/dist/assets/{PersonasPage-Bdcoay3P.js → PersonasPage-BJkSuDTN.js} +2 -2
  151. package/dashboard/dist/assets/{PersonasPage-Bdcoay3P.js.map → PersonasPage-BJkSuDTN.js.map} +1 -1
  152. package/dashboard/dist/assets/{PriorityBadge-CCERr9vQ.js → PriorityBadge-BETdj4M-.js} +2 -2
  153. package/dashboard/dist/assets/{PriorityBadge-CCERr9vQ.js.map → PriorityBadge-BETdj4M-.js.map} +1 -1
  154. package/dashboard/dist/assets/{ProcessDetailPage-HrmVQq7S.js → ProcessDetailPage-DT9BlJXK.js} +2 -2
  155. package/dashboard/dist/assets/{ProcessDetailPage-HrmVQq7S.js.map → ProcessDetailPage-DT9BlJXK.js.map} +1 -1
  156. package/dashboard/dist/assets/{ProcessesListPage-_xmj6Bo-.js → ProcessesListPage-DgSGzTDT.js} +2 -2
  157. package/dashboard/dist/assets/{ProcessesListPage-_xmj6Bo-.js.map → ProcessesListPage-DgSGzTDT.js.map} +1 -1
  158. package/dashboard/dist/assets/{RoleDetailPage-C0ju2-4K.js → RoleDetailPage-DMphTvro.js} +3 -3
  159. package/dashboard/dist/assets/{RoleDetailPage-C0ju2-4K.js.map → RoleDetailPage-DMphTvro.js.map} +1 -1
  160. package/dashboard/dist/assets/{RolePill-CQlnEWkK.js → RolePill-BBYjhAPj.js} +2 -2
  161. package/dashboard/dist/assets/{RolePill-CQlnEWkK.js.map → RolePill-BBYjhAPj.js.map} +1 -1
  162. package/dashboard/dist/assets/{RolesPage-CKluVSpB.js → RolesPage-gi_kaot1.js} +2 -2
  163. package/dashboard/dist/assets/{RolesPage-CKluVSpB.js.map → RolesPage-gi_kaot1.js.map} +1 -1
  164. package/dashboard/dist/assets/{RowActions-BA9L9djf.js → RowActions-eYrzgQSj.js} +2 -2
  165. package/dashboard/dist/assets/{RowActions-BA9L9djf.js.map → RowActions-eYrzgQSj.js.map} +1 -1
  166. package/dashboard/dist/assets/RunAsSelector-CateuvcC.js +2 -0
  167. package/dashboard/dist/assets/{RunAsSelector-DdfecQ1U.js.map → RunAsSelector-CateuvcC.js.map} +1 -1
  168. package/dashboard/dist/assets/ScanCodesPage-CQ8RxMug.js +2 -0
  169. package/dashboard/dist/assets/ScanCodesPage-CQ8RxMug.js.map +1 -0
  170. package/dashboard/dist/assets/ScanSchemeDetailPage-puSbuxcV.js +2 -0
  171. package/dashboard/dist/assets/ScanSchemeDetailPage-puSbuxcV.js.map +1 -0
  172. package/dashboard/dist/assets/{ScopeBadge-BBYkevuR.js → ScopeBadge-xs2Nhjy4.js} +2 -2
  173. package/dashboard/dist/assets/{ScopeBadge-BBYkevuR.js.map → ScopeBadge-xs2Nhjy4.js.map} +1 -1
  174. package/dashboard/dist/assets/SegmentedTabs-DXNzY05q.js +2 -0
  175. package/dashboard/dist/assets/SegmentedTabs-DXNzY05q.js.map +1 -0
  176. package/dashboard/dist/assets/{StatCard-Ca-ngCaD.js → StatCard-BXQ8dD9Y.js} +2 -2
  177. package/dashboard/dist/assets/{StatCard-Ca-ngCaD.js.map → StatCard-BXQ8dD9Y.js.map} +1 -1
  178. package/dashboard/dist/assets/{StatusBadge-BwUvykDo.js → StatusBadge-DkgllZHv.js} +2 -2
  179. package/dashboard/dist/assets/{StatusBadge-BwUvykDo.js.map → StatusBadge-DkgllZHv.js.map} +1 -1
  180. package/dashboard/dist/assets/StickyPagination-Cg-QdYWL.js +2 -0
  181. package/dashboard/dist/assets/StickyPagination-Cg-QdYWL.js.map +1 -0
  182. package/dashboard/dist/assets/{StreamMessageDetail-CZXWDawC.js → StreamMessageDetail-DEeuh4_-.js} +2 -2
  183. package/dashboard/dist/assets/{StreamMessageDetail-CZXWDawC.js.map → StreamMessageDetail-DEeuh4_-.js.map} +1 -1
  184. package/dashboard/dist/assets/{SwimlaneTimeline-fWY0gaf3.js → SwimlaneTimeline-DMY0jL2F.js} +2 -2
  185. package/dashboard/dist/assets/{SwimlaneTimeline-fWY0gaf3.js.map → SwimlaneTimeline-DMY0jL2F.js.map} +1 -1
  186. package/dashboard/dist/assets/{TagInput-CDKbslLx.js → TagInput-BMmiV-MD.js} +2 -2
  187. package/dashboard/dist/assets/{TagInput-CDKbslLx.js.map → TagInput-BMmiV-MD.js.map} +1 -1
  188. package/dashboard/dist/assets/{TaskDetailPage-BjE4G2yn.js → TaskDetailPage-CPbkIvfF.js} +2 -2
  189. package/dashboard/dist/assets/{TaskDetailPage-BjE4G2yn.js.map → TaskDetailPage-CPbkIvfF.js.map} +1 -1
  190. package/dashboard/dist/assets/{TaskQueuePill-G3RuYRNZ.js → TaskQueuePill-DLgYaw1x.js} +2 -2
  191. package/dashboard/dist/assets/{TaskQueuePill-G3RuYRNZ.js.map → TaskQueuePill-DLgYaw1x.js.map} +1 -1
  192. package/dashboard/dist/assets/{TasksListPage-KAhmCWB2.js → TasksListPage-CtHudKhQ.js} +2 -2
  193. package/dashboard/dist/assets/{TasksListPage-KAhmCWB2.js.map → TasksListPage-CtHudKhQ.js.map} +1 -1
  194. package/dashboard/dist/assets/TimeAgo-BdHOizWg.js +2 -0
  195. package/dashboard/dist/assets/{TimeAgo-C_H2TyZw.js.map → TimeAgo-BdHOizWg.js.map} +1 -1
  196. package/dashboard/dist/assets/{TimestampCell-COG_4Flg.js → TimestampCell-FVukzKRe.js} +2 -2
  197. package/dashboard/dist/assets/{TimestampCell-COG_4Flg.js.map → TimestampCell-FVukzKRe.js.map} +1 -1
  198. package/dashboard/dist/assets/{ToolPill-ChSyRJZC.js → ToolPill-BvS53hxP.js} +2 -2
  199. package/dashboard/dist/assets/{ToolPill-ChSyRJZC.js.map → ToolPill-BvS53hxP.js.map} +1 -1
  200. package/dashboard/dist/assets/{ToolTestPanel-BPdJECW0.js → ToolTestPanel-HN0OCYTL.js} +2 -2
  201. package/dashboard/dist/assets/{ToolTestPanel-BPdJECW0.js.map → ToolTestPanel-HN0OCYTL.js.map} +1 -1
  202. package/dashboard/dist/assets/{TopicDetailPage-DAqx5JqA.js → TopicDetailPage-DHdSpN61.js} +4 -4
  203. package/dashboard/dist/assets/{TopicDetailPage-DAqx5JqA.js.map → TopicDetailPage-DHdSpN61.js.map} +1 -1
  204. package/dashboard/dist/assets/TopicsPage-Clr6Tl5P.js +2 -0
  205. package/dashboard/dist/assets/{TopicsPage-DoGqAdPm.js.map → TopicsPage-Clr6Tl5P.js.map} +1 -1
  206. package/dashboard/dist/assets/UserName-BUVYyIAS.js +2 -0
  207. package/dashboard/dist/assets/{UserName-CKO_rk1R.js.map → UserName-BUVYyIAS.js.map} +1 -1
  208. package/dashboard/dist/assets/WorkflowExecutionPage-kncWFfe5.js +2 -0
  209. package/dashboard/dist/assets/WorkflowExecutionPage-kncWFfe5.js.map +1 -0
  210. package/dashboard/dist/assets/{WorkflowPill-CNbwug5p.js → WorkflowPill-BPC_Dc_I.js} +2 -2
  211. package/dashboard/dist/assets/{WorkflowPill-CNbwug5p.js.map → WorkflowPill-BPC_Dc_I.js.map} +1 -1
  212. package/dashboard/dist/assets/WorkflowsDashboard-4ypPDGKx.js +2 -0
  213. package/dashboard/dist/assets/{WorkflowsDashboard-DdJ86We6.js.map → WorkflowsDashboard-4ypPDGKx.js.map} +1 -1
  214. package/dashboard/dist/assets/{WorkflowsOverview-ZfFBzePp.js → WorkflowsOverview-CeQlZkkd.js} +2 -2
  215. package/dashboard/dist/assets/{WorkflowsOverview-ZfFBzePp.js.map → WorkflowsOverview-CeQlZkkd.js.map} +1 -1
  216. package/dashboard/dist/assets/{YamlWorkflowDetailPage-4bd5yXdA.js → YamlWorkflowDetailPage-DLAlEzwT.js} +13 -13
  217. package/dashboard/dist/assets/{YamlWorkflowDetailPage-4bd5yXdA.js.map → YamlWorkflowDetailPage-DLAlEzwT.js.map} +1 -1
  218. package/dashboard/dist/assets/{YamlWorkflowsPage-iHPNXjQj.js → YamlWorkflowsPage-DQhenKFT.js} +2 -2
  219. package/dashboard/dist/assets/{YamlWorkflowsPage-iHPNXjQj.js.map → YamlWorkflowsPage-DQhenKFT.js.map} +1 -1
  220. package/dashboard/dist/assets/{agents-DjD5U3Wb.js → agents-s3feet3W.js} +2 -2
  221. package/dashboard/dist/assets/{agents-DjD5U3Wb.js.map → agents-s3feet3W.js.map} +1 -1
  222. package/dashboard/dist/assets/{bots-DiljVapH.js → bots-CkSd2rn9.js} +2 -2
  223. package/dashboard/dist/assets/{bots-DiljVapH.js.map → bots-CkSd2rn9.js.map} +1 -1
  224. package/dashboard/dist/assets/capabilities-DA_r09tM.js +2 -0
  225. package/dashboard/dist/assets/{capabilities-DV_5ghHT.js.map → capabilities-DA_r09tM.js.map} +1 -1
  226. package/dashboard/dist/assets/{controlplane-BKMvfWCB.js → controlplane-C9c25q21.js} +2 -2
  227. package/dashboard/dist/assets/{controlplane-BKMvfWCB.js.map → controlplane-C9c25q21.js.map} +1 -1
  228. package/dashboard/dist/assets/{escalation-columns-BQpCaJId.js → escalation-columns-Cp3UrT48.js} +2 -2
  229. package/dashboard/dist/assets/{escalation-columns-BQpCaJId.js.map → escalation-columns-Cp3UrT48.js.map} +1 -1
  230. package/dashboard/dist/assets/{index-BO-7S9Xw.js → index--7Vdkzwd.js} +2 -2
  231. package/dashboard/dist/assets/{index-BO-7S9Xw.js.map → index--7Vdkzwd.js.map} +1 -1
  232. package/dashboard/dist/assets/index--DG-qQBT.js +65 -0
  233. package/dashboard/dist/assets/index--DG-qQBT.js.map +1 -0
  234. package/dashboard/dist/assets/{index-BaV3l0UE.js → index-BIcYbDVf.js} +2 -2
  235. package/dashboard/dist/assets/{index-BaV3l0UE.js.map → index-BIcYbDVf.js.map} +1 -1
  236. package/dashboard/dist/assets/index-BU5FFAJo.js +2 -0
  237. package/dashboard/dist/assets/{index-CItsikDw.js.map → index-BU5FFAJo.js.map} +1 -1
  238. package/dashboard/dist/assets/{index-BsOxMMmb.js → index-Bo5TtX9l.js} +2 -2
  239. package/dashboard/dist/assets/{index-BsOxMMmb.js.map → index-Bo5TtX9l.js.map} +1 -1
  240. package/dashboard/dist/assets/{index-Tx_ETzcH.js → index-C-MmR-jf.js} +2 -2
  241. package/dashboard/dist/assets/{index-Tx_ETzcH.js.map → index-C-MmR-jf.js.map} +1 -1
  242. package/dashboard/dist/assets/index-C7ABSOU2.js +6 -0
  243. package/dashboard/dist/assets/index-C7ABSOU2.js.map +1 -0
  244. package/dashboard/dist/assets/index-Cmxzk4ay.js +5 -0
  245. package/dashboard/dist/assets/{index-nIrYejxe.js.map → index-Cmxzk4ay.js.map} +1 -1
  246. package/dashboard/dist/assets/{index-CI8rrKjx.js → index-Cw9poaez.js} +2 -2
  247. package/dashboard/dist/assets/{index-CI8rrKjx.js.map → index-Cw9poaez.js.map} +1 -1
  248. package/dashboard/dist/assets/index-DEbY57_c.js +3 -0
  249. package/dashboard/dist/assets/index-DEbY57_c.js.map +1 -0
  250. package/dashboard/dist/assets/index-DnV6LSeY.css +1 -0
  251. package/dashboard/dist/assets/{index-xZqQxqu2.js → index-DvoMXQqO.js} +2 -2
  252. package/dashboard/dist/assets/{index-xZqQxqu2.js.map → index-DvoMXQqO.js.map} +1 -1
  253. package/dashboard/dist/assets/{index-DhATO1cS.js → index-S13oPvuS.js} +2 -2
  254. package/dashboard/dist/assets/{index-DhATO1cS.js.map → index-S13oPvuS.js.map} +1 -1
  255. package/dashboard/dist/assets/index-WxE3ONia.js +2 -0
  256. package/dashboard/dist/assets/{index-CStR4uIU.js.map → index-WxE3ONia.js.map} +1 -1
  257. package/dashboard/dist/assets/{knowledge-BocTnSiA.js → knowledge-Bpln0zy_.js} +2 -2
  258. package/dashboard/dist/assets/{knowledge-BocTnSiA.js.map → knowledge-Bpln0zy_.js.map} +1 -1
  259. package/dashboard/dist/assets/{mcp-C1KBjKQ_.js → mcp-BqDq3RZH.js} +2 -2
  260. package/dashboard/dist/assets/{mcp-C1KBjKQ_.js.map → mcp-BqDq3RZH.js.map} +1 -1
  261. package/dashboard/dist/assets/{mcp-query-B3cjukkA.js → mcp-query-DGue75R6.js} +2 -2
  262. package/dashboard/dist/assets/{mcp-query-B3cjukkA.js.map → mcp-query-DGue75R6.js.map} +1 -1
  263. package/dashboard/dist/assets/{personas-DiA2bJaX.js → personas-B8z_sTiJ.js} +2 -2
  264. package/dashboard/dist/assets/{personas-DiA2bJaX.js.map → personas-B8z_sTiJ.js.map} +1 -1
  265. package/dashboard/dist/assets/{pipelines-Dt2d2EFR.js → pipelines-DYgNd9nB.js} +2 -2
  266. package/dashboard/dist/assets/{pipelines-Dt2d2EFR.js.map → pipelines-DYgNd9nB.js.map} +1 -1
  267. package/dashboard/dist/assets/{tasks-cDh2hNml.js → tasks-CJdjjhgO.js} +2 -2
  268. package/dashboard/dist/assets/{tasks-cDh2hNml.js.map → tasks-CJdjjhgO.js.map} +1 -1
  269. package/dashboard/dist/assets/{topics-yFlGF-u1.js → topics-DPrL8Dtq.js} +2 -2
  270. package/dashboard/dist/assets/{topics-yFlGF-u1.js.map → topics-DPrL8Dtq.js.map} +1 -1
  271. package/dashboard/dist/assets/{useDebouncedValue-BA5S7V54.js → useDebouncedValue-C4P2jQuh.js} +2 -2
  272. package/dashboard/dist/assets/{useDebouncedValue-BA5S7V54.js.map → useDebouncedValue-C4P2jQuh.js.map} +1 -1
  273. package/dashboard/dist/assets/{useEventHooks-D2R_ckS8.js → useEventHooks-DXCgDgiu.js} +2 -2
  274. package/dashboard/dist/assets/{useEventHooks-D2R_ckS8.js.map → useEventHooks-DXCgDgiu.js.map} +1 -1
  275. package/dashboard/dist/assets/{useFilterParams-B7suPsIK.js → useFilterParams-crmlBw_l.js} +2 -2
  276. package/dashboard/dist/assets/{useFilterParams-B7suPsIK.js.map → useFilterParams-crmlBw_l.js.map} +1 -1
  277. package/dashboard/dist/assets/{useNamespace-u-V1GVUD.js → useNamespace-DnFZfy7N.js} +2 -2
  278. package/dashboard/dist/assets/{useNamespace-u-V1GVUD.js.map → useNamespace-DnFZfy7N.js.map} +1 -1
  279. package/dashboard/dist/assets/{useYamlActivityEvents-BhOZeqgE.js → useYamlActivityEvents-kx5CLENv.js} +2 -2
  280. package/dashboard/dist/assets/{useYamlActivityEvents-BhOZeqgE.js.map → useYamlActivityEvents-kx5CLENv.js.map} +1 -1
  281. package/dashboard/dist/assets/{users-BoXPwdee.js → users-DKng7vAG.js} +2 -2
  282. package/dashboard/dist/assets/{users-BoXPwdee.js.map → users-DKng7vAG.js.map} +1 -1
  283. package/dashboard/dist/assets/{vendor-icons-D71XjkNy.js → vendor-icons-CN-bAo9U.js} +144 -134
  284. package/dashboard/dist/assets/vendor-icons-CN-bAo9U.js.map +1 -0
  285. package/dashboard/dist/assets/{vendor-query-B2UbickB.js → vendor-query-RUZdMvN6.js} +2 -2
  286. package/dashboard/dist/assets/{vendor-query-B2UbickB.js.map → vendor-query-RUZdMvN6.js.map} +1 -1
  287. package/dashboard/dist/assets/{vendor-react-C1YOyCSV.js → vendor-react-CdqEC2zv.js} +2 -2
  288. package/dashboard/dist/assets/{vendor-react-C1YOyCSV.js.map → vendor-react-CdqEC2zv.js.map} +1 -1
  289. package/dashboard/dist/assets/{workflows-mCoyKuLZ.js → workflows-C4V0rMkM.js} +2 -2
  290. package/dashboard/dist/assets/{workflows-mCoyKuLZ.js.map → workflows-C4V0rMkM.js.map} +1 -1
  291. package/dashboard/dist/assets/{yaml-workflows-CWxXGDpn.js → yaml-workflows-D3PAiJ9d.js} +2 -2
  292. package/dashboard/dist/assets/{yaml-workflows-CWxXGDpn.js.map → yaml-workflows-D3PAiJ9d.js.map} +1 -1
  293. package/dashboard/dist/index.html +5 -5
  294. package/docs/design-principles.md +9 -7
  295. package/docs/hitl/x-lt-embed.md +8 -4
  296. package/docs/hitl/x-lt-footer.md +68 -0
  297. package/docs/hitl/x-lt-list-schema.md +10 -3
  298. package/docs/hitl/x-lt-transition.md +105 -0
  299. package/docs/hitl-guide.md +9 -0
  300. package/docs/scan-codes.md +243 -0
  301. package/package.json +2 -2
  302. package/dashboard/dist/assets/AgentsPage-bSx_mdae.js +0 -2
  303. package/dashboard/dist/assets/AvailableEscalationsPage-8pMC7Xv6.js +0 -2
  304. package/dashboard/dist/assets/BotPicker-C4uGH2x9.js +0 -2
  305. package/dashboard/dist/assets/CountdownTimer-D3t0XMhE.js +0 -2
  306. package/dashboard/dist/assets/CountdownTimer-D3t0XMhE.js.map +0 -1
  307. package/dashboard/dist/assets/EventTable-CIrrtL7_.js +0 -2
  308. package/dashboard/dist/assets/EventTable-CIrrtL7_.js.map +0 -1
  309. package/dashboard/dist/assets/FilterBar-CzjtH74v.js +0 -2
  310. package/dashboard/dist/assets/FilterBar-CzjtH74v.js.map +0 -1
  311. package/dashboard/dist/assets/ListToolbar-B2fub0DY.js +0 -2
  312. package/dashboard/dist/assets/McpQueryPage-CPkVwNIK.js +0 -2
  313. package/dashboard/dist/assets/McpRunDetailPage-D-Rz9MRw.js +0 -2
  314. package/dashboard/dist/assets/McpRunDetailPage-D-Rz9MRw.js.map +0 -1
  315. package/dashboard/dist/assets/OperationsPage-DlyGLPAs.js +0 -2
  316. package/dashboard/dist/assets/RunAsSelector-DdfecQ1U.js +0 -2
  317. package/dashboard/dist/assets/StickyPagination-cLddIdtT.js +0 -2
  318. package/dashboard/dist/assets/StickyPagination-cLddIdtT.js.map +0 -1
  319. package/dashboard/dist/assets/TimeAgo-C_H2TyZw.js +0 -2
  320. package/dashboard/dist/assets/TopicsPage-DoGqAdPm.js +0 -2
  321. package/dashboard/dist/assets/UserName-CKO_rk1R.js +0 -2
  322. package/dashboard/dist/assets/WorkflowExecutionPage-D3VQ9iQV.js +0 -2
  323. package/dashboard/dist/assets/WorkflowExecutionPage-D3VQ9iQV.js.map +0 -1
  324. package/dashboard/dist/assets/WorkflowsDashboard-DdJ86We6.js +0 -2
  325. package/dashboard/dist/assets/capabilities-DV_5ghHT.js +0 -2
  326. package/dashboard/dist/assets/index-B-WkiNRN.js +0 -6
  327. package/dashboard/dist/assets/index-B-WkiNRN.js.map +0 -1
  328. package/dashboard/dist/assets/index-CItsikDw.js +0 -2
  329. package/dashboard/dist/assets/index-CStR4uIU.js +0 -2
  330. package/dashboard/dist/assets/index-DbTD-dio.js +0 -63
  331. package/dashboard/dist/assets/index-DbTD-dio.js.map +0 -1
  332. package/dashboard/dist/assets/index-DnlsDaAw.css +0 -1
  333. package/dashboard/dist/assets/index-kzIIeVbx.js +0 -5
  334. package/dashboard/dist/assets/index-kzIIeVbx.js.map +0 -1
  335. package/dashboard/dist/assets/index-nIrYejxe.js +0 -5
  336. package/dashboard/dist/assets/vendor-icons-D71XjkNy.js.map +0 -1
@@ -96,6 +96,7 @@ export declare function createClient(options?: LTClientOptions): {
96
96
  type?: string;
97
97
  subtype?: string;
98
98
  assigned_to?: string;
99
+ parent_id?: string;
99
100
  claimed?: boolean;
100
101
  priority?: number;
101
102
  limit?: number;
@@ -202,6 +203,7 @@ export declare function createClient(options?: LTClientOptions): {
202
203
  assignee?: string;
203
204
  metadata?: Record<string, any>;
204
205
  provisionIfAbsent?: import("../api/escalations/helpers").ProvisionIfAbsent;
206
+ restrictRoles?: string[];
205
207
  }, auth?: LTApiAuth) => Promise<LTApiResult<any>>;
206
208
  resolveByMetadata: (input: {
207
209
  key: string;
@@ -209,6 +211,8 @@ export declare function createClient(options?: LTClientOptions): {
209
211
  resolverPayload: Record<string, any>;
210
212
  assignee?: string;
211
213
  metadata?: Record<string, any>;
214
+ restrictRoles?: string[];
215
+ extraFacets?: Record<string, any>;
212
216
  }, auth?: LTApiAuth) => Promise<LTApiResult<any>>;
213
217
  searchByFacets: (input: import("..").FacetQuery, auth?: LTApiAuth) => Promise<LTApiResult<any>>;
214
218
  claimGroups: (input: {
@@ -241,4 +241,4 @@ export interface ResolveByMetadataResult {
241
241
  * business logic over the shared table, so it runs as one atomic statement on
242
242
  * `hmsh_escalations` rather than through the generic SDK resolve.
243
243
  */
244
- export declare function resolveByMetadataAtomic(key: string, value: string, userId: string, resolverPayload: Record<string, any>, metadata?: Record<string, any>, writeAllRoles?: string[] | null, writeSelfRoles?: string[] | null, enforcingRoles?: string[] | null, assertId?: string | null): Promise<ResolveByMetadataResult>;
244
+ export declare function resolveByMetadataAtomic(key: string, value: string, userId: string, resolverPayload: Record<string, any>, metadata?: Record<string, any>, writeAllRoles?: string[] | null, writeSelfRoles?: string[] | null, enforcingRoles?: string[] | null, assertId?: string | null, extraFacets?: Record<string, any> | null): Promise<ResolveByMetadataResult>;
@@ -554,10 +554,12 @@ async function claimByMetadata(key, value, userId, durationMinutes = 30, metadat
554
554
  * business logic over the shared table, so it runs as one atomic statement on
555
555
  * `hmsh_escalations` rather than through the generic SDK resolve.
556
556
  */
557
- async function resolveByMetadataAtomic(key, value, userId, resolverPayload, metadata, writeAllRoles, writeSelfRoles, enforcingRoles, assertId) {
557
+ async function resolveByMetadataAtomic(key, value, userId, resolverPayload, metadata, writeAllRoles, writeSelfRoles, enforcingRoles, assertId, extraFacets) {
558
558
  await (0, client_1.ensureEscalationCompatView)();
559
559
  const pool = (0, db_1.getPool)();
560
- const filter = JSON.stringify({ [key]: value });
560
+ // The statement's filter is jsonb containment extra facet guards simply
561
+ // widen the containment object and ride the same atomic WHERE.
562
+ const filter = JSON.stringify({ [key]: value, ...(extraFacets ?? {}) });
561
563
  const payloadJson = JSON.stringify(resolverPayload);
562
564
  const metaPatch = metadata ? JSON.stringify(metadata) : null;
563
565
  // null write_all roles = global (no filter). A scoped caller passes its arrays
@@ -62,6 +62,7 @@ export declare function listEscalations(filters: {
62
62
  type?: string;
63
63
  subtype?: string;
64
64
  assigned_to?: string;
65
+ parent_id?: string;
65
66
  claimed?: boolean;
66
67
  priority?: number;
67
68
  limit?: number;
@@ -298,6 +298,8 @@ async function listEscalations(filters) {
298
298
  };
299
299
  if (filters.assigned_to)
300
300
  where.assignedTo = filters.assigned_to;
301
+ if (filters.parent_id)
302
+ where.parentId = filters.parent_id;
301
303
  if (heldNow)
302
304
  where.available = false;
303
305
  if (filters.metadata)
@@ -23,6 +23,6 @@ export interface ResolverSchemaViolationReport {
23
23
  * surface's task fallback); by default the row's own envelope column is used.
24
24
  * It is only invoked when the role actually enforces.
25
25
  */
26
- export declare function checkResolverPayload(escalation: ResolvableEscalationRow, resolverPayload: Record<string, any>, loadEnvelope?: () => Promise<Record<string, any>>): Promise<ResolverSchemaViolationReport | null>;
26
+ export declare function checkResolverPayload(escalation: ResolvableEscalationRow, resolverPayload: Record<string, any>, loadEnvelope?: () => Promise<Record<string, any>>, resolvingUserId?: string): Promise<ResolverSchemaViolationReport | null>;
27
27
  /** The canonical 422 body for a violation report (types/validation.ts). */
28
28
  export declare function toValidationErrorBody(report: ResolverSchemaViolationReport): LTValidationErrorBody;
@@ -22,6 +22,7 @@ exports.toValidationErrorBody = toValidationErrorBody;
22
22
  * the gate passes.
23
23
  */
24
24
  const form_validation_1 = require("../../shared/form-validation");
25
+ const submit_guard_1 = require("./submit-guard");
25
26
  const enforcement_cache_1 = require("../role/enforcement-cache");
26
27
  const escalation_1 = require("../../types/escalation");
27
28
  const validation_1 = require("../../types/validation");
@@ -54,7 +55,7 @@ function pinnedVersionOf(metadata) {
54
55
  * surface's task fallback); by default the row's own envelope column is used.
55
56
  * It is only invoked when the role actually enforces.
56
57
  */
57
- async function checkResolverPayload(escalation, resolverPayload, loadEnvelope) {
58
+ async function checkResolverPayload(escalation, resolverPayload, loadEnvelope, resolvingUserId) {
58
59
  const role = escalation.role;
59
60
  if (!role)
60
61
  return null;
@@ -72,15 +73,21 @@ async function checkResolverPayload(escalation, resolverPayload, loadEnvelope) {
72
73
  const envelope = loadEnvelope
73
74
  ? await loadEnvelope()
74
75
  : parseJsonOrNull(escalation.envelope) ?? {};
75
- const violations = (0, form_validation_1.validateResolverPayload)(schema, resolverPayload, {
76
+ const ctx = {
76
77
  escalation: escalation,
77
78
  metadata,
78
79
  envelope,
79
80
  payload: parseJsonOrNull(escalation.escalation_payload),
80
- });
81
- if (violations.length === 0)
81
+ };
82
+ const violations = (0, form_validation_1.validateResolverPayload)(schema, resolverPayload, ctx);
83
+ // The query precondition (x-lt-submit-guard): reject while the embedded query
84
+ // still returns rows. Enforced on the same enforce_schema opt-in as the field
85
+ // contract, so a raw-API resolve honors the gate the dashboard shows.
86
+ const guardViolation = await (0, submit_guard_1.checkSubmitGuard)(schema, ctx, resolvingUserId);
87
+ const allViolations = guardViolation ? [...violations, guardViolation] : violations;
88
+ if (allViolations.length === 0)
82
89
  return null;
83
- return { role, schemaVersion: pin, violations };
90
+ return { role, schemaVersion: pin, violations: allViolations };
84
91
  }
85
92
  /** The canonical 422 body for a violation report (types/validation.ts). */
86
93
  function toValidationErrorBody(report) {
@@ -26,13 +26,18 @@ export declare function searchEscalationsQuery(orderBy: string): string;
26
26
  * 3. `metadata.signal_id` present, row already claimed and claim not expired →
27
27
  * a concurrent caller is handling the signal. `signal_already_claimed = true`;
28
28
  * caller returns 409 without re-signaling.
29
- * 4. `signal_key` present (atomic conditionLT) → `claimed` and `resolved` both skip.
29
+ * 4. `signal_key` present (atomic conditionLT) → the write skips entirely.
30
30
  * Caller invokes SDK resolve to atomically mark resolved + deliver the signal.
31
31
  *
32
- * Signal_id hardening: the `claimed` CTE runs for signal_id rows (previously excluded).
33
- * This stamps `assigned_to` on the row inside the FOR UPDATE transaction, so a
34
- * concurrent second caller sees `signal_already_claimed = true` and aborts.
35
- * The `resolved` CTE still skips signal_id rows — the workflow resolves durably.
32
+ * Signal_id hardening: the write runs for signal_id rows too, stamping
33
+ * `assigned_to` inside the FOR UPDATE transaction so a concurrent second caller
34
+ * sees `signal_already_claimed = true` and aborts. The resolve columns skip
35
+ * signal_id rows (CASE branches) — the workflow resolves durably.
36
+ *
37
+ * ONE UPDATE does both claim and resolve: Postgres does not support a second
38
+ * same-statement UPDATE of a row already updated by an earlier CTE (the second
39
+ * silently no-ops), so a chained claim→resolve pair leaves the row claimed but
40
+ * pending. The resolve columns ride the claim UPDATE as CASE branches instead.
36
41
  *
37
42
  * $1 = metadata filter (jsonb), $2 = userId, $3 = resolver_payload (jsonb),
38
43
  * $4 = metadata patch (jsonb, nullable), $5 = write_all roles (text[], null = global /
@@ -53,7 +58,7 @@ export declare function searchEscalationsQuery(orderBy: string): string;
53
58
  * resolution surfaces as zero rows → the caller's conflict handling). This is
54
59
  * the same pick-then-guarded-finish shape the signal outcomes already use.
55
60
  */
56
- export declare const RESOLVE_BY_METADATA_ATOMIC = "WITH target AS MATERIALIZED (\n SELECT *\n FROM public.hmsh_escalations\n WHERE metadata @> $1::jsonb\n AND status = 'pending'\n AND (\n $5::text[] IS NULL\n OR role = ANY($5)\n OR (role = ANY($6::text[]) AND assigned_to = $2)\n )\n AND ($8::uuid IS NULL OR id = $8::uuid)\n ORDER BY priority ASC, created_at ASC\n LIMIT 1\n FOR UPDATE\n),\nclaimed AS (\n UPDATE public.hmsh_escalations e\n SET assigned_to = COALESCE(e.assigned_to, $2),\n claimed_at = COALESCE(e.claimed_at, NOW()),\n assigned_until = CASE\n WHEN e.assigned_to IS NOT NULL AND e.assigned_until > NOW() THEN e.assigned_until\n ELSE NOW() + INTERVAL '5 minutes' END,\n claim_expires_at = CASE\n WHEN e.assigned_to IS NOT NULL AND e.assigned_until > NOW() THEN e.claim_expires_at\n ELSE NOW() + INTERVAL '5 minutes' END,\n metadata = CASE WHEN $4::jsonb IS NOT NULL\n THEN COALESCE(e.metadata, '{}'::jsonb) || $4::jsonb\n ELSE e.metadata END,\n updated_at = NOW()\n FROM target\n WHERE e.id = target.id\n AND target.signal_key IS NULL\n AND ($7::text[] IS NULL OR NOT (target.role = ANY($7)))\n RETURNING e.*\n),\nresolved AS (\n UPDATE public.hmsh_escalations e\n SET status = 'resolved',\n resolved_at = NOW(),\n resolver_payload = $3,\n updated_at = NOW()\n FROM claimed\n WHERE e.id = claimed.id\n AND (claimed.metadata->>'signal_id') IS NULL\n RETURNING e.*\n)\nSELECT\n resolved.*,\n target.id AS target_id,\n target.role AS target_role,\n target.metadata AS target_metadata,\n target.envelope AS target_envelope,\n target.escalation_payload AS target_escalation_payload,\n target.metadata->>'signal_id' AS signal_id,\n target.signal_key AS signal_key,\n target.workflow_id AS target_workflow_id,\n target.workflow_type AS target_workflow_type,\n target.task_queue AS target_task_queue,\n (target.assigned_to IS NOT NULL\n AND target.assigned_until IS NOT NULL\n AND target.assigned_until > NOW()) AS signal_already_claimed,\n CASE\n WHEN resolved.id IS NOT NULL THEN 'resolved'\n WHEN $7::text[] IS NOT NULL AND target.role = ANY($7) THEN 'validation_required'\n ELSE 'signal_required'\n END AS outcome\nFROM target\nLEFT JOIN resolved ON resolved.id = target.id";
61
+ export declare const RESOLVE_BY_METADATA_ATOMIC = "WITH target AS MATERIALIZED (\n SELECT *\n FROM public.hmsh_escalations\n WHERE metadata @> $1::jsonb\n AND status = 'pending'\n AND (\n $5::text[] IS NULL\n OR role = ANY($5)\n OR (role = ANY($6::text[]) AND assigned_to = $2)\n )\n AND ($8::uuid IS NULL OR id = $8::uuid)\n ORDER BY priority ASC, created_at ASC\n LIMIT 1\n FOR UPDATE\n),\nwritten AS (\n UPDATE public.hmsh_escalations e\n SET assigned_to = COALESCE(e.assigned_to, $2),\n claimed_at = COALESCE(e.claimed_at, NOW()),\n assigned_until = CASE\n WHEN e.assigned_to IS NOT NULL AND e.assigned_until > NOW() THEN e.assigned_until\n ELSE NOW() + INTERVAL '5 minutes' END,\n claim_expires_at = CASE\n WHEN e.assigned_to IS NOT NULL AND e.assigned_until > NOW() THEN e.claim_expires_at\n ELSE NOW() + INTERVAL '5 minutes' END,\n metadata = CASE WHEN $4::jsonb IS NOT NULL\n THEN COALESCE(e.metadata, '{}'::jsonb) || $4::jsonb\n ELSE e.metadata END,\n status = CASE WHEN (target.metadata->>'signal_id') IS NULL\n THEN 'resolved' ELSE e.status END,\n resolved_at = CASE WHEN (target.metadata->>'signal_id') IS NULL\n THEN NOW() ELSE e.resolved_at END,\n resolver_payload = CASE WHEN (target.metadata->>'signal_id') IS NULL\n THEN $3 ELSE e.resolver_payload END,\n updated_at = NOW()\n FROM target\n WHERE e.id = target.id\n AND target.signal_key IS NULL\n AND ($7::text[] IS NULL OR NOT (target.role = ANY($7)))\n RETURNING e.*\n)\nSELECT\n written.*,\n target.id AS target_id,\n target.role AS target_role,\n target.metadata AS target_metadata,\n target.envelope AS target_envelope,\n target.escalation_payload AS target_escalation_payload,\n target.metadata->>'signal_id' AS signal_id,\n target.signal_key AS signal_key,\n target.workflow_id AS target_workflow_id,\n target.workflow_type AS target_workflow_type,\n target.task_queue AS target_task_queue,\n (target.assigned_to IS NOT NULL\n AND target.assigned_until IS NOT NULL\n AND target.assigned_until > NOW()) AS signal_already_claimed,\n CASE\n WHEN written.status = 'resolved' THEN 'resolved'\n WHEN $7::text[] IS NOT NULL AND target.role = ANY($7) THEN 'validation_required'\n ELSE 'signal_required'\n END AS outcome\nFROM target\nLEFT JOIN written ON written.id = target.id";
57
62
  /**
58
63
  * Live counts — pending, active claims, and priority (past-threshold) per role.
59
64
  *
@@ -108,13 +108,18 @@ function searchEscalationsQuery(orderBy) {
108
108
  * 3. `metadata.signal_id` present, row already claimed and claim not expired →
109
109
  * a concurrent caller is handling the signal. `signal_already_claimed = true`;
110
110
  * caller returns 409 without re-signaling.
111
- * 4. `signal_key` present (atomic conditionLT) → `claimed` and `resolved` both skip.
111
+ * 4. `signal_key` present (atomic conditionLT) → the write skips entirely.
112
112
  * Caller invokes SDK resolve to atomically mark resolved + deliver the signal.
113
113
  *
114
- * Signal_id hardening: the `claimed` CTE runs for signal_id rows (previously excluded).
115
- * This stamps `assigned_to` on the row inside the FOR UPDATE transaction, so a
116
- * concurrent second caller sees `signal_already_claimed = true` and aborts.
117
- * The `resolved` CTE still skips signal_id rows — the workflow resolves durably.
114
+ * Signal_id hardening: the write runs for signal_id rows too, stamping
115
+ * `assigned_to` inside the FOR UPDATE transaction so a concurrent second caller
116
+ * sees `signal_already_claimed = true` and aborts. The resolve columns skip
117
+ * signal_id rows (CASE branches) — the workflow resolves durably.
118
+ *
119
+ * ONE UPDATE does both claim and resolve: Postgres does not support a second
120
+ * same-statement UPDATE of a row already updated by an earlier CTE (the second
121
+ * silently no-ops), so a chained claim→resolve pair leaves the row claimed but
122
+ * pending. The resolve columns ride the claim UPDATE as CASE branches instead.
118
123
  *
119
124
  * $1 = metadata filter (jsonb), $2 = userId, $3 = resolver_payload (jsonb),
120
125
  * $4 = metadata patch (jsonb, nullable), $5 = write_all roles (text[], null = global /
@@ -151,7 +156,7 @@ WITH target AS MATERIALIZED (
151
156
  LIMIT 1
152
157
  FOR UPDATE
153
158
  ),
154
- claimed AS (
159
+ written AS (
155
160
  UPDATE public.hmsh_escalations e
156
161
  SET assigned_to = COALESCE(e.assigned_to, $2),
157
162
  claimed_at = COALESCE(e.claimed_at, NOW()),
@@ -164,26 +169,21 @@ claimed AS (
164
169
  metadata = CASE WHEN $4::jsonb IS NOT NULL
165
170
  THEN COALESCE(e.metadata, '{}'::jsonb) || $4::jsonb
166
171
  ELSE e.metadata END,
172
+ status = CASE WHEN (target.metadata->>'signal_id') IS NULL
173
+ THEN 'resolved' ELSE e.status END,
174
+ resolved_at = CASE WHEN (target.metadata->>'signal_id') IS NULL
175
+ THEN NOW() ELSE e.resolved_at END,
176
+ resolver_payload = CASE WHEN (target.metadata->>'signal_id') IS NULL
177
+ THEN $3 ELSE e.resolver_payload END,
167
178
  updated_at = NOW()
168
179
  FROM target
169
180
  WHERE e.id = target.id
170
181
  AND target.signal_key IS NULL
171
182
  AND ($7::text[] IS NULL OR NOT (target.role = ANY($7)))
172
183
  RETURNING e.*
173
- ),
174
- resolved AS (
175
- UPDATE public.hmsh_escalations e
176
- SET status = 'resolved',
177
- resolved_at = NOW(),
178
- resolver_payload = $3,
179
- updated_at = NOW()
180
- FROM claimed
181
- WHERE e.id = claimed.id
182
- AND (claimed.metadata->>'signal_id') IS NULL
183
- RETURNING e.*
184
184
  )
185
185
  SELECT
186
- resolved.*,
186
+ written.*,
187
187
  target.id AS target_id,
188
188
  target.role AS target_role,
189
189
  target.metadata AS target_metadata,
@@ -198,12 +198,12 @@ SELECT
198
198
  AND target.assigned_until IS NOT NULL
199
199
  AND target.assigned_until > NOW()) AS signal_already_claimed,
200
200
  CASE
201
- WHEN resolved.id IS NOT NULL THEN 'resolved'
201
+ WHEN written.status = 'resolved' THEN 'resolved'
202
202
  WHEN $7::text[] IS NOT NULL AND target.role = ANY($7) THEN 'validation_required'
203
203
  ELSE 'signal_required'
204
204
  END AS outcome
205
205
  FROM target
206
- LEFT JOIN resolved ON resolved.id = target.id`;
206
+ LEFT JOIN written ON written.id = target.id`;
207
207
  // ---------------------------------------------------------------------------
208
208
  // Station metrics — split into two queries with very different cost profiles.
209
209
  //
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Server-side enforcement of the `x-lt-submit-guard` query precondition — the
3
+ * API-first counterpart of the dashboard's `useSubmitGuard`. Before an
4
+ * escalation resolves, if its form schema declares a submit guard, the same
5
+ * embedded query runs and the resolve is REJECTED while it still returns rows.
6
+ *
7
+ * Isomorphism with the dashboard is exact: the guard reuses `resolveScopedQuery`
8
+ * (the mapping the escalation-list embed uses) and runs it through
9
+ * `searchEscalationsFaceted` — the same faceted query the list API composes.
10
+ *
11
+ * Two deliberate rules:
12
+ * - The count is taken with `global: true`, bypassing the resolver's read
13
+ * scope, so a role that cannot SEE the children can never falsely clear the
14
+ * gate. Only a real, empty result count clears it (the "403 ≠ empty" rule).
15
+ * - A guard whose scope cannot be evaluated (e.g. `assigned:'me'` on a surface
16
+ * with no resolving user, like an MCP resolve) is skipped here; the consuming
17
+ * workflow's own verification remains the durable backstop.
18
+ */
19
+ import { type ShowIfContext } from '../../shared/form-validation';
20
+ import type { LTFieldViolation } from '../../types/validation';
21
+ /** The synthetic violation field for a guard rejection — not a form field. */
22
+ export declare const SUBMIT_GUARD_VIOLATION_FIELD = "_submitGuard";
23
+ /**
24
+ * Returns a violation when the escalation's submit guard still matches rows, or
25
+ * null when there is no guard, its scope is inert, or the query is confirmed
26
+ * empty. The context carries the escalation domains the query facets and the
27
+ * message interpolate against.
28
+ */
29
+ export declare function checkSubmitGuard(schema: Record<string, any> | null | undefined, ctx: ShowIfContext, resolvingUserId: string | undefined): Promise<LTFieldViolation | null>;
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SUBMIT_GUARD_VIOLATION_FIELD = void 0;
4
+ exports.checkSubmitGuard = checkSubmitGuard;
5
+ /**
6
+ * Server-side enforcement of the `x-lt-submit-guard` query precondition — the
7
+ * API-first counterpart of the dashboard's `useSubmitGuard`. Before an
8
+ * escalation resolves, if its form schema declares a submit guard, the same
9
+ * embedded query runs and the resolve is REJECTED while it still returns rows.
10
+ *
11
+ * Isomorphism with the dashboard is exact: the guard reuses `resolveScopedQuery`
12
+ * (the mapping the escalation-list embed uses) and runs it through
13
+ * `searchEscalationsFaceted` — the same faceted query the list API composes.
14
+ *
15
+ * Two deliberate rules:
16
+ * - The count is taken with `global: true`, bypassing the resolver's read
17
+ * scope, so a role that cannot SEE the children can never falsely clear the
18
+ * gate. Only a real, empty result count clears it (the "403 ≠ empty" rule).
19
+ * - A guard whose scope cannot be evaluated (e.g. `assigned:'me'` on a surface
20
+ * with no resolving user, like an MCP resolve) is skipped here; the consuming
21
+ * workflow's own verification remains the durable backstop.
22
+ */
23
+ const form_validation_1 = require("../../shared/form-validation");
24
+ const queries_1 = require("./queries");
25
+ /** The synthetic violation field for a guard rejection — not a form field. */
26
+ exports.SUBMIT_GUARD_VIOLATION_FIELD = '_submitGuard';
27
+ /**
28
+ * Returns a violation when the escalation's submit guard still matches rows, or
29
+ * null when there is no guard, its scope is inert, or the query is confirmed
30
+ * empty. The context carries the escalation domains the query facets and the
31
+ * message interpolate against.
32
+ */
33
+ async function checkSubmitGuard(schema, ctx, resolvingUserId) {
34
+ const guard = (0, form_validation_1.readSubmitGuard)(schema);
35
+ if (!guard || guard.mustBeEmpty === false)
36
+ return null;
37
+ const scoped = (0, form_validation_1.resolveScopedQuery)(guard.query, ctx, resolvingUserId);
38
+ if (!scoped.enabled)
39
+ return null;
40
+ const { total } = await (0, queries_1.searchEscalationsFaceted)({
41
+ global: true,
42
+ facet: {
43
+ role: scoped.role,
44
+ status: scoped.status,
45
+ available: scoped.available,
46
+ facets: scoped.facets,
47
+ },
48
+ assigned_to: scoped.assigned_to,
49
+ limit: 1,
50
+ offset: 0,
51
+ });
52
+ if (total <= 0)
53
+ return null;
54
+ const template = guard.message ?? form_validation_1.SUBMIT_GUARD_DEFAULT_MESSAGE;
55
+ const message = (0, form_validation_1.interpolateHelp)(template.replace(/\{\{count\}\}/g, String(total)), ctx);
56
+ return { field: exports.SUBMIT_GUARD_VIOLATION_FIELD, message };
57
+ }
@@ -0,0 +1,4 @@
1
+ export { listScanSchemes, getScanScheme, listScanRules, getScanRule, } from './read';
2
+ export { upsertScanScheme, deleteScanScheme, upsertScanRule, deleteScanRule, seedScanScheme, seedScanRule, type ScanSchemeInput, type ScanRuleInput, } from './write';
3
+ export { parseScanCode, interpolateScanTemplate, type ScanParseResult, type ScanParseFailure, type ScanTemplateContext, } from './parse';
4
+ export { assertValidScheme, assertValidSteps } from './validate';
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.assertValidSteps = exports.assertValidScheme = exports.interpolateScanTemplate = exports.parseScanCode = exports.seedScanRule = exports.seedScanScheme = exports.deleteScanRule = exports.upsertScanRule = exports.deleteScanScheme = exports.upsertScanScheme = exports.getScanRule = exports.listScanRules = exports.getScanScheme = exports.listScanSchemes = void 0;
4
+ var read_1 = require("./read");
5
+ Object.defineProperty(exports, "listScanSchemes", { enumerable: true, get: function () { return read_1.listScanSchemes; } });
6
+ Object.defineProperty(exports, "getScanScheme", { enumerable: true, get: function () { return read_1.getScanScheme; } });
7
+ Object.defineProperty(exports, "listScanRules", { enumerable: true, get: function () { return read_1.listScanRules; } });
8
+ Object.defineProperty(exports, "getScanRule", { enumerable: true, get: function () { return read_1.getScanRule; } });
9
+ var write_1 = require("./write");
10
+ Object.defineProperty(exports, "upsertScanScheme", { enumerable: true, get: function () { return write_1.upsertScanScheme; } });
11
+ Object.defineProperty(exports, "deleteScanScheme", { enumerable: true, get: function () { return write_1.deleteScanScheme; } });
12
+ Object.defineProperty(exports, "upsertScanRule", { enumerable: true, get: function () { return write_1.upsertScanRule; } });
13
+ Object.defineProperty(exports, "deleteScanRule", { enumerable: true, get: function () { return write_1.deleteScanRule; } });
14
+ Object.defineProperty(exports, "seedScanScheme", { enumerable: true, get: function () { return write_1.seedScanScheme; } });
15
+ Object.defineProperty(exports, "seedScanRule", { enumerable: true, get: function () { return write_1.seedScanRule; } });
16
+ var parse_1 = require("./parse");
17
+ Object.defineProperty(exports, "parseScanCode", { enumerable: true, get: function () { return parse_1.parseScanCode; } });
18
+ Object.defineProperty(exports, "interpolateScanTemplate", { enumerable: true, get: function () { return parse_1.interpolateScanTemplate; } });
19
+ var validate_1 = require("./validate");
20
+ Object.defineProperty(exports, "assertValidScheme", { enumerable: true, get: function () { return validate_1.assertValidScheme; } });
21
+ Object.defineProperty(exports, "assertValidSteps", { enumerable: true, get: function () { return validate_1.assertValidSteps; } });
@@ -0,0 +1,35 @@
1
+ import { type ParsedScanCode, type ScanScheme } from '../../types';
2
+ export interface ScanParseFailure {
3
+ /** Why the code did not parse. */
4
+ reason: 'empty' | 'unknown_version' | 'scheme_disabled' | 'malformed';
5
+ detail: string;
6
+ }
7
+ export type ScanParseResult = {
8
+ ok: true;
9
+ parsed: ParsedScanCode;
10
+ scheme: ScanScheme;
11
+ } | {
12
+ ok: false;
13
+ failure: ScanParseFailure;
14
+ };
15
+ /**
16
+ * Parse a raw scan string against the configured schemes. Pure — no I/O.
17
+ *
18
+ * The leading TWO digits pick the scheme (10-99, so a code never starts with a
19
+ * leading zero); the scheme then defines how the remainder splits into a
20
+ * single-digit category (0-9) and the target:
21
+ * - delimited: `10:1:ABC-123` (delimiter from the scheme row)
22
+ * - fixed: `1017554332` (one category digit, then target_length digits)
23
+ */
24
+ export declare function parseScanCode(raw: string, schemes: ScanScheme[]): ScanParseResult;
25
+ export interface ScanTemplateContext {
26
+ target: string;
27
+ category: string;
28
+ scannedAt: string;
29
+ }
30
+ /**
31
+ * Replace SCAN_TEMPLATE_TOKENS inside string values of a params object.
32
+ * Deep, pure, non-mutating. Only exact-token and in-string replacement of
33
+ * the three known tokens — no expression language.
34
+ */
35
+ export declare function interpolateScanTemplate<T>(value: T, ctx: ScanTemplateContext): T;
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseScanCode = parseScanCode;
4
+ exports.interpolateScanTemplate = interpolateScanTemplate;
5
+ const types_1 = require("../../types");
6
+ /**
7
+ * Parse a raw scan string against the configured schemes. Pure — no I/O.
8
+ *
9
+ * The leading TWO digits pick the scheme (10-99, so a code never starts with a
10
+ * leading zero); the scheme then defines how the remainder splits into a
11
+ * single-digit category (0-9) and the target:
12
+ * - delimited: `10:1:ABC-123` (delimiter from the scheme row)
13
+ * - fixed: `1017554332` (one category digit, then target_length digits)
14
+ */
15
+ function parseScanCode(raw, schemes) {
16
+ const code = raw.trim();
17
+ if (!code) {
18
+ return { ok: false, failure: { reason: 'empty', detail: 'empty scan code' } };
19
+ }
20
+ const versionToken = code.slice(0, 2);
21
+ const version = Number(versionToken);
22
+ if (!/^[0-9]{2}$/.test(versionToken) || version < 10 || version > 99) {
23
+ return {
24
+ ok: false,
25
+ failure: { reason: 'unknown_version', detail: `code must start with a two-digit scheme 10-99, got "${versionToken}"` },
26
+ };
27
+ }
28
+ const scheme = schemes.find((s) => s.version === version);
29
+ if (!scheme) {
30
+ return {
31
+ ok: false,
32
+ failure: { reason: 'unknown_version', detail: `no scan scheme configured for version ${version}` },
33
+ };
34
+ }
35
+ if (!scheme.enabled) {
36
+ return {
37
+ ok: false,
38
+ failure: { reason: 'scheme_disabled', detail: `scan scheme ${version} ("${scheme.name}") is disabled` },
39
+ };
40
+ }
41
+ if (scheme.encoding === types_1.SCAN_ENCODINGS.DELIMITED) {
42
+ return parseDelimited(code, version, scheme);
43
+ }
44
+ return parseFixed(code, version, scheme);
45
+ }
46
+ function parseDelimited(code, version, scheme) {
47
+ const d = scheme.delimiter;
48
+ // version(2 digits) <d> category(1 digit) <d> target(rest, non-empty)
49
+ if (code[2] !== d) {
50
+ return malformed(scheme, `expected "${d}" after the two-digit scheme`);
51
+ }
52
+ const category = code.slice(3, 4);
53
+ if (!/^[0-9]$/.test(category)) {
54
+ return malformed(scheme, 'category must be a single digit');
55
+ }
56
+ if (code[4] !== d) {
57
+ return malformed(scheme, `expected "${d}" after the category`);
58
+ }
59
+ const target = code.slice(5);
60
+ if (!target) {
61
+ return malformed(scheme, 'target is empty');
62
+ }
63
+ return { ok: true, parsed: { version, category, target }, scheme };
64
+ }
65
+ function parseFixed(code, version, scheme) {
66
+ const targetLength = scheme.target_length ?? 0;
67
+ const expected = 2 + 1 + targetLength;
68
+ // UPC-A wedges deliver the trailing check digit too; accept it as slack.
69
+ if (!/^[0-9]+$/.test(code)) {
70
+ return malformed(scheme, 'fixed encoding accepts digits only');
71
+ }
72
+ if (code.length !== expected && code.length !== expected + 1) {
73
+ return malformed(scheme, `expected ${expected} digits (or ${expected + 1} with check digit), got ${code.length}`);
74
+ }
75
+ const category = code.slice(2, 3);
76
+ const target = code.slice(3, 3 + targetLength);
77
+ return { ok: true, parsed: { version, category, target }, scheme };
78
+ }
79
+ function malformed(scheme, detail) {
80
+ return {
81
+ ok: false,
82
+ failure: { reason: 'malformed', detail: `scheme ${scheme.version} ("${scheme.name}"): ${detail}` },
83
+ };
84
+ }
85
+ /**
86
+ * Replace SCAN_TEMPLATE_TOKENS inside string values of a params object.
87
+ * Deep, pure, non-mutating. Only exact-token and in-string replacement of
88
+ * the three known tokens — no expression language.
89
+ */
90
+ function interpolateScanTemplate(value, ctx) {
91
+ if (typeof value === 'string') {
92
+ return value
93
+ .split(types_1.SCAN_TEMPLATE_TOKENS.TARGET).join(ctx.target)
94
+ .split(types_1.SCAN_TEMPLATE_TOKENS.CATEGORY).join(ctx.category)
95
+ .split(types_1.SCAN_TEMPLATE_TOKENS.SCANNED_AT).join(ctx.scannedAt);
96
+ }
97
+ if (Array.isArray(value)) {
98
+ return value.map((v) => interpolateScanTemplate(v, ctx));
99
+ }
100
+ if (value && typeof value === 'object') {
101
+ const out = {};
102
+ for (const [k, v] of Object.entries(value)) {
103
+ out[k] = interpolateScanTemplate(v, ctx);
104
+ }
105
+ return out;
106
+ }
107
+ return value;
108
+ }
@@ -0,0 +1,5 @@
1
+ import type { ScanScheme, ScanRule } from '../../types';
2
+ export declare function listScanSchemes(): Promise<ScanScheme[]>;
3
+ export declare function getScanScheme(version: number): Promise<ScanScheme | null>;
4
+ export declare function listScanRules(schemeVersion: number): Promise<ScanRule[]>;
5
+ export declare function getScanRule(schemeVersion: number, category: string): Promise<ScanRule | null>;
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.listScanSchemes = listScanSchemes;
4
+ exports.getScanScheme = getScanScheme;
5
+ exports.listScanRules = listScanRules;
6
+ exports.getScanRule = getScanRule;
7
+ const db_1 = require("../../lib/db");
8
+ const sql_1 = require("./sql");
9
+ function mapScheme(row) {
10
+ return {
11
+ version: row.version,
12
+ name: row.name,
13
+ description: row.description ?? null,
14
+ target_facet: row.target_facet,
15
+ encoding: row.encoding,
16
+ delimiter: row.delimiter,
17
+ target_length: row.target_length ?? null,
18
+ enabled: row.enabled,
19
+ created_at: row.created_at,
20
+ updated_at: row.updated_at,
21
+ };
22
+ }
23
+ function mapRule(row) {
24
+ return {
25
+ scheme_version: row.scheme_version,
26
+ category: row.category,
27
+ name: row.name,
28
+ steps: row.steps ?? [],
29
+ fallback: row.fallback ?? {},
30
+ enabled: row.enabled,
31
+ created_at: row.created_at,
32
+ updated_at: row.updated_at,
33
+ };
34
+ }
35
+ async function listScanSchemes() {
36
+ const { rows } = await (0, db_1.getPool)().query(sql_1.LIST_SCHEMES);
37
+ return rows.map(mapScheme);
38
+ }
39
+ async function getScanScheme(version) {
40
+ const { rows } = await (0, db_1.getPool)().query(sql_1.GET_SCHEME, [version]);
41
+ return rows.length ? mapScheme(rows[0]) : null;
42
+ }
43
+ async function listScanRules(schemeVersion) {
44
+ const { rows } = await (0, db_1.getPool)().query(sql_1.LIST_ACTIONS, [schemeVersion]);
45
+ return rows.map(mapRule);
46
+ }
47
+ async function getScanRule(schemeVersion, category) {
48
+ const { rows } = await (0, db_1.getPool)().query(sql_1.GET_ACTION, [schemeVersion, category]);
49
+ return rows.length ? mapRule(rows[0]) : null;
50
+ }
@@ -0,0 +1,10 @@
1
+ export declare const LIST_SCHEMES = "SELECT * FROM lt_config_scan_schemes ORDER BY version";
2
+ export declare const GET_SCHEME = "SELECT * FROM lt_config_scan_schemes WHERE version = $1";
3
+ export declare const LIST_ACTIONS = "SELECT * FROM lt_config_scan_actions WHERE scheme_version = $1 ORDER BY category";
4
+ export declare const GET_ACTION = "SELECT * FROM lt_config_scan_actions WHERE scheme_version = $1 AND category = $2";
5
+ export declare const UPSERT_SCHEME = "INSERT INTO lt_config_scan_schemes\n (version, name, description, target_facet, encoding, delimiter, target_length, enabled)\nVALUES ($1, $2, $3, $4, $5, $6, $7, $8)\nON CONFLICT (version) DO UPDATE SET\n name = EXCLUDED.name,\n description = EXCLUDED.description,\n target_facet = EXCLUDED.target_facet,\n encoding = EXCLUDED.encoding,\n delimiter = EXCLUDED.delimiter,\n target_length = EXCLUDED.target_length,\n enabled = EXCLUDED.enabled\nRETURNING *";
6
+ export declare const DELETE_SCHEME = "DELETE FROM lt_config_scan_schemes WHERE version = $1";
7
+ export declare const UPSERT_ACTION = "INSERT INTO lt_config_scan_actions\n (scheme_version, category, name, steps, fallback, enabled)\nVALUES ($1, $2, $3, $4, $5, $6)\nON CONFLICT (scheme_version, category) DO UPDATE SET\n name = EXCLUDED.name,\n steps = EXCLUDED.steps,\n fallback = EXCLUDED.fallback,\n enabled = EXCLUDED.enabled\nRETURNING *";
8
+ export declare const DELETE_ACTION = "DELETE FROM lt_config_scan_actions WHERE scheme_version = $1 AND category = $2";
9
+ export declare const SEED_SCHEME = "INSERT INTO lt_config_scan_schemes\n (version, name, description, target_facet, encoding, delimiter, target_length, enabled)\nVALUES ($1, $2, $3, $4, $5, $6, $7, $8)\nON CONFLICT (version) DO NOTHING";
10
+ export declare const SEED_ACTION = "INSERT INTO lt_config_scan_actions\n (scheme_version, category, name, steps, fallback, enabled)\nVALUES ($1, $2, $3, $4, $5, $6)\nON CONFLICT (scheme_version, category) DO NOTHING";
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ // ------------------------------------------------------------------ //
3
+ // Read queries //
4
+ // ------------------------------------------------------------------ //
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.SEED_ACTION = exports.SEED_SCHEME = exports.DELETE_ACTION = exports.UPSERT_ACTION = exports.DELETE_SCHEME = exports.UPSERT_SCHEME = exports.GET_ACTION = exports.LIST_ACTIONS = exports.GET_SCHEME = exports.LIST_SCHEMES = void 0;
7
+ exports.LIST_SCHEMES = `\
8
+ SELECT * FROM lt_config_scan_schemes ORDER BY version`;
9
+ exports.GET_SCHEME = `\
10
+ SELECT * FROM lt_config_scan_schemes WHERE version = $1`;
11
+ exports.LIST_ACTIONS = `\
12
+ SELECT * FROM lt_config_scan_actions WHERE scheme_version = $1 ORDER BY category`;
13
+ exports.GET_ACTION = `\
14
+ SELECT * FROM lt_config_scan_actions WHERE scheme_version = $1 AND category = $2`;
15
+ // ------------------------------------------------------------------ //
16
+ // Write / upsert queries //
17
+ // ------------------------------------------------------------------ //
18
+ exports.UPSERT_SCHEME = `\
19
+ INSERT INTO lt_config_scan_schemes
20
+ (version, name, description, target_facet, encoding, delimiter, target_length, enabled)
21
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
22
+ ON CONFLICT (version) DO UPDATE SET
23
+ name = EXCLUDED.name,
24
+ description = EXCLUDED.description,
25
+ target_facet = EXCLUDED.target_facet,
26
+ encoding = EXCLUDED.encoding,
27
+ delimiter = EXCLUDED.delimiter,
28
+ target_length = EXCLUDED.target_length,
29
+ enabled = EXCLUDED.enabled
30
+ RETURNING *`;
31
+ exports.DELETE_SCHEME = `\
32
+ DELETE FROM lt_config_scan_schemes WHERE version = $1`;
33
+ exports.UPSERT_ACTION = `\
34
+ INSERT INTO lt_config_scan_actions
35
+ (scheme_version, category, name, steps, fallback, enabled)
36
+ VALUES ($1, $2, $3, $4, $5, $6)
37
+ ON CONFLICT (scheme_version, category) DO UPDATE SET
38
+ name = EXCLUDED.name,
39
+ steps = EXCLUDED.steps,
40
+ fallback = EXCLUDED.fallback,
41
+ enabled = EXCLUDED.enabled
42
+ RETURNING *`;
43
+ exports.DELETE_ACTION = `\
44
+ DELETE FROM lt_config_scan_actions WHERE scheme_version = $1 AND category = $2`;
45
+ // ------------------------------------------------------------------ //
46
+ // Seed (insert-if-absent — used at startup, DB is source of truth) //
47
+ // ------------------------------------------------------------------ //
48
+ exports.SEED_SCHEME = `\
49
+ INSERT INTO lt_config_scan_schemes
50
+ (version, name, description, target_facet, encoding, delimiter, target_length, enabled)
51
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
52
+ ON CONFLICT (version) DO NOTHING`;
53
+ exports.SEED_ACTION = `\
54
+ INSERT INTO lt_config_scan_actions
55
+ (scheme_version, category, name, steps, fallback, enabled)
56
+ VALUES ($1, $2, $3, $4, $5, $6)
57
+ ON CONFLICT (scheme_version, category) DO NOTHING`;