@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,98 @@
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.listLabelTemplates = listLabelTemplates;
37
+ exports.getLabelTemplate = getLabelTemplate;
38
+ exports.upsertLabelTemplate = upsertLabelTemplate;
39
+ exports.deleteLabelTemplate = deleteLabelTemplate;
40
+ exports.listLabelMedia = listLabelMedia;
41
+ exports.listLabelTransports = listLabelTransports;
42
+ const labels = __importStar(require("../../services/labels"));
43
+ const transports_1 = require("../../lib/labels/transports");
44
+ const errors_1 = require("./errors");
45
+ /**
46
+ * List label templates, optionally for one scan scheme.
47
+ *
48
+ * @param input.scheme — scheme version to filter by
49
+ * @returns `{ status: 200, data: { templates } }`
50
+ */
51
+ async function listLabelTemplates(input = {}) {
52
+ try {
53
+ return { status: 200, data: { templates: await labels.listLabelTemplates(input.scheme) } };
54
+ }
55
+ catch (err) {
56
+ return (0, errors_1.labelFailure)(err);
57
+ }
58
+ }
59
+ /** One label template by name; 404 when absent. */
60
+ async function getLabelTemplate(input) {
61
+ try {
62
+ const template = await labels.getLabelTemplate(input.name);
63
+ return template ? { status: 200, data: template } : { status: 404, error: 'Label template not found' };
64
+ }
65
+ catch (err) {
66
+ return (0, errors_1.labelFailure)(err);
67
+ }
68
+ }
69
+ /**
70
+ * Create or replace a label template. With `expected_revision`, the write
71
+ * lands only on that revision (409 otherwise).
72
+ */
73
+ async function upsertLabelTemplate(input) {
74
+ try {
75
+ const { expected_revision, ...template } = input;
76
+ return { status: 200, data: await labels.upsertLabelTemplate(template, expected_revision) };
77
+ }
78
+ catch (err) {
79
+ return (0, errors_1.labelFailure)(err);
80
+ }
81
+ }
82
+ async function deleteLabelTemplate(input) {
83
+ try {
84
+ const deleted = await labels.deleteLabelTemplate(input.name);
85
+ return deleted ? { status: 200, data: { deleted: true } } : { status: 404, error: 'Label template not found' };
86
+ }
87
+ catch (err) {
88
+ return (0, errors_1.labelFailure)(err);
89
+ }
90
+ }
91
+ /** Media presets and the deployment's default. */
92
+ async function listLabelMedia() {
93
+ return { status: 200, data: { media: labels.labelMediaPresets(), defaultMedia: labels.defaultLabelMediaId() } };
94
+ }
95
+ /** Registered printer transports by name. */
96
+ async function listLabelTransports() {
97
+ return { status: 200, data: { transports: transports_1.labelTransportRegistry.list() } };
98
+ }
@@ -1,5 +1,5 @@
1
1
  import * as scanCodeService from '../../services/scan-code';
2
- import { type LTEscalationRecord, type ParsedScanCode, type ScanExecuteResponse, type ScanRule, type ScanScheme, type ScanStep } from '../../types';
2
+ import { type LTEscalationRecord, type ParsedScanCode, type ScanDoneCopy, type ScanExecuteResponse, type ScanRule, type ScanScheme, type ScanStep } from '../../types';
3
3
  import type { LTApiAuth, LTApiResult } from '../../types/sdk';
4
4
  /** The held subject, re-derived from the client's pointer on this request. */
5
5
  export interface HeldSubject {
@@ -42,6 +42,10 @@ export interface StepContext {
42
42
  subject?: HeldSubject;
43
43
  /** The station sent a subject pointer that no longer checks out. */
44
44
  subjectStale?: boolean;
45
+ /** The scanned code's own pending row, read once a step's copy or Open asks for it; null when none. */
46
+ located?: LTEscalationRecord | null;
47
+ /** The located row's role title. */
48
+ locatedTitle?: string | null;
45
49
  }
46
50
  export declare function targetFilter(step: ScanStep, ctx: StepContext): Record<string, any>;
47
51
  /**
@@ -51,6 +55,8 @@ export declare function targetFilter(step: ScanStep, ctx: StepContext): Record<s
51
55
  */
52
56
  export declare function targetValue(ctx: Pick<StepContext, 'scheme' | 'parsed'>): string | string[];
53
57
  export declare function templateContext(ctx: StepContext): scanCodeService.ScanTemplateContext;
58
+ /** The `{located.x}` bag: the row's metadata plus its id, role and role title. */
59
+ export declare function locatedBag(row: LTEscalationRecord, title?: string | null): Record<string, unknown>;
54
60
  /** The `{subject.x}` bag: the held row's metadata plus its id. */
55
61
  export declare function subjectBag(row: LTEscalationRecord): Record<string, unknown>;
56
62
  /**
@@ -85,6 +91,8 @@ export declare function templated<T>(step: ScanStep, ctx: StepContext, render: (
85
91
  * batch); an unreadable token renders empty rather than failing the act.
86
92
  */
87
93
  export declare function withDone(result: LTApiResult<ScanExecuteResponse>, step: Pick<ScanStep, 'done'>, tpl: scanCodeService.ScanTemplateContext): LTApiResult<ScanExecuteResponse>;
94
+ /** A done copy rendered for the station: the markdown, its pause, and the line under it. */
95
+ export declare function renderDone(done: ScanDoneCopy, tpl: scanCodeService.ScanTemplateContext): ScanDoneCopy;
88
96
  /**
89
97
  * Attach the step's `follow` to a write that completed the held subject: the
90
98
  * code the station replays and the target it waits for, so the subject's
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.targetFilter = targetFilter;
37
37
  exports.targetValue = targetValue;
38
38
  exports.templateContext = templateContext;
39
+ exports.locatedBag = locatedBag;
39
40
  exports.subjectBag = subjectBag;
40
41
  exports.liveClaimMetadata = liveClaimMetadata;
41
42
  exports.stepTemplate = stepTemplate;
@@ -48,6 +49,7 @@ exports.notPrimed = notPrimed;
48
49
  exports.refused = refused;
49
50
  exports.templated = templated;
50
51
  exports.withDone = withDone;
52
+ exports.renderDone = renderDone;
51
53
  exports.withFollow = withFollow;
52
54
  const scanCodeService = __importStar(require("../../services/scan-code"));
53
55
  const escalationService = __importStar(require("../../services/escalation"));
@@ -70,8 +72,13 @@ function templateContext(ctx) {
70
72
  scannedAt: ctx.scannedAt,
71
73
  code: ctx.parsed.raw ?? ctx.parsed.target,
72
74
  ...(ctx.subject ? { subject: subjectBag(ctx.subject.row) } : {}),
75
+ ...(ctx.located ? { located: locatedBag(ctx.located, ctx.locatedTitle) } : {}),
73
76
  };
74
77
  }
78
+ /** The `{located.x}` bag: the row's metadata plus its id, role and role title. */
79
+ function locatedBag(row, title) {
80
+ return { ...(row.metadata ?? {}), id: row.id, role: row.role, roleTitle: title || row.role };
81
+ }
75
82
  /** The `{subject.x}` bag: the held row's metadata plus its id. */
76
83
  function subjectBag(row) {
77
84
  return { ...(row.metadata ?? {}), id: row.id };
@@ -168,7 +175,15 @@ function withDone(result, step, tpl) {
168
175
  const data = result.data;
169
176
  if (!step.done || !data || data.outcome !== types_1.SCAN_OUTCOMES.EXECUTED || data.already || data.done)
170
177
  return result;
171
- return { ...result, data: { ...data, done: { markdown: scanCodeService.renderScanCopy(step.done.markdown, tpl) } } };
178
+ return { ...result, data: { ...data, done: renderDone(step.done, tpl) } };
179
+ }
180
+ /** A done copy rendered for the station: the markdown, its pause, and the line under it. */
181
+ function renderDone(done, tpl) {
182
+ return {
183
+ markdown: scanCodeService.renderScanCopy(done.markdown, tpl),
184
+ ...(done.afterSeconds !== undefined ? { afterSeconds: done.afterSeconds } : {}),
185
+ ...(done.nextPrompt ? { nextPrompt: scanCodeService.renderScanCopy(done.nextPrompt, tpl) } : {}),
186
+ };
172
187
  }
173
188
  /**
174
189
  * Attach the step's `follow` to a write that completed the held subject: the
@@ -39,7 +39,9 @@ const identity_1 = require("./identity");
39
39
  const context_1 = require("./context");
40
40
  const grant_1 = require("./grant");
41
41
  const hold_1 = require("./hold");
42
+ const located_1 = require("./located");
42
43
  const locate_1 = require("./locate");
44
+ const open_1 = require("./open");
43
45
  const present_1 = require("./present");
44
46
  const subject_1 = require("./subject");
45
47
  const verb_fill_1 = require("./verb-fill");
@@ -116,7 +118,8 @@ async function executeScanCode(input, auth) {
116
118
  const stepResult = await executeStep(rule.steps[i], ctx);
117
119
  if (stepResult) {
118
120
  const step = rule.steps[i];
119
- result = decorate((0, context_1.withFollow)((0, context_1.withDone)(stepResult, step, (0, context_1.templateContext)(ctx)), step, ctx), ctx, i);
121
+ const answered = (0, context_1.withFollow)((0, context_1.withDone)(stepResult, step, (0, context_1.templateContext)(ctx)), step, ctx);
122
+ result = decorate(await (0, open_1.withOpen)(answered, step, ctx), ctx, i);
120
123
  }
121
124
  }
122
125
  // 4. Nothing matched: a stale subject, or the fallback screen
@@ -177,6 +180,8 @@ function subjectGateOpen(step, ctx) {
177
180
  async function executeStep(step, ctx) {
178
181
  if (!subjectGateOpen(step, ctx))
179
182
  return null;
183
+ if ((0, located_1.readsLocated)(step))
184
+ await (0, located_1.loadLocated)(ctx);
180
185
  // The identity pre-condition: the effective actor must be a real acting
181
186
  // identity — a badge grant, or an authenticated user whose own write scope
182
187
  // covers the step. A write-incapable shared account can never self-satisfy,
@@ -3,6 +3,14 @@ import { type LTEscalationRecord, type ScanFillParams, type ScanScheme } from '.
3
3
  export type EntryLabeler = (key: string, code: string) => string;
4
4
  /** The code as the package prints it on a GTIN scheme, as scanned otherwise. */
5
5
  export declare function printedCode(code: string, scheme: ScanScheme): string;
6
+ /** A per-key map the batch row carries (`envelope.<map>` or `metadata.<map>`); empty when absent. */
7
+ export declare function rowMap(path: string, row: LTEscalationRecord): Record<string, unknown>;
8
+ /**
9
+ * The open keys in the order a fill tries them. With `prefer`, the keys whose
10
+ * mapped value equals (or, for a list, contains) the held subject's target
11
+ * come first; the rest keep the row's order.
12
+ */
13
+ export declare function preferredKeys(keys: string[], fill: ScanFillParams, row: LTEscalationRecord, heldTarget: string | undefined): string[];
6
14
  /**
7
15
  * The labeler a fill step declares, or null without `labels`. The map is
8
16
  * read from the batch row (`envelope.<map>` or `metadata.<map>`) and keyed by
@@ -34,6 +34,8 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.printedCode = printedCode;
37
+ exports.rowMap = rowMap;
38
+ exports.preferredKeys = preferredKeys;
37
39
  exports.entryLabeler = entryLabeler;
38
40
  exports.pendingLabels = pendingLabels;
39
41
  const scanCodeService = __importStar(require("../../services/scan-code"));
@@ -63,6 +65,26 @@ function asObject(v) {
63
65
  function printedCode(code, scheme) {
64
66
  return scheme.encoding === types_1.SCAN_ENCODINGS.GTIN ? scanCodeService.displayGtin(code) : code;
65
67
  }
68
+ /** A per-key map the batch row carries (`envelope.<map>` or `metadata.<map>`); empty when absent. */
69
+ function rowMap(path, row) {
70
+ const map = (0, ctx_path_1.resolveCtxPath)(path, { envelope: asObject(row.envelope), metadata: asObject(row.metadata) });
71
+ return isRecord(map) ? map : {};
72
+ }
73
+ /**
74
+ * The open keys in the order a fill tries them. With `prefer`, the keys whose
75
+ * mapped value equals (or, for a list, contains) the held subject's target
76
+ * come first; the rest keep the row's order.
77
+ */
78
+ function preferredKeys(keys, fill, row, heldTarget) {
79
+ if (!fill.prefer || heldTarget === undefined)
80
+ return keys;
81
+ const owners = rowMap(fill.prefer, row);
82
+ const owns = (key) => {
83
+ const value = owners[key];
84
+ return (Array.isArray(value) ? value : [value]).some((v) => v !== null && v !== undefined && String(v) === heldTarget);
85
+ };
86
+ return [...keys.filter(owns), ...keys.filter((key) => !owns(key))];
87
+ }
66
88
  /**
67
89
  * The labeler a fill step declares, or null without `labels`. The map is
68
90
  * read from the batch row (`envelope.<map>` or `metadata.<map>`) and keyed by
@@ -73,8 +95,7 @@ function printedCode(code, scheme) {
73
95
  function entryLabeler(fill, row, scheme) {
74
96
  if (!fill.labels)
75
97
  return null;
76
- const map = (0, ctx_path_1.resolveCtxPath)(fill.labels, { envelope: asObject(row.envelope), metadata: asObject(row.metadata) });
77
- const labels = isRecord(map) ? map : {};
98
+ const labels = rowMap(fill.labels, row);
78
99
  return (key, code) => {
79
100
  const printed = printedCode(code, scheme);
80
101
  const value = labels[key];
@@ -79,6 +79,8 @@ async function heldSubject(step, ctx, row) {
79
79
  } : {}),
80
80
  ...(claimant ? { claimedBy: claimant } : {}),
81
81
  ...(hold.show ? { show: hold.show } : {}),
82
+ ...(hold.release ? { release: hold.release } : {}),
83
+ ...(hold.whenAllIn ? { whenAllIn: (0, context_1.renderDone)(hold.whenAllIn, tpl) } : {}),
82
84
  };
83
85
  }
84
86
  /** The canonical code for the held row, as the station would scan it. */
@@ -0,0 +1,10 @@
1
+ import type { ScanStep } from '../../types';
2
+ import { type StepContext } from './context';
3
+ /** True when the step's copy or Open reads the scanned code's own pending row. */
4
+ export declare function readsLocated(step: ScanStep): boolean;
5
+ /**
6
+ * The scanned code's own pending row, read once per request: the newest
7
+ * pending row whose scheme facet holds the scanned target, in any role the
8
+ * actor may read, other than the held subject. Sets null when there is none.
9
+ */
10
+ export declare function loadLocated(ctx: StepContext): Promise<void>;
@@ -0,0 +1,74 @@
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.readsLocated = readsLocated;
37
+ exports.loadLocated = loadLocated;
38
+ const scanCodeService = __importStar(require("../../services/scan-code"));
39
+ const escalationService = __importStar(require("../../services/escalation"));
40
+ const role_1 = require("../../services/role");
41
+ const helpers_1 = require("../escalations/helpers");
42
+ const metadata_1 = require("../escalations/metadata");
43
+ const context_1 = require("./context");
44
+ /** True when the step's copy or Open reads the scanned code's own pending row. */
45
+ function readsLocated(step) {
46
+ return step.open?.target === 'located'
47
+ || scanCodeService.mentionsLocatedToken(step.refuse)
48
+ || scanCodeService.mentionsLocatedToken(step.done);
49
+ }
50
+ /**
51
+ * The scanned code's own pending row, read once per request: the newest
52
+ * pending row whose scheme facet holds the scanned target, in any role the
53
+ * actor may read, other than the held subject. Sets null when there is none.
54
+ */
55
+ async function loadLocated(ctx) {
56
+ if (ctx.located !== undefined)
57
+ return;
58
+ const scope = await (0, helpers_1.getEscalationReadScope)(ctx.auth.userId);
59
+ const roles = (0, metadata_1.restrictScopeRoles)(scope.allRoles, scope.global);
60
+ if (roles !== null && roles.length === 0) {
61
+ ctx.located = null;
62
+ return;
63
+ }
64
+ const found = await escalationService.searchByFacets({
65
+ roles: roles ?? undefined,
66
+ facets: { [ctx.scheme.target_facet]: (0, context_1.targetValue)(ctx) },
67
+ status: 'pending',
68
+ orderBy: [{ field: 'created_at', direction: 'desc' }],
69
+ limit: 2,
70
+ }, { total: false });
71
+ const row = found.escalations.find((r) => r.id !== ctx.subject?.row.id) ?? null;
72
+ ctx.located = row;
73
+ ctx.locatedTitle = row ? await (0, role_1.getRoleTitle)(row.role) : null;
74
+ }
@@ -0,0 +1,9 @@
1
+ import { type ScanExecuteResponse, type ScanStep } from '../../types';
2
+ import type { LTApiResult } from '../../types/sdk';
3
+ import type { StepContext } from './context';
4
+ /**
5
+ * Attach the step's Open button to the answer: on the held subject for a
6
+ * hold, so it stays while the row is held, else on the response. A target
7
+ * with no row, or a list facet the row does not carry, offers no button.
8
+ */
9
+ export declare function withOpen(result: LTApiResult<ScanExecuteResponse>, step: Pick<ScanStep, 'open'>, ctx: StepContext): Promise<LTApiResult<ScanExecuteResponse>>;
@@ -0,0 +1,99 @@
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.withOpen = withOpen;
37
+ const escalationService = __importStar(require("../../services/escalation"));
38
+ const types_1 = require("../../types");
39
+ const OPEN_LABEL_DEFAULT = 'Open';
40
+ /** The answers the station shows on its own screen: a hold, a refusal, a write's done copy. */
41
+ function screenOf(data) {
42
+ if (data.outcome === types_1.SCAN_OUTCOMES.HELD && data.subject)
43
+ return 'hold';
44
+ if (data.outcome === types_1.SCAN_OUTCOMES.REFUSED)
45
+ return 'screen';
46
+ if (data.outcome === types_1.SCAN_OUTCOMES.EXECUTED
47
+ && (data.done || data.clearSubject || data.progress || data.already))
48
+ return 'screen';
49
+ return null;
50
+ }
51
+ /**
52
+ * Attach the step's Open button to the answer: on the held subject for a
53
+ * hold, so it stays while the row is held, else on the response. A target
54
+ * with no row, or a list facet the row does not carry, offers no button.
55
+ */
56
+ async function withOpen(result, step, ctx) {
57
+ const data = result.data;
58
+ if (!step.open || !data)
59
+ return result;
60
+ const screen = screenOf(data);
61
+ if (!screen)
62
+ return result;
63
+ const link = await resolveOpen(step.open, ctx, data);
64
+ if (!link)
65
+ return result;
66
+ if (screen === 'hold')
67
+ return { ...result, data: { ...data, subject: { ...data.subject, open: link } } };
68
+ return { ...result, data: { ...data, open: link } };
69
+ }
70
+ async function resolveOpen(open, ctx, data) {
71
+ const row = await targetRow(open, ctx, data);
72
+ if (!row)
73
+ return null;
74
+ const label = open.label ?? OPEN_LABEL_DEFAULT;
75
+ if (!open.list)
76
+ return { label, escalationId: row.id, ...(open.claim ? { claim: true } : {}) };
77
+ const meta = (row.metadata ?? {});
78
+ const facets = {};
79
+ for (const key of open.list.facets) {
80
+ const value = meta[key];
81
+ if (!['string', 'number', 'boolean'].includes(typeof value) || value === '')
82
+ return null;
83
+ facets[key] = value;
84
+ }
85
+ return { label, facets, ...(open.list.role ? { role: open.list.role } : {}) };
86
+ }
87
+ /** The row the button opens: the one the step answered with, the held subject, or the scanned code's own row. */
88
+ async function targetRow(open, ctx, data) {
89
+ const answered = data.escalation;
90
+ if (open.target === 'located')
91
+ return ctx.located ?? null;
92
+ if (open.target === 'subject' && data.outcome !== types_1.SCAN_OUTCOMES.HELD)
93
+ return ctx.subject?.row ?? null;
94
+ if (!answered?.id)
95
+ return null;
96
+ if (!open.list || answered.metadata)
97
+ return answered;
98
+ return escalationService.getEscalation(String(answered.id));
99
+ }
@@ -117,6 +117,7 @@ async function presentStep(step, ctx) {
117
117
  escalation,
118
118
  choices,
119
119
  ...(step.facts ? { facts: renderFacts(step, ctx, escalation) } : {}),
120
+ ...(step.show ? { show: step.show } : {}),
120
121
  notPrimed: ctx.rule.notPrimed,
121
122
  ...(autoSelect ? { autoSelect: true } : {}),
122
123
  },
@@ -105,7 +105,7 @@ async function fillStep(step, ctx) {
105
105
  filled: batch.keys.length - batch.pending.length,
106
106
  },
107
107
  };
108
- const candidates = keysFor(batch.pending, ctx.parsed.target, separator);
108
+ const candidates = (0, fill_labels_1.preferredKeys)(keysFor(batch.pending, ctx.parsed.target, separator), options, row, ctx.subject?.parsed.target);
109
109
  if (candidates.length === 0) {
110
110
  const declared = keysFor(batch.keys, ctx.parsed.target, separator);
111
111
  const markdown = declared.length
@@ -1,4 +1,4 @@
1
- import type { LTApiResult } from '../types/sdk';
1
+ import type { LTApiAuth, LTApiResult } from '../types/sdk';
2
2
  import type { LTRoleType } from '../types';
3
3
  /**
4
4
  * List users with optional filters for role, role type, status, and pagination.
@@ -92,13 +92,17 @@ export declare function updateUser(input: {
92
92
  * (`remove`); a key absent from the patch is kept. `rename` preserves the
93
93
  * value with no key-absent window. Identity-binding keys (badge scan
94
94
  * scheme target facets) assert uniqueness among active users in the same
95
- * statement.
95
+ * statement. Touching an identity key binds a credential: it needs the
96
+ * credentialIssuer capability and is recorded in lt_label_jobs by the same
97
+ * statement as the patch.
96
98
  *
97
99
  * @param input.id — the user's unique identifier
98
100
  * @param input.set — properties to set (typed JSON values)
99
101
  * @param input.remove — property keys to delete
100
102
  * @param input.rename — `{ oldKey: newKey }` renames, values preserved
101
- * @returns `{ status: 200, data: User }`; 400 malformed patch; 404 unknown
103
+ * @param auth — the caller; required to touch an identity key
104
+ * @returns `{ status: 200, data: User }` with identity keys redacted; 400
105
+ * malformed patch; 403 identity key without credentialIssuer; 404 unknown
102
106
  * user; 409 when an identity value already belongs to another active user
103
107
  */
104
108
  export declare function patchUserProperties(input: {
@@ -106,7 +110,7 @@ export declare function patchUserProperties(input: {
106
110
  set?: Record<string, unknown>;
107
111
  remove?: string[];
108
112
  rename?: Record<string, string>;
109
- }): Promise<LTApiResult>;
113
+ }, auth?: LTApiAuth): Promise<LTApiResult>;
110
114
  /**
111
115
  * The property keys the platform itself resolves identities against — every
112
116
  * enabled identity scan scheme's target facet. The dashboard marks these as
@@ -45,6 +45,20 @@ exports.getUserRoles = getUserRoles;
45
45
  exports.addUserRole = addUserRole;
46
46
  exports.removeUserRole = removeUserRole;
47
47
  const userService = __importStar(require("../services/user"));
48
+ const capabilities_1 = require("../modules/capabilities");
49
+ /** A user as the API returns it: identity keys redacted. */
50
+ async function asRead(user) {
51
+ return userService.redactIdentityKeys(user, await userService.getIdentityPropertyKeys());
52
+ }
53
+ /** A refusal when a wholesale metadata write names an identity key; bindings go through patchUserProperties. */
54
+ async function identityKeyInMetadata(metadata) {
55
+ if (!metadata || !userService.identityKeysProtected())
56
+ return null;
57
+ const named = (await userService.getIdentityPropertyKeys()).filter((k) => k in metadata);
58
+ if (named.length === 0)
59
+ return null;
60
+ return { status: 400, error: `"${named[0]}" is an identity binding; set it with patchUserProperties` };
61
+ }
48
62
  /**
49
63
  * List users with optional filters for role, role type, status, and pagination.
50
64
  *
@@ -59,7 +73,8 @@ const userService = __importStar(require("../services/user"));
59
73
  async function listUsers(input) {
60
74
  try {
61
75
  const result = await userService.listUsers(input);
62
- return { status: 200, data: result };
76
+ const keys = await userService.getIdentityPropertyKeys();
77
+ return { status: 200, data: { ...result, users: result.users.map((u) => userService.redactIdentityKeys(u, keys)) } };
63
78
  }
64
79
  catch (err) {
65
80
  return { status: 500, error: err.message };
@@ -95,7 +110,7 @@ async function getUser(input) {
95
110
  if (!user) {
96
111
  return { status: 404, error: 'User not found' };
97
112
  }
98
- return { status: 200, data: user };
113
+ return { status: 200, data: await asRead(user) };
99
114
  }
100
115
  catch (err) {
101
116
  return { status: 500, error: err.message };
@@ -119,6 +134,9 @@ async function createUser(input) {
119
134
  if (!input.external_id) {
120
135
  return { status: 400, error: 'external_id is required' };
121
136
  }
137
+ const identityRefusal = await identityKeyInMetadata(input.metadata);
138
+ if (identityRefusal)
139
+ return identityRefusal;
122
140
  if (input.roles) {
123
141
  for (const r of input.roles) {
124
142
  if (!r.role || !r.type || !userService.isValidRoleType(r.type)) {
@@ -148,7 +166,7 @@ async function createUser(input) {
148
166
  roles: input.roles,
149
167
  metadata: input.metadata,
150
168
  });
151
- return { status: 201, data: user };
169
+ return { status: 201, data: await asRead(user) };
152
170
  }
153
171
  catch (err) {
154
172
  if (err.code === '23505') {
@@ -173,11 +191,14 @@ async function createUser(input) {
173
191
  async function updateUser(input) {
174
192
  try {
175
193
  const { id, ...fields } = input;
194
+ const identityRefusal = await identityKeyInMetadata(fields.metadata);
195
+ if (identityRefusal)
196
+ return identityRefusal;
176
197
  const user = await userService.updateUser(id, fields);
177
198
  if (!user) {
178
199
  return { status: 404, error: 'User not found' };
179
200
  }
180
- return { status: 200, data: user };
201
+ return { status: 200, data: await asRead(user) };
181
202
  }
182
203
  catch (err) {
183
204
  return { status: 500, error: err.message };
@@ -189,26 +210,43 @@ async function updateUser(input) {
189
210
  * (`remove`); a key absent from the patch is kept. `rename` preserves the
190
211
  * value with no key-absent window. Identity-binding keys (badge scan
191
212
  * scheme target facets) assert uniqueness among active users in the same
192
- * statement.
213
+ * statement. Touching an identity key binds a credential: it needs the
214
+ * credentialIssuer capability and is recorded in lt_label_jobs by the same
215
+ * statement as the patch.
193
216
  *
194
217
  * @param input.id — the user's unique identifier
195
218
  * @param input.set — properties to set (typed JSON values)
196
219
  * @param input.remove — property keys to delete
197
220
  * @param input.rename — `{ oldKey: newKey }` renames, values preserved
198
- * @returns `{ status: 200, data: User }`; 400 malformed patch; 404 unknown
221
+ * @param auth — the caller; required to touch an identity key
222
+ * @returns `{ status: 200, data: User }` with identity keys redacted; 400
223
+ * malformed patch; 403 identity key without credentialIssuer; 404 unknown
199
224
  * user; 409 when an identity value already belongs to another active user
200
225
  */
201
- async function patchUserProperties(input) {
226
+ async function patchUserProperties(input, auth) {
202
227
  try {
203
- const user = await userService.patchUserProperties(input.id, {
204
- set: input.set,
205
- remove: input.remove,
206
- rename: input.rename,
207
- });
228
+ const ops = { set: input.set, remove: input.remove, rename: input.rename };
229
+ const touched = await userService.identityKeysTouched(ops);
230
+ let user;
231
+ const protectedKeys = userService.identityKeysProtected();
232
+ if (touched.length > 0 && (protectedKeys || auth)) {
233
+ if (protectedKeys && (!auth || !(await (0, capabilities_1.mayIssueCredentials)(auth)))) {
234
+ return { status: 403, error: `"${touched[0]}" is an identity binding; credential-issuer access required` };
235
+ }
236
+ const recorded = await userService.patchUserPropertiesRecorded(input.id, ops, {
237
+ action: 'bind',
238
+ requested_by: auth.userId,
239
+ source: { keys: touched },
240
+ });
241
+ user = recorded?.user ?? null;
242
+ }
243
+ else {
244
+ user = await userService.patchUserProperties(input.id, ops);
245
+ }
208
246
  if (!user) {
209
247
  return { status: 404, error: 'User not found' };
210
248
  }
211
- return { status: 200, data: user };
249
+ return { status: 200, data: await asRead(user) };
212
250
  }
213
251
  catch (err) {
214
252
  if (err.status === 400 || err.status === 409) {