@hotmeshio/long-tail 0.30.4 → 0.31.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 (413) hide show
  1. package/build/api/escalations/index.d.ts +1 -0
  2. package/build/api/escalations/index.js +5 -2
  3. package/build/api/escalations/roster-action.d.ts +11 -0
  4. package/build/api/escalations/roster-action.js +47 -30
  5. package/build/api/escalations/roster-scan.d.ts +26 -0
  6. package/build/api/escalations/roster-scan.js +114 -0
  7. package/build/api/labels/errors.d.ts +3 -0
  8. package/build/api/labels/errors.js +15 -0
  9. package/build/api/labels/index.d.ts +2 -0
  10. package/build/api/labels/index.js +17 -0
  11. package/build/api/labels/issue.d.ts +54 -0
  12. package/build/api/labels/issue.js +144 -0
  13. package/build/api/labels/templates.d.ts +29 -0
  14. package/build/api/labels/templates.js +98 -0
  15. package/build/api/scan-codes/context.d.ts +9 -1
  16. package/build/api/scan-codes/context.js +16 -1
  17. package/build/api/scan-codes/execute.js +6 -1
  18. package/build/api/scan-codes/fill-labels.d.ts +8 -0
  19. package/build/api/scan-codes/fill-labels.js +23 -2
  20. package/build/api/scan-codes/hold.js +2 -0
  21. package/build/api/scan-codes/located.d.ts +10 -0
  22. package/build/api/scan-codes/located.js +74 -0
  23. package/build/api/scan-codes/open.d.ts +9 -0
  24. package/build/api/scan-codes/open.js +99 -0
  25. package/build/api/scan-codes/present.js +1 -0
  26. package/build/api/scan-codes/verb-fill.js +1 -1
  27. package/build/api/users.d.ts +8 -4
  28. package/build/api/users.js +51 -13
  29. package/build/index.d.ts +1 -0
  30. package/build/index.js +4 -2
  31. package/build/lib/db/schemas/044_label_sheets.sql +65 -0
  32. package/build/lib/db/schemas/045_label_job_delivery.sql +14 -0
  33. package/build/lib/labels/transports.d.ts +23 -0
  34. package/build/lib/labels/transports.js +39 -0
  35. package/build/modules/auth.d.ts +2 -0
  36. package/build/modules/auth.js +3 -1
  37. package/build/modules/capabilities.d.ts +5 -1
  38. package/build/modules/capabilities.js +38 -8
  39. package/build/modules/config.d.ts +10 -0
  40. package/build/modules/config.js +10 -0
  41. package/build/routes/escalations/resolve.js +18 -0
  42. package/build/routes/index.js +2 -0
  43. package/build/routes/labels.d.ts +2 -0
  44. package/build/routes/labels.js +135 -0
  45. package/build/routes/users.js +1 -1
  46. package/build/services/labels/content.d.ts +13 -0
  47. package/build/services/labels/content.js +81 -0
  48. package/build/services/labels/errors.d.ts +5 -0
  49. package/build/services/labels/errors.js +12 -0
  50. package/build/services/labels/index.d.ts +11 -0
  51. package/build/services/labels/index.js +52 -0
  52. package/build/services/labels/issue.d.ts +38 -0
  53. package/build/services/labels/issue.js +181 -0
  54. package/build/services/labels/jobs.d.ts +37 -0
  55. package/build/services/labels/jobs.js +75 -0
  56. package/build/services/labels/media.d.ts +11 -0
  57. package/build/services/labels/media.js +44 -0
  58. package/build/services/labels/reissue.d.ts +13 -0
  59. package/build/services/labels/reissue.js +65 -0
  60. package/build/services/labels/render-pdf.d.ts +11 -0
  61. package/build/services/labels/render-pdf.js +138 -0
  62. package/build/services/labels/targets.d.ts +18 -0
  63. package/build/services/labels/targets.js +216 -0
  64. package/build/services/labels/templates/index.d.ts +3 -0
  65. package/build/services/labels/templates/index.js +18 -0
  66. package/build/services/labels/templates/read.d.ts +4 -0
  67. package/build/services/labels/templates/read.js +36 -0
  68. package/build/services/labels/templates/sql.d.ts +8 -0
  69. package/build/services/labels/templates/sql.js +50 -0
  70. package/build/services/labels/templates/validate.d.ts +19 -0
  71. package/build/services/labels/templates/validate.js +93 -0
  72. package/build/services/labels/templates/write.d.ts +16 -0
  73. package/build/services/labels/templates/write.js +75 -0
  74. package/build/services/labels/token.d.ts +9 -0
  75. package/build/services/labels/token.js +28 -0
  76. package/build/services/labels/verify.d.ts +4 -0
  77. package/build/services/labels/verify.js +38 -0
  78. package/build/services/role/index.d.ts +2 -0
  79. package/build/services/role/index.js +7 -0
  80. package/build/services/role/scan-done.js +4 -1
  81. package/build/services/role/sql.d.ts +1 -0
  82. package/build/services/role/sql.js +3 -1
  83. package/build/services/role/types.d.ts +2 -0
  84. package/build/services/scan-code/index.d.ts +1 -1
  85. package/build/services/scan-code/index.js +2 -1
  86. package/build/services/scan-code/parse.d.ts +5 -1
  87. package/build/services/scan-code/parse.js +8 -2
  88. package/build/services/scan-code/validate-station.d.ts +13 -0
  89. package/build/services/scan-code/validate-station.js +81 -0
  90. package/build/services/scan-code/validate-subject.js +33 -6
  91. package/build/services/scan-code/validate.d.ts +3 -0
  92. package/build/services/scan-code/validate.js +22 -18
  93. package/build/services/user/crud.d.ts +13 -1
  94. package/build/services/user/crud.js +42 -11
  95. package/build/services/user/index.d.ts +3 -2
  96. package/build/services/user/index.js +7 -1
  97. package/build/services/user/redact.d.ts +17 -0
  98. package/build/services/user/redact.js +32 -0
  99. package/build/services/user/sql.d.ts +8 -15
  100. package/build/services/user/sql.js +27 -3
  101. package/build/services/user/types.d.ts +21 -1
  102. package/build/shared/labels/compose.d.ts +12 -0
  103. package/build/shared/labels/compose.js +43 -0
  104. package/build/shared/labels/index.d.ts +9 -0
  105. package/build/shared/labels/index.js +54 -0
  106. package/build/shared/labels/label-content.d.ts +17 -0
  107. package/build/shared/labels/label-content.js +137 -0
  108. package/build/shared/labels/layout.d.ts +23 -0
  109. package/build/shared/labels/layout.js +81 -0
  110. package/build/shared/labels/media.d.ts +22 -0
  111. package/build/shared/labels/media.js +116 -0
  112. package/build/shared/labels/render-svg.d.ts +10 -0
  113. package/build/shared/labels/render-svg.js +58 -0
  114. package/build/shared/labels/render-zpl.d.ts +9 -0
  115. package/build/shared/labels/render-zpl.js +63 -0
  116. package/build/shared/labels/symbol.d.ts +18 -0
  117. package/build/shared/labels/symbol.js +74 -0
  118. package/build/shared/labels/tokens.d.ts +18 -0
  119. package/build/shared/labels/tokens.js +43 -0
  120. package/build/shared/labels/types.d.ts +105 -0
  121. package/build/shared/labels/types.js +11 -0
  122. package/build/start/adapters.js +16 -0
  123. package/build/start/workers.js +18 -2
  124. package/build/system/mcp-servers/admin/index.js +2 -0
  125. package/build/system/mcp-servers/admin/labels-schemas.d.ts +192 -0
  126. package/build/system/mcp-servers/admin/labels-schemas.js +46 -0
  127. package/build/system/mcp-servers/admin/labels.d.ts +9 -0
  128. package/build/system/mcp-servers/admin/labels.js +101 -0
  129. package/build/system/mcp-servers/admin/schemas.d.ts +491 -24
  130. package/build/system/mcp-servers/admin/schemas.js +32 -4
  131. package/build/system/mcp-servers/admin/users.js +1 -1
  132. package/build/system/seed/tool-manifests-admin.js +5 -0
  133. package/build/tsconfig.tsbuildinfo +1 -1
  134. package/build/types/capability.d.ts +2 -1
  135. package/build/types/index.d.ts +3 -2
  136. package/build/types/labels/index.d.ts +4 -0
  137. package/build/types/labels/index.js +2 -0
  138. package/build/types/labels/job.d.ts +51 -0
  139. package/build/types/labels/job.js +2 -0
  140. package/build/types/labels/source.d.ts +44 -0
  141. package/build/types/labels/source.js +2 -0
  142. package/build/types/labels/template.d.ts +46 -0
  143. package/build/types/labels/template.js +2 -0
  144. package/build/types/labels/transport.d.ts +24 -0
  145. package/build/types/labels/transport.js +2 -0
  146. package/build/types/scan-choice.d.ts +2 -4
  147. package/build/types/scan-code/constants.d.ts +1 -0
  148. package/build/types/scan-code/constants.js +1 -0
  149. package/build/types/scan-code/response.d.ts +22 -4
  150. package/build/types/scan-code/rule.d.ts +66 -3
  151. package/build/types/startup.d.ts +37 -0
  152. package/build/types/user.d.ts +2 -0
  153. package/dashboard/dist/assets/{AdminDashboard-VQ1fhhJP.js → AdminDashboard-BafKaq50.js} +2 -2
  154. package/dashboard/dist/assets/{AdminDashboard-VQ1fhhJP.js.map → AdminDashboard-BafKaq50.js.map} +1 -1
  155. package/dashboard/dist/assets/{AgentConfigPage-BOe_W2Ij.js → AgentConfigPage-CFHf31DT.js} +6 -6
  156. package/dashboard/dist/assets/{AgentConfigPage-BOe_W2Ij.js.map → AgentConfigPage-CFHf31DT.js.map} +1 -1
  157. package/dashboard/dist/assets/{AgentDetailPage-5ov5D9V2.js → AgentDetailPage-CEvz5rJr.js} +3 -3
  158. package/dashboard/dist/assets/{AgentDetailPage-5ov5D9V2.js.map → AgentDetailPage-CEvz5rJr.js.map} +1 -1
  159. package/dashboard/dist/assets/{AgentsPage-DDFMKHhI.js → AgentsPage-DjQaio0O.js} +2 -2
  160. package/dashboard/dist/assets/{AgentsPage-DDFMKHhI.js.map → AgentsPage-DjQaio0O.js.map} +1 -1
  161. package/dashboard/dist/assets/AvailableEscalationsPage-UB03VTJx.js +2 -0
  162. package/dashboard/dist/assets/AvailableEscalationsPage-UB03VTJx.js.map +1 -0
  163. package/dashboard/dist/assets/{BotPicker-Dqpo36dM.js → BotPicker-C7MNWOF7.js} +2 -2
  164. package/dashboard/dist/assets/{BotPicker-Dqpo36dM.js.map → BotPicker-C7MNWOF7.js.map} +1 -1
  165. package/dashboard/dist/assets/BulkAssignModal-h5fX-_cV.js +2 -0
  166. package/dashboard/dist/assets/{BulkAssignModal-CmLVxkz-.js.map → BulkAssignModal-h5fX-_cV.js.map} +1 -1
  167. package/dashboard/dist/assets/{CapabilitiesPage-Dfkip6_b.js → CapabilitiesPage-BIzDl-ZT.js} +2 -2
  168. package/dashboard/dist/assets/{CapabilitiesPage-Dfkip6_b.js.map → CapabilitiesPage-BIzDl-ZT.js.map} +1 -1
  169. package/dashboard/dist/assets/{CollapsibleSection-CYNYMYSa.js → CollapsibleSection-B5TivtEg.js} +2 -2
  170. package/dashboard/dist/assets/{CollapsibleSection-CYNYMYSa.js.map → CollapsibleSection-B5TivtEg.js.map} +1 -1
  171. package/dashboard/dist/assets/{ConfirmDeleteModal-CpJNP-8w.js → ConfirmDeleteModal-CB4nKePb.js} +2 -2
  172. package/dashboard/dist/assets/{ConfirmDeleteModal-CpJNP-8w.js.map → ConfirmDeleteModal-CB4nKePb.js.map} +1 -1
  173. package/dashboard/dist/assets/{ConnectedAppsPage-DXIp2Dpl.js → ConnectedAppsPage-B3S5gVWw.js} +2 -2
  174. package/dashboard/dist/assets/{ConnectedAppsPage-DXIp2Dpl.js.map → ConnectedAppsPage-B3S5gVWw.js.map} +1 -1
  175. package/dashboard/dist/assets/{CountdownTimer-CuPY7zkb.js → CountdownTimer-BHVIq3kA.js} +2 -2
  176. package/dashboard/dist/assets/{CountdownTimer-CuPY7zkb.js.map → CountdownTimer-BHVIq3kA.js.map} +1 -1
  177. package/dashboard/dist/assets/CredentialConfirmModal-w0AGmCIe.js +2 -0
  178. package/dashboard/dist/assets/CredentialConfirmModal-w0AGmCIe.js.map +1 -0
  179. package/dashboard/dist/assets/{CredentialsPage-CtrnkHcj.js → CredentialsPage-BtCGBJrT.js} +2 -2
  180. package/dashboard/dist/assets/{CredentialsPage-CtrnkHcj.js.map → CredentialsPage-BtCGBJrT.js.map} +1 -1
  181. package/dashboard/dist/assets/{CronLabel-DVjTw5Ri.js → CronLabel-BG1rZK-5.js} +2 -2
  182. package/dashboard/dist/assets/{CronLabel-DVjTw5Ri.js.map → CronLabel-BG1rZK-5.js.map} +1 -1
  183. package/dashboard/dist/assets/{DropZone-DefYTYQy.js → DropZone-D8ZVdEb5.js} +2 -2
  184. package/dashboard/dist/assets/{DropZone-DefYTYQy.js.map → DropZone-D8ZVdEb5.js.map} +1 -1
  185. package/dashboard/dist/assets/{ElapsedCell-gY_mGMTF.js → ElapsedCell-l4m8Yvfv.js} +2 -2
  186. package/dashboard/dist/assets/{ElapsedCell-gY_mGMTF.js.map → ElapsedCell-l4m8Yvfv.js.map} +1 -1
  187. package/dashboard/dist/assets/{EntityTimelinePanel-DJN_ZEQa.js → EntityTimelinePanel-BOHlIaxF.js} +2 -2
  188. package/dashboard/dist/assets/{EntityTimelinePanel-DJN_ZEQa.js.map → EntityTimelinePanel-BOHlIaxF.js.map} +1 -1
  189. package/dashboard/dist/assets/{EscalationListSchemaPage-A4KpTdJA.js → EscalationListSchemaPage-BotlwlX3.js} +3 -3
  190. package/dashboard/dist/assets/{EscalationListSchemaPage-A4KpTdJA.js.map → EscalationListSchemaPage-BotlwlX3.js.map} +1 -1
  191. package/dashboard/dist/assets/{EscalationSchemaPage-nfCn42hT.js → EscalationSchemaPage-CfZSVOSD.js} +3 -3
  192. package/dashboard/dist/assets/{EscalationSchemaPage-nfCn42hT.js.map → EscalationSchemaPage-CfZSVOSD.js.map} +1 -1
  193. package/dashboard/dist/assets/{EscalationTimeline-CLvSr1SD.js → EscalationTimeline-CCKpuRBU.js} +2 -2
  194. package/dashboard/dist/assets/{EscalationTimeline-CLvSr1SD.js.map → EscalationTimeline-CCKpuRBU.js.map} +1 -1
  195. package/dashboard/dist/assets/{EscalationTitleSelect-CT7mYHkb.js → EscalationTitleSelect-cpTzPHiW.js} +2 -2
  196. package/dashboard/dist/assets/{EscalationTitleSelect-CT7mYHkb.js.map → EscalationTitleSelect-cpTzPHiW.js.map} +1 -1
  197. package/dashboard/dist/assets/{EscalationsOverview-CKaGRh-E.js → EscalationsOverview-DS-nK0qV.js} +2 -2
  198. package/dashboard/dist/assets/{EscalationsOverview-CKaGRh-E.js.map → EscalationsOverview-DS-nK0qV.js.map} +1 -1
  199. package/dashboard/dist/assets/{EventTable-2ywJsOLy.js → EventTable-UfebhJf0.js} +2 -2
  200. package/dashboard/dist/assets/{EventTable-2ywJsOLy.js.map → EventTable-UfebhJf0.js.map} +1 -1
  201. package/dashboard/dist/assets/{FilterBar-Dy0b7wwf.js → FilterBar-newA5l-X.js} +2 -2
  202. package/dashboard/dist/assets/{FilterBar-Dy0b7wwf.js.map → FilterBar-newA5l-X.js.map} +1 -1
  203. package/dashboard/dist/assets/{GraphInvokePage-yOVpraAy.js → GraphInvokePage-6SCDyQcK.js} +2 -2
  204. package/dashboard/dist/assets/{GraphInvokePage-yOVpraAy.js.map → GraphInvokePage-6SCDyQcK.js.map} +1 -1
  205. package/dashboard/dist/assets/HomePage-BEc-XdKj.js +2 -0
  206. package/dashboard/dist/assets/{HomePage-67xXjKjN.js.map → HomePage-BEc-XdKj.js.map} +1 -1
  207. package/dashboard/dist/assets/LabelJobsPage-BO50zXT5.js +2 -0
  208. package/dashboard/dist/assets/LabelJobsPage-BO50zXT5.js.map +1 -0
  209. package/dashboard/dist/assets/{LinePage-CMsYtukW.js → LinePage-NYxJQ-ex.js} +3 -3
  210. package/dashboard/dist/assets/{LinePage-CMsYtukW.js.map → LinePage-NYxJQ-ex.js.map} +1 -1
  211. package/dashboard/dist/assets/{LinesPage-pwL46mOS.js → LinesPage-RbWTaQRh.js} +3 -3
  212. package/dashboard/dist/assets/{LinesPage-pwL46mOS.js.map → LinesPage-RbWTaQRh.js.map} +1 -1
  213. package/dashboard/dist/assets/{ListToolbar-CJmvGy2B.js → ListToolbar-B-E9-toh.js} +2 -2
  214. package/dashboard/dist/assets/{ListToolbar-CJmvGy2B.js.map → ListToolbar-B-E9-toh.js.map} +1 -1
  215. package/dashboard/dist/assets/{McpOverview-DA9LLvNG.js → McpOverview-Shcf9QhZ.js} +2 -2
  216. package/dashboard/dist/assets/{McpOverview-DA9LLvNG.js.map → McpOverview-Shcf9QhZ.js.map} +1 -1
  217. package/dashboard/dist/assets/{McpQueryDetailPage-N7qLmfE8.js → McpQueryDetailPage-D8kmjy2v.js} +3 -3
  218. package/dashboard/dist/assets/{McpQueryDetailPage-N7qLmfE8.js.map → McpQueryDetailPage-D8kmjy2v.js.map} +1 -1
  219. package/dashboard/dist/assets/{McpQueryPage-CpsP3w7x.js → McpQueryPage-ck-o5m8A.js} +2 -2
  220. package/dashboard/dist/assets/{McpQueryPage-CpsP3w7x.js.map → McpQueryPage-ck-o5m8A.js.map} +1 -1
  221. package/dashboard/dist/assets/McpRunDetailPage-BJKkM9-3.js +2 -0
  222. package/dashboard/dist/assets/{McpRunDetailPage-qHRQ1pEY.js.map → McpRunDetailPage-BJKkM9-3.js.map} +1 -1
  223. package/dashboard/dist/assets/{McpRunsPage-BRDDYpTM.js → McpRunsPage-DqhHfD5G.js} +2 -2
  224. package/dashboard/dist/assets/{McpRunsPage-BRDDYpTM.js.map → McpRunsPage-DqhHfD5G.js.map} +1 -1
  225. package/dashboard/dist/assets/{NamespacePill-CeSfHH-j.js → NamespacePill--uIaGtrN.js} +2 -2
  226. package/dashboard/dist/assets/{NamespacePill-CeSfHH-j.js.map → NamespacePill--uIaGtrN.js.map} +1 -1
  227. package/dashboard/dist/assets/{OperationsPage-zUaab-CL.js → OperationsPage-D6B9Vv__.js} +3 -3
  228. package/dashboard/dist/assets/{OperationsPage-zUaab-CL.js.map → OperationsPage-D6B9Vv__.js.map} +1 -1
  229. package/dashboard/dist/assets/OperatorDashboard-CIH1cxjQ.js +2 -0
  230. package/dashboard/dist/assets/{OperatorDashboard-el5BquXN.js.map → OperatorDashboard-CIH1cxjQ.js.map} +1 -1
  231. package/dashboard/dist/assets/{PageHeader-DiGWAQlR.js → PageHeader-DClJ33fV.js} +2 -2
  232. package/dashboard/dist/assets/{PageHeader-DiGWAQlR.js.map → PageHeader-DClJ33fV.js.map} +1 -1
  233. package/dashboard/dist/assets/{PageHeaderWithStats-DwnKQ06j.js → PageHeaderWithStats-C-TrbKQL.js} +2 -2
  234. package/dashboard/dist/assets/{PageHeaderWithStats-DwnKQ06j.js.map → PageHeaderWithStats-C-TrbKQL.js.map} +1 -1
  235. package/dashboard/dist/assets/PersonaDetailPage-DjvfyIph.js +2 -0
  236. package/dashboard/dist/assets/{PersonaDetailPage-B_tb8gfl.js.map → PersonaDetailPage-DjvfyIph.js.map} +1 -1
  237. package/dashboard/dist/assets/{PersonasPage-BPI7mqM8.js → PersonasPage-D7ryA8Vc.js} +2 -2
  238. package/dashboard/dist/assets/{PersonasPage-BPI7mqM8.js.map → PersonasPage-D7ryA8Vc.js.map} +1 -1
  239. package/dashboard/dist/assets/{PortalPage-e_rBb1do.js → PortalPage-D3ybr0mo.js} +2 -2
  240. package/dashboard/dist/assets/{PortalPage-e_rBb1do.js.map → PortalPage-D3ybr0mo.js.map} +1 -1
  241. package/dashboard/dist/assets/PrintLabelsPanel-D0HF5x8b.js +2 -0
  242. package/dashboard/dist/assets/PrintLabelsPanel-D0HF5x8b.js.map +1 -0
  243. package/dashboard/dist/assets/{ProcessDetailPage-D35RX1bB.js → ProcessDetailPage-0xS9EdHe.js} +2 -2
  244. package/dashboard/dist/assets/{ProcessDetailPage-D35RX1bB.js.map → ProcessDetailPage-0xS9EdHe.js.map} +1 -1
  245. package/dashboard/dist/assets/{ProcessesListPage-CT81miI5.js → ProcessesListPage-93SMj1Fd.js} +2 -2
  246. package/dashboard/dist/assets/{ProcessesListPage-CT81miI5.js.map → ProcessesListPage-93SMj1Fd.js.map} +1 -1
  247. package/dashboard/dist/assets/{ResolverForm-BxJkoKAO.js → ResolverForm-DfogHDzl.js} +5 -5
  248. package/dashboard/dist/assets/{ResolverForm-BxJkoKAO.js.map → ResolverForm-DfogHDzl.js.map} +1 -1
  249. package/dashboard/dist/assets/RoleDetailPage-DlUOJWSB.js +8 -0
  250. package/dashboard/dist/assets/{RoleDetailPage-DtU7vsJm.js.map → RoleDetailPage-DlUOJWSB.js.map} +1 -1
  251. package/dashboard/dist/assets/{RolePill-D3hkAdKf.js → RolePill-BjD1Qw5y.js} +2 -2
  252. package/dashboard/dist/assets/{RolePill-D3hkAdKf.js.map → RolePill-BjD1Qw5y.js.map} +1 -1
  253. package/dashboard/dist/assets/RolesPage-DqhHSvaw.js +2 -0
  254. package/dashboard/dist/assets/{RolesPage-BE7RWt9q.js.map → RolesPage-DqhHSvaw.js.map} +1 -1
  255. package/dashboard/dist/assets/{RosterWidget-BJMx0a8Z.js → RosterWidget-BrIq61HR.js} +2 -2
  256. package/dashboard/dist/assets/RosterWidget-BrIq61HR.js.map +1 -0
  257. package/dashboard/dist/assets/RunAsSelector-D6zQrCNr.js +2 -0
  258. package/dashboard/dist/assets/{RunAsSelector-Co6s9bqA.js.map → RunAsSelector-D6zQrCNr.js.map} +1 -1
  259. package/dashboard/dist/assets/ScanCodesPage-B2S9DR2f.js +2 -0
  260. package/dashboard/dist/assets/{ScanCodesPage-C2TETaj5.js.map → ScanCodesPage-B2S9DR2f.js.map} +1 -1
  261. package/dashboard/dist/assets/ScanSchemeDetailPage-gpxKN-pL.js +5 -0
  262. package/dashboard/dist/assets/ScanSchemeDetailPage-gpxKN-pL.js.map +1 -0
  263. package/dashboard/dist/assets/ScanStationPage-B-UTgXsG.js +2 -0
  264. package/dashboard/dist/assets/ScanStationPage-B-UTgXsG.js.map +1 -0
  265. package/dashboard/dist/assets/{SchemeMatchFields-9H7SmbED.js → SchemeMatchFields-BK24aa7K.js} +2 -2
  266. package/dashboard/dist/assets/{SchemeMatchFields-9H7SmbED.js.map → SchemeMatchFields-BK24aa7K.js.map} +1 -1
  267. package/dashboard/dist/assets/{ScopeBadge-DGz79rmG.js → ScopeBadge-ofLQ6HW-.js} +2 -2
  268. package/dashboard/dist/assets/{ScopeBadge-DGz79rmG.js.map → ScopeBadge-ofLQ6HW-.js.map} +1 -1
  269. package/dashboard/dist/assets/{StickyPagination-miUdVAKw.js → StickyPagination-CgVv7vc_.js} +2 -2
  270. package/dashboard/dist/assets/{StickyPagination-miUdVAKw.js.map → StickyPagination-CgVv7vc_.js.map} +1 -1
  271. package/dashboard/dist/assets/{StreamMessageDetail-D5Rk7pn7.js → StreamMessageDetail-B9sxDVw4.js} +2 -2
  272. package/dashboard/dist/assets/{StreamMessageDetail-D5Rk7pn7.js.map → StreamMessageDetail-B9sxDVw4.js.map} +1 -1
  273. package/dashboard/dist/assets/{SwimlaneTimeline-B1QY1ZzH.js → SwimlaneTimeline-DQc0CYSL.js} +2 -2
  274. package/dashboard/dist/assets/{SwimlaneTimeline-B1QY1ZzH.js.map → SwimlaneTimeline-DQc0CYSL.js.map} +1 -1
  275. package/dashboard/dist/assets/{TagInput-DaIdhv3h.js → TagInput-47qVYzke.js} +2 -2
  276. package/dashboard/dist/assets/{TagInput-DaIdhv3h.js.map → TagInput-47qVYzke.js.map} +1 -1
  277. package/dashboard/dist/assets/{TaskDetailPage-DKUM37o8.js → TaskDetailPage-D6VOsA1f.js} +2 -2
  278. package/dashboard/dist/assets/{TaskDetailPage-DKUM37o8.js.map → TaskDetailPage-D6VOsA1f.js.map} +1 -1
  279. package/dashboard/dist/assets/{TaskQueuePill-sUA1nZe-.js → TaskQueuePill-C5KmdXAl.js} +2 -2
  280. package/dashboard/dist/assets/{TaskQueuePill-sUA1nZe-.js.map → TaskQueuePill-C5KmdXAl.js.map} +1 -1
  281. package/dashboard/dist/assets/{TasksListPage-CUulwvm-.js → TasksListPage-DG8hvO8G.js} +2 -2
  282. package/dashboard/dist/assets/{TasksListPage-CUulwvm-.js.map → TasksListPage-DG8hvO8G.js.map} +1 -1
  283. package/dashboard/dist/assets/{TimeAgo-CHTelacB.js → TimeAgo-CL02EhFi.js} +2 -2
  284. package/dashboard/dist/assets/{TimeAgo-CHTelacB.js.map → TimeAgo-CL02EhFi.js.map} +1 -1
  285. package/dashboard/dist/assets/{TimestampCell-NanLWLKo.js → TimestampCell-BE7oKVJg.js} +2 -2
  286. package/dashboard/dist/assets/{TimestampCell-NanLWLKo.js.map → TimestampCell-BE7oKVJg.js.map} +1 -1
  287. package/dashboard/dist/assets/{ToolPill-CpBAFdEX.js → ToolPill-Cp9Drk1s.js} +2 -2
  288. package/dashboard/dist/assets/{ToolPill-CpBAFdEX.js.map → ToolPill-Cp9Drk1s.js.map} +1 -1
  289. package/dashboard/dist/assets/{ToolTestPanel-CF1CHzgz.js → ToolTestPanel-CRecLh6S.js} +2 -2
  290. package/dashboard/dist/assets/{ToolTestPanel-CF1CHzgz.js.map → ToolTestPanel-CRecLh6S.js.map} +1 -1
  291. package/dashboard/dist/assets/{TopicDetailPage-CGO8XV_a.js → TopicDetailPage-QzkinTfN.js} +3 -3
  292. package/dashboard/dist/assets/{TopicDetailPage-CGO8XV_a.js.map → TopicDetailPage-QzkinTfN.js.map} +1 -1
  293. package/dashboard/dist/assets/{TopicsPage-Bt8gOKYr.js → TopicsPage-D8dW6J65.js} +2 -2
  294. package/dashboard/dist/assets/{TopicsPage-Bt8gOKYr.js.map → TopicsPage-D8dW6J65.js.map} +1 -1
  295. package/dashboard/dist/assets/{UserName-DKXnK7DD.js → UserName-Dw3R_zrl.js} +2 -2
  296. package/dashboard/dist/assets/{UserName-DKXnK7DD.js.map → UserName-Dw3R_zrl.js.map} +1 -1
  297. package/dashboard/dist/assets/WorkflowExecutionPage-BTocv8or.js +2 -0
  298. package/dashboard/dist/assets/{WorkflowExecutionPage-Crf7AIFc.js.map → WorkflowExecutionPage-BTocv8or.js.map} +1 -1
  299. package/dashboard/dist/assets/{WorkflowPill-CKHip3hH.js → WorkflowPill-BiLYq__w.js} +2 -2
  300. package/dashboard/dist/assets/{WorkflowPill-CKHip3hH.js.map → WorkflowPill-BiLYq__w.js.map} +1 -1
  301. package/dashboard/dist/assets/WorkflowsDashboard-CIPEt3et.js +2 -0
  302. package/dashboard/dist/assets/{WorkflowsDashboard--isjt06C.js.map → WorkflowsDashboard-CIPEt3et.js.map} +1 -1
  303. package/dashboard/dist/assets/{WorkflowsOverview-D7Oqf4-V.js → WorkflowsOverview-Bj4MJIE-.js} +2 -2
  304. package/dashboard/dist/assets/{WorkflowsOverview-D7Oqf4-V.js.map → WorkflowsOverview-Bj4MJIE-.js.map} +1 -1
  305. package/dashboard/dist/assets/{YamlWorkflowDetailPage-B0wxgrGP.js → YamlWorkflowDetailPage-DMEk5k9-.js} +2 -2
  306. package/dashboard/dist/assets/{YamlWorkflowDetailPage-B0wxgrGP.js.map → YamlWorkflowDetailPage-DMEk5k9-.js.map} +1 -1
  307. package/dashboard/dist/assets/{YamlWorkflowsPage-BVdLnm6K.js → YamlWorkflowsPage-F2yyyoiB.js} +2 -2
  308. package/dashboard/dist/assets/{YamlWorkflowsPage-BVdLnm6K.js.map → YamlWorkflowsPage-F2yyyoiB.js.map} +1 -1
  309. package/dashboard/dist/assets/{agents-CHjbjHXA.js → agents-mSgxEPpI.js} +2 -2
  310. package/dashboard/dist/assets/{agents-CHjbjHXA.js.map → agents-mSgxEPpI.js.map} +1 -1
  311. package/dashboard/dist/assets/{bots-WrUhEPWs.js → bots-p4Hp0CV6.js} +2 -2
  312. package/dashboard/dist/assets/{bots-WrUhEPWs.js.map → bots-p4Hp0CV6.js.map} +1 -1
  313. package/dashboard/dist/assets/{capabilities-CunMmkj8.js → capabilities-D_-I_SXR.js} +2 -2
  314. package/dashboard/dist/assets/{capabilities-CunMmkj8.js.map → capabilities-D_-I_SXR.js.map} +1 -1
  315. package/dashboard/dist/assets/{controlplane-D6IZIZoh.js → controlplane-DjdoQnRU.js} +2 -2
  316. package/dashboard/dist/assets/{controlplane-D6IZIZoh.js.map → controlplane-DjdoQnRU.js.map} +1 -1
  317. package/dashboard/dist/assets/{escalation-columns-Bvo6JI4Z.js → escalation-columns-R_IEVQjQ.js} +2 -2
  318. package/dashboard/dist/assets/{escalation-columns-Bvo6JI4Z.js.map → escalation-columns-R_IEVQjQ.js.map} +1 -1
  319. package/dashboard/dist/assets/{escalation-items-DFGRwo49.js → escalation-items-BGZlJMpk.js} +2 -2
  320. package/dashboard/dist/assets/{escalation-items-DFGRwo49.js.map → escalation-items-BGZlJMpk.js.map} +1 -1
  321. package/dashboard/dist/assets/{index-OuKQ_0eB.js → index-BEMdD58x.js} +2 -2
  322. package/dashboard/dist/assets/{index-OuKQ_0eB.js.map → index-BEMdD58x.js.map} +1 -1
  323. package/dashboard/dist/assets/index-BUmz0NMg.css +1 -0
  324. package/dashboard/dist/assets/{index-C7EIu1mG.js → index-BuCEhhnl.js} +2 -2
  325. package/dashboard/dist/assets/{index-C7EIu1mG.js.map → index-BuCEhhnl.js.map} +1 -1
  326. package/dashboard/dist/assets/{index-Bo8QU31k.js → index-BxbQmeqh.js} +2 -2
  327. package/dashboard/dist/assets/{index-Bo8QU31k.js.map → index-BxbQmeqh.js.map} +1 -1
  328. package/dashboard/dist/assets/index-C5osluV3.js +2 -0
  329. package/dashboard/dist/assets/{index-DRK7M1_9.js.map → index-C5osluV3.js.map} +1 -1
  330. package/dashboard/dist/assets/{index-ygxyAKcc.js → index-C_dAJUzh.js} +27 -27
  331. package/dashboard/dist/assets/index-C_dAJUzh.js.map +1 -0
  332. package/dashboard/dist/assets/{index-DRw0FXdX.js → index-D-FYj9jT.js} +2 -2
  333. package/dashboard/dist/assets/{index-DRw0FXdX.js.map → index-D-FYj9jT.js.map} +1 -1
  334. package/dashboard/dist/assets/{index-B8qrHwp9.js → index-D6K_IgCz.js} +2 -2
  335. package/dashboard/dist/assets/{index-B8qrHwp9.js.map → index-D6K_IgCz.js.map} +1 -1
  336. package/dashboard/dist/assets/index-D7L_VoBD.js +2 -0
  337. package/dashboard/dist/assets/index-D7L_VoBD.js.map +1 -0
  338. package/dashboard/dist/assets/{index-BZFSXEkr.js → index-D9RAN9sA.js} +2 -2
  339. package/dashboard/dist/assets/{index-BZFSXEkr.js.map → index-D9RAN9sA.js.map} +1 -1
  340. package/dashboard/dist/assets/{index-DCJ483vt.js → index-DUYAGxwc.js} +2 -2
  341. package/dashboard/dist/assets/{index-DCJ483vt.js.map → index-DUYAGxwc.js.map} +1 -1
  342. package/dashboard/dist/assets/{index-boT612Jo.js → index-Dk2KKo0z.js} +2 -2
  343. package/dashboard/dist/assets/{index-boT612Jo.js.map → index-Dk2KKo0z.js.map} +1 -1
  344. package/dashboard/dist/assets/{index-CpCchhQv.js → index-DlJkZ12b.js} +2 -2
  345. package/dashboard/dist/assets/{index-CpCchhQv.js.map → index-DlJkZ12b.js.map} +1 -1
  346. package/dashboard/dist/assets/index-FiNThtNU.js +3 -0
  347. package/dashboard/dist/assets/index-FiNThtNU.js.map +1 -0
  348. package/dashboard/dist/assets/{knowledge-BubJBTwg.js → knowledge-DSsPTqkK.js} +2 -2
  349. package/dashboard/dist/assets/{knowledge-BubJBTwg.js.map → knowledge-DSsPTqkK.js.map} +1 -1
  350. package/dashboard/dist/assets/{machines-DSm5NFgs.js → machines-DSgGtqqr.js} +2 -2
  351. package/dashboard/dist/assets/{machines-DSm5NFgs.js.map → machines-DSgGtqqr.js.map} +1 -1
  352. package/dashboard/dist/assets/{mcp-D6MckqOV.js → mcp-Cg-_uLw8.js} +2 -2
  353. package/dashboard/dist/assets/{mcp-D6MckqOV.js.map → mcp-Cg-_uLw8.js.map} +1 -1
  354. package/dashboard/dist/assets/{mcp-query-VyCdOag6.js → mcp-query-DQombEK_.js} +2 -2
  355. package/dashboard/dist/assets/{mcp-query-VyCdOag6.js.map → mcp-query-DQombEK_.js.map} +1 -1
  356. package/dashboard/dist/assets/{personas-CyJc10xe.js → personas-DYrcoVBu.js} +2 -2
  357. package/dashboard/dist/assets/{personas-CyJc10xe.js.map → personas-DYrcoVBu.js.map} +1 -1
  358. package/dashboard/dist/assets/{pipelines-B2inDtx3.js → pipelines-wdb4xsey.js} +2 -2
  359. package/dashboard/dist/assets/{pipelines-B2inDtx3.js.map → pipelines-wdb4xsey.js.map} +1 -1
  360. package/dashboard/dist/assets/{tasks-DOP4d3M6.js → tasks-Bil7gvm9.js} +2 -2
  361. package/dashboard/dist/assets/{tasks-DOP4d3M6.js.map → tasks-Bil7gvm9.js.map} +1 -1
  362. package/dashboard/dist/assets/{topics-CNOjSWpX.js → topics-wBqaVhRR.js} +2 -2
  363. package/dashboard/dist/assets/{topics-CNOjSWpX.js.map → topics-wBqaVhRR.js.map} +1 -1
  364. package/dashboard/dist/assets/{useDebouncedValue-CgO0TGMd.js → useDebouncedValue-CwrY8TpV.js} +2 -2
  365. package/dashboard/dist/assets/{useDebouncedValue-CgO0TGMd.js.map → useDebouncedValue-CwrY8TpV.js.map} +1 -1
  366. package/dashboard/dist/assets/{useNamespace-BWHvUKtK.js → useNamespace-Sod_xApz.js} +2 -2
  367. package/dashboard/dist/assets/{useNamespace-BWHvUKtK.js.map → useNamespace-Sod_xApz.js.map} +1 -1
  368. package/dashboard/dist/assets/{useYamlActivityEvents-BZQ__ZGD.js → useYamlActivityEvents-CKLInV3C.js} +2 -2
  369. package/dashboard/dist/assets/{useYamlActivityEvents-BZQ__ZGD.js.map → useYamlActivityEvents-CKLInV3C.js.map} +1 -1
  370. package/dashboard/dist/assets/{validate-CAin6WM_.js → validate-CYhW1xMJ.js} +2 -2
  371. package/dashboard/dist/assets/{validate-CAin6WM_.js.map → validate-CYhW1xMJ.js.map} +1 -1
  372. package/dashboard/dist/assets/{vendor-icons-en0_uSRD.js → vendor-icons-ed7mYQw4.js} +2 -2
  373. package/dashboard/dist/assets/{vendor-icons-en0_uSRD.js.map → vendor-icons-ed7mYQw4.js.map} +1 -1
  374. package/dashboard/dist/assets/{yaml-workflows-Dyln3od-.js → yaml-workflows-C20qHo3L.js} +2 -2
  375. package/dashboard/dist/assets/{yaml-workflows-Dyln3od-.js.map → yaml-workflows-C20qHo3L.js.map} +1 -1
  376. package/dashboard/dist/index.html +3 -3
  377. package/docs/api/http/escalations.md +15 -0
  378. package/docs/api/http/labels.md +115 -0
  379. package/docs/api/http/users.md +2 -0
  380. package/docs/api/mcp/admin.md +76 -1
  381. package/docs/code-owned-configuration.md +1 -1
  382. package/docs/dashboard.md +2 -2
  383. package/docs/hitl/x-lt-roster.md +2 -0
  384. package/docs/hitl/x-lt-scan.md +12 -0
  385. package/docs/iam.md +12 -0
  386. package/docs/label-sheets.md +267 -0
  387. package/docs/scan-codes.md +93 -9
  388. package/package.json +4 -1
  389. package/dashboard/dist/assets/AvailableEscalationsPage-GFn8Sgg1.js +0 -2
  390. package/dashboard/dist/assets/AvailableEscalationsPage-GFn8Sgg1.js.map +0 -1
  391. package/dashboard/dist/assets/BulkAssignModal-CmLVxkz-.js +0 -2
  392. package/dashboard/dist/assets/HomePage-67xXjKjN.js +0 -2
  393. package/dashboard/dist/assets/McpRunDetailPage-qHRQ1pEY.js +0 -2
  394. package/dashboard/dist/assets/OperatorDashboard-el5BquXN.js +0 -2
  395. package/dashboard/dist/assets/PersonaDetailPage-B_tb8gfl.js +0 -2
  396. package/dashboard/dist/assets/RoleDetailPage-DtU7vsJm.js +0 -8
  397. package/dashboard/dist/assets/RolesPage-BE7RWt9q.js +0 -2
  398. package/dashboard/dist/assets/RosterWidget-BJMx0a8Z.js.map +0 -1
  399. package/dashboard/dist/assets/RunAsSelector-Co6s9bqA.js +0 -2
  400. package/dashboard/dist/assets/ScanCodesPage-C2TETaj5.js +0 -2
  401. package/dashboard/dist/assets/ScanSchemeDetailPage-C2UgU8l-.js +0 -5
  402. package/dashboard/dist/assets/ScanSchemeDetailPage-C2UgU8l-.js.map +0 -1
  403. package/dashboard/dist/assets/ScanStationPage-nWYz-OD3.js +0 -2
  404. package/dashboard/dist/assets/ScanStationPage-nWYz-OD3.js.map +0 -1
  405. package/dashboard/dist/assets/WorkflowExecutionPage-Crf7AIFc.js +0 -2
  406. package/dashboard/dist/assets/WorkflowsDashboard--isjt06C.js +0 -2
  407. package/dashboard/dist/assets/index-B95LbYhW.js +0 -2
  408. package/dashboard/dist/assets/index-B95LbYhW.js.map +0 -1
  409. package/dashboard/dist/assets/index-BmzscsXK.css +0 -1
  410. package/dashboard/dist/assets/index-DRK7M1_9.js +0 -2
  411. package/dashboard/dist/assets/index-P-DlgAWj.js +0 -3
  412. package/dashboard/dist/assets/index-P-DlgAWj.js.map +0 -1
  413. package/dashboard/dist/assets/index-ygxyAKcc.js.map +0 -1
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LabelTemplateConflictError = void 0;
4
+ exports.upsertLabelTemplate = upsertLabelTemplate;
5
+ exports.deleteLabelTemplate = deleteLabelTemplate;
6
+ exports.seedLabelTemplate = seedLabelTemplate;
7
+ exports.applyLabelTemplate = applyLabelTemplate;
8
+ const db_1 = require("../../../lib/db");
9
+ const types_1 = require("../../../types");
10
+ const scan_code_1 = require("../../scan-code");
11
+ const user_1 = require("../../user");
12
+ const media_1 = require("../media");
13
+ const read_1 = require("./read");
14
+ const sql_1 = require("./sql");
15
+ const validate_1 = require("./validate");
16
+ /** An API write raced another: the stored revision is not the one the caller read. */
17
+ class LabelTemplateConflictError extends Error {
18
+ constructor(name, revision) {
19
+ super(`label template "${name}" changed (now revision ${revision}); reload and try again`);
20
+ this.status = 409;
21
+ this.name = 'LabelTemplateConflictError';
22
+ }
23
+ }
24
+ exports.LabelTemplateConflictError = LabelTemplateConflictError;
25
+ async function validated(input) {
26
+ const [scheme, rules, identityKeys] = await Promise.all([
27
+ (0, scan_code_1.getScanScheme)(input.scheme_version),
28
+ (0, scan_code_1.listScanRules)(input.scheme_version),
29
+ (0, user_1.getIdentityPropertyKeys)(),
30
+ ]);
31
+ (0, validate_1.assertValidTemplate)(input, { scheme, rules, identityKeys, mediaIds: (0, media_1.labelMediaPresets)().map((m) => m.id) });
32
+ return { ...input, sensitive: scheme.kind === types_1.SCAN_SCHEME_KINDS.IDENTITY || !!input.sensitive };
33
+ }
34
+ function params(input, source) {
35
+ return [
36
+ input.name,
37
+ input.scheme_version,
38
+ input.title,
39
+ input.description ?? null,
40
+ JSON.stringify(input.codes.map((c) => ({ category: c.category, caption: c.caption ?? null, tone: c.tone }))),
41
+ JSON.stringify({ title: input.text?.title ?? '', lines: input.text?.lines ?? [] }),
42
+ input.symbology ?? 'code128',
43
+ input.human_readable ?? true,
44
+ input.media ?? null,
45
+ input.sensitive,
46
+ input.enabled ?? true,
47
+ source,
48
+ ];
49
+ }
50
+ /**
51
+ * Create or replace a template from the API. With `expectedRevision`, the
52
+ * write lands only on that revision; otherwise LabelTemplateConflictError.
53
+ */
54
+ async function upsertLabelTemplate(input, expectedRevision) {
55
+ const row = await validated(input);
56
+ const { rows } = await (0, db_1.getPool)().query(sql_1.UPSERT_TEMPLATE, [...params(row, 'api'), expectedRevision ?? null]);
57
+ if (rows[0])
58
+ return (0, read_1.mapTemplate)(rows[0]);
59
+ const current = await (0, db_1.getPool)().query(sql_1.GET_TEMPLATE, [input.name]);
60
+ throw new LabelTemplateConflictError(input.name, current.rows[0]?.revision ?? 0);
61
+ }
62
+ async function deleteLabelTemplate(name) {
63
+ const { rowCount } = await (0, db_1.getPool)().query(sql_1.DELETE_TEMPLATE, [name]);
64
+ return (rowCount ?? 0) > 0;
65
+ }
66
+ /** Insert a template only when absent (database-owned configuration). */
67
+ async function seedLabelTemplate(input) {
68
+ const { rowCount } = await (0, db_1.getPool)().query(sql_1.SEED_TEMPLATE, params(await validated(input), 'api'));
69
+ return (rowCount ?? 0) > 0;
70
+ }
71
+ /** Apply a template declared in code; unchanged declarations write nothing. */
72
+ async function applyLabelTemplate(input) {
73
+ const { rowCount } = await (0, db_1.getPool)().query(sql_1.APPLY_TEMPLATE, params(await validated(input), 'code'));
74
+ return (rowCount ?? 0) > 0 ? 'applied' : 'unchanged';
75
+ }
@@ -0,0 +1,9 @@
1
+ import type { ScanScheme } from '../../types';
2
+ /** Characters in a minted delimited credential when the scheme sets no target_length (about 50 bits). */
3
+ export declare const DEFAULT_IDENTITY_TOKEN_LENGTH = 10;
4
+ /**
5
+ * A random credential for the scheme: Crockford base32 of the scheme's
6
+ * target_length (default 10) when delimited, that many digits when fixed.
7
+ * The scheme prefix is added when the code is composed, never stored.
8
+ */
9
+ export declare function mintIdentityToken(scheme: Pick<ScanScheme, 'encoding' | 'target_length'>): string;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ // New identity credentials, minted to fit the scheme's encoding.
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.DEFAULT_IDENTITY_TOKEN_LENGTH = void 0;
5
+ exports.mintIdentityToken = mintIdentityToken;
6
+ const crypto_1 = require("crypto");
7
+ const errors_1 = require("./errors");
8
+ const CROCKFORD = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
9
+ /** Characters in a minted delimited credential when the scheme sets no target_length (about 50 bits). */
10
+ exports.DEFAULT_IDENTITY_TOKEN_LENGTH = 10;
11
+ /**
12
+ * A random credential for the scheme: Crockford base32 of the scheme's
13
+ * target_length (default 10) when delimited, that many digits when fixed.
14
+ * The scheme prefix is added when the code is composed, never stored.
15
+ */
16
+ function mintIdentityToken(scheme) {
17
+ if (scheme.encoding === 'delimited') {
18
+ const bytes = (0, crypto_1.randomBytes)(scheme.target_length ?? exports.DEFAULT_IDENTITY_TOKEN_LENGTH);
19
+ return Array.from(bytes, (b) => CROCKFORD[b % 32]).join('');
20
+ }
21
+ if (scheme.encoding === 'fixed') {
22
+ const length = scheme.target_length ?? 0;
23
+ if (length < 1)
24
+ throw new errors_1.LabelRequestError(400, 'the scheme has no target length');
25
+ return Array.from({ length }, () => String((0, crypto_1.randomInt)(10))).join('');
26
+ }
27
+ throw new errors_1.LabelRequestError(400, `credentials are minted for fixed and delimited schemes, not ${scheme.encoding}`);
28
+ }
@@ -0,0 +1,4 @@
1
+ import { type ScanRule, type ScanScheme } from '../../types';
2
+ import type { LabelContent, LabelWarning } from '../../shared/labels/types';
3
+ import type { LabelTarget, LabelTemplate } from '../../types/labels';
4
+ export declare function verifyLabels(template: LabelTemplate, scheme: ScanScheme, schemes: ScanScheme[], rules: ScanRule[], targets: LabelTarget[], contents: LabelContent[]): LabelWarning[];
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ // Flags labels that would fail on the floor: a code that does not parse back,
3
+ // a disabled rule or scheme, or a target that names nothing today.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.verifyLabels = verifyLabels;
6
+ const parse_1 = require("../../shared/scan-code/parse");
7
+ const types_1 = require("../../types");
8
+ function verifyLabels(template, scheme, schemes, rules, targets, contents) {
9
+ const identity = scheme.kind === types_1.SCAN_SCHEME_KINDS.IDENTITY;
10
+ const warnings = [];
11
+ if (!scheme.enabled) {
12
+ contents.forEach((_c, index) => warnings.push({ index, kind: 'unparseable', detail: `scheme ${scheme.version} is disabled; its codes do not scan` }));
13
+ return warnings;
14
+ }
15
+ const disabled = template.codes.filter((c) => !rules.find((r) => r.category === c.category)?.enabled);
16
+ contents.forEach((content, index) => {
17
+ for (const c of disabled) {
18
+ warnings.push({ index, kind: 'rule_disabled', detail: `the rule for category ${c.category} is disabled; that code does nothing when scanned` });
19
+ }
20
+ for (const { code } of content.codes) {
21
+ const parsed = (0, parse_1.parseScanCode)(code, schemes);
22
+ const same = parsed.ok && parsed.parsed.version === scheme.version && parsed.parsed.target === targets[index].target;
23
+ if (!same) {
24
+ warnings.push({
25
+ index, kind: 'unparseable',
26
+ detail: identity ? 'a badge code does not read back as this scheme' : `${code} does not read back as scheme ${scheme.version}`,
27
+ });
28
+ }
29
+ }
30
+ if (targets[index].resolved === false) {
31
+ warnings.push({
32
+ index, kind: 'unresolved',
33
+ detail: identity ? 'the badge holder is not an active user' : `${targets[index].target} names no row today`,
34
+ });
35
+ }
36
+ });
37
+ return warnings;
38
+ }
@@ -84,6 +84,8 @@ export declare function getRoleFormSchema(role: string): Promise<Record<string,
84
84
  export declare function getRoleMetadataSchema(role: string): Promise<Record<string, any> | null>;
85
85
  /** The role's `properties` bag (incl. the reserved ROLE_PROPERTY_KEYS). One PK read. */
86
86
  export declare function getRoleProperties(role: string): Promise<Record<string, any> | null>;
87
+ /** The role's display title, or null when it declares none. One PK read. */
88
+ export declare function getRoleTitle(role: string): Promise<string | null>;
87
89
  /**
88
90
  * Delete a role. Returns an error message if the role is referenced.
89
91
  */
@@ -18,6 +18,7 @@ exports.getRoleListSchema = getRoleListSchema;
18
18
  exports.getRoleFormSchema = getRoleFormSchema;
19
19
  exports.getRoleMetadataSchema = getRoleMetadataSchema;
20
20
  exports.getRoleProperties = getRoleProperties;
21
+ exports.getRoleTitle = getRoleTitle;
21
22
  exports.deleteRole = deleteRole;
22
23
  const list_schema_1 = require("../../shared/list-schema");
23
24
  const db_1 = require("../../lib/db");
@@ -252,6 +253,12 @@ async function getRoleProperties(role) {
252
253
  const { rows } = await pool.query(sql_1.GET_ROLE_PROPERTIES, [role]);
253
254
  return rows[0]?.properties ?? null;
254
255
  }
256
+ /** The role's display title, or null when it declares none. One PK read. */
257
+ async function getRoleTitle(role) {
258
+ const pool = (0, db_1.getPool)();
259
+ const { rows } = await pool.query(sql_1.GET_ROLE_TITLE, [role]);
260
+ return rows[0]?.title ?? null;
261
+ }
255
262
  /**
256
263
  * Delete a role. Returns an error message if the role is referenced.
257
264
  */
@@ -14,7 +14,7 @@ function scanDoneError(value) {
14
14
  if (typeof value !== 'object' || Array.isArray(value))
15
15
  return 'properties.scan_done must be an object';
16
16
  const done = value;
17
- const known = new Set(['return', 'after_seconds']);
17
+ const known = new Set(['return', 'after_seconds', 'button']);
18
18
  const extra = Object.keys(done).filter((k) => !known.has(k));
19
19
  if (extra.length)
20
20
  return `properties.scan_done has unknown key(s): ${extra.join(', ')}`;
@@ -25,6 +25,9 @@ function scanDoneError(value) {
25
25
  && (!Number.isInteger(done.after_seconds) || done.after_seconds < 0 || done.after_seconds > AFTER_SECONDS_MAX)) {
26
26
  return `properties.scan_done.after_seconds must be an integer from 0 to ${AFTER_SECONDS_MAX}`;
27
27
  }
28
+ if (done.button !== undefined && (typeof done.button !== 'string' || !done.button.trim())) {
29
+ return 'properties.scan_done.button must be non-empty text';
30
+ }
28
31
  return null;
29
32
  }
30
33
  /** The role's return policy from its properties bag, or null when it declares none (or an unusable one). */
@@ -80,6 +80,7 @@ export declare const GET_ROLE_FORM_SCHEMA = "\n SELECT form_schema FROM lt_role
80
80
  export declare const LIST_ENFORCING_ROLES = "\n SELECT role FROM lt_roles WHERE enforce_schema";
81
81
  export declare const GET_ROLE_METADATA_SCHEMA = "\n SELECT metadata_schema FROM lt_roles WHERE role = $1";
82
82
  export declare const GET_ROLE_PROPERTIES = "\n SELECT properties FROM lt_roles WHERE role = $1";
83
+ export declare const GET_ROLE_TITLE = "\n SELECT title FROM lt_roles WHERE role = $1";
83
84
  export declare const GET_ROLE_UPSTREAMS = "\n SELECT upstream_role FROM lt_role_upstreams WHERE role = $1 ORDER BY upstream_role";
84
85
  export declare const LIST_ROLE_SCHEMA_VERSIONS = "\n SELECT\n s.version,\n s.form_schema IS NOT NULL AS has_form_schema,\n s.metadata_schema IS NOT NULL AS has_metadata_schema,\n s.change_summary,\n s.created_at,\n s.version = r.current_schema_version AS is_current\n FROM lt_role_schemas s\n JOIN lt_roles r ON r.role = s.role\n WHERE s.role = $1\n ORDER BY s.version DESC";
85
86
  export declare const GET_ROLE_SCHEMA_VERSION = "\n SELECT s.role, s.version, s.form_schema, s.metadata_schema,\n s.change_summary, s.created_at, r.current_schema_version AS latest_version\n FROM lt_role_schemas s\n JOIN lt_roles r ON r.role = s.role\n WHERE s.role = $1 AND s.version = $2";
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  // ─── Escalation chain queries ───────────────────────────────────────────────
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.COUNT_ACTIVE_ESCALATION_REFS = exports.COUNT_WORKFLOW_REFS = exports.COUNT_CHAIN_REFS = exports.COUNT_USER_ROLE_REFS = exports.LIST_ROLES_WITH_DETAILS = exports.GET_ROLE_LIST_SCHEMA_CURRENT = exports.GET_ROLE_LIST_SCHEMA_VERSION = exports.LIST_ROLE_LIST_SCHEMA_VERSIONS = exports.GET_ROLE_SCHEMA_CURRENT = exports.GET_ROLE_SCHEMA_VERSION = exports.LIST_ROLE_SCHEMA_VERSIONS = exports.GET_ROLE_UPSTREAMS = exports.GET_ROLE_PROPERTIES = exports.GET_ROLE_METADATA_SCHEMA = exports.LIST_ENFORCING_ROLES = exports.GET_ROLE_FORM_SCHEMA = exports.UPDATE_ROLE_METADATA = exports.DELETE_ROLE = exports.GET_ROLE_ROW = exports.LIST_CONFIGURED_ROLES = exports.LIST_ROLES = exports.ENSURE_ROLE_EXISTS = exports.CHECK_ESCALATION_CHAIN_EXISTS = exports.DELETE_ESCALATION_CHAINS_BY_SOURCE = exports.DELETE_ESCALATION_CHAIN = exports.ADD_ESCALATION_CHAIN = exports.INSERT_ESCALATION_CHAIN = exports.GET_ALL_ESCALATION_CHAINS = exports.GET_ESCALATION_TARGETS = void 0;
4
+ exports.COUNT_ACTIVE_ESCALATION_REFS = exports.COUNT_WORKFLOW_REFS = exports.COUNT_CHAIN_REFS = exports.COUNT_USER_ROLE_REFS = exports.LIST_ROLES_WITH_DETAILS = exports.GET_ROLE_LIST_SCHEMA_CURRENT = exports.GET_ROLE_LIST_SCHEMA_VERSION = exports.LIST_ROLE_LIST_SCHEMA_VERSIONS = exports.GET_ROLE_SCHEMA_CURRENT = exports.GET_ROLE_SCHEMA_VERSION = exports.LIST_ROLE_SCHEMA_VERSIONS = exports.GET_ROLE_UPSTREAMS = exports.GET_ROLE_TITLE = exports.GET_ROLE_PROPERTIES = exports.GET_ROLE_METADATA_SCHEMA = exports.LIST_ENFORCING_ROLES = exports.GET_ROLE_FORM_SCHEMA = exports.UPDATE_ROLE_METADATA = exports.DELETE_ROLE = exports.GET_ROLE_ROW = exports.LIST_CONFIGURED_ROLES = exports.LIST_ROLES = exports.ENSURE_ROLE_EXISTS = exports.CHECK_ESCALATION_CHAIN_EXISTS = exports.DELETE_ESCALATION_CHAINS_BY_SOURCE = exports.DELETE_ESCALATION_CHAIN = exports.ADD_ESCALATION_CHAIN = exports.INSERT_ESCALATION_CHAIN = exports.GET_ALL_ESCALATION_CHAINS = exports.GET_ESCALATION_TARGETS = void 0;
5
5
  exports.GET_ESCALATION_TARGETS = `
6
6
  SELECT target_role
7
7
  FROM lt_config_role_escalations
@@ -197,6 +197,8 @@ exports.GET_ROLE_METADATA_SCHEMA = `
197
197
  SELECT metadata_schema FROM lt_roles WHERE role = $1`;
198
198
  exports.GET_ROLE_PROPERTIES = `
199
199
  SELECT properties FROM lt_roles WHERE role = $1`;
200
+ exports.GET_ROLE_TITLE = `
201
+ SELECT title FROM lt_roles WHERE role = $1`;
200
202
  exports.GET_ROLE_UPSTREAMS = `
201
203
  SELECT upstream_role FROM lt_role_upstreams WHERE role = $1 ORDER BY upstream_role`;
202
204
  // ─── Versioned role schemas ─────────────────────────────────────────────────
@@ -43,6 +43,8 @@ export interface RoleScanDone {
43
43
  return: 'home' | string;
44
44
  /** Seconds the done copy stays up first (0-60, default 2). */
45
45
  after_seconds?: number;
46
+ /** A button on the done screen that returns at once, e.g. "Done". */
47
+ button?: string;
46
48
  }
47
49
  /** A station role's badge policy. Absent fields keep the badge scheme's value. */
48
50
  export interface RoleBadgeGrant {
@@ -1,5 +1,5 @@
1
1
  export { listScanSchemes, getScanScheme, listScanRules, getScanRule, } from './read';
2
2
  export { upsertScanScheme, deleteScanScheme, upsertScanRule, deleteScanRule, seedScanScheme, seedScanRule, applyScanScheme, applyScanRule, type ScanSchemeInput, type ScanRuleInput, } from './write';
3
- export { parseScanCode, interpolateScanTemplate, mentionsClaimToken, renderScanCopy, ScanTemplateError, type ScanParseResult, type ScanParseFailure, type ScanTemplateContext, } from './parse';
3
+ export { parseScanCode, interpolateScanTemplate, mentionsClaimToken, mentionsLocatedToken, renderScanCopy, ScanTemplateError, type ScanParseResult, type ScanParseFailure, type ScanTemplateContext, } from './parse';
4
4
  export { assertValidScheme, assertValidSteps, assertValidIdentityRule, assertSchemesCoexist, } from './validate';
5
5
  export { isValidGtin, normalizeGtin, displayGtin } from '../../shared/scan-code';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.displayGtin = exports.normalizeGtin = exports.isValidGtin = exports.assertSchemesCoexist = exports.assertValidIdentityRule = exports.assertValidSteps = exports.assertValidScheme = exports.ScanTemplateError = exports.renderScanCopy = exports.mentionsClaimToken = exports.interpolateScanTemplate = exports.parseScanCode = exports.applyScanRule = exports.applyScanScheme = exports.seedScanRule = exports.seedScanScheme = exports.deleteScanRule = exports.upsertScanRule = exports.deleteScanScheme = exports.upsertScanScheme = exports.getScanRule = exports.listScanRules = exports.getScanScheme = exports.listScanSchemes = void 0;
3
+ exports.displayGtin = exports.normalizeGtin = exports.isValidGtin = exports.assertSchemesCoexist = exports.assertValidIdentityRule = exports.assertValidSteps = exports.assertValidScheme = exports.ScanTemplateError = exports.renderScanCopy = exports.mentionsLocatedToken = exports.mentionsClaimToken = exports.interpolateScanTemplate = exports.parseScanCode = exports.applyScanRule = exports.applyScanScheme = exports.seedScanRule = exports.seedScanScheme = exports.deleteScanRule = exports.upsertScanRule = exports.deleteScanScheme = exports.upsertScanScheme = exports.getScanRule = exports.listScanRules = exports.getScanScheme = exports.listScanSchemes = void 0;
4
4
  var read_1 = require("./read");
5
5
  Object.defineProperty(exports, "listScanSchemes", { enumerable: true, get: function () { return read_1.listScanSchemes; } });
6
6
  Object.defineProperty(exports, "getScanScheme", { enumerable: true, get: function () { return read_1.getScanScheme; } });
@@ -19,6 +19,7 @@ var parse_1 = require("./parse");
19
19
  Object.defineProperty(exports, "parseScanCode", { enumerable: true, get: function () { return parse_1.parseScanCode; } });
20
20
  Object.defineProperty(exports, "interpolateScanTemplate", { enumerable: true, get: function () { return parse_1.interpolateScanTemplate; } });
21
21
  Object.defineProperty(exports, "mentionsClaimToken", { enumerable: true, get: function () { return parse_1.mentionsClaimToken; } });
22
+ Object.defineProperty(exports, "mentionsLocatedToken", { enumerable: true, get: function () { return parse_1.mentionsLocatedToken; } });
22
23
  Object.defineProperty(exports, "renderScanCopy", { enumerable: true, get: function () { return parse_1.renderScanCopy; } });
23
24
  Object.defineProperty(exports, "ScanTemplateError", { enumerable: true, get: function () { return parse_1.ScanTemplateError; } });
24
25
  var validate_1 = require("./validate");
@@ -27,6 +27,8 @@ export interface ScanTemplateContext {
27
27
  container?: Record<string, unknown>;
28
28
  /** The batch a fill step read: `pending`, `total`, `filled`. */
29
29
  fill?: Record<string, unknown>;
30
+ /** The scanned code's own pending row: its metadata plus `id`, `role` and `roleTitle`. */
31
+ located?: Record<string, unknown>;
30
32
  }
31
33
  /** A bag token the context cannot resolve. */
32
34
  export declare class ScanTemplateError extends Error {
@@ -36,11 +38,13 @@ export declare class ScanTemplateError extends Error {
36
38
  }
37
39
  /** True when any string in the params mentions a `{claim.…}` token. */
38
40
  export declare function mentionsClaimToken(value: unknown): boolean;
41
+ /** True when any string in the value mentions a `{located.…}` token. */
42
+ export declare function mentionsLocatedToken(value: unknown): boolean;
39
43
  /**
40
44
  * Replace the template tokens inside string values of a params object.
41
45
  * Deep, pure, non-mutating. The scan tokens are plain text replacement; the
42
46
  * bag tokens (`{claim.x}`, `{item.x}`, `{subject.x}`, `{container.x}`,
43
- * `{fill.x}`) read the context's facet bags and throw
47
+ * `{fill.x}`, `{located.x}`) read the context's facet bags and throw
44
48
  * {@link ScanTemplateError} when they cannot resolve, so a literal token
45
49
  * never reaches a row. No expression language.
46
50
  */
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ScanTemplateError = void 0;
4
4
  exports.parseScanCode = parseScanCode;
5
5
  exports.mentionsClaimToken = mentionsClaimToken;
6
+ exports.mentionsLocatedToken = mentionsLocatedToken;
6
7
  exports.interpolateScanTemplate = interpolateScanTemplate;
7
8
  exports.renderScanCopy = renderScanCopy;
8
9
  const scan_code_1 = require("../../shared/scan-code");
@@ -21,18 +22,23 @@ class ScanTemplateError extends Error {
21
22
  }
22
23
  }
23
24
  exports.ScanTemplateError = ScanTemplateError;
24
- const BAG_TOKEN = /\{(claim|item|subject|container|fill)\.([a-zA-Z0-9_]+)\}/g;
25
+ const BAG_TOKEN = /\{(claim|item|subject|container|fill|located)\.([a-zA-Z0-9_]+)\}/g;
25
26
  const MISSING_BAG = {
26
27
  claim: 'the actor holds no single live claim',
27
28
  item: 'no located item row on this step',
28
29
  subject: 'no subject is held',
29
30
  container: 'no container was located',
30
31
  fill: 'no batch was read',
32
+ located: 'the scanned code has no pending row the reader can read',
31
33
  };
32
34
  /** True when any string in the params mentions a `{claim.…}` token. */
33
35
  function mentionsClaimToken(value) {
34
36
  return JSON.stringify(value ?? null).includes(`{${types_1.SCAN_TEMPLATE_BAGS.CLAIM}.`);
35
37
  }
38
+ /** True when any string in the value mentions a `{located.…}` token. */
39
+ function mentionsLocatedToken(value) {
40
+ return JSON.stringify(value ?? null).includes(`{${types_1.SCAN_TEMPLATE_BAGS.LOCATED}.`);
41
+ }
36
42
  function resolveBagToken(ctx, bag, facet, token) {
37
43
  const source = ctx[bag];
38
44
  if (!source)
@@ -49,7 +55,7 @@ function resolveBagToken(ctx, bag, facet, token) {
49
55
  * Replace the template tokens inside string values of a params object.
50
56
  * Deep, pure, non-mutating. The scan tokens are plain text replacement; the
51
57
  * bag tokens (`{claim.x}`, `{item.x}`, `{subject.x}`, `{container.x}`,
52
- * `{fill.x}`) read the context's facet bags and throw
58
+ * `{fill.x}`, `{located.x}`) read the context's facet bags and throw
53
59
  * {@link ScanTemplateError} when they cannot resolve, so a literal token
54
60
  * never reaches a row. No expression language.
55
61
  */
@@ -0,0 +1,13 @@
1
+ import { type ScanDoneCopy, type ScanStep, type ScanVerb } from '../../types';
2
+ /** A form field name, as `hold.show` and a present step's `show` name one. */
3
+ export declare const ROSTER_FIELD: RegExp;
4
+ /** The longest a done screen waits before the station returns. */
5
+ export declare const SCAN_DONE_AFTER_SECONDS_MAX = 60;
6
+ /** A done copy: markdown, an optional pause before the station returns, and the line under it. */
7
+ export declare function assertValidDoneCopy(done: ScanDoneCopy | undefined, at: string, field?: string): void;
8
+ /** `done` on a step or a choice that writes. */
9
+ export declare function assertValidDone(done: ScanDoneCopy | undefined, verb: ScanVerb, at: string, kind?: 'steps' | 'choices'): void;
10
+ /** `open`: the Open button on the hold, done or refusal screen a step answers with. */
11
+ export declare function assertValidOpen(step: ScanStep, at: string): void;
12
+ /** `show` on a present step: the roster field rendered above the choices. */
13
+ export declare function assertValidPresentShow(step: ScanStep, at: string): void;
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SCAN_DONE_AFTER_SECONDS_MAX = exports.ROSTER_FIELD = void 0;
4
+ exports.assertValidDoneCopy = assertValidDoneCopy;
5
+ exports.assertValidDone = assertValidDone;
6
+ exports.assertValidOpen = assertValidOpen;
7
+ exports.assertValidPresentShow = assertValidPresentShow;
8
+ const types_1 = require("../../types");
9
+ const facet_sql_1 = require("../escalation/facet-sql");
10
+ /** A form field name, as `hold.show` and a present step's `show` name one. */
11
+ exports.ROSTER_FIELD = /^[A-Za-z_][A-Za-z0-9_-]*$/;
12
+ /** The longest a done screen waits before the station returns. */
13
+ exports.SCAN_DONE_AFTER_SECONDS_MAX = 60;
14
+ const OPEN_TARGETS = new Set(['row', 'subject', 'located']);
15
+ function isPlainObject(value) {
16
+ return !!value && typeof value === 'object' && !Array.isArray(value);
17
+ }
18
+ /** A done copy: markdown, an optional pause before the station returns, and the line under it. */
19
+ function assertValidDoneCopy(done, at, field = 'done') {
20
+ if (!isPlainObject(done) || typeof done.markdown !== 'string' || !done.markdown) {
21
+ throw new Error(`${at}: ${field}.markdown is required`);
22
+ }
23
+ const after = done.afterSeconds;
24
+ if (after !== undefined && (typeof after !== 'number' || !Number.isInteger(after)
25
+ || after < 0 || after > exports.SCAN_DONE_AFTER_SECONDS_MAX)) {
26
+ throw new Error(`${at}: ${field}.afterSeconds must be an integer from 0 to ${exports.SCAN_DONE_AFTER_SECONDS_MAX}`);
27
+ }
28
+ if (done.nextPrompt !== undefined && (typeof done.nextPrompt !== 'string' || !done.nextPrompt.trim())) {
29
+ throw new Error(`${at}: ${field}.nextPrompt must be non-empty markdown`);
30
+ }
31
+ }
32
+ /** `done` on a step or a choice that writes. */
33
+ function assertValidDone(done, verb, at, kind = 'steps') {
34
+ if (done === undefined)
35
+ return;
36
+ assertValidDoneCopy(done, at);
37
+ if (!types_1.SCAN_MUTATING_VERBS.includes(verb))
38
+ throw new Error(`${at}: done applies only to ${kind} that write`);
39
+ }
40
+ /** `open`: the Open button on the hold, done or refusal screen a step answers with. */
41
+ function assertValidOpen(step, at) {
42
+ const open = step.open;
43
+ if (open === undefined)
44
+ return;
45
+ if (!isPlainObject(open))
46
+ throw new Error(`${at}: open must be an object`);
47
+ if (!OPEN_TARGETS.has(open.target)) {
48
+ throw new Error(`${at}: open.target must be 'row', 'subject' or 'located'`);
49
+ }
50
+ if (open.target === 'subject' && !step.subject && step.verb !== types_1.SCAN_VERBS.HOLD) {
51
+ throw new Error(`${at}: open.target 'subject' needs a held subject (a hold step, or a step with a subject gate)`);
52
+ }
53
+ if (open.label !== undefined && (typeof open.label !== 'string' || !open.label.trim())) {
54
+ throw new Error(`${at}: open.label must be non-empty text`);
55
+ }
56
+ if (open.claim !== undefined && typeof open.claim !== 'boolean') {
57
+ throw new Error(`${at}: open.claim must be a boolean`);
58
+ }
59
+ if (open.list !== undefined) {
60
+ const list = open.list;
61
+ if (!isPlainObject(list) || !Array.isArray(list.facets) || list.facets.length === 0
62
+ || !list.facets.every((f) => typeof f === 'string' && facet_sql_1.FACET_KEY.test(f))) {
63
+ throw new Error(`${at}: open.list.facets must be a non-empty array of facet keys`);
64
+ }
65
+ if (list.role !== undefined && (typeof list.role !== 'string' || !list.role)) {
66
+ throw new Error(`${at}: open.list.role must be a role name`);
67
+ }
68
+ if (open.claim)
69
+ throw new Error(`${at}: open.claim applies to a row, not a list`);
70
+ }
71
+ }
72
+ /** `show` on a present step: the roster field rendered above the choices. */
73
+ function assertValidPresentShow(step, at) {
74
+ if (step.show === undefined)
75
+ return;
76
+ if (step.verb !== types_1.SCAN_VERBS.PRESENT)
77
+ throw new Error(`${at}: show applies only to present steps (a hold uses params.hold.show)`);
78
+ if (typeof step.show !== 'string' || !exports.ROSTER_FIELD.test(step.show)) {
79
+ throw new Error(`${at}: show must name a roster field of the row's form`);
80
+ }
81
+ }
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.assertValidSubjectStep = assertValidSubjectStep;
4
4
  const types_1 = require("../../types");
5
5
  const facet_sql_1 = require("../escalation/facet-sql");
6
+ const validate_station_1 = require("./validate-station");
6
7
  function isSchemeList(value) {
7
8
  return Array.isArray(value) && value.length > 0
8
9
  && value.every((v) => Number.isInteger(v) && v >= 10 && v <= 99);
@@ -10,9 +11,7 @@ function isSchemeList(value) {
10
11
  function isStringList(value) {
11
12
  return Array.isArray(value) && value.length > 0 && value.every((v) => typeof v === 'string' && v);
12
13
  }
13
- /** A form field name, as `hold.show` names one. */
14
- const HOLD_SHOW_FIELD = /^[A-Za-z_][A-Za-z0-9_-]*$/;
15
- /** A fill's label map lives on the batch row: `envelope.<path>` or `metadata.<path>`. */
14
+ /** A fill's per-key maps live on the batch row: `envelope.<path>` or `metadata.<path>`. */
16
15
  const FILL_LABELS_PATH = /^(envelope|metadata)\.[A-Za-z0-9_.-]+$/;
17
16
  function isPlainObject(value) {
18
17
  return !!value && typeof value === 'object' && !Array.isArray(value);
@@ -91,8 +90,8 @@ function assertValidSubjectStep(step, at) {
91
90
  if (!isStringList(step.match.facets) || !step.match.facets.every((f) => facet_sql_1.FACET_KEY.test(f))) {
92
91
  throw new Error(`${at}: match.facets must be a non-empty array of facet keys`);
93
92
  }
94
- if (accumulate?.from !== 'subject') {
95
- throw new Error(`${at}: match.facets compares the located container, which only a from-subject accumulate has`);
93
+ if (accumulate?.from !== 'subject' && !(accumulate?.into === 'subject' && accumulate.item)) {
94
+ throw new Error(`${at}: match.facets compares the subject with a located row: the container of a from-subject accumulate, or the item's own row of an into-subject accumulate with item`);
96
95
  }
97
96
  }
98
97
  }
@@ -169,9 +168,30 @@ function assertValidHold(step, at) {
169
168
  throw new Error(`${at}: params.hold.expect.prompt must be markdown`);
170
169
  }
171
170
  }
172
- if (hold.show !== undefined && (typeof hold.show !== 'string' || !HOLD_SHOW_FIELD.test(hold.show))) {
171
+ if (hold.show !== undefined && (typeof hold.show !== 'string' || !validate_station_1.ROSTER_FIELD.test(hold.show))) {
173
172
  throw new Error(`${at}: params.hold.show must name a roster field of the held row's form`);
174
173
  }
174
+ if (hold.release !== undefined)
175
+ assertValidRelease(hold.release, at);
176
+ if (hold.whenAllIn !== undefined) {
177
+ if (hold.show === undefined)
178
+ throw new Error(`${at}: params.hold.whenAllIn requires params.hold.show`);
179
+ (0, validate_station_1.assertValidDoneCopy)(hold.whenAllIn, at, 'params.hold.whenAllIn');
180
+ }
181
+ }
182
+ function assertValidRelease(release, at) {
183
+ if (!isPlainObject(release))
184
+ throw new Error(`${at}: params.hold.release must be an object`);
185
+ if (release.label !== undefined && (typeof release.label !== 'string' || !release.label.trim())) {
186
+ throw new Error(`${at}: params.hold.release.label must be non-empty text`);
187
+ }
188
+ if (release.tone !== undefined && release.tone !== 'neutral' && release.tone !== 'accent') {
189
+ throw new Error(`${at}: params.hold.release.tone must be 'neutral' or 'accent'`);
190
+ }
191
+ if (release.return !== undefined
192
+ && (typeof release.return !== 'string' || !(release.return === 'home' || release.return.startsWith('/')))) {
193
+ throw new Error(`${at}: params.hold.release.return must be 'home' or a dashboard-relative route`);
194
+ }
175
195
  }
176
196
  function assertValidFill(step, at) {
177
197
  const fill = step.params?.fill;
@@ -196,6 +216,13 @@ function assertValidFill(step, at) {
196
216
  if (fill.label !== undefined && fill.labels === undefined) {
197
217
  throw new Error(`${at}: params.fill.label requires params.fill.labels`);
198
218
  }
219
+ if (fill.prefer !== undefined) {
220
+ if (typeof fill.prefer !== 'string' || !FILL_LABELS_PATH.test(fill.prefer)) {
221
+ throw new Error(`${at}: params.fill.prefer must name a map on the row, e.g. "envelope.key_owners"`);
222
+ }
223
+ if (fill.into !== 'subject')
224
+ throw new Error(`${at}: params.fill.prefer compares with the held subject, so it needs into: 'subject'`);
225
+ }
199
226
  if (step.confirm)
200
227
  throw new Error(`${at}: fill cannot carry confirm`);
201
228
  }
@@ -4,6 +4,9 @@ import { type ScanScheme, type ScanStep } from '../../types';
4
4
  * problem — a bad scheme silently misparsing every scan is far worse
5
5
  * than a loud upsert failure.
6
6
  */
7
+ /** Generated badges on a delimited identity scheme: long enough to resist guessing, short enough to scan. */
8
+ export declare const IDENTITY_TOKEN_MIN_LENGTH = 8;
9
+ export declare const IDENTITY_TOKEN_MAX_LENGTH = 64;
7
10
  export declare function assertValidScheme(scheme: Partial<ScanScheme>): void;
8
11
  /**
9
12
  * A scheme must read codes no other scheme reads. Delimited and fixed
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.IDENTITY_TOKEN_MAX_LENGTH = exports.IDENTITY_TOKEN_MIN_LENGTH = void 0;
3
4
  exports.assertValidScheme = assertValidScheme;
4
5
  exports.assertSchemesCoexist = assertSchemesCoexist;
5
6
  exports.assertValidIdentityRule = assertValidIdentityRule;
@@ -10,6 +11,7 @@ const facet_sql_1 = require("../escalation/facet-sql");
10
11
  const validate_subject_1 = require("./validate-subject");
11
12
  const validate_query_1 = require("./validate-query");
12
13
  const validate_facts_1 = require("./validate-facts");
14
+ const validate_station_1 = require("./validate-station");
13
15
  const validate_scheme_pattern_1 = require("./validate-scheme-pattern");
14
16
  const VALID_VERBS = new Set(Object.values(types_1.SCAN_VERBS));
15
17
  /** Double-scan selection tokens — short, label-printable, never scheme-shaped. */
@@ -19,6 +21,9 @@ const CHOICE_CODE = /^[A-Za-z0-9_-]{1,32}$/;
19
21
  * problem — a bad scheme silently misparsing every scan is far worse
20
22
  * than a loud upsert failure.
21
23
  */
24
+ /** Generated badges on a delimited identity scheme: long enough to resist guessing, short enough to scan. */
25
+ exports.IDENTITY_TOKEN_MIN_LENGTH = 8;
26
+ exports.IDENTITY_TOKEN_MAX_LENGTH = 64;
22
27
  function assertValidScheme(scheme) {
23
28
  if (!Number.isInteger(scheme.version) || scheme.version < 10 || scheme.version > 99) {
24
29
  throw new Error('scheme version must be a two-digit integer between 10 and 99');
@@ -52,6 +57,12 @@ function assertValidScheme(scheme) {
52
57
  if (kind !== types_1.SCAN_SCHEME_KINDS.ACTION && kind !== types_1.SCAN_SCHEME_KINDS.IDENTITY) {
53
58
  throw new Error(`unknown scheme kind "${kind}"`);
54
59
  }
60
+ if (kind === types_1.SCAN_SCHEME_KINDS.IDENTITY && encoding === types_1.SCAN_ENCODINGS.DELIMITED && scheme.target_length != null) {
61
+ const length = scheme.target_length;
62
+ if (!Number.isInteger(length) || length < exports.IDENTITY_TOKEN_MIN_LENGTH || length > exports.IDENTITY_TOKEN_MAX_LENGTH) {
63
+ throw new Error(`a delimited identity scheme's target_length (the length of a generated badge) must be ${exports.IDENTITY_TOKEN_MIN_LENGTH} to ${exports.IDENTITY_TOKEN_MAX_LENGTH}`);
64
+ }
65
+ }
55
66
  if (kind === types_1.SCAN_SCHEME_KINDS.IDENTITY) {
56
67
  const ttl = scheme.grant_ttl_seconds;
57
68
  if (!Number.isInteger(ttl) || ttl < 1 || ttl > 86_400) {
@@ -156,14 +167,7 @@ function assertValidChoices(choices, at) {
156
167
  throw new Error(`${cat}: duplicate code "${choice.code}"`);
157
168
  codes.add(choice.code);
158
169
  }
159
- if (choice.done !== undefined) {
160
- if (!choice.done || typeof choice.done !== 'object' || typeof choice.done.markdown !== 'string' || !choice.done.markdown) {
161
- throw new Error(`${cat}: done.markdown is required`);
162
- }
163
- if (!types_1.SCAN_MUTATING_VERBS.includes(choice.verb)) {
164
- throw new Error(`${cat}: done applies only to choices that write`);
165
- }
166
- }
170
+ (0, validate_station_1.assertValidDone)(choice.done, choice.verb, cat, 'choices');
167
171
  if (choice.hidden !== undefined) {
168
172
  if (typeof choice.hidden !== 'boolean')
169
173
  throw new Error(`${cat}: hidden must be a boolean`);
@@ -293,14 +297,9 @@ function assertValidSteps(steps) {
293
297
  }
294
298
  }
295
299
  (0, validate_subject_1.assertValidSubjectStep)(step, at);
296
- if (step.done !== undefined) {
297
- if (!step.done || typeof step.done !== 'object' || typeof step.done.markdown !== 'string' || !step.done.markdown) {
298
- throw new Error(`${at}: done.markdown is required`);
299
- }
300
- if (!types_1.SCAN_MUTATING_VERBS.includes(step.verb)) {
301
- throw new Error(`${at}: done applies only to steps that write`);
302
- }
303
- }
300
+ (0, validate_station_1.assertValidDone)(step.done, step.verb, at);
301
+ (0, validate_station_1.assertValidOpen)(step, at);
302
+ (0, validate_station_1.assertValidPresentShow)(step, at);
304
303
  assertValidFollow(step, at);
305
304
  assertValidTemplateTokens(step, at);
306
305
  if (step.query && step.query.roles && !Array.isArray(step.query.roles)) {
@@ -322,7 +321,7 @@ function assertValidSteps(steps) {
322
321
  }
323
322
  });
324
323
  }
325
- const BAG_TOKEN = /\{(claim|item|subject|container|fill)\.([^}]*)\}/g;
324
+ const BAG_TOKEN = /\{(claim|item|subject|container|fill|located)\.([^}]*)\}/g;
326
325
  /**
327
326
  * Bag tokens name facet keys and may only read what the step has:
328
327
  * `{item.…}` the row an item-mode accumulate, an into-subject accumulate
@@ -330,7 +329,9 @@ const BAG_TOKEN = /\{(claim|item|subject|container|fill)\.([^}]*)\}/g;
330
329
  * presents),
331
330
  * `{subject.…}` the held subject (steps with a subject gate), and
332
331
  * `{container.…}` / `{fill.…}` only inside refusal and done copy, where a
333
- * subject accumulate or a fill has read them (into-subject: the held row).
332
+ * subject accumulate or a fill has read them (into-subject: the held row),
333
+ * and `{located.…}` (the scanned code's own pending row) only inside refusal
334
+ * and done copy.
334
335
  */
335
336
  function assertValidTemplateTokens(step, at) {
336
337
  const accumulate = step.verb === types_1.SCAN_VERBS.ACCUMULATE ? step.params?.accumulate : undefined;
@@ -355,6 +356,9 @@ function assertValidTemplateTokens(step, at) {
355
356
  if (bag === 'fill' && !(inRefusal && step.verb === types_1.SCAN_VERBS.FILL)) {
356
357
  throw new Error(`${at}: ${token} is readable only in the refusal or done copy of a fill step`);
357
358
  }
359
+ if (bag === 'located' && !inRefusal) {
360
+ throw new Error(`${at}: ${token} is readable only in refusal or done copy`);
361
+ }
358
362
  }
359
363
  };
360
364
  check(step.params, false);