@hotmeshio/long-tail 0.10.13 → 0.11.0

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 (373) hide show
  1. package/README.md +2 -4
  2. package/build/api/escalations/analytics.d.ts +6 -0
  3. package/build/api/escalations/analytics.js +123 -0
  4. package/build/api/escalations/index.d.ts +1 -0
  5. package/build/api/escalations/index.js +4 -1
  6. package/build/api/escalations/metadata.js +1 -1
  7. package/build/api/escalations/resolve.js +4 -4
  8. package/build/api/roles.d.ts +4 -0
  9. package/build/api/roles.js +8 -0
  10. package/build/api/scan-codes/choice.d.ts +11 -0
  11. package/build/api/scan-codes/choice.js +136 -0
  12. package/build/api/scan-codes/context.d.ts +24 -0
  13. package/build/api/scan-codes/context.js +86 -0
  14. package/build/api/scan-codes/execute.d.ts +1 -0
  15. package/build/api/scan-codes/execute.js +49 -244
  16. package/build/api/scan-codes/identity.d.ts +18 -0
  17. package/build/api/scan-codes/identity.js +116 -0
  18. package/build/api/scan-codes/index.d.ts +2 -0
  19. package/build/api/scan-codes/index.js +6 -1
  20. package/build/api/scan-codes/locate.d.ts +14 -0
  21. package/build/api/scan-codes/locate.js +127 -0
  22. package/build/api/scan-codes/present.d.ts +9 -0
  23. package/build/api/scan-codes/present.js +59 -0
  24. package/build/api/scan-codes/verbs.d.ts +15 -0
  25. package/build/api/scan-codes/verbs.js +205 -0
  26. package/build/bin/ltc.js +33 -0
  27. package/build/lib/cli/commands/escalations.d.ts +31 -0
  28. package/build/lib/cli/commands/escalations.js +88 -0
  29. package/build/lib/db/schemas/028_role_entity_facet.sql +18 -0
  30. package/build/lib/db/schemas/029_scan_scheme_kind.sql +31 -0
  31. package/build/modules/config.d.ts +5 -0
  32. package/build/modules/config.js +12 -0
  33. package/build/routes/escalations/acting.d.ts +12 -0
  34. package/build/routes/escalations/acting.js +25 -0
  35. package/build/routes/escalations/analytics.d.ts +8 -0
  36. package/build/routes/escalations/analytics.js +63 -0
  37. package/build/routes/escalations/index.js +3 -0
  38. package/build/routes/escalations/resolve.js +8 -1
  39. package/build/routes/escalations/single.js +13 -4
  40. package/build/routes/roles.js +1 -1
  41. package/build/routes/scan-codes.js +28 -2
  42. package/build/scripts/ortho-populate.js +14 -0
  43. package/build/scripts/printer-cycle.d.ts +25 -0
  44. package/build/scripts/printer-cycle.js +169 -0
  45. package/build/scripts/twin-farm.js +19 -5
  46. package/build/sdk/index.d.ts +2 -0
  47. package/build/sdk/index.js +3 -0
  48. package/build/services/escalation/aggregate-sql.d.ts +36 -0
  49. package/build/services/escalation/aggregate-sql.js +253 -0
  50. package/build/services/escalation/aggregate-validate.d.ts +57 -0
  51. package/build/services/escalation/aggregate-validate.js +218 -0
  52. package/build/services/escalation/aggregates.d.ts +26 -0
  53. package/build/services/escalation/aggregates.js +204 -0
  54. package/build/services/escalation/client.js +57 -21
  55. package/build/services/escalation/facet-sql.js +17 -0
  56. package/build/services/escalation/index.d.ts +2 -0
  57. package/build/services/escalation/index.js +8 -1
  58. package/build/services/escalation/metrics-cache.d.ts +18 -0
  59. package/build/services/escalation/metrics-cache.js +47 -1
  60. package/build/services/escalation/queries.js +2 -0
  61. package/build/services/escalation/resolver-validation.d.ts +1 -1
  62. package/build/services/escalation/resolver-validation.js +12 -5
  63. package/build/services/escalation/submit-guard.d.ts +29 -0
  64. package/build/services/escalation/submit-guard.js +57 -0
  65. package/build/services/iam/acting-identity.d.ts +16 -0
  66. package/build/services/iam/acting-identity.js +60 -0
  67. package/build/services/role/index.js +2 -0
  68. package/build/services/role/sql.d.ts +10 -2
  69. package/build/services/role/sql.js +14 -1
  70. package/build/services/role/types.d.ts +16 -0
  71. package/build/services/scan-code/read.js +4 -0
  72. package/build/services/scan-code/sql.d.ts +4 -4
  73. package/build/services/scan-code/sql.js +14 -8
  74. package/build/services/scan-code/validate.d.ts +2 -0
  75. package/build/services/scan-code/validate.js +86 -0
  76. package/build/services/scan-code/write.d.ts +4 -0
  77. package/build/services/scan-code/write.js +16 -2
  78. package/build/services/user/crud.d.ts +6 -0
  79. package/build/services/user/crud.js +16 -0
  80. package/build/services/user/index.d.ts +1 -1
  81. package/build/services/user/index.js +2 -1
  82. package/build/services/user/sql.d.ts +8 -0
  83. package/build/services/user/sql.js +9 -1
  84. package/build/shared/form-validation/index.d.ts +4 -0
  85. package/build/shared/form-validation/index.js +4 -0
  86. package/build/shared/form-validation/x-lt-labels.d.ts +28 -0
  87. package/build/shared/form-validation/x-lt-labels.js +42 -0
  88. package/build/shared/form-validation/x-lt-query.d.ts +56 -0
  89. package/build/shared/form-validation/x-lt-query.js +49 -0
  90. package/build/shared/form-validation/x-lt-submit-guard.d.ts +46 -0
  91. package/build/shared/form-validation/x-lt-submit-guard.js +25 -0
  92. package/build/shared/form-validation/x-lt-submit-on-claim.d.ts +22 -0
  93. package/build/shared/form-validation/x-lt-submit-on-claim.js +28 -0
  94. package/build/system/mcp-servers/admin/escalations.js +34 -0
  95. package/build/system/mcp-servers/admin/scan-codes.js +17 -1
  96. package/build/system/mcp-servers/admin/schemas.d.ts +643 -25
  97. package/build/system/mcp-servers/admin/schemas.js +127 -19
  98. package/build/system/mcp-servers/admin/users.js +3 -1
  99. package/build/system/mcp-servers/human-queue-schemas.d.ts +2 -2
  100. package/build/system/seed/tool-manifests-admin.d.ts +2283 -0
  101. package/build/system/seed/tool-manifests-admin.js +8 -5
  102. package/build/tsconfig.tsbuildinfo +1 -1
  103. package/build/types/analytics.d.ts +154 -0
  104. package/build/types/analytics.js +14 -0
  105. package/build/types/facets.d.ts +13 -0
  106. package/build/types/index.d.ts +5 -2
  107. package/build/types/index.js +5 -1
  108. package/build/types/scan-choice.d.ts +49 -0
  109. package/build/types/scan-choice.js +9 -0
  110. package/build/types/scan-code.d.ts +72 -1
  111. package/build/types/scan-code.js +30 -1
  112. package/dashboard/dist/assets/{AdminDashboard-Bv3pHBzn.js → AdminDashboard-DJ3LJQ09.js} +2 -2
  113. package/dashboard/dist/assets/{AdminDashboard-Bv3pHBzn.js.map → AdminDashboard-DJ3LJQ09.js.map} +1 -1
  114. package/dashboard/dist/assets/{AgentConfigPage-Dk2zlvDb.js → AgentConfigPage-BMMvaD0z.js} +2 -2
  115. package/dashboard/dist/assets/{AgentConfigPage-Dk2zlvDb.js.map → AgentConfigPage-BMMvaD0z.js.map} +1 -1
  116. package/dashboard/dist/assets/{AgentDetailPage-DUno6EGs.js → AgentDetailPage-C6wfsnRe.js} +2 -2
  117. package/dashboard/dist/assets/{AgentDetailPage-DUno6EGs.js.map → AgentDetailPage-C6wfsnRe.js.map} +1 -1
  118. package/dashboard/dist/assets/AgentsPage-Cwqka7nE.js +2 -0
  119. package/dashboard/dist/assets/{AgentsPage-CToVu1qj.js.map → AgentsPage-Cwqka7nE.js.map} +1 -1
  120. package/dashboard/dist/assets/AvailableEscalationsPage-CVlG_AVC.js +2 -0
  121. package/dashboard/dist/assets/AvailableEscalationsPage-CVlG_AVC.js.map +1 -0
  122. package/dashboard/dist/assets/{BotPicker-DQOpVB4M.js → BotPicker-BBkJBXZB.js} +2 -2
  123. package/dashboard/dist/assets/{BotPicker-DQOpVB4M.js.map → BotPicker-BBkJBXZB.js.map} +1 -1
  124. package/dashboard/dist/assets/{CapabilitiesPage-Dmf46PUJ.js → CapabilitiesPage-wxmE4917.js} +2 -2
  125. package/dashboard/dist/assets/{CapabilitiesPage-Dmf46PUJ.js.map → CapabilitiesPage-wxmE4917.js.map} +1 -1
  126. package/dashboard/dist/assets/{CollapsibleSection-CDADefUY.js → CollapsibleSection-B3FsrHwH.js} +2 -2
  127. package/dashboard/dist/assets/{CollapsibleSection-CDADefUY.js.map → CollapsibleSection-B3FsrHwH.js.map} +1 -1
  128. package/dashboard/dist/assets/CountdownTimer-B3nCqJdC.js +2 -0
  129. package/dashboard/dist/assets/CountdownTimer-B3nCqJdC.js.map +1 -0
  130. package/dashboard/dist/assets/{CredentialsPage-8LIEvomi.js → CredentialsPage-Bv875IHe.js} +2 -2
  131. package/dashboard/dist/assets/{CredentialsPage-8LIEvomi.js.map → CredentialsPage-Bv875IHe.js.map} +1 -1
  132. package/dashboard/dist/assets/{CronLabel-CK3WSsM5.js → CronLabel-CSzjWuwj.js} +2 -2
  133. package/dashboard/dist/assets/{CronLabel-CK3WSsM5.js.map → CronLabel-CSzjWuwj.js.map} +1 -1
  134. package/dashboard/dist/assets/{CustomDurationPicker-FPmlA6cE.js → CustomDurationPicker-CCpqf3e4.js} +2 -2
  135. package/dashboard/dist/assets/{CustomDurationPicker-FPmlA6cE.js.map → CustomDurationPicker-CCpqf3e4.js.map} +1 -1
  136. package/dashboard/dist/assets/{DropZone-CL9gA7pu.js → DropZone-CJkk-U3o.js} +2 -2
  137. package/dashboard/dist/assets/{DropZone-CL9gA7pu.js.map → DropZone-CJkk-U3o.js.map} +1 -1
  138. package/dashboard/dist/assets/{ElapsedCell-BZVkVxE0.js → ElapsedCell-WV6pUaKo.js} +2 -2
  139. package/dashboard/dist/assets/{ElapsedCell-BZVkVxE0.js.map → ElapsedCell-WV6pUaKo.js.map} +1 -1
  140. package/dashboard/dist/assets/EntityTimelinePanel-DrL86Yrf.js +2 -0
  141. package/dashboard/dist/assets/EntityTimelinePanel-DrL86Yrf.js.map +1 -0
  142. package/dashboard/dist/assets/{EscalationListSchemaPage-kYLdUtZX.js → EscalationListSchemaPage-CTQCALw4.js} +3 -3
  143. package/dashboard/dist/assets/{EscalationListSchemaPage-kYLdUtZX.js.map → EscalationListSchemaPage-CTQCALw4.js.map} +1 -1
  144. package/dashboard/dist/assets/{EscalationSchemaPage-kUmCDivo.js → EscalationSchemaPage-D_UgP0pv.js} +3 -3
  145. package/dashboard/dist/assets/{EscalationSchemaPage-kUmCDivo.js.map → EscalationSchemaPage-D_UgP0pv.js.map} +1 -1
  146. package/dashboard/dist/assets/{EscalationsOverview-D17auO-m.js → EscalationsOverview-DuIUyxr0.js} +2 -2
  147. package/dashboard/dist/assets/{EscalationsOverview-D17auO-m.js.map → EscalationsOverview-DuIUyxr0.js.map} +1 -1
  148. package/dashboard/dist/assets/EventTable-BV6unphX.js +2 -0
  149. package/dashboard/dist/assets/EventTable-BV6unphX.js.map +1 -0
  150. package/dashboard/dist/assets/FilterBar-DYFgzXNB.js +2 -0
  151. package/dashboard/dist/assets/FilterBar-DYFgzXNB.js.map +1 -0
  152. package/dashboard/dist/assets/{GraphInvokePage-D11uOnZi.js → GraphInvokePage-BGHVUipJ.js} +2 -2
  153. package/dashboard/dist/assets/{GraphInvokePage-D11uOnZi.js.map → GraphInvokePage-BGHVUipJ.js.map} +1 -1
  154. package/dashboard/dist/assets/HomePage-B-S2cK3E.js +2 -0
  155. package/dashboard/dist/assets/{HomePage-Bcq10Bxx.js.map → HomePage-B-S2cK3E.js.map} +1 -1
  156. package/dashboard/dist/assets/ListToolbar-Bl7F3A28.js +2 -0
  157. package/dashboard/dist/assets/{ListToolbar-IPXsTb3Q.js.map → ListToolbar-Bl7F3A28.js.map} +1 -1
  158. package/dashboard/dist/assets/{McpOverview-Dx2j0KkF.js → McpOverview-_T9IsCD_.js} +2 -2
  159. package/dashboard/dist/assets/{McpOverview-Dx2j0KkF.js.map → McpOverview-_T9IsCD_.js.map} +1 -1
  160. package/dashboard/dist/assets/{McpQueryDetailPage-CzF_bna8.js → McpQueryDetailPage-DtsVqKPw.js} +2 -2
  161. package/dashboard/dist/assets/{McpQueryDetailPage-CzF_bna8.js.map → McpQueryDetailPage-DtsVqKPw.js.map} +1 -1
  162. package/dashboard/dist/assets/McpQueryPage-DX5u-1bx.js +2 -0
  163. package/dashboard/dist/assets/{McpQueryPage-CNsuiw_q.js.map → McpQueryPage-DX5u-1bx.js.map} +1 -1
  164. package/dashboard/dist/assets/McpRunDetailPage-BhcqqtYS.js +2 -0
  165. package/dashboard/dist/assets/McpRunDetailPage-BhcqqtYS.js.map +1 -0
  166. package/dashboard/dist/assets/{McpRunsPage-CK96s3Nt.js → McpRunsPage-L-1y8wnX.js} +2 -2
  167. package/dashboard/dist/assets/{McpRunsPage-CK96s3Nt.js.map → McpRunsPage-L-1y8wnX.js.map} +1 -1
  168. package/dashboard/dist/assets/{NamespacePill-B9Vc_Pz2.js → NamespacePill-in1SLd0W.js} +2 -2
  169. package/dashboard/dist/assets/{NamespacePill-B9Vc_Pz2.js.map → NamespacePill-in1SLd0W.js.map} +1 -1
  170. package/dashboard/dist/assets/OperationsPage-i8KcDpKo.js +3 -0
  171. package/dashboard/dist/assets/OperationsPage-i8KcDpKo.js.map +1 -0
  172. package/dashboard/dist/assets/OperatorDashboard-CIbDzOlh.js +2 -0
  173. package/dashboard/dist/assets/{OperatorDashboard-C-jE0IRA.js.map → OperatorDashboard-CIbDzOlh.js.map} +1 -1
  174. package/dashboard/dist/assets/{PageHeader-Ce4GcIYo.js → PageHeader-BJgWMZtw.js} +2 -2
  175. package/dashboard/dist/assets/{PageHeader-Ce4GcIYo.js.map → PageHeader-BJgWMZtw.js.map} +1 -1
  176. package/dashboard/dist/assets/{PageHeaderWithStats-Ck0KZvXD.js → PageHeaderWithStats-Ccio4vyG.js} +2 -2
  177. package/dashboard/dist/assets/{PageHeaderWithStats-Ck0KZvXD.js.map → PageHeaderWithStats-Ccio4vyG.js.map} +1 -1
  178. package/dashboard/dist/assets/{PersonaDetailPage-CJ6jqo7h.js → PersonaDetailPage-BOaf0TW1.js} +2 -2
  179. package/dashboard/dist/assets/{PersonaDetailPage-CJ6jqo7h.js.map → PersonaDetailPage-BOaf0TW1.js.map} +1 -1
  180. package/dashboard/dist/assets/{PersonasPage-D8hL3kL5.js → PersonasPage-DSdRb90f.js} +2 -2
  181. package/dashboard/dist/assets/{PersonasPage-D8hL3kL5.js.map → PersonasPage-DSdRb90f.js.map} +1 -1
  182. package/dashboard/dist/assets/{ProcessDetailPage-Vnx8Z5_y.js → ProcessDetailPage-DN9NqfeP.js} +2 -2
  183. package/dashboard/dist/assets/{ProcessDetailPage-Vnx8Z5_y.js.map → ProcessDetailPage-DN9NqfeP.js.map} +1 -1
  184. package/dashboard/dist/assets/{ProcessesListPage-DRYtvS3N.js → ProcessesListPage-CfQEWaD4.js} +2 -2
  185. package/dashboard/dist/assets/{ProcessesListPage-DRYtvS3N.js.map → ProcessesListPage-CfQEWaD4.js.map} +1 -1
  186. package/dashboard/dist/assets/RoleDetailPage-BC5HL7ls.js +8 -0
  187. package/dashboard/dist/assets/RoleDetailPage-BC5HL7ls.js.map +1 -0
  188. package/dashboard/dist/assets/{RolePill-CnuBPhPw.js → RolePill-BNAP-uK6.js} +2 -2
  189. package/dashboard/dist/assets/{RolePill-CnuBPhPw.js.map → RolePill-BNAP-uK6.js.map} +1 -1
  190. package/dashboard/dist/assets/RolesPage-DCnW0VmD.js +2 -0
  191. package/dashboard/dist/assets/RolesPage-DCnW0VmD.js.map +1 -0
  192. package/dashboard/dist/assets/RunAsSelector-twbuX7fB.js +2 -0
  193. package/dashboard/dist/assets/{RunAsSelector-CS3KQ-BF.js.map → RunAsSelector-twbuX7fB.js.map} +1 -1
  194. package/dashboard/dist/assets/ScanCodesPage-CPNg6K--.js +2 -0
  195. package/dashboard/dist/assets/ScanCodesPage-CPNg6K--.js.map +1 -0
  196. package/dashboard/dist/assets/ScanSchemeDetailPage-DyLmCamO.js +2 -0
  197. package/dashboard/dist/assets/ScanSchemeDetailPage-DyLmCamO.js.map +1 -0
  198. package/dashboard/dist/assets/ScanStationPage-DoZccU5B.js +2 -0
  199. package/dashboard/dist/assets/ScanStationPage-DoZccU5B.js.map +1 -0
  200. package/dashboard/dist/assets/{ScopeBadge-BUpYpS3x.js → ScopeBadge-BG7KkZ8Q.js} +2 -2
  201. package/dashboard/dist/assets/{ScopeBadge-BUpYpS3x.js.map → ScopeBadge-BG7KkZ8Q.js.map} +1 -1
  202. package/dashboard/dist/assets/SegmentedTabs-DXNzY05q.js +2 -0
  203. package/dashboard/dist/assets/SegmentedTabs-DXNzY05q.js.map +1 -0
  204. package/dashboard/dist/assets/StickyPagination-DIeYMPPd.js +2 -0
  205. package/dashboard/dist/assets/StickyPagination-DIeYMPPd.js.map +1 -0
  206. package/dashboard/dist/assets/{StreamMessageDetail-DyJyZwBl.js → StreamMessageDetail-gU4CUeQI.js} +2 -2
  207. package/dashboard/dist/assets/{StreamMessageDetail-DyJyZwBl.js.map → StreamMessageDetail-gU4CUeQI.js.map} +1 -1
  208. package/dashboard/dist/assets/{SwimlaneTimeline-BlzV74V5.js → SwimlaneTimeline-Br-nBA4l.js} +2 -2
  209. package/dashboard/dist/assets/{SwimlaneTimeline-BlzV74V5.js.map → SwimlaneTimeline-Br-nBA4l.js.map} +1 -1
  210. package/dashboard/dist/assets/{TagInput-BbZ25nNe.js → TagInput-CvM5n6ww.js} +2 -2
  211. package/dashboard/dist/assets/{TagInput-BbZ25nNe.js.map → TagInput-CvM5n6ww.js.map} +1 -1
  212. package/dashboard/dist/assets/{TaskDetailPage-B0p_Z4J_.js → TaskDetailPage-_9cr_R0u.js} +2 -2
  213. package/dashboard/dist/assets/{TaskDetailPage-B0p_Z4J_.js.map → TaskDetailPage-_9cr_R0u.js.map} +1 -1
  214. package/dashboard/dist/assets/{TaskQueuePill-D0QKBrN3.js → TaskQueuePill-D4JPHXOq.js} +2 -2
  215. package/dashboard/dist/assets/{TaskQueuePill-D0QKBrN3.js.map → TaskQueuePill-D4JPHXOq.js.map} +1 -1
  216. package/dashboard/dist/assets/{TasksListPage-CiGR2QiQ.js → TasksListPage-DVENC9Jp.js} +2 -2
  217. package/dashboard/dist/assets/{TasksListPage-CiGR2QiQ.js.map → TasksListPage-DVENC9Jp.js.map} +1 -1
  218. package/dashboard/dist/assets/{TimeAgo-D_DA9ucC.js → TimeAgo-C9yYnOui.js} +2 -2
  219. package/dashboard/dist/assets/{TimeAgo-D_DA9ucC.js.map → TimeAgo-C9yYnOui.js.map} +1 -1
  220. package/dashboard/dist/assets/{TimestampCell-C7rkC9nh.js → TimestampCell-DoB8cYgw.js} +2 -2
  221. package/dashboard/dist/assets/{TimestampCell-C7rkC9nh.js.map → TimestampCell-DoB8cYgw.js.map} +1 -1
  222. package/dashboard/dist/assets/{ToolPill-8xY9rkoc.js → ToolPill-BUjbC-Tj.js} +2 -2
  223. package/dashboard/dist/assets/{ToolPill-8xY9rkoc.js.map → ToolPill-BUjbC-Tj.js.map} +1 -1
  224. package/dashboard/dist/assets/{ToolTestPanel-E8efYGYs.js → ToolTestPanel-CBtsIP8K.js} +2 -2
  225. package/dashboard/dist/assets/{ToolTestPanel-E8efYGYs.js.map → ToolTestPanel-CBtsIP8K.js.map} +1 -1
  226. package/dashboard/dist/assets/{TopicDetailPage-B455XrRc.js → TopicDetailPage-mR4Jaz83.js} +4 -4
  227. package/dashboard/dist/assets/{TopicDetailPage-B455XrRc.js.map → TopicDetailPage-mR4Jaz83.js.map} +1 -1
  228. package/dashboard/dist/assets/TopicsPage-CP7HFxIC.js +2 -0
  229. package/dashboard/dist/assets/{TopicsPage-1VAc29Qw.js.map → TopicsPage-CP7HFxIC.js.map} +1 -1
  230. package/dashboard/dist/assets/{UserName-DikzjQHJ.js → UserName-BnLF6yhz.js} +2 -2
  231. package/dashboard/dist/assets/{UserName-DikzjQHJ.js.map → UserName-BnLF6yhz.js.map} +1 -1
  232. package/dashboard/dist/assets/WorkflowExecutionPage-xL956RZi.js +2 -0
  233. package/dashboard/dist/assets/WorkflowExecutionPage-xL956RZi.js.map +1 -0
  234. package/dashboard/dist/assets/{WorkflowPill-Da406nEj.js → WorkflowPill-tXU0-eXu.js} +2 -2
  235. package/dashboard/dist/assets/{WorkflowPill-Da406nEj.js.map → WorkflowPill-tXU0-eXu.js.map} +1 -1
  236. package/dashboard/dist/assets/WorkflowsDashboard-B-u7zFKM.js +2 -0
  237. package/dashboard/dist/assets/{WorkflowsDashboard-BMQd_0tW.js.map → WorkflowsDashboard-B-u7zFKM.js.map} +1 -1
  238. package/dashboard/dist/assets/{WorkflowsOverview-CdxjVifp.js → WorkflowsOverview-CqZVarK-.js} +2 -2
  239. package/dashboard/dist/assets/{WorkflowsOverview-CdxjVifp.js.map → WorkflowsOverview-CqZVarK-.js.map} +1 -1
  240. package/dashboard/dist/assets/{YamlWorkflowDetailPage-DNVffIXa.js → YamlWorkflowDetailPage-DiFLavW0.js} +10 -10
  241. package/dashboard/dist/assets/{YamlWorkflowDetailPage-DNVffIXa.js.map → YamlWorkflowDetailPage-DiFLavW0.js.map} +1 -1
  242. package/dashboard/dist/assets/{YamlWorkflowsPage-BGP8wuos.js → YamlWorkflowsPage-BuQM6uZA.js} +2 -2
  243. package/dashboard/dist/assets/{YamlWorkflowsPage-BGP8wuos.js.map → YamlWorkflowsPage-BuQM6uZA.js.map} +1 -1
  244. package/dashboard/dist/assets/{agents-BZJLIJ4h.js → agents-DU9GPovp.js} +2 -2
  245. package/dashboard/dist/assets/{agents-BZJLIJ4h.js.map → agents-DU9GPovp.js.map} +1 -1
  246. package/dashboard/dist/assets/{bots-ClLcDGJb.js → bots-Cy-Hmg7w.js} +2 -2
  247. package/dashboard/dist/assets/{bots-ClLcDGJb.js.map → bots-Cy-Hmg7w.js.map} +1 -1
  248. package/dashboard/dist/assets/capabilities-sSJJqrp-.js +2 -0
  249. package/dashboard/dist/assets/{capabilities-IaCcS7ge.js.map → capabilities-sSJJqrp-.js.map} +1 -1
  250. package/dashboard/dist/assets/{controlplane-Zi4m_MSx.js → controlplane-TVCjDHQ-.js} +2 -2
  251. package/dashboard/dist/assets/{controlplane-Zi4m_MSx.js.map → controlplane-TVCjDHQ-.js.map} +1 -1
  252. package/dashboard/dist/assets/escalation-columns-BpkjKYGd.js +2 -0
  253. package/dashboard/dist/assets/escalation-columns-BpkjKYGd.js.map +1 -0
  254. package/dashboard/dist/assets/index-5TblaCXQ.css +1 -0
  255. package/dashboard/dist/assets/index-7BP6FaCZ.js +2 -0
  256. package/dashboard/dist/assets/{index-Dldi3Q3M.js.map → index-7BP6FaCZ.js.map} +1 -1
  257. package/dashboard/dist/assets/{index-BzkE48xJ.js → index-B7IaBPBg.js} +4 -4
  258. package/dashboard/dist/assets/{index-BzkE48xJ.js.map → index-B7IaBPBg.js.map} +1 -1
  259. package/dashboard/dist/assets/index-BE0phFw0.js +2 -0
  260. package/dashboard/dist/assets/{index-CLmZaNTK.js.map → index-BE0phFw0.js.map} +1 -1
  261. package/dashboard/dist/assets/{index-BqGnhkh0.js → index-BYNN9N1T.js} +2 -2
  262. package/dashboard/dist/assets/{index-BqGnhkh0.js.map → index-BYNN9N1T.js.map} +1 -1
  263. package/dashboard/dist/assets/{index-kiKZresb.js → index-CLPVqbVY.js} +2 -2
  264. package/dashboard/dist/assets/{index-kiKZresb.js.map → index-CLPVqbVY.js.map} +1 -1
  265. package/dashboard/dist/assets/{index-C3o4OisO.js → index-Cfv86_L9.js} +2 -2
  266. package/dashboard/dist/assets/{index-C3o4OisO.js.map → index-Cfv86_L9.js.map} +1 -1
  267. package/dashboard/dist/assets/{index-yGNt29V9.js → index-CtwbQ_-m.js} +2 -2
  268. package/dashboard/dist/assets/{index-yGNt29V9.js.map → index-CtwbQ_-m.js.map} +1 -1
  269. package/dashboard/dist/assets/index-DOai950R.js +3 -0
  270. package/dashboard/dist/assets/index-DOai950R.js.map +1 -0
  271. package/dashboard/dist/assets/index-DTtHNC-D.js +5 -0
  272. package/dashboard/dist/assets/{index-CvNBdkB1.js.map → index-DTtHNC-D.js.map} +1 -1
  273. package/dashboard/dist/assets/{index-CJu2PBNx.js → index-DsWnVyVN.js} +2 -2
  274. package/dashboard/dist/assets/{index-CJu2PBNx.js.map → index-DsWnVyVN.js.map} +1 -1
  275. package/dashboard/dist/assets/{index-D0zFReGL.js → index-Dy-MMYti.js} +2 -2
  276. package/dashboard/dist/assets/{index-D0zFReGL.js.map → index-Dy-MMYti.js.map} +1 -1
  277. package/dashboard/dist/assets/index-errgQT5x.js +65 -0
  278. package/dashboard/dist/assets/index-errgQT5x.js.map +1 -0
  279. package/dashboard/dist/assets/{index-CmnNqpWg.js → index-fgBDhnI6.js} +2 -2
  280. package/dashboard/dist/assets/{index-CmnNqpWg.js.map → index-fgBDhnI6.js.map} +1 -1
  281. package/dashboard/dist/assets/{knowledge-DWLxGTib.js → knowledge-arh4NfmL.js} +2 -2
  282. package/dashboard/dist/assets/{knowledge-DWLxGTib.js.map → knowledge-arh4NfmL.js.map} +1 -1
  283. package/dashboard/dist/assets/{mcp-B6AARZ2I.js → mcp-QGf5jHCo.js} +2 -2
  284. package/dashboard/dist/assets/{mcp-B6AARZ2I.js.map → mcp-QGf5jHCo.js.map} +1 -1
  285. package/dashboard/dist/assets/{mcp-query-DrkvBU3a.js → mcp-query-BEJN1nMZ.js} +2 -2
  286. package/dashboard/dist/assets/{mcp-query-DrkvBU3a.js.map → mcp-query-BEJN1nMZ.js.map} +1 -1
  287. package/dashboard/dist/assets/{personas-Cmz2SAEU.js → personas-DYtw1COf.js} +2 -2
  288. package/dashboard/dist/assets/{personas-Cmz2SAEU.js.map → personas-DYtw1COf.js.map} +1 -1
  289. package/dashboard/dist/assets/{pipelines-CSgfVCMy.js → pipelines-Byi6PnbE.js} +2 -2
  290. package/dashboard/dist/assets/{pipelines-CSgfVCMy.js.map → pipelines-Byi6PnbE.js.map} +1 -1
  291. package/dashboard/dist/assets/{tasks-UOtUkDk-.js → tasks-D0SQdENz.js} +2 -2
  292. package/dashboard/dist/assets/{tasks-UOtUkDk-.js.map → tasks-D0SQdENz.js.map} +1 -1
  293. package/dashboard/dist/assets/{topics-Df5hGh6o.js → topics-DgDv5ZXP.js} +2 -2
  294. package/dashboard/dist/assets/{topics-Df5hGh6o.js.map → topics-DgDv5ZXP.js.map} +1 -1
  295. package/dashboard/dist/assets/useEventHooks-DZaYzE7s.js +2 -0
  296. package/dashboard/dist/assets/{useEventHooks-PDbuSJ12.js.map → useEventHooks-DZaYzE7s.js.map} +1 -1
  297. package/dashboard/dist/assets/{useNamespace-tZSOlge3.js → useNamespace-C1OqiNXN.js} +2 -2
  298. package/dashboard/dist/assets/{useNamespace-tZSOlge3.js.map → useNamespace-C1OqiNXN.js.map} +1 -1
  299. package/dashboard/dist/assets/{useYamlActivityEvents-CINLzE32.js → useYamlActivityEvents-CkmXDm-Z.js} +2 -2
  300. package/dashboard/dist/assets/{useYamlActivityEvents-CINLzE32.js.map → useYamlActivityEvents-CkmXDm-Z.js.map} +1 -1
  301. package/dashboard/dist/assets/{users-G8qwyZKS.js → users-D4DCFPH1.js} +2 -2
  302. package/dashboard/dist/assets/{users-G8qwyZKS.js.map → users-D4DCFPH1.js.map} +1 -1
  303. package/dashboard/dist/assets/{vendor-icons-BpZiWH2f.js → vendor-icons-BxuyFxH2.js} +156 -136
  304. package/dashboard/dist/assets/vendor-icons-BxuyFxH2.js.map +1 -0
  305. package/dashboard/dist/assets/{workflows-DbPqi1TW.js → workflows-qyc0ku_5.js} +2 -2
  306. package/dashboard/dist/assets/{workflows-DbPqi1TW.js.map → workflows-qyc0ku_5.js.map} +1 -1
  307. package/dashboard/dist/assets/{yaml-workflows-DozD8hpR.js → yaml-workflows-DWFww9Xn.js} +2 -2
  308. package/dashboard/dist/assets/{yaml-workflows-DozD8hpR.js.map → yaml-workflows-DWFww9Xn.js.map} +1 -1
  309. package/dashboard/dist/index.html +3 -3
  310. package/docs/api/http/escalations.md +133 -0
  311. package/docs/api/http/roles.md +6 -0
  312. package/docs/api/mcp/admin.md +53 -0
  313. package/docs/api/sdk/escalations.md +58 -0
  314. package/docs/cli.md +11 -0
  315. package/docs/dashboard.md +22 -20
  316. package/docs/data.md +12 -4
  317. package/docs/design-principles.md +9 -7
  318. package/docs/escalation-analytics.md +251 -0
  319. package/docs/hitl/roles.md +1 -1
  320. package/docs/hitl/x-lt-embed.md +8 -4
  321. package/docs/hitl/x-lt-footer.md +67 -0
  322. package/docs/hitl/x-lt-list-schema.md +10 -3
  323. package/docs/hitl-guide.md +11 -2
  324. package/docs/iam.md +12 -0
  325. package/docs/operations.md +17 -0
  326. package/docs/scan-codes.md +112 -0
  327. package/docs/sdk.md +1 -1
  328. package/package.json +2 -1
  329. package/dashboard/dist/assets/AgentsPage-CToVu1qj.js +0 -2
  330. package/dashboard/dist/assets/AvailableEscalationsPage-DldboL4W.js +0 -2
  331. package/dashboard/dist/assets/AvailableEscalationsPage-DldboL4W.js.map +0 -1
  332. package/dashboard/dist/assets/CountdownTimer-DPjIkerB.js +0 -2
  333. package/dashboard/dist/assets/CountdownTimer-DPjIkerB.js.map +0 -1
  334. package/dashboard/dist/assets/EventTable-CwPWl163.js +0 -2
  335. package/dashboard/dist/assets/EventTable-CwPWl163.js.map +0 -1
  336. package/dashboard/dist/assets/FilterBar-D7GghUsU.js +0 -2
  337. package/dashboard/dist/assets/FilterBar-D7GghUsU.js.map +0 -1
  338. package/dashboard/dist/assets/HomePage-Bcq10Bxx.js +0 -2
  339. package/dashboard/dist/assets/ListToolbar-IPXsTb3Q.js +0 -2
  340. package/dashboard/dist/assets/McpQueryPage-CNsuiw_q.js +0 -2
  341. package/dashboard/dist/assets/McpRunDetailPage-BJguEMS0.js +0 -2
  342. package/dashboard/dist/assets/McpRunDetailPage-BJguEMS0.js.map +0 -1
  343. package/dashboard/dist/assets/OperationsPage-DvWrLuH6.js +0 -2
  344. package/dashboard/dist/assets/OperationsPage-DvWrLuH6.js.map +0 -1
  345. package/dashboard/dist/assets/OperatorDashboard-C-jE0IRA.js +0 -2
  346. package/dashboard/dist/assets/RoleDetailPage-BKkUvTO-.js +0 -8
  347. package/dashboard/dist/assets/RoleDetailPage-BKkUvTO-.js.map +0 -1
  348. package/dashboard/dist/assets/RolesPage-BHzWK9n6.js +0 -2
  349. package/dashboard/dist/assets/RolesPage-BHzWK9n6.js.map +0 -1
  350. package/dashboard/dist/assets/RunAsSelector-CS3KQ-BF.js +0 -2
  351. package/dashboard/dist/assets/ScanCodesPage-BW4P4zWf.js +0 -2
  352. package/dashboard/dist/assets/ScanCodesPage-BW4P4zWf.js.map +0 -1
  353. package/dashboard/dist/assets/ScanSchemeDetailPage-BLykA4j-.js +0 -2
  354. package/dashboard/dist/assets/ScanSchemeDetailPage-BLykA4j-.js.map +0 -1
  355. package/dashboard/dist/assets/StickyPagination-hMrnLXde.js +0 -2
  356. package/dashboard/dist/assets/StickyPagination-hMrnLXde.js.map +0 -1
  357. package/dashboard/dist/assets/TopicsPage-1VAc29Qw.js +0 -2
  358. package/dashboard/dist/assets/WorkflowExecutionPage-C15GSAoe.js +0 -2
  359. package/dashboard/dist/assets/WorkflowExecutionPage-C15GSAoe.js.map +0 -1
  360. package/dashboard/dist/assets/WorkflowsDashboard-BMQd_0tW.js +0 -2
  361. package/dashboard/dist/assets/capabilities-IaCcS7ge.js +0 -2
  362. package/dashboard/dist/assets/escalation-columns-BY2mg9DY.js +0 -2
  363. package/dashboard/dist/assets/escalation-columns-BY2mg9DY.js.map +0 -1
  364. package/dashboard/dist/assets/index-CLmZaNTK.js +0 -2
  365. package/dashboard/dist/assets/index-CfAi1OsI.js +0 -65
  366. package/dashboard/dist/assets/index-CfAi1OsI.js.map +0 -1
  367. package/dashboard/dist/assets/index-CvNBdkB1.js +0 -5
  368. package/dashboard/dist/assets/index-Dldi3Q3M.js +0 -2
  369. package/dashboard/dist/assets/index-mKcQGi2B.js +0 -3
  370. package/dashboard/dist/assets/index-mKcQGi2B.js.map +0 -1
  371. package/dashboard/dist/assets/index-zQiUPfxA.css +0 -1
  372. package/dashboard/dist/assets/useEventHooks-PDbuSJ12.js +0 -2
  373. package/dashboard/dist/assets/vendor-icons-BpZiWH2f.js.map +0 -1
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.resolveActingAuth = resolveActingAuth;
37
+ const userService = __importStar(require("../user"));
38
+ const ephemeral_1 = require("./ephemeral");
39
+ const types_1 = require("../../types");
40
+ /**
41
+ * Exchange a supplied acting grant for the person it names. A supplied token
42
+ * that fails — wrong label, expired, exhausted, or a vanished user — is a
43
+ * terminal error, never a silent fall-back to the session identity: that
44
+ * would misattribute whatever follows.
45
+ */
46
+ async function resolveActingAuth(actingToken) {
47
+ const parsed = (0, ephemeral_1.parseEphemeralToken)(actingToken);
48
+ if (!parsed || parsed.label !== types_1.ACTING_IDENTITY_LABEL) {
49
+ return { ok: false, error: 'actingToken is not an acting-identity grant' };
50
+ }
51
+ const userId = await (0, ephemeral_1.exchangeEphemeralToken)(actingToken);
52
+ if (!userId) {
53
+ return { ok: false, error: 'acting identity expired — scan your badge again' };
54
+ }
55
+ const user = await userService.getUser(userId);
56
+ if (!user || user.status !== 'active') {
57
+ return { ok: false, error: 'acting identity is no longer an active user' };
58
+ }
59
+ return { ok: true, auth: { userId: user.id } };
60
+ }
@@ -150,6 +150,8 @@ async function updateRoleMetadata(role, input) {
150
150
  provided('default_pins'), input.default_pins != null ? JSON.stringify(input.default_pins) : null,
151
151
  provided('enforce_schema'), input.enforce_schema ?? null,
152
152
  provided('ops_home_default'), input.ops_home_default ?? null,
153
+ provided('entity_facet'), input.entity_facet ?? null,
154
+ provided('entity_state_source'), input.entity_state_source ?? null,
153
155
  ]);
154
156
  if (!rows[0])
155
157
  return null;
@@ -50,8 +50,16 @@ export declare const DELETE_ROLE = "\n DELETE FROM lt_roles WHERE role = $1";
50
50
  * ops_home_default ($35 = provided sentinel, $36 = value) is single-holder:
51
51
  * setting it true clears the flag on every other role in the same statement
52
52
  * (the home_clear CTE touches only OTHER rows, so the two UPDATEs never meet).
53
+ *
54
+ * entity_facet ($37 = provided sentinel, $38 = value) is unversioned config:
55
+ * the metadata key naming the entity that moves through this role (powers the
56
+ * analytics surfaces — entity counts, per-entity dwell, timelines).
57
+ *
58
+ * entity_state_source ($39 = provided sentinel, $40 = value) is unversioned
59
+ * config: 'role' | 'subtype' — how this role names its contribution to the
60
+ * entity's state space (the station itself, or its subtypes).
53
61
  */
54
- export declare const UPDATE_ROLE_METADATA = "\n WITH home_clear AS (\n UPDATE lt_roles SET ops_home_default = false\n WHERE $35::boolean AND COALESCE($36::boolean, false) AND role <> $1 AND ops_home_default\n ), updated AS (\n UPDATE lt_roles SET\n title = CASE WHEN $2::boolean THEN $3 ELSE title END,\n description = CASE WHEN $4::boolean THEN $5 ELSE description END,\n form_schema = CASE WHEN $6::boolean THEN $7::jsonb ELSE form_schema END,\n metadata_schema = CASE WHEN $8::boolean THEN $9::jsonb ELSE metadata_schema END,\n properties = CASE WHEN $10::boolean THEN COALESCE($11::jsonb, '{}'::jsonb) ELSE properties END,\n ops_visible = CASE WHEN $12::boolean THEN $13::boolean ELSE ops_visible END,\n parent_role = CASE WHEN $14::boolean THEN $15 ELSE parent_role END,\n sla_minutes = CASE WHEN $16::boolean THEN $17::numeric ELSE sla_minutes END,\n target_per_hour = CASE WHEN $18::boolean THEN $19::numeric ELSE target_per_hour END,\n worker_count = CASE WHEN $20::boolean THEN $21::int ELSE worker_count END,\n priority_threshold_minutes\n = CASE WHEN $22::boolean THEN $23::numeric ELSE priority_threshold_minutes END,\n priority_facet = CASE WHEN $24::boolean THEN $25 ELSE priority_facet END,\n list_schema = CASE WHEN $29::boolean THEN $30::jsonb ELSE list_schema END,\n default_pins = CASE WHEN $31::boolean THEN $32::jsonb ELSE default_pins END,\n enforce_schema = CASE WHEN $33::boolean THEN COALESCE($34::boolean, false) ELSE enforce_schema END,\n ops_home_default = CASE WHEN $35::boolean THEN COALESCE($36::boolean, false) ELSE ops_home_default END,\n current_schema_version = CASE\n WHEN ($6::boolean AND $7::jsonb IS DISTINCT FROM form_schema)\n OR ($8::boolean AND $9::jsonb IS DISTINCT FROM metadata_schema)\n THEN COALESCE(current_schema_version, 0) + 1\n ELSE current_schema_version END,\n current_list_schema_version = CASE\n WHEN $29::boolean AND $30::jsonb IS DISTINCT FROM list_schema\n THEN COALESCE(current_list_schema_version, 0) + 1\n ELSE current_list_schema_version END\n WHERE role = $1\n RETURNING\n role, title, description, form_schema, metadata_schema, properties,\n ops_visible, ops_home_default, parent_role, sla_minutes, target_per_hour, worker_count,\n priority_threshold_minutes, priority_facet,\n current_schema_version, list_schema, current_list_schema_version,\n default_pins, enforce_schema\n ), snapshot AS (\n INSERT INTO lt_role_schemas (role, version, form_schema, metadata_schema, change_summary)\n SELECT role, current_schema_version, form_schema, metadata_schema, $26\n FROM updated\n WHERE ($6::boolean OR $8::boolean) AND current_schema_version IS NOT NULL\n ON CONFLICT (role, version) DO NOTHING\n ), list_snapshot AS (\n INSERT INTO lt_role_list_schemas (role, version, list_schema, change_summary)\n SELECT role, current_list_schema_version, list_schema, $26\n FROM updated\n WHERE $29::boolean AND current_list_schema_version IS NOT NULL\n ON CONFLICT (role, version) DO NOTHING\n ), upstream_prune AS (\n DELETE FROM lt_role_upstreams\n WHERE $27::boolean AND role = $1 AND upstream_role <> ALL($28::text[])\n ), upstream_add AS (\n INSERT INTO lt_role_upstreams (role, upstream_role)\n SELECT $1, u FROM unnest($28::text[]) AS u\n WHERE $27::boolean\n ON CONFLICT DO NOTHING\n )\n SELECT * FROM updated";
62
+ export declare const UPDATE_ROLE_METADATA = "\n WITH home_clear AS (\n UPDATE lt_roles SET ops_home_default = false\n WHERE $35::boolean AND COALESCE($36::boolean, false) AND role <> $1 AND ops_home_default\n ), updated AS (\n UPDATE lt_roles SET\n title = CASE WHEN $2::boolean THEN $3 ELSE title END,\n description = CASE WHEN $4::boolean THEN $5 ELSE description END,\n form_schema = CASE WHEN $6::boolean THEN $7::jsonb ELSE form_schema END,\n metadata_schema = CASE WHEN $8::boolean THEN $9::jsonb ELSE metadata_schema END,\n properties = CASE WHEN $10::boolean THEN COALESCE($11::jsonb, '{}'::jsonb) ELSE properties END,\n ops_visible = CASE WHEN $12::boolean THEN $13::boolean ELSE ops_visible END,\n parent_role = CASE WHEN $14::boolean THEN $15 ELSE parent_role END,\n sla_minutes = CASE WHEN $16::boolean THEN $17::numeric ELSE sla_minutes END,\n target_per_hour = CASE WHEN $18::boolean THEN $19::numeric ELSE target_per_hour END,\n worker_count = CASE WHEN $20::boolean THEN $21::int ELSE worker_count END,\n priority_threshold_minutes\n = CASE WHEN $22::boolean THEN $23::numeric ELSE priority_threshold_minutes END,\n priority_facet = CASE WHEN $24::boolean THEN $25 ELSE priority_facet END,\n entity_facet = CASE WHEN $37::boolean THEN $38 ELSE entity_facet END,\n entity_state_source\n = CASE WHEN $39::boolean THEN COALESCE($40, 'role') ELSE entity_state_source END,\n list_schema = CASE WHEN $29::boolean THEN $30::jsonb ELSE list_schema END,\n default_pins = CASE WHEN $31::boolean THEN $32::jsonb ELSE default_pins END,\n enforce_schema = CASE WHEN $33::boolean THEN COALESCE($34::boolean, false) ELSE enforce_schema END,\n ops_home_default = CASE WHEN $35::boolean THEN COALESCE($36::boolean, false) ELSE ops_home_default END,\n current_schema_version = CASE\n WHEN ($6::boolean AND $7::jsonb IS DISTINCT FROM form_schema)\n OR ($8::boolean AND $9::jsonb IS DISTINCT FROM metadata_schema)\n THEN COALESCE(current_schema_version, 0) + 1\n ELSE current_schema_version END,\n current_list_schema_version = CASE\n WHEN $29::boolean AND $30::jsonb IS DISTINCT FROM list_schema\n THEN COALESCE(current_list_schema_version, 0) + 1\n ELSE current_list_schema_version END\n WHERE role = $1\n RETURNING\n role, title, description, form_schema, metadata_schema, properties,\n ops_visible, ops_home_default, parent_role, sla_minutes, target_per_hour, worker_count,\n priority_threshold_minutes, priority_facet, entity_facet, entity_state_source,\n current_schema_version, list_schema, current_list_schema_version,\n default_pins, enforce_schema\n ), snapshot AS (\n INSERT INTO lt_role_schemas (role, version, form_schema, metadata_schema, change_summary)\n SELECT role, current_schema_version, form_schema, metadata_schema, $26\n FROM updated\n WHERE ($6::boolean OR $8::boolean) AND current_schema_version IS NOT NULL\n ON CONFLICT (role, version) DO NOTHING\n ), list_snapshot AS (\n INSERT INTO lt_role_list_schemas (role, version, list_schema, change_summary)\n SELECT role, current_list_schema_version, list_schema, $26\n FROM updated\n WHERE $29::boolean AND current_list_schema_version IS NOT NULL\n ON CONFLICT (role, version) DO NOTHING\n ), upstream_prune AS (\n DELETE FROM lt_role_upstreams\n WHERE $27::boolean AND role = $1 AND upstream_role <> ALL($28::text[])\n ), upstream_add AS (\n INSERT INTO lt_role_upstreams (role, upstream_role)\n SELECT $1, u FROM unnest($28::text[]) AS u\n WHERE $27::boolean\n ON CONFLICT DO NOTHING\n )\n SELECT * FROM updated";
55
63
  export declare const GET_ROLE_FORM_SCHEMA = "\n SELECT form_schema FROM lt_roles WHERE role = $1";
56
64
  /**
57
65
  * The set of roles with server-side resolver validation turned on. Small and
@@ -75,7 +83,7 @@ export declare const GET_ROLE_LIST_SCHEMA_VERSION = "\n SELECT s.role, s.versio
75
83
  * never versioned its list schema still answers, with version NULL).
76
84
  */
77
85
  export declare const GET_ROLE_LIST_SCHEMA_CURRENT = "\n SELECT r.role, r.current_list_schema_version AS version, r.list_schema,\n s.change_summary, s.created_at,\n r.current_list_schema_version AS latest_version\n FROM lt_roles r\n LEFT JOIN lt_role_list_schemas s\n ON s.role = r.role AND s.version = r.current_list_schema_version\n WHERE r.role = $1";
78
- export declare const LIST_ROLES_WITH_DETAILS = "\n WITH\n user_counts AS (\n SELECT role, COUNT(DISTINCT user_id)::int AS cnt\n FROM lt_user_roles\n GROUP BY role\n ),\n chain_counts AS (\n SELECT role, COUNT(*)::int AS cnt\n FROM (\n SELECT source_role AS role FROM lt_config_role_escalations\n UNION ALL\n SELECT target_role AS role FROM lt_config_role_escalations\n ) c\n GROUP BY role\n ),\n workflow_counts AS (\n SELECT role, COUNT(*)::int AS cnt\n FROM lt_config_roles\n GROUP BY role\n ),\n upstreams AS (\n SELECT role, array_agg(upstream_role ORDER BY upstream_role) AS ups\n FROM lt_role_upstreams\n GROUP BY role\n )\n SELECT\n r.role,\n r.title,\n r.description,\n r.form_schema,\n r.metadata_schema,\n r.properties,\n r.ops_visible,\n r.ops_home_default,\n r.parent_role,\n r.sla_minutes,\n r.target_per_hour,\n r.worker_count,\n r.priority_threshold_minutes,\n r.priority_facet,\n r.current_schema_version,\n r.list_schema,\n r.current_list_schema_version,\n r.default_pins,\n r.enforce_schema,\n COALESCE(up.ups, '{}') AS upstream_roles,\n COALESCE(uc.cnt, 0) AS user_count,\n COALESCE(cc.cnt, 0) AS chain_count,\n COALESCE(wc.cnt, 0) AS workflow_count\n FROM lt_roles r\n LEFT JOIN user_counts uc ON uc.role = r.role\n LEFT JOIN chain_counts cc ON cc.role = r.role\n LEFT JOIN workflow_counts wc ON wc.role = r.role\n LEFT JOIN upstreams up ON up.role = r.role\n ORDER BY r.role";
86
+ export declare const LIST_ROLES_WITH_DETAILS = "\n WITH\n user_counts AS (\n SELECT role, COUNT(DISTINCT user_id)::int AS cnt\n FROM lt_user_roles\n GROUP BY role\n ),\n chain_counts AS (\n SELECT role, COUNT(*)::int AS cnt\n FROM (\n SELECT source_role AS role FROM lt_config_role_escalations\n UNION ALL\n SELECT target_role AS role FROM lt_config_role_escalations\n ) c\n GROUP BY role\n ),\n workflow_counts AS (\n SELECT role, COUNT(*)::int AS cnt\n FROM lt_config_roles\n GROUP BY role\n ),\n upstreams AS (\n SELECT role, array_agg(upstream_role ORDER BY upstream_role) AS ups\n FROM lt_role_upstreams\n GROUP BY role\n )\n SELECT\n r.role,\n r.title,\n r.description,\n r.form_schema,\n r.metadata_schema,\n r.properties,\n r.ops_visible,\n r.ops_home_default,\n r.parent_role,\n r.sla_minutes,\n r.target_per_hour,\n r.worker_count,\n r.priority_threshold_minutes,\n r.priority_facet,\n r.entity_facet,\n r.entity_state_source,\n r.current_schema_version,\n r.list_schema,\n r.current_list_schema_version,\n r.default_pins,\n r.enforce_schema,\n COALESCE(up.ups, '{}') AS upstream_roles,\n COALESCE(uc.cnt, 0) AS user_count,\n COALESCE(cc.cnt, 0) AS chain_count,\n COALESCE(wc.cnt, 0) AS workflow_count\n FROM lt_roles r\n LEFT JOIN user_counts uc ON uc.role = r.role\n LEFT JOIN chain_counts cc ON cc.role = r.role\n LEFT JOIN workflow_counts wc ON wc.role = r.role\n LEFT JOIN upstreams up ON up.role = r.role\n ORDER BY r.role";
79
87
  export declare const COUNT_USER_ROLE_REFS = "\n SELECT COUNT(*)::int AS cnt FROM lt_user_roles WHERE role = $1";
80
88
  export declare const COUNT_CHAIN_REFS = "\n SELECT COUNT(*)::int AS cnt\n FROM lt_config_role_escalations\n WHERE source_role = $1 OR target_role = $1";
81
89
  export declare const COUNT_WORKFLOW_REFS = "\n SELECT COUNT(*)::int AS cnt FROM lt_config_roles WHERE role = $1";
@@ -84,6 +84,14 @@ exports.DELETE_ROLE = `
84
84
  * ops_home_default ($35 = provided sentinel, $36 = value) is single-holder:
85
85
  * setting it true clears the flag on every other role in the same statement
86
86
  * (the home_clear CTE touches only OTHER rows, so the two UPDATEs never meet).
87
+ *
88
+ * entity_facet ($37 = provided sentinel, $38 = value) is unversioned config:
89
+ * the metadata key naming the entity that moves through this role (powers the
90
+ * analytics surfaces — entity counts, per-entity dwell, timelines).
91
+ *
92
+ * entity_state_source ($39 = provided sentinel, $40 = value) is unversioned
93
+ * config: 'role' | 'subtype' — how this role names its contribution to the
94
+ * entity's state space (the station itself, or its subtypes).
87
95
  */
88
96
  exports.UPDATE_ROLE_METADATA = `
89
97
  WITH home_clear AS (
@@ -104,6 +112,9 @@ exports.UPDATE_ROLE_METADATA = `
104
112
  priority_threshold_minutes
105
113
  = CASE WHEN $22::boolean THEN $23::numeric ELSE priority_threshold_minutes END,
106
114
  priority_facet = CASE WHEN $24::boolean THEN $25 ELSE priority_facet END,
115
+ entity_facet = CASE WHEN $37::boolean THEN $38 ELSE entity_facet END,
116
+ entity_state_source
117
+ = CASE WHEN $39::boolean THEN COALESCE($40, 'role') ELSE entity_state_source END,
107
118
  list_schema = CASE WHEN $29::boolean THEN $30::jsonb ELSE list_schema END,
108
119
  default_pins = CASE WHEN $31::boolean THEN $32::jsonb ELSE default_pins END,
109
120
  enforce_schema = CASE WHEN $33::boolean THEN COALESCE($34::boolean, false) ELSE enforce_schema END,
@@ -121,7 +132,7 @@ exports.UPDATE_ROLE_METADATA = `
121
132
  RETURNING
122
133
  role, title, description, form_schema, metadata_schema, properties,
123
134
  ops_visible, ops_home_default, parent_role, sla_minutes, target_per_hour, worker_count,
124
- priority_threshold_minutes, priority_facet,
135
+ priority_threshold_minutes, priority_facet, entity_facet, entity_state_source,
125
136
  current_schema_version, list_schema, current_list_schema_version,
126
137
  default_pins, enforce_schema
127
138
  ), snapshot AS (
@@ -262,6 +273,8 @@ exports.LIST_ROLES_WITH_DETAILS = `
262
273
  r.worker_count,
263
274
  r.priority_threshold_minutes,
264
275
  r.priority_facet,
276
+ r.entity_facet,
277
+ r.entity_state_source,
265
278
  r.current_schema_version,
266
279
  r.list_schema,
267
280
  r.current_list_schema_version,
@@ -46,6 +46,19 @@ export interface RoleDetail {
46
46
  * an unparseable value are not counted.
47
47
  */
48
48
  priority_facet: string | null;
49
+ /**
50
+ * lt_escalations.metadata key identifying the ENTITY that moves through
51
+ * this role (e.g. serialNumber, orderId). Powers the analytics surfaces —
52
+ * distinct-entity counts, per-entity dwell, entity timelines. Null = the
53
+ * role has no entity notion.
54
+ */
55
+ entity_facet: string | null;
56
+ /**
57
+ * How this role names its contribution to the entity's state space:
58
+ * 'role' (the station itself is the state) or 'subtype' (the role's
59
+ * subtypes are its states). Only meaningful while entity_facet is set.
60
+ */
61
+ entity_state_source: 'role' | 'subtype';
49
62
  /**
50
63
  * Version of the live form_schema. Advances whenever the form (or
51
64
  * metadata_schema) changes; each version is snapshotted in lt_role_schemas so
@@ -149,6 +162,9 @@ export interface UpdateRoleInput {
149
162
  worker_count?: number | null;
150
163
  priority_threshold_minutes?: number | null;
151
164
  priority_facet?: string | null;
165
+ entity_facet?: string | null;
166
+ /** 'role' | 'subtype' — null resets to the 'role' default. */
167
+ entity_state_source?: 'role' | 'subtype' | null;
152
168
  /** Turn server-side resolver schema validation on/off for this role. */
153
169
  enforce_schema?: boolean;
154
170
  /**
@@ -15,6 +15,9 @@ function mapScheme(row) {
15
15
  encoding: row.encoding,
16
16
  delimiter: row.delimiter,
17
17
  target_length: row.target_length ?? null,
18
+ kind: row.kind ?? 'action',
19
+ grant_ttl_seconds: row.grant_ttl_seconds ?? null,
20
+ grant_max_uses: row.grant_max_uses ?? 0,
18
21
  enabled: row.enabled,
19
22
  created_at: row.created_at,
20
23
  updated_at: row.updated_at,
@@ -27,6 +30,7 @@ function mapRule(row) {
27
30
  name: row.name,
28
31
  steps: row.steps ?? [],
29
32
  fallback: row.fallback ?? {},
33
+ notPrimed: row.not_primed ?? {},
30
34
  enabled: row.enabled,
31
35
  created_at: row.created_at,
32
36
  updated_at: row.updated_at,
@@ -2,9 +2,9 @@ export declare const LIST_SCHEMES = "SELECT * FROM lt_config_scan_schemes ORDER
2
2
  export declare const GET_SCHEME = "SELECT * FROM lt_config_scan_schemes WHERE version = $1";
3
3
  export declare const LIST_ACTIONS = "SELECT * FROM lt_config_scan_actions WHERE scheme_version = $1 ORDER BY category";
4
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 *";
5
+ export declare const UPSERT_SCHEME = "INSERT INTO lt_config_scan_schemes\n (version, name, description, target_facet, encoding, delimiter, target_length,\n kind, grant_ttl_seconds, grant_max_uses, enabled)\nVALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)\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 kind = EXCLUDED.kind,\n grant_ttl_seconds = EXCLUDED.grant_ttl_seconds,\n grant_max_uses = EXCLUDED.grant_max_uses,\n enabled = EXCLUDED.enabled\nRETURNING *";
6
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 *";
7
+ export declare const UPSERT_ACTION = "INSERT INTO lt_config_scan_actions\n (scheme_version, category, name, steps, fallback, not_primed, enabled)\nVALUES ($1, $2, $3, $4, $5, $6, $7)\nON CONFLICT (scheme_version, category) DO UPDATE SET\n name = EXCLUDED.name,\n steps = EXCLUDED.steps,\n fallback = EXCLUDED.fallback,\n not_primed = EXCLUDED.not_primed,\n enabled = EXCLUDED.enabled\nRETURNING *";
8
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";
9
+ export declare const SEED_SCHEME = "INSERT INTO lt_config_scan_schemes\n (version, name, description, target_facet, encoding, delimiter, target_length,\n kind, grant_ttl_seconds, grant_max_uses, enabled)\nVALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)\nON CONFLICT (version) DO NOTHING";
10
+ export declare const SEED_ACTION = "INSERT INTO lt_config_scan_actions\n (scheme_version, category, name, steps, fallback, not_primed, enabled)\nVALUES ($1, $2, $3, $4, $5, $6, $7)\nON CONFLICT (scheme_version, category) DO NOTHING";
@@ -17,8 +17,9 @@ SELECT * FROM lt_config_scan_actions WHERE scheme_version = $1 AND category = $2
17
17
  // ------------------------------------------------------------------ //
18
18
  exports.UPSERT_SCHEME = `\
19
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)
20
+ (version, name, description, target_facet, encoding, delimiter, target_length,
21
+ kind, grant_ttl_seconds, grant_max_uses, enabled)
22
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
22
23
  ON CONFLICT (version) DO UPDATE SET
23
24
  name = EXCLUDED.name,
24
25
  description = EXCLUDED.description,
@@ -26,18 +27,22 @@ ON CONFLICT (version) DO UPDATE SET
26
27
  encoding = EXCLUDED.encoding,
27
28
  delimiter = EXCLUDED.delimiter,
28
29
  target_length = EXCLUDED.target_length,
30
+ kind = EXCLUDED.kind,
31
+ grant_ttl_seconds = EXCLUDED.grant_ttl_seconds,
32
+ grant_max_uses = EXCLUDED.grant_max_uses,
29
33
  enabled = EXCLUDED.enabled
30
34
  RETURNING *`;
31
35
  exports.DELETE_SCHEME = `\
32
36
  DELETE FROM lt_config_scan_schemes WHERE version = $1`;
33
37
  exports.UPSERT_ACTION = `\
34
38
  INSERT INTO lt_config_scan_actions
35
- (scheme_version, category, name, steps, fallback, enabled)
36
- VALUES ($1, $2, $3, $4, $5, $6)
39
+ (scheme_version, category, name, steps, fallback, not_primed, enabled)
40
+ VALUES ($1, $2, $3, $4, $5, $6, $7)
37
41
  ON CONFLICT (scheme_version, category) DO UPDATE SET
38
42
  name = EXCLUDED.name,
39
43
  steps = EXCLUDED.steps,
40
44
  fallback = EXCLUDED.fallback,
45
+ not_primed = EXCLUDED.not_primed,
41
46
  enabled = EXCLUDED.enabled
42
47
  RETURNING *`;
43
48
  exports.DELETE_ACTION = `\
@@ -47,11 +52,12 @@ DELETE FROM lt_config_scan_actions WHERE scheme_version = $1 AND category = $2`;
47
52
  // ------------------------------------------------------------------ //
48
53
  exports.SEED_SCHEME = `\
49
54
  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)
55
+ (version, name, description, target_facet, encoding, delimiter, target_length,
56
+ kind, grant_ttl_seconds, grant_max_uses, enabled)
57
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
52
58
  ON CONFLICT (version) DO NOTHING`;
53
59
  exports.SEED_ACTION = `\
54
60
  INSERT INTO lt_config_scan_actions
55
- (scheme_version, category, name, steps, fallback, enabled)
56
- VALUES ($1, $2, $3, $4, $5, $6)
61
+ (scheme_version, category, name, steps, fallback, not_primed, enabled)
62
+ VALUES ($1, $2, $3, $4, $5, $6, $7)
57
63
  ON CONFLICT (scheme_version, category) DO NOTHING`;
@@ -5,6 +5,8 @@ import { type ScanScheme, type ScanStep } from '../../types';
5
5
  * than a loud upsert failure.
6
6
  */
7
7
  export declare function assertValidScheme(scheme: Partial<ScanScheme>): void;
8
+ /** Identity rules never walk steps — their fallback is the unknown-badge screen. */
9
+ export declare function assertValidIdentityRule(steps: ScanStep[]): void;
8
10
  /**
9
11
  * Reject incoherent rule steps at write time: a rule that can never
10
12
  * execute its verb must fail the upsert, not the factory-floor scan.
@@ -1,9 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.assertValidScheme = assertValidScheme;
4
+ exports.assertValidIdentityRule = assertValidIdentityRule;
4
5
  exports.assertValidSteps = assertValidSteps;
5
6
  const types_1 = require("../../types");
6
7
  const VALID_VERBS = new Set(Object.values(types_1.SCAN_VERBS));
8
+ /** Double-scan selection tokens — short, label-printable, never scheme-shaped. */
9
+ const CHOICE_CODE = /^[A-Za-z0-9_-]{1,32}$/;
7
10
  /**
8
11
  * Reject incoherent scheme config at write time. Throws with the exact
9
12
  * problem — a bad scheme silently misparsing every scan is far worse
@@ -32,6 +35,64 @@ function assertValidScheme(scheme) {
32
35
  throw new Error('delimiter must not be a digit');
33
36
  }
34
37
  }
38
+ const kind = scheme.kind ?? types_1.SCAN_SCHEME_KINDS.ACTION;
39
+ if (kind !== types_1.SCAN_SCHEME_KINDS.ACTION && kind !== types_1.SCAN_SCHEME_KINDS.IDENTITY) {
40
+ throw new Error(`unknown scheme kind "${kind}"`);
41
+ }
42
+ if (kind === types_1.SCAN_SCHEME_KINDS.IDENTITY) {
43
+ const ttl = scheme.grant_ttl_seconds;
44
+ if (!Number.isInteger(ttl) || ttl < 1 || ttl > 86_400) {
45
+ throw new Error('identity schemes require grant_ttl_seconds between 1 and 86400');
46
+ }
47
+ if (!Number.isInteger(scheme.grant_max_uses ?? 0) || (scheme.grant_max_uses ?? 0) < 0) {
48
+ throw new Error('grant_max_uses must be a non-negative integer');
49
+ }
50
+ }
51
+ else if (scheme.grant_ttl_seconds != null || (scheme.grant_max_uses ?? 0) !== 0) {
52
+ throw new Error('grant policy applies only to identity schemes');
53
+ }
54
+ }
55
+ /** Identity rules never walk steps — their fallback is the unknown-badge screen. */
56
+ function assertValidIdentityRule(steps) {
57
+ if (Array.isArray(steps) && steps.length > 0) {
58
+ throw new Error('identity-scheme rules must have no steps (the fallback is the unknown-badge screen)');
59
+ }
60
+ }
61
+ /** Per-choice validation — a choice is a step verb with a label, minus locate concerns. */
62
+ function assertValidChoices(choices, at) {
63
+ if (!Array.isArray(choices) || choices.length === 0) {
64
+ throw new Error(`${at}: present requires a non-empty choices array`);
65
+ }
66
+ const codes = new Set();
67
+ choices.forEach((choice, j) => {
68
+ const cat = `${at} choice ${j + 1}`;
69
+ if (!choice || typeof choice !== 'object')
70
+ throw new Error(`${cat} must be an object`);
71
+ if (!choice.label)
72
+ throw new Error(`${cat}: label is required`);
73
+ if (!VALID_VERBS.has(choice.verb))
74
+ throw new Error(`${cat}: unknown verb "${choice.verb}"`);
75
+ if (choice.verb === types_1.SCAN_VERBS.PRESENT || choice.verb === types_1.SCAN_VERBS.SHOW_LIST) {
76
+ throw new Error(`${cat}: ${choice.verb} cannot be a choice verb`);
77
+ }
78
+ if (choice.confirm && !choice.confirm.prompt) {
79
+ throw new Error(`${cat}: confirm requires a prompt`);
80
+ }
81
+ if (choice.verb === types_1.SCAN_VERBS.ESCALATE && !choice.params?.targetRole) {
82
+ throw new Error(`${cat}: escalate requires params.targetRole`);
83
+ }
84
+ if (choice.verb === types_1.SCAN_VERBS.RESOLVE && !choice.params?.resolverPayload) {
85
+ throw new Error(`${cat}: resolve requires params.resolverPayload`);
86
+ }
87
+ if (choice.code !== undefined) {
88
+ if (!CHOICE_CODE.test(choice.code)) {
89
+ throw new Error(`${cat}: code must be 1-32 letters, digits, underscore, or dash`);
90
+ }
91
+ if (codes.has(choice.code))
92
+ throw new Error(`${cat}: duplicate code "${choice.code}"`);
93
+ codes.add(choice.code);
94
+ }
95
+ });
35
96
  }
36
97
  /**
37
98
  * Reject incoherent rule steps at write time: a rule that can never
@@ -53,6 +114,31 @@ function assertValidSteps(steps) {
53
114
  if (step.confirm && !step.confirm.prompt) {
54
115
  throw new Error(`${at}: confirm requires a prompt`);
55
116
  }
117
+ // The classic confirm flow completes through per-id endpoints as the
118
+ // logged-in principal — it cannot carry an acting identity. Identity-gated
119
+ // ask-first flows are authored as PRESENT choices with confirm.
120
+ if (step.confirm && step.requireActingIdentity) {
121
+ throw new Error(`${at}: confirm and requireActingIdentity are incompatible — use a present step with a confirming choice`);
122
+ }
123
+ if (step.verb === types_1.SCAN_VERBS.PRESENT) {
124
+ if (step.confirm)
125
+ throw new Error(`${at}: present steps cannot carry confirm (choices confirm individually)`);
126
+ if (step.cardinality === 'many')
127
+ throw new Error(`${at}: present locates a single row (cardinality first)`);
128
+ assertValidChoices(step.choices, at);
129
+ if (step.autoSelectSingle && step.choices.length !== 1) {
130
+ throw new Error(`${at}: autoSelectSingle requires exactly one choice`);
131
+ }
132
+ if (step.autoSelectSingle && step.choices[0].confirm) {
133
+ throw new Error(`${at}: autoSelectSingle cannot skip a confirming choice — drop the confirm or the auto-select`);
134
+ }
135
+ }
136
+ else {
137
+ if (step.choices !== undefined)
138
+ throw new Error(`${at}: choices apply only to present steps`);
139
+ if (step.autoSelectSingle)
140
+ throw new Error(`${at}: autoSelectSingle applies only to present steps`);
141
+ }
56
142
  if (step.verb === types_1.SCAN_VERBS.ESCALATE && !step.params?.targetRole) {
57
143
  throw new Error(`${at}: escalate requires params.targetRole`);
58
144
  }
@@ -7,6 +7,9 @@ export interface ScanSchemeInput {
7
7
  encoding?: ScanScheme['encoding'];
8
8
  delimiter?: string;
9
9
  target_length?: number | null;
10
+ kind?: ScanScheme['kind'];
11
+ grant_ttl_seconds?: number | null;
12
+ grant_max_uses?: number;
10
13
  enabled?: boolean;
11
14
  }
12
15
  export interface ScanRuleInput {
@@ -15,6 +18,7 @@ export interface ScanRuleInput {
15
18
  name: string;
16
19
  steps: ScanStep[];
17
20
  fallback?: ScanRuleFallback;
21
+ notPrimed?: ScanRuleFallback;
18
22
  enabled?: boolean;
19
23
  }
20
24
  export declare function upsertScanScheme(input: ScanSchemeInput): Promise<ScanScheme>;
@@ -10,6 +10,7 @@ const db_1 = require("../../lib/db");
10
10
  const types_1 = require("../../types");
11
11
  const sql_1 = require("./sql");
12
12
  const validate_1 = require("./validate");
13
+ const read_1 = require("./read");
13
14
  function schemeParams(input) {
14
15
  return [
15
16
  input.version,
@@ -19,6 +20,9 @@ function schemeParams(input) {
19
20
  input.encoding ?? types_1.SCAN_ENCODINGS.FIXED,
20
21
  input.delimiter ?? ':',
21
22
  input.target_length ?? null,
23
+ input.kind ?? types_1.SCAN_SCHEME_KINDS.ACTION,
24
+ input.grant_ttl_seconds ?? null,
25
+ input.grant_max_uses ?? 0,
22
26
  input.enabled ?? true,
23
27
  ];
24
28
  }
@@ -29,9 +33,19 @@ function ruleParams(input) {
29
33
  input.name,
30
34
  JSON.stringify(input.steps),
31
35
  JSON.stringify(input.fallback ?? {}),
36
+ JSON.stringify(input.notPrimed ?? {}),
32
37
  input.enabled ?? true,
33
38
  ];
34
39
  }
40
+ /** Identity-scheme rules never walk steps; validated against the OWNING scheme's kind. */
41
+ async function assertStepsForScheme(input) {
42
+ const scheme = await (0, read_1.getScanScheme)(input.scheme_version);
43
+ if (scheme?.kind === types_1.SCAN_SCHEME_KINDS.IDENTITY) {
44
+ (0, validate_1.assertValidIdentityRule)(input.steps);
45
+ return;
46
+ }
47
+ (0, validate_1.assertValidSteps)(input.steps);
48
+ }
35
49
  async function upsertScanScheme(input) {
36
50
  (0, validate_1.assertValidScheme)(input);
37
51
  const { rows } = await (0, db_1.getPool)().query(sql_1.UPSERT_SCHEME, schemeParams(input));
@@ -47,7 +61,7 @@ async function upsertScanRule(input) {
47
61
  }
48
62
  if (!input.name)
49
63
  throw new Error('rule name is required');
50
- (0, validate_1.assertValidSteps)(input.steps);
64
+ await assertStepsForScheme(input);
51
65
  if (input.steps.length === 0 && !input.fallback?.markdown && !input.fallback?.route) {
52
66
  throw new Error('a rule needs at least one step or a fallback');
53
67
  }
@@ -65,7 +79,7 @@ async function seedScanScheme(input) {
65
79
  return (rowCount ?? 0) > 0;
66
80
  }
67
81
  async function seedScanRule(input) {
68
- (0, validate_1.assertValidSteps)(input.steps);
82
+ await assertStepsForScheme(input);
69
83
  const { rowCount } = await (0, db_1.getPool)().query(sql_1.SEED_ACTION, ruleParams(input));
70
84
  return (rowCount ?? 0) > 0;
71
85
  }
@@ -5,6 +5,12 @@ export declare function createUser(input: CreateUserInput): Promise<LTUserRecord
5
5
  export declare function getUser(id: string): Promise<LTUserRecord | null>;
6
6
  export declare function getUserByExternalId(externalId: string): Promise<LTUserRecord | null>;
7
7
  export declare function getUserByEmail(email: string): Promise<LTUserRecord | null>;
8
+ /**
9
+ * Resolve an ACTIVE user by a metadata binding (e.g. metadata.badge_id).
10
+ * Two users carrying the same value is a configuration fault, not a pick —
11
+ * it throws so the binding gets fixed instead of misattributing work.
12
+ */
13
+ export declare function getUserByMetadataValue(key: string, value: string): Promise<LTUserRecord | null>;
8
14
  export declare function updateUser(id: string, input: UpdateUserInput): Promise<LTUserRecord | null>;
9
15
  export declare function deleteUser(id: string): Promise<boolean>;
10
16
  export declare function listUsers(filters: {
@@ -8,6 +8,7 @@ exports.createUser = createUser;
8
8
  exports.getUser = getUser;
9
9
  exports.getUserByExternalId = getUserByExternalId;
10
10
  exports.getUserByEmail = getUserByEmail;
11
+ exports.getUserByMetadataValue = getUserByMetadataValue;
11
12
  exports.updateUser = updateUser;
12
13
  exports.deleteUser = deleteUser;
13
14
  exports.listUsers = listUsers;
@@ -93,6 +94,21 @@ async function getUserByEmail(email) {
93
94
  return null;
94
95
  return attachRoles(rows[0]);
95
96
  }
97
+ /**
98
+ * Resolve an ACTIVE user by a metadata binding (e.g. metadata.badge_id).
99
+ * Two users carrying the same value is a configuration fault, not a pick —
100
+ * it throws so the binding gets fixed instead of misattributing work.
101
+ */
102
+ async function getUserByMetadataValue(key, value) {
103
+ const pool = (0, db_1.getPool)();
104
+ const { rows } = await pool.query(sql_1.GET_USERS_BY_METADATA_VALUE, [key, value]);
105
+ if (rows.length === 0)
106
+ return null;
107
+ if (rows.length > 1) {
108
+ throw new Error(`metadata binding "${key}" is ambiguous — multiple users carry the same value`);
109
+ }
110
+ return attachRoles(rows[0]);
111
+ }
96
112
  async function updateUser(id, input) {
97
113
  const pool = (0, db_1.getPool)();
98
114
  const sets = [];
@@ -1,5 +1,5 @@
1
1
  export { CreateUserInput, UpdateUserInput, VALID_ROLE_TYPES } from './types';
2
- export { createUser, getUser, getUserByExternalId, getUserByEmail, updateUser, deleteUser, listUsers, } from './crud';
2
+ export { createUser, getUser, getUserByExternalId, getUserByEmail, getUserByMetadataValue, updateUser, deleteUser, listUsers, } from './crud';
3
3
  export { isValidRoleType, addUserRole, removeUserRole, getUserRoles, hasRole, hasRoleType, } from './roles';
4
4
  export { isSuperAdmin, isGroupAdmin, canManageRole, hasGlobalEscalationAccess, hasRolesAsAdmin, getRoleScope, getRoleWriteScope } from './rbac';
5
5
  export { READ_SCOPES, WRITE_SCOPES, DEFAULT_READ_SCOPE, DEFAULT_WRITE_SCOPE, isValidReadScope, isValidWriteScope, isValidScopePair, effectiveScope, } from './scope';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PREFERENCES_MAX_BYTES = exports.patchPreferences = exports.getPreferences = exports.seedAdmin = exports.verifyPassword = exports.effectiveScope = exports.isValidScopePair = exports.isValidWriteScope = exports.isValidReadScope = exports.DEFAULT_WRITE_SCOPE = exports.DEFAULT_READ_SCOPE = exports.WRITE_SCOPES = exports.READ_SCOPES = exports.getRoleWriteScope = exports.getRoleScope = exports.hasRolesAsAdmin = exports.hasGlobalEscalationAccess = exports.canManageRole = exports.isGroupAdmin = exports.isSuperAdmin = exports.hasRoleType = exports.hasRole = exports.getUserRoles = exports.removeUserRole = exports.addUserRole = exports.isValidRoleType = exports.listUsers = exports.deleteUser = exports.updateUser = exports.getUserByEmail = exports.getUserByExternalId = exports.getUser = exports.createUser = exports.VALID_ROLE_TYPES = void 0;
3
+ exports.PREFERENCES_MAX_BYTES = exports.patchPreferences = exports.getPreferences = exports.seedAdmin = exports.verifyPassword = exports.effectiveScope = exports.isValidScopePair = exports.isValidWriteScope = exports.isValidReadScope = exports.DEFAULT_WRITE_SCOPE = exports.DEFAULT_READ_SCOPE = exports.WRITE_SCOPES = exports.READ_SCOPES = exports.getRoleWriteScope = exports.getRoleScope = exports.hasRolesAsAdmin = exports.hasGlobalEscalationAccess = exports.canManageRole = exports.isGroupAdmin = exports.isSuperAdmin = exports.hasRoleType = exports.hasRole = exports.getUserRoles = exports.removeUserRole = exports.addUserRole = exports.isValidRoleType = exports.listUsers = exports.deleteUser = exports.updateUser = exports.getUserByMetadataValue = exports.getUserByEmail = exports.getUserByExternalId = exports.getUser = exports.createUser = exports.VALID_ROLE_TYPES = void 0;
4
4
  var types_1 = require("./types");
5
5
  Object.defineProperty(exports, "VALID_ROLE_TYPES", { enumerable: true, get: function () { return types_1.VALID_ROLE_TYPES; } });
6
6
  var crud_1 = require("./crud");
@@ -8,6 +8,7 @@ Object.defineProperty(exports, "createUser", { enumerable: true, get: function (
8
8
  Object.defineProperty(exports, "getUser", { enumerable: true, get: function () { return crud_1.getUser; } });
9
9
  Object.defineProperty(exports, "getUserByExternalId", { enumerable: true, get: function () { return crud_1.getUserByExternalId; } });
10
10
  Object.defineProperty(exports, "getUserByEmail", { enumerable: true, get: function () { return crud_1.getUserByEmail; } });
11
+ Object.defineProperty(exports, "getUserByMetadataValue", { enumerable: true, get: function () { return crud_1.getUserByMetadataValue; } });
11
12
  Object.defineProperty(exports, "updateUser", { enumerable: true, get: function () { return crud_1.updateUser; } });
12
13
  Object.defineProperty(exports, "deleteUser", { enumerable: true, get: function () { return crud_1.deleteUser; } });
13
14
  Object.defineProperty(exports, "listUsers", { enumerable: true, get: function () { return crud_1.listUsers; } });
@@ -18,6 +18,14 @@ export declare const GET_USER_BY_EXTERNAL_ID = "SELECT * FROM lt_users WHERE ext
18
18
  export declare const CREATE_USER_WITH_ROLES = "WITH new_user AS (\n INSERT INTO lt_users (external_id, email, display_name, status, metadata, password_hash, oauth_provider, oauth_provider_id)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8)\n RETURNING *\n ), ensured_roles AS (\n INSERT INTO lt_roles (role)\n SELECT DISTINCT unnest($9::text[])\n ON CONFLICT DO NOTHING\n ), assigned_roles AS (\n INSERT INTO lt_user_roles (user_id, role, type, read_scope, write_scope)\n SELECT (SELECT id FROM new_user), x.role, x.type, x.read_scope, x.write_scope\n FROM unnest($9::text[], $10::text[], $11::text[], $12::text[]) AS x(role, type, read_scope, write_scope)\n ON CONFLICT DO NOTHING\n )\n SELECT * FROM new_user";
19
19
  export declare const GET_USER_BY_EMAIL = "SELECT * FROM lt_users WHERE email = $1 LIMIT 1";
20
20
  export declare const GET_USER_BY_ID = "SELECT * FROM lt_users WHERE id = $1";
21
+ /**
22
+ * Lookup by a caller-named metadata key (e.g. a badge binding). LIMIT 2 so an
23
+ * ambiguous binding — two users carrying the same value — is detectable and
24
+ * can fail loudly rather than silently picking one. Seq scan by design: this
25
+ * is the people table (small); revisit with a GIN index on metadata if a
26
+ * deployment ever holds tens of thousands of users.
27
+ */
28
+ export declare const GET_USERS_BY_METADATA_VALUE = "SELECT * FROM lt_users WHERE metadata->>$1 = $2 AND status = 'active' LIMIT 2";
21
29
  /** Check if a user exists by id. Lightweight — returns only the id column. */
22
30
  export declare const VERIFY_USER_BY_ID = "SELECT id FROM lt_users WHERE id = $1 LIMIT 1";
23
31
  /** Fetch user + roles in a single query. Returns one row per role (or one row with nulls if no roles). */
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  // ─── Shared queries (used by multiple modules) ──────────────────────────────
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.IS_GROUP_ADMIN = exports.GET_ROLE_SCOPE = exports.HAS_ROLE_TYPE = exports.HAS_ROLE = exports.DELETE_USER_ROLE = exports.UPSERT_USER_ROLE = exports.GET_ROLES_BY_USER_IDS = exports.DELETE_USER_BY_ID = exports.GET_USER_WITH_ROLES = exports.VERIFY_USER_BY_ID = exports.GET_USER_BY_ID = exports.GET_USER_BY_EMAIL = exports.CREATE_USER_WITH_ROLES = exports.GET_USER_BY_EXTERNAL_ID = exports.GET_ROLES_BY_USER_ID = exports.ENSURE_ROLE_EXISTS = void 0;
4
+ exports.IS_GROUP_ADMIN = exports.GET_ROLE_SCOPE = exports.HAS_ROLE_TYPE = exports.HAS_ROLE = exports.DELETE_USER_ROLE = exports.UPSERT_USER_ROLE = exports.GET_ROLES_BY_USER_IDS = exports.DELETE_USER_BY_ID = exports.GET_USER_WITH_ROLES = exports.VERIFY_USER_BY_ID = exports.GET_USERS_BY_METADATA_VALUE = exports.GET_USER_BY_ID = exports.GET_USER_BY_EMAIL = exports.CREATE_USER_WITH_ROLES = exports.GET_USER_BY_EXTERNAL_ID = exports.GET_ROLES_BY_USER_ID = exports.ENSURE_ROLE_EXISTS = void 0;
5
5
  /** Ensure a role name exists in the lt_roles lookup table (FK target). */
6
6
  exports.ENSURE_ROLE_EXISTS = 'INSERT INTO lt_roles (role) VALUES ($1) ON CONFLICT DO NOTHING';
7
7
  /** Fetch roles for a single user, ordered by creation time. granted_by_persona
@@ -40,6 +40,14 @@ exports.CREATE_USER_WITH_ROLES = `WITH new_user AS (
40
40
  SELECT * FROM new_user`;
41
41
  exports.GET_USER_BY_EMAIL = `SELECT * FROM lt_users WHERE email = $1 LIMIT 1`;
42
42
  exports.GET_USER_BY_ID = 'SELECT * FROM lt_users WHERE id = $1';
43
+ /**
44
+ * Lookup by a caller-named metadata key (e.g. a badge binding). LIMIT 2 so an
45
+ * ambiguous binding — two users carrying the same value — is detectable and
46
+ * can fail loudly rather than silently picking one. Seq scan by design: this
47
+ * is the people table (small); revisit with a GIN index on metadata if a
48
+ * deployment ever holds tens of thousands of users.
49
+ */
50
+ exports.GET_USERS_BY_METADATA_VALUE = `SELECT * FROM lt_users WHERE metadata->>$1 = $2 AND status = 'active' LIMIT 2`;
43
51
  /** Check if a user exists by id. Lightweight — returns only the id column. */
44
52
  exports.VERIFY_USER_BY_ID = 'SELECT id FROM lt_users WHERE id = $1 LIMIT 1';
45
53
  /** Fetch user + roles in a single query. Returns one row per role (or one row with nulls if no roles). */
@@ -8,6 +8,10 @@ export * from './derive-field-label';
8
8
  export * from './x-lt-bind';
9
9
  export * from './x-lt-help';
10
10
  export * from './x-lt-transition';
11
+ export * from './x-lt-submit-on-claim';
12
+ export * from './x-lt-labels';
13
+ export * from './x-lt-query';
14
+ export * from './x-lt-submit-guard';
11
15
  export * from './x-lt-show-if';
12
16
  export * from './field-validator';
13
17
  export * from './validate-resolver-payload';
@@ -24,6 +24,10 @@ __exportStar(require("./derive-field-label"), exports);
24
24
  __exportStar(require("./x-lt-bind"), exports);
25
25
  __exportStar(require("./x-lt-help"), exports);
26
26
  __exportStar(require("./x-lt-transition"), exports);
27
+ __exportStar(require("./x-lt-submit-on-claim"), exports);
28
+ __exportStar(require("./x-lt-labels"), exports);
29
+ __exportStar(require("./x-lt-query"), exports);
30
+ __exportStar(require("./x-lt-submit-guard"), exports);
27
31
  __exportStar(require("./x-lt-show-if"), exports);
28
32
  __exportStar(require("./field-validator"), exports);
29
33
  __exportStar(require("./validate-resolver-payload"), exports);