@hotmeshio/long-tail 0.30.5 → 0.31.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (373) hide show
  1. package/build/api/labels/errors.d.ts +3 -0
  2. package/build/api/labels/errors.js +15 -0
  3. package/build/api/labels/index.d.ts +2 -0
  4. package/build/api/labels/index.js +17 -0
  5. package/build/api/labels/issue.d.ts +54 -0
  6. package/build/api/labels/issue.js +144 -0
  7. package/build/api/labels/templates.d.ts +29 -0
  8. package/build/api/labels/templates.js +98 -0
  9. package/build/api/users.d.ts +8 -4
  10. package/build/api/users.js +51 -13
  11. package/build/index.d.ts +1 -0
  12. package/build/index.js +4 -2
  13. package/build/lib/db/schemas/044_label_sheets.sql +65 -0
  14. package/build/lib/db/schemas/045_label_job_delivery.sql +14 -0
  15. package/build/lib/labels/transports.d.ts +23 -0
  16. package/build/lib/labels/transports.js +39 -0
  17. package/build/modules/auth.d.ts +2 -0
  18. package/build/modules/auth.js +3 -1
  19. package/build/modules/capabilities.d.ts +5 -1
  20. package/build/modules/capabilities.js +38 -8
  21. package/build/modules/config.d.ts +10 -0
  22. package/build/modules/config.js +10 -0
  23. package/build/routes/index.js +2 -0
  24. package/build/routes/labels.d.ts +2 -0
  25. package/build/routes/labels.js +135 -0
  26. package/build/routes/users.js +1 -1
  27. package/build/scripts/bambu-boat.d.ts +4 -2
  28. package/build/scripts/bambu-boat.js +4 -2
  29. package/build/scripts/bambu-print.d.ts +2 -1
  30. package/build/scripts/bambu-print.js +7 -3
  31. package/build/scripts/machine-line.js +2 -1
  32. package/build/services/labels/content.d.ts +13 -0
  33. package/build/services/labels/content.js +81 -0
  34. package/build/services/labels/errors.d.ts +5 -0
  35. package/build/services/labels/errors.js +12 -0
  36. package/build/services/labels/index.d.ts +11 -0
  37. package/build/services/labels/index.js +52 -0
  38. package/build/services/labels/issue.d.ts +38 -0
  39. package/build/services/labels/issue.js +181 -0
  40. package/build/services/labels/jobs.d.ts +37 -0
  41. package/build/services/labels/jobs.js +75 -0
  42. package/build/services/labels/media.d.ts +11 -0
  43. package/build/services/labels/media.js +44 -0
  44. package/build/services/labels/reissue.d.ts +13 -0
  45. package/build/services/labels/reissue.js +65 -0
  46. package/build/services/labels/render-pdf.d.ts +11 -0
  47. package/build/services/labels/render-pdf.js +138 -0
  48. package/build/services/labels/targets.d.ts +18 -0
  49. package/build/services/labels/targets.js +216 -0
  50. package/build/services/labels/templates/index.d.ts +3 -0
  51. package/build/services/labels/templates/index.js +18 -0
  52. package/build/services/labels/templates/read.d.ts +4 -0
  53. package/build/services/labels/templates/read.js +36 -0
  54. package/build/services/labels/templates/sql.d.ts +8 -0
  55. package/build/services/labels/templates/sql.js +50 -0
  56. package/build/services/labels/templates/validate.d.ts +19 -0
  57. package/build/services/labels/templates/validate.js +93 -0
  58. package/build/services/labels/templates/write.d.ts +16 -0
  59. package/build/services/labels/templates/write.js +75 -0
  60. package/build/services/labels/token.d.ts +9 -0
  61. package/build/services/labels/token.js +28 -0
  62. package/build/services/labels/verify.d.ts +4 -0
  63. package/build/services/labels/verify.js +38 -0
  64. package/build/services/scan-code/validate.d.ts +3 -0
  65. package/build/services/scan-code/validate.js +10 -0
  66. package/build/services/user/crud.d.ts +13 -1
  67. package/build/services/user/crud.js +42 -11
  68. package/build/services/user/index.d.ts +3 -2
  69. package/build/services/user/index.js +7 -1
  70. package/build/services/user/redact.d.ts +17 -0
  71. package/build/services/user/redact.js +32 -0
  72. package/build/services/user/sql.d.ts +8 -15
  73. package/build/services/user/sql.js +27 -3
  74. package/build/services/user/types.d.ts +21 -1
  75. package/build/shared/labels/compose.d.ts +12 -0
  76. package/build/shared/labels/compose.js +43 -0
  77. package/build/shared/labels/index.d.ts +9 -0
  78. package/build/shared/labels/index.js +54 -0
  79. package/build/shared/labels/label-content.d.ts +17 -0
  80. package/build/shared/labels/label-content.js +137 -0
  81. package/build/shared/labels/layout.d.ts +23 -0
  82. package/build/shared/labels/layout.js +81 -0
  83. package/build/shared/labels/media.d.ts +22 -0
  84. package/build/shared/labels/media.js +116 -0
  85. package/build/shared/labels/render-svg.d.ts +10 -0
  86. package/build/shared/labels/render-svg.js +58 -0
  87. package/build/shared/labels/render-zpl.d.ts +9 -0
  88. package/build/shared/labels/render-zpl.js +63 -0
  89. package/build/shared/labels/symbol.d.ts +18 -0
  90. package/build/shared/labels/symbol.js +74 -0
  91. package/build/shared/labels/tokens.d.ts +18 -0
  92. package/build/shared/labels/tokens.js +43 -0
  93. package/build/shared/labels/types.d.ts +105 -0
  94. package/build/shared/labels/types.js +11 -0
  95. package/build/start/adapters.js +16 -0
  96. package/build/start/workers.js +18 -2
  97. package/build/system/mcp-servers/admin/index.js +2 -0
  98. package/build/system/mcp-servers/admin/labels-schemas.d.ts +192 -0
  99. package/build/system/mcp-servers/admin/labels-schemas.js +46 -0
  100. package/build/system/mcp-servers/admin/labels.d.ts +9 -0
  101. package/build/system/mcp-servers/admin/labels.js +101 -0
  102. package/build/system/mcp-servers/admin/schemas.d.ts +30 -30
  103. package/build/system/mcp-servers/admin/users.js +1 -1
  104. package/build/system/seed/tool-manifests-admin.js +5 -0
  105. package/build/tsconfig.tsbuildinfo +1 -1
  106. package/build/types/capability.d.ts +2 -1
  107. package/build/types/index.d.ts +2 -1
  108. package/build/types/labels/index.d.ts +4 -0
  109. package/build/types/labels/index.js +2 -0
  110. package/build/types/labels/job.d.ts +51 -0
  111. package/build/types/labels/job.js +2 -0
  112. package/build/types/labels/source.d.ts +44 -0
  113. package/build/types/labels/source.js +2 -0
  114. package/build/types/labels/template.d.ts +46 -0
  115. package/build/types/labels/template.js +2 -0
  116. package/build/types/labels/transport.d.ts +24 -0
  117. package/build/types/labels/transport.js +2 -0
  118. package/build/types/scan-code/rule.d.ts +5 -0
  119. package/build/types/startup.d.ts +37 -0
  120. package/build/types/user.d.ts +2 -0
  121. package/dashboard/dist/assets/{AdminDashboard-D12QiMM5.js → AdminDashboard-BafKaq50.js} +2 -2
  122. package/dashboard/dist/assets/{AdminDashboard-D12QiMM5.js.map → AdminDashboard-BafKaq50.js.map} +1 -1
  123. package/dashboard/dist/assets/{AgentConfigPage-BKQd9b8m.js → AgentConfigPage-CFHf31DT.js} +6 -6
  124. package/dashboard/dist/assets/{AgentConfigPage-BKQd9b8m.js.map → AgentConfigPage-CFHf31DT.js.map} +1 -1
  125. package/dashboard/dist/assets/{AgentDetailPage-ie-DxsIj.js → AgentDetailPage-CEvz5rJr.js} +3 -3
  126. package/dashboard/dist/assets/{AgentDetailPage-ie-DxsIj.js.map → AgentDetailPage-CEvz5rJr.js.map} +1 -1
  127. package/dashboard/dist/assets/{AgentsPage-Nqm2DxCP.js → AgentsPage-DjQaio0O.js} +2 -2
  128. package/dashboard/dist/assets/{AgentsPage-Nqm2DxCP.js.map → AgentsPage-DjQaio0O.js.map} +1 -1
  129. package/dashboard/dist/assets/AvailableEscalationsPage-UB03VTJx.js +2 -0
  130. package/dashboard/dist/assets/AvailableEscalationsPage-UB03VTJx.js.map +1 -0
  131. package/dashboard/dist/assets/{BotPicker-BizdmeJp.js → BotPicker-C7MNWOF7.js} +2 -2
  132. package/dashboard/dist/assets/{BotPicker-BizdmeJp.js.map → BotPicker-C7MNWOF7.js.map} +1 -1
  133. package/dashboard/dist/assets/BulkAssignModal-h5fX-_cV.js +2 -0
  134. package/dashboard/dist/assets/{BulkAssignModal-BWfzPrRk.js.map → BulkAssignModal-h5fX-_cV.js.map} +1 -1
  135. package/dashboard/dist/assets/{CapabilitiesPage-DT8q7Zlh.js → CapabilitiesPage-BIzDl-ZT.js} +2 -2
  136. package/dashboard/dist/assets/{CapabilitiesPage-DT8q7Zlh.js.map → CapabilitiesPage-BIzDl-ZT.js.map} +1 -1
  137. package/dashboard/dist/assets/{CollapsibleSection-al5mqR4O.js → CollapsibleSection-B5TivtEg.js} +2 -2
  138. package/dashboard/dist/assets/{CollapsibleSection-al5mqR4O.js.map → CollapsibleSection-B5TivtEg.js.map} +1 -1
  139. package/dashboard/dist/assets/{ConfirmDeleteModal-BrlVktv2.js → ConfirmDeleteModal-CB4nKePb.js} +2 -2
  140. package/dashboard/dist/assets/{ConfirmDeleteModal-BrlVktv2.js.map → ConfirmDeleteModal-CB4nKePb.js.map} +1 -1
  141. package/dashboard/dist/assets/{ConnectedAppsPage-CLAsJ2yQ.js → ConnectedAppsPage-B3S5gVWw.js} +2 -2
  142. package/dashboard/dist/assets/{ConnectedAppsPage-CLAsJ2yQ.js.map → ConnectedAppsPage-B3S5gVWw.js.map} +1 -1
  143. package/dashboard/dist/assets/{CountdownTimer-D2D68exl.js → CountdownTimer-BHVIq3kA.js} +2 -2
  144. package/dashboard/dist/assets/{CountdownTimer-D2D68exl.js.map → CountdownTimer-BHVIq3kA.js.map} +1 -1
  145. package/dashboard/dist/assets/CredentialConfirmModal-w0AGmCIe.js +2 -0
  146. package/dashboard/dist/assets/CredentialConfirmModal-w0AGmCIe.js.map +1 -0
  147. package/dashboard/dist/assets/{CredentialsPage-DWrZbEI0.js → CredentialsPage-BtCGBJrT.js} +2 -2
  148. package/dashboard/dist/assets/{CredentialsPage-DWrZbEI0.js.map → CredentialsPage-BtCGBJrT.js.map} +1 -1
  149. package/dashboard/dist/assets/{CronLabel-DuXR8iWq.js → CronLabel-BG1rZK-5.js} +2 -2
  150. package/dashboard/dist/assets/{CronLabel-DuXR8iWq.js.map → CronLabel-BG1rZK-5.js.map} +1 -1
  151. package/dashboard/dist/assets/{DropZone-DefYTYQy.js → DropZone-D8ZVdEb5.js} +2 -2
  152. package/dashboard/dist/assets/{DropZone-DefYTYQy.js.map → DropZone-D8ZVdEb5.js.map} +1 -1
  153. package/dashboard/dist/assets/{ElapsedCell-ronqG5-E.js → ElapsedCell-l4m8Yvfv.js} +2 -2
  154. package/dashboard/dist/assets/{ElapsedCell-ronqG5-E.js.map → ElapsedCell-l4m8Yvfv.js.map} +1 -1
  155. package/dashboard/dist/assets/{EntityTimelinePanel-CKsktd84.js → EntityTimelinePanel-BOHlIaxF.js} +2 -2
  156. package/dashboard/dist/assets/{EntityTimelinePanel-CKsktd84.js.map → EntityTimelinePanel-BOHlIaxF.js.map} +1 -1
  157. package/dashboard/dist/assets/{EscalationListSchemaPage-C954ngy3.js → EscalationListSchemaPage-BotlwlX3.js} +3 -3
  158. package/dashboard/dist/assets/{EscalationListSchemaPage-C954ngy3.js.map → EscalationListSchemaPage-BotlwlX3.js.map} +1 -1
  159. package/dashboard/dist/assets/{EscalationSchemaPage-Dij9K0ON.js → EscalationSchemaPage-CfZSVOSD.js} +3 -3
  160. package/dashboard/dist/assets/{EscalationSchemaPage-Dij9K0ON.js.map → EscalationSchemaPage-CfZSVOSD.js.map} +1 -1
  161. package/dashboard/dist/assets/{EscalationTimeline-DT2Owdl0.js → EscalationTimeline-CCKpuRBU.js} +2 -2
  162. package/dashboard/dist/assets/{EscalationTimeline-DT2Owdl0.js.map → EscalationTimeline-CCKpuRBU.js.map} +1 -1
  163. package/dashboard/dist/assets/{EscalationTitleSelect-BdbfMA98.js → EscalationTitleSelect-cpTzPHiW.js} +2 -2
  164. package/dashboard/dist/assets/{EscalationTitleSelect-BdbfMA98.js.map → EscalationTitleSelect-cpTzPHiW.js.map} +1 -1
  165. package/dashboard/dist/assets/{EscalationsOverview-niahs84P.js → EscalationsOverview-DS-nK0qV.js} +2 -2
  166. package/dashboard/dist/assets/{EscalationsOverview-niahs84P.js.map → EscalationsOverview-DS-nK0qV.js.map} +1 -1
  167. package/dashboard/dist/assets/{EventTable-DuLMBrSx.js → EventTable-UfebhJf0.js} +2 -2
  168. package/dashboard/dist/assets/{EventTable-DuLMBrSx.js.map → EventTable-UfebhJf0.js.map} +1 -1
  169. package/dashboard/dist/assets/{FilterBar-jtY6KNpL.js → FilterBar-newA5l-X.js} +2 -2
  170. package/dashboard/dist/assets/{FilterBar-jtY6KNpL.js.map → FilterBar-newA5l-X.js.map} +1 -1
  171. package/dashboard/dist/assets/{GraphInvokePage-DSRAI0Zt.js → GraphInvokePage-6SCDyQcK.js} +2 -2
  172. package/dashboard/dist/assets/{GraphInvokePage-DSRAI0Zt.js.map → GraphInvokePage-6SCDyQcK.js.map} +1 -1
  173. package/dashboard/dist/assets/HomePage-BEc-XdKj.js +2 -0
  174. package/dashboard/dist/assets/{HomePage-BUlSnCg8.js.map → HomePage-BEc-XdKj.js.map} +1 -1
  175. package/dashboard/dist/assets/LabelJobsPage-BO50zXT5.js +2 -0
  176. package/dashboard/dist/assets/LabelJobsPage-BO50zXT5.js.map +1 -0
  177. package/dashboard/dist/assets/{LinePage-BJKhVM9Y.js → LinePage-NYxJQ-ex.js} +3 -3
  178. package/dashboard/dist/assets/{LinePage-BJKhVM9Y.js.map → LinePage-NYxJQ-ex.js.map} +1 -1
  179. package/dashboard/dist/assets/{LinesPage-CrpJua3_.js → LinesPage-RbWTaQRh.js} +3 -3
  180. package/dashboard/dist/assets/{LinesPage-CrpJua3_.js.map → LinesPage-RbWTaQRh.js.map} +1 -1
  181. package/dashboard/dist/assets/{ListToolbar-BN0UPt0L.js → ListToolbar-B-E9-toh.js} +2 -2
  182. package/dashboard/dist/assets/{ListToolbar-BN0UPt0L.js.map → ListToolbar-B-E9-toh.js.map} +1 -1
  183. package/dashboard/dist/assets/{McpOverview-BgbJXYPh.js → McpOverview-Shcf9QhZ.js} +2 -2
  184. package/dashboard/dist/assets/{McpOverview-BgbJXYPh.js.map → McpOverview-Shcf9QhZ.js.map} +1 -1
  185. package/dashboard/dist/assets/{McpQueryDetailPage-BNjm2nrc.js → McpQueryDetailPage-D8kmjy2v.js} +3 -3
  186. package/dashboard/dist/assets/{McpQueryDetailPage-BNjm2nrc.js.map → McpQueryDetailPage-D8kmjy2v.js.map} +1 -1
  187. package/dashboard/dist/assets/{McpQueryPage-DplR8wP9.js → McpQueryPage-ck-o5m8A.js} +2 -2
  188. package/dashboard/dist/assets/{McpQueryPage-DplR8wP9.js.map → McpQueryPage-ck-o5m8A.js.map} +1 -1
  189. package/dashboard/dist/assets/McpRunDetailPage-BJKkM9-3.js +2 -0
  190. package/dashboard/dist/assets/{McpRunDetailPage-BHVEcKV5.js.map → McpRunDetailPage-BJKkM9-3.js.map} +1 -1
  191. package/dashboard/dist/assets/{McpRunsPage-CtlLagcs.js → McpRunsPage-DqhHfD5G.js} +2 -2
  192. package/dashboard/dist/assets/{McpRunsPage-CtlLagcs.js.map → McpRunsPage-DqhHfD5G.js.map} +1 -1
  193. package/dashboard/dist/assets/{NamespacePill-CeSfHH-j.js → NamespacePill--uIaGtrN.js} +2 -2
  194. package/dashboard/dist/assets/{NamespacePill-CeSfHH-j.js.map → NamespacePill--uIaGtrN.js.map} +1 -1
  195. package/dashboard/dist/assets/{OperationsPage-DH67bcW9.js → OperationsPage-D6B9Vv__.js} +3 -3
  196. package/dashboard/dist/assets/{OperationsPage-DH67bcW9.js.map → OperationsPage-D6B9Vv__.js.map} +1 -1
  197. package/dashboard/dist/assets/OperatorDashboard-CIH1cxjQ.js +2 -0
  198. package/dashboard/dist/assets/{OperatorDashboard-CMkgMewd.js.map → OperatorDashboard-CIH1cxjQ.js.map} +1 -1
  199. package/dashboard/dist/assets/{PageHeader-DiGWAQlR.js → PageHeader-DClJ33fV.js} +2 -2
  200. package/dashboard/dist/assets/{PageHeader-DiGWAQlR.js.map → PageHeader-DClJ33fV.js.map} +1 -1
  201. package/dashboard/dist/assets/{PageHeaderWithStats-DwnKQ06j.js → PageHeaderWithStats-C-TrbKQL.js} +2 -2
  202. package/dashboard/dist/assets/{PageHeaderWithStats-DwnKQ06j.js.map → PageHeaderWithStats-C-TrbKQL.js.map} +1 -1
  203. package/dashboard/dist/assets/PersonaDetailPage-DjvfyIph.js +2 -0
  204. package/dashboard/dist/assets/{PersonaDetailPage-Cs1FFdNq.js.map → PersonaDetailPage-DjvfyIph.js.map} +1 -1
  205. package/dashboard/dist/assets/{PersonasPage-CHTRdneF.js → PersonasPage-D7ryA8Vc.js} +2 -2
  206. package/dashboard/dist/assets/{PersonasPage-CHTRdneF.js.map → PersonasPage-D7ryA8Vc.js.map} +1 -1
  207. package/dashboard/dist/assets/{PortalPage-ChB5pBTZ.js → PortalPage-D3ybr0mo.js} +2 -2
  208. package/dashboard/dist/assets/{PortalPage-ChB5pBTZ.js.map → PortalPage-D3ybr0mo.js.map} +1 -1
  209. package/dashboard/dist/assets/PrintLabelsPanel-D0HF5x8b.js +2 -0
  210. package/dashboard/dist/assets/PrintLabelsPanel-D0HF5x8b.js.map +1 -0
  211. package/dashboard/dist/assets/{ProcessDetailPage-CzyqSfal.js → ProcessDetailPage-0xS9EdHe.js} +2 -2
  212. package/dashboard/dist/assets/{ProcessDetailPage-CzyqSfal.js.map → ProcessDetailPage-0xS9EdHe.js.map} +1 -1
  213. package/dashboard/dist/assets/{ProcessesListPage-rOwNkaU9.js → ProcessesListPage-93SMj1Fd.js} +2 -2
  214. package/dashboard/dist/assets/{ProcessesListPage-rOwNkaU9.js.map → ProcessesListPage-93SMj1Fd.js.map} +1 -1
  215. package/dashboard/dist/assets/{ResolverForm-DibnlZ-A.js → ResolverForm-DfogHDzl.js} +5 -5
  216. package/dashboard/dist/assets/{ResolverForm-DibnlZ-A.js.map → ResolverForm-DfogHDzl.js.map} +1 -1
  217. package/dashboard/dist/assets/{RoleDetailPage-Bv9R7iQC.js → RoleDetailPage-DlUOJWSB.js} +3 -3
  218. package/dashboard/dist/assets/{RoleDetailPage-Bv9R7iQC.js.map → RoleDetailPage-DlUOJWSB.js.map} +1 -1
  219. package/dashboard/dist/assets/{RolePill-D3hkAdKf.js → RolePill-BjD1Qw5y.js} +2 -2
  220. package/dashboard/dist/assets/{RolePill-D3hkAdKf.js.map → RolePill-BjD1Qw5y.js.map} +1 -1
  221. package/dashboard/dist/assets/RolesPage-DqhHSvaw.js +2 -0
  222. package/dashboard/dist/assets/{RolesPage-CUP7EH5U.js.map → RolesPage-DqhHSvaw.js.map} +1 -1
  223. package/dashboard/dist/assets/{RosterWidget-DZtmQcjU.js → RosterWidget-BrIq61HR.js} +2 -2
  224. package/dashboard/dist/assets/{RosterWidget-DZtmQcjU.js.map → RosterWidget-BrIq61HR.js.map} +1 -1
  225. package/dashboard/dist/assets/RunAsSelector-D6zQrCNr.js +2 -0
  226. package/dashboard/dist/assets/{RunAsSelector-B9-1vgZr.js.map → RunAsSelector-D6zQrCNr.js.map} +1 -1
  227. package/dashboard/dist/assets/ScanCodesPage-B2S9DR2f.js +2 -0
  228. package/dashboard/dist/assets/{ScanCodesPage-KN_e2rJl.js.map → ScanCodesPage-B2S9DR2f.js.map} +1 -1
  229. package/dashboard/dist/assets/ScanSchemeDetailPage-gpxKN-pL.js +5 -0
  230. package/dashboard/dist/assets/ScanSchemeDetailPage-gpxKN-pL.js.map +1 -0
  231. package/dashboard/dist/assets/ScanStationPage-B-UTgXsG.js +2 -0
  232. package/dashboard/dist/assets/{ScanStationPage-B0qbUOwc.js.map → ScanStationPage-B-UTgXsG.js.map} +1 -1
  233. package/dashboard/dist/assets/{SchemeMatchFields-CL7TKnw3.js → SchemeMatchFields-BK24aa7K.js} +2 -2
  234. package/dashboard/dist/assets/{SchemeMatchFields-CL7TKnw3.js.map → SchemeMatchFields-BK24aa7K.js.map} +1 -1
  235. package/dashboard/dist/assets/{ScopeBadge-DGz79rmG.js → ScopeBadge-ofLQ6HW-.js} +2 -2
  236. package/dashboard/dist/assets/{ScopeBadge-DGz79rmG.js.map → ScopeBadge-ofLQ6HW-.js.map} +1 -1
  237. package/dashboard/dist/assets/{StickyPagination-CUwxfBQH.js → StickyPagination-CgVv7vc_.js} +2 -2
  238. package/dashboard/dist/assets/{StickyPagination-CUwxfBQH.js.map → StickyPagination-CgVv7vc_.js.map} +1 -1
  239. package/dashboard/dist/assets/{StreamMessageDetail-DOjcO7d2.js → StreamMessageDetail-B9sxDVw4.js} +2 -2
  240. package/dashboard/dist/assets/{StreamMessageDetail-DOjcO7d2.js.map → StreamMessageDetail-B9sxDVw4.js.map} +1 -1
  241. package/dashboard/dist/assets/{SwimlaneTimeline-SPMpoLHP.js → SwimlaneTimeline-DQc0CYSL.js} +2 -2
  242. package/dashboard/dist/assets/{SwimlaneTimeline-SPMpoLHP.js.map → SwimlaneTimeline-DQc0CYSL.js.map} +1 -1
  243. package/dashboard/dist/assets/{TagInput-DaIdhv3h.js → TagInput-47qVYzke.js} +2 -2
  244. package/dashboard/dist/assets/{TagInput-DaIdhv3h.js.map → TagInput-47qVYzke.js.map} +1 -1
  245. package/dashboard/dist/assets/{TaskDetailPage-DvfzR2IQ.js → TaskDetailPage-D6VOsA1f.js} +2 -2
  246. package/dashboard/dist/assets/{TaskDetailPage-DvfzR2IQ.js.map → TaskDetailPage-D6VOsA1f.js.map} +1 -1
  247. package/dashboard/dist/assets/{TaskQueuePill-sUA1nZe-.js → TaskQueuePill-C5KmdXAl.js} +2 -2
  248. package/dashboard/dist/assets/{TaskQueuePill-sUA1nZe-.js.map → TaskQueuePill-C5KmdXAl.js.map} +1 -1
  249. package/dashboard/dist/assets/{TasksListPage-Jp6wmL7t.js → TasksListPage-DG8hvO8G.js} +2 -2
  250. package/dashboard/dist/assets/{TasksListPage-Jp6wmL7t.js.map → TasksListPage-DG8hvO8G.js.map} +1 -1
  251. package/dashboard/dist/assets/{TimeAgo-BCQA0Gb_.js → TimeAgo-CL02EhFi.js} +2 -2
  252. package/dashboard/dist/assets/{TimeAgo-BCQA0Gb_.js.map → TimeAgo-CL02EhFi.js.map} +1 -1
  253. package/dashboard/dist/assets/{TimestampCell-xhdMHDQt.js → TimestampCell-BE7oKVJg.js} +2 -2
  254. package/dashboard/dist/assets/{TimestampCell-xhdMHDQt.js.map → TimestampCell-BE7oKVJg.js.map} +1 -1
  255. package/dashboard/dist/assets/{ToolPill-CpBAFdEX.js → ToolPill-Cp9Drk1s.js} +2 -2
  256. package/dashboard/dist/assets/{ToolPill-CpBAFdEX.js.map → ToolPill-Cp9Drk1s.js.map} +1 -1
  257. package/dashboard/dist/assets/{ToolTestPanel-D8M3ITrJ.js → ToolTestPanel-CRecLh6S.js} +2 -2
  258. package/dashboard/dist/assets/{ToolTestPanel-D8M3ITrJ.js.map → ToolTestPanel-CRecLh6S.js.map} +1 -1
  259. package/dashboard/dist/assets/{TopicDetailPage-DdBJQp31.js → TopicDetailPage-QzkinTfN.js} +3 -3
  260. package/dashboard/dist/assets/{TopicDetailPage-DdBJQp31.js.map → TopicDetailPage-QzkinTfN.js.map} +1 -1
  261. package/dashboard/dist/assets/{TopicsPage-vpvsynD9.js → TopicsPage-D8dW6J65.js} +2 -2
  262. package/dashboard/dist/assets/{TopicsPage-vpvsynD9.js.map → TopicsPage-D8dW6J65.js.map} +1 -1
  263. package/dashboard/dist/assets/{UserName-BK6Lzsdw.js → UserName-Dw3R_zrl.js} +2 -2
  264. package/dashboard/dist/assets/{UserName-BK6Lzsdw.js.map → UserName-Dw3R_zrl.js.map} +1 -1
  265. package/dashboard/dist/assets/WorkflowExecutionPage-BTocv8or.js +2 -0
  266. package/dashboard/dist/assets/{WorkflowExecutionPage-DkM1TS4I.js.map → WorkflowExecutionPage-BTocv8or.js.map} +1 -1
  267. package/dashboard/dist/assets/{WorkflowPill-CKHip3hH.js → WorkflowPill-BiLYq__w.js} +2 -2
  268. package/dashboard/dist/assets/{WorkflowPill-CKHip3hH.js.map → WorkflowPill-BiLYq__w.js.map} +1 -1
  269. package/dashboard/dist/assets/WorkflowsDashboard-CIPEt3et.js +2 -0
  270. package/dashboard/dist/assets/{WorkflowsDashboard-g_N4y3QS.js.map → WorkflowsDashboard-CIPEt3et.js.map} +1 -1
  271. package/dashboard/dist/assets/{WorkflowsOverview-Drjo-Lu-.js → WorkflowsOverview-Bj4MJIE-.js} +2 -2
  272. package/dashboard/dist/assets/{WorkflowsOverview-Drjo-Lu-.js.map → WorkflowsOverview-Bj4MJIE-.js.map} +1 -1
  273. package/dashboard/dist/assets/{YamlWorkflowDetailPage-CLltNHjZ.js → YamlWorkflowDetailPage-DMEk5k9-.js} +2 -2
  274. package/dashboard/dist/assets/{YamlWorkflowDetailPage-CLltNHjZ.js.map → YamlWorkflowDetailPage-DMEk5k9-.js.map} +1 -1
  275. package/dashboard/dist/assets/{YamlWorkflowsPage-CxQCB-Zi.js → YamlWorkflowsPage-F2yyyoiB.js} +2 -2
  276. package/dashboard/dist/assets/{YamlWorkflowsPage-CxQCB-Zi.js.map → YamlWorkflowsPage-F2yyyoiB.js.map} +1 -1
  277. package/dashboard/dist/assets/{agents-Dk25jjhj.js → agents-mSgxEPpI.js} +2 -2
  278. package/dashboard/dist/assets/{agents-Dk25jjhj.js.map → agents-mSgxEPpI.js.map} +1 -1
  279. package/dashboard/dist/assets/{bots-bRkCqhlq.js → bots-p4Hp0CV6.js} +2 -2
  280. package/dashboard/dist/assets/{bots-bRkCqhlq.js.map → bots-p4Hp0CV6.js.map} +1 -1
  281. package/dashboard/dist/assets/{capabilities-DARawLry.js → capabilities-D_-I_SXR.js} +2 -2
  282. package/dashboard/dist/assets/{capabilities-DARawLry.js.map → capabilities-D_-I_SXR.js.map} +1 -1
  283. package/dashboard/dist/assets/{controlplane-DKccxxs6.js → controlplane-DjdoQnRU.js} +2 -2
  284. package/dashboard/dist/assets/{controlplane-DKccxxs6.js.map → controlplane-DjdoQnRU.js.map} +1 -1
  285. package/dashboard/dist/assets/{escalation-columns-BaYuzMYf.js → escalation-columns-R_IEVQjQ.js} +2 -2
  286. package/dashboard/dist/assets/{escalation-columns-BaYuzMYf.js.map → escalation-columns-R_IEVQjQ.js.map} +1 -1
  287. package/dashboard/dist/assets/{escalation-items-CwbNFnsH.js → escalation-items-BGZlJMpk.js} +2 -2
  288. package/dashboard/dist/assets/{escalation-items-CwbNFnsH.js.map → escalation-items-BGZlJMpk.js.map} +1 -1
  289. package/dashboard/dist/assets/{index-Cf6qCgTf.js → index-BEMdD58x.js} +2 -2
  290. package/dashboard/dist/assets/{index-Cf6qCgTf.js.map → index-BEMdD58x.js.map} +1 -1
  291. package/dashboard/dist/assets/index-BUmz0NMg.css +1 -0
  292. package/dashboard/dist/assets/{index-hKOlahpE.js → index-BuCEhhnl.js} +2 -2
  293. package/dashboard/dist/assets/{index-hKOlahpE.js.map → index-BuCEhhnl.js.map} +1 -1
  294. package/dashboard/dist/assets/{index-D1uliPqS.js → index-BxbQmeqh.js} +2 -2
  295. package/dashboard/dist/assets/{index-D1uliPqS.js.map → index-BxbQmeqh.js.map} +1 -1
  296. package/dashboard/dist/assets/index-C5osluV3.js +2 -0
  297. package/dashboard/dist/assets/{index-CtrSYqmL.js.map → index-C5osluV3.js.map} +1 -1
  298. package/dashboard/dist/assets/{index-CU2UW2y6.js → index-C_dAJUzh.js} +25 -25
  299. package/dashboard/dist/assets/index-C_dAJUzh.js.map +1 -0
  300. package/dashboard/dist/assets/{index-Bx9HVzuT.js → index-D-FYj9jT.js} +2 -2
  301. package/dashboard/dist/assets/{index-Bx9HVzuT.js.map → index-D-FYj9jT.js.map} +1 -1
  302. package/dashboard/dist/assets/{index-BZgtzkkG.js → index-D6K_IgCz.js} +2 -2
  303. package/dashboard/dist/assets/{index-BZgtzkkG.js.map → index-D6K_IgCz.js.map} +1 -1
  304. package/dashboard/dist/assets/index-D7L_VoBD.js +2 -0
  305. package/dashboard/dist/assets/index-D7L_VoBD.js.map +1 -0
  306. package/dashboard/dist/assets/{index-DgpL_Lgc.js → index-D9RAN9sA.js} +2 -2
  307. package/dashboard/dist/assets/{index-DgpL_Lgc.js.map → index-D9RAN9sA.js.map} +1 -1
  308. package/dashboard/dist/assets/{index-dShcvdg3.js → index-DUYAGxwc.js} +2 -2
  309. package/dashboard/dist/assets/{index-dShcvdg3.js.map → index-DUYAGxwc.js.map} +1 -1
  310. package/dashboard/dist/assets/{index-E_hJ7vtX.js → index-Dk2KKo0z.js} +2 -2
  311. package/dashboard/dist/assets/{index-E_hJ7vtX.js.map → index-Dk2KKo0z.js.map} +1 -1
  312. package/dashboard/dist/assets/{index-DU2QCbgH.js → index-DlJkZ12b.js} +2 -2
  313. package/dashboard/dist/assets/{index-DU2QCbgH.js.map → index-DlJkZ12b.js.map} +1 -1
  314. package/dashboard/dist/assets/{index-kzifJWbM.js → index-FiNThtNU.js} +3 -3
  315. package/dashboard/dist/assets/{index-kzifJWbM.js.map → index-FiNThtNU.js.map} +1 -1
  316. package/dashboard/dist/assets/{knowledge-DOe5ks-E.js → knowledge-DSsPTqkK.js} +2 -2
  317. package/dashboard/dist/assets/{knowledge-DOe5ks-E.js.map → knowledge-DSsPTqkK.js.map} +1 -1
  318. package/dashboard/dist/assets/{machines-Zq_00v7k.js → machines-DSgGtqqr.js} +2 -2
  319. package/dashboard/dist/assets/{machines-Zq_00v7k.js.map → machines-DSgGtqqr.js.map} +1 -1
  320. package/dashboard/dist/assets/{mcp-BL8kD0oh.js → mcp-Cg-_uLw8.js} +2 -2
  321. package/dashboard/dist/assets/{mcp-BL8kD0oh.js.map → mcp-Cg-_uLw8.js.map} +1 -1
  322. package/dashboard/dist/assets/{mcp-query-BpokmJWi.js → mcp-query-DQombEK_.js} +2 -2
  323. package/dashboard/dist/assets/{mcp-query-BpokmJWi.js.map → mcp-query-DQombEK_.js.map} +1 -1
  324. package/dashboard/dist/assets/{personas-BubCnQZ8.js → personas-DYrcoVBu.js} +2 -2
  325. package/dashboard/dist/assets/{personas-BubCnQZ8.js.map → personas-DYrcoVBu.js.map} +1 -1
  326. package/dashboard/dist/assets/{pipelines--DUoMx7K.js → pipelines-wdb4xsey.js} +2 -2
  327. package/dashboard/dist/assets/{pipelines--DUoMx7K.js.map → pipelines-wdb4xsey.js.map} +1 -1
  328. package/dashboard/dist/assets/{tasks-CJXN4OB4.js → tasks-Bil7gvm9.js} +2 -2
  329. package/dashboard/dist/assets/{tasks-CJXN4OB4.js.map → tasks-Bil7gvm9.js.map} +1 -1
  330. package/dashboard/dist/assets/{topics-CAG08Ruo.js → topics-wBqaVhRR.js} +2 -2
  331. package/dashboard/dist/assets/{topics-CAG08Ruo.js.map → topics-wBqaVhRR.js.map} +1 -1
  332. package/dashboard/dist/assets/{useDebouncedValue-DQ2D8cm2.js → useDebouncedValue-CwrY8TpV.js} +2 -2
  333. package/dashboard/dist/assets/{useDebouncedValue-DQ2D8cm2.js.map → useDebouncedValue-CwrY8TpV.js.map} +1 -1
  334. package/dashboard/dist/assets/{useNamespace-DjEVAlJQ.js → useNamespace-Sod_xApz.js} +2 -2
  335. package/dashboard/dist/assets/{useNamespace-DjEVAlJQ.js.map → useNamespace-Sod_xApz.js.map} +1 -1
  336. package/dashboard/dist/assets/{useYamlActivityEvents-etcpfIwo.js → useYamlActivityEvents-CKLInV3C.js} +2 -2
  337. package/dashboard/dist/assets/{useYamlActivityEvents-etcpfIwo.js.map → useYamlActivityEvents-CKLInV3C.js.map} +1 -1
  338. package/dashboard/dist/assets/{validate-YJK_6a7m.js → validate-CYhW1xMJ.js} +2 -2
  339. package/dashboard/dist/assets/{validate-YJK_6a7m.js.map → validate-CYhW1xMJ.js.map} +1 -1
  340. package/dashboard/dist/assets/{vendor-icons-en0_uSRD.js → vendor-icons-ed7mYQw4.js} +2 -2
  341. package/dashboard/dist/assets/{vendor-icons-en0_uSRD.js.map → vendor-icons-ed7mYQw4.js.map} +1 -1
  342. package/dashboard/dist/assets/{yaml-workflows-D97Bz6li.js → yaml-workflows-C20qHo3L.js} +2 -2
  343. package/dashboard/dist/assets/{yaml-workflows-D97Bz6li.js.map → yaml-workflows-C20qHo3L.js.map} +1 -1
  344. package/dashboard/dist/index.html +3 -3
  345. package/docs/api/http/labels.md +115 -0
  346. package/docs/api/http/users.md +2 -0
  347. package/docs/api/mcp/admin.md +76 -1
  348. package/docs/code-owned-configuration.md +1 -1
  349. package/docs/iam.md +12 -0
  350. package/docs/label-sheets.md +267 -0
  351. package/docs/machines.md +2 -2
  352. package/docs/scan-codes.md +11 -5
  353. package/package.json +4 -1
  354. package/dashboard/dist/assets/AvailableEscalationsPage-BRKyG5qZ.js +0 -2
  355. package/dashboard/dist/assets/AvailableEscalationsPage-BRKyG5qZ.js.map +0 -1
  356. package/dashboard/dist/assets/BulkAssignModal-BWfzPrRk.js +0 -2
  357. package/dashboard/dist/assets/HomePage-BUlSnCg8.js +0 -2
  358. package/dashboard/dist/assets/McpRunDetailPage-BHVEcKV5.js +0 -2
  359. package/dashboard/dist/assets/OperatorDashboard-CMkgMewd.js +0 -2
  360. package/dashboard/dist/assets/PersonaDetailPage-Cs1FFdNq.js +0 -2
  361. package/dashboard/dist/assets/RolesPage-CUP7EH5U.js +0 -2
  362. package/dashboard/dist/assets/RunAsSelector-B9-1vgZr.js +0 -2
  363. package/dashboard/dist/assets/ScanCodesPage-KN_e2rJl.js +0 -2
  364. package/dashboard/dist/assets/ScanSchemeDetailPage-CqItQ67Y.js +0 -5
  365. package/dashboard/dist/assets/ScanSchemeDetailPage-CqItQ67Y.js.map +0 -1
  366. package/dashboard/dist/assets/ScanStationPage-B0qbUOwc.js +0 -2
  367. package/dashboard/dist/assets/WorkflowExecutionPage-DkM1TS4I.js +0 -2
  368. package/dashboard/dist/assets/WorkflowsDashboard-g_N4y3QS.js +0 -2
  369. package/dashboard/dist/assets/index-BmzscsXK.css +0 -1
  370. package/dashboard/dist/assets/index-CU2UW2y6.js.map +0 -1
  371. package/dashboard/dist/assets/index-CtrSYqmL.js +0 -2
  372. package/dashboard/dist/assets/index-DU-1gMks.js +0 -2
  373. package/dashboard/dist/assets/index-DU-1gMks.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
+ }
@@ -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;
@@ -20,6 +21,9 @@ const CHOICE_CODE = /^[A-Za-z0-9_-]{1,32}$/;
20
21
  * problem — a bad scheme silently misparsing every scan is far worse
21
22
  * than a loud upsert failure.
22
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;
23
27
  function assertValidScheme(scheme) {
24
28
  if (!Number.isInteger(scheme.version) || scheme.version < 10 || scheme.version > 99) {
25
29
  throw new Error('scheme version must be a two-digit integer between 10 and 99');
@@ -53,6 +57,12 @@ function assertValidScheme(scheme) {
53
57
  if (kind !== types_1.SCAN_SCHEME_KINDS.ACTION && kind !== types_1.SCAN_SCHEME_KINDS.IDENTITY) {
54
58
  throw new Error(`unknown scheme kind "${kind}"`);
55
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
+ }
56
66
  if (kind === types_1.SCAN_SCHEME_KINDS.IDENTITY) {
57
67
  const ttl = scheme.grant_ttl_seconds;
58
68
  if (!Number.isInteger(ttl) || ttl < 1 || ttl > 86_400) {
@@ -1,5 +1,5 @@
1
1
  import type { LTUserRecord, LTRoleType, LTUserStatus } from '../../types';
2
- import type { CreateUserInput, UpdateUserInput, UserPropertyOps } from './types';
2
+ import type { CreateUserInput, PropertyPatchRecord, UpdateUserInput, UserPropertyOps } from './types';
3
3
  export declare function attachRoles(user: any): Promise<LTUserRecord>;
4
4
  export declare function createUser(input: CreateUserInput): Promise<LTUserRecord>;
5
5
  export declare function getUser(id: string): Promise<LTUserRecord | null>;
@@ -56,6 +56,18 @@ export declare function getIdentityPropertyKeys(): Promise<string[]>;
56
56
  * A tripped guard raises UserPropertyConflictError (409).
57
57
  */
58
58
  export declare function patchUserProperties(id: string, ops: UserPropertyOps): Promise<LTUserRecord | null>;
59
+ /**
60
+ * The identity keys a patch touches: set, removed, or renamed from or to.
61
+ */
62
+ export declare function identityKeysTouched(ops: UserPropertyOps): Promise<string[]>;
63
+ /**
64
+ * patchUserProperties, with an lt_label_jobs row written by the same
65
+ * statement. Returns the user and the ledger row id; null for an unknown user.
66
+ */
67
+ export declare function patchUserPropertiesRecorded(id: string, ops: UserPropertyOps, record: PropertyPatchRecord): Promise<{
68
+ user: LTUserRecord;
69
+ jobId: string;
70
+ } | null>;
59
71
  export declare function deleteUser(id: string): Promise<boolean>;
60
72
  export declare function listUsers(filters: {
61
73
  role?: string;
@@ -14,6 +14,8 @@ exports.getUserByMetadataValue = getUserByMetadataValue;
14
14
  exports.updateUser = updateUser;
15
15
  exports.getIdentityPropertyKeys = getIdentityPropertyKeys;
16
16
  exports.patchUserProperties = patchUserProperties;
17
+ exports.identityKeysTouched = identityKeysTouched;
18
+ exports.patchUserPropertiesRecorded = patchUserPropertiesRecorded;
17
19
  exports.deleteUser = deleteUser;
18
20
  exports.listUsers = listUsers;
19
21
  const bcryptjs_1 = __importDefault(require("bcryptjs"));
@@ -159,8 +161,12 @@ async function updateUser(id, input) {
159
161
  values.push(await bcryptjs_1.default.hash(input.password, 10));
160
162
  }
161
163
  if (input.metadata !== undefined) {
162
- sets.push(`metadata = $${idx++}`);
163
- values.push(JSON.stringify(input.metadata));
164
+ // Identity bindings the replacement leaves out are kept, read in the same statement.
165
+ const keysIdx = idx++;
166
+ const metadataIdx = idx++;
167
+ sets.push(`metadata = COALESCE((SELECT jsonb_object_agg(k, lt_users.metadata -> k) FROM unnest($${keysIdx}::text[]) AS k ` +
168
+ `WHERE COALESCE(lt_users.metadata, '{}'::jsonb) ? k), '{}'::jsonb) || $${metadataIdx}::jsonb`);
169
+ values.push(await getIdentityPropertyKeys(), JSON.stringify(input.metadata));
164
170
  }
165
171
  if (sets.length === 0) {
166
172
  return getUser(id);
@@ -215,6 +221,29 @@ async function getIdentityPropertyKeys() {
215
221
  * A tripped guard raises UserPropertyConflictError (409).
216
222
  */
217
223
  async function patchUserProperties(id, ops) {
224
+ const patched = await runPropertyPatch(id, ops, null);
225
+ return patched?.user ?? null;
226
+ }
227
+ /**
228
+ * The identity keys a patch touches: set, removed, or renamed from or to.
229
+ */
230
+ async function identityKeysTouched(ops) {
231
+ const keys = new Set([
232
+ ...Object.keys(ops.set ?? {}),
233
+ ...(ops.remove ?? []),
234
+ ...Object.entries(ops.rename ?? {}).flat(),
235
+ ]);
236
+ return (await getIdentityPropertyKeys()).filter((k) => keys.has(k));
237
+ }
238
+ /**
239
+ * patchUserProperties, with an lt_label_jobs row written by the same
240
+ * statement. Returns the user and the ledger row id; null for an unknown user.
241
+ */
242
+ async function patchUserPropertiesRecorded(id, ops, record) {
243
+ const patched = await runPropertyPatch(id, ops, record);
244
+ return patched ? { user: patched.user, jobId: patched.jobId } : null;
245
+ }
246
+ async function runPropertyPatch(id, ops, record) {
218
247
  const set = ops.set ?? {};
219
248
  const remove = ops.remove ?? [];
220
249
  const rename = ops.rename ?? {};
@@ -258,18 +287,20 @@ async function patchUserProperties(id, ops) {
258
287
  const removeAll = [...new Set([...remove, ...renameEntries.map(([prev]) => prev)])];
259
288
  const renamePairs = renameEntries.map(([prev, next]) => ({ prev, next }));
260
289
  const pool = (0, db_1.getPool)();
261
- const { rows } = await pool.query(sql_1.PATCH_USER_PROPERTIES, [
262
- id,
263
- removeAll,
264
- JSON.stringify(renamePairs),
265
- JSON.stringify(set),
266
- JSON.stringify(guard),
267
- ]);
268
- if (rows[0])
269
- return attachRoles(rows[0]);
290
+ const params = [id, removeAll, JSON.stringify(renamePairs), JSON.stringify(set), JSON.stringify(guard)];
291
+ const { rows } = record
292
+ ? await pool.query(sql_1.PATCH_USER_PROPERTIES_RECORDED, [...params, JSON.stringify(record)])
293
+ : await pool.query(sql_1.PATCH_USER_PROPERTIES, params);
294
+ if (rows[0]) {
295
+ const { ledger_id: jobId = null, ...row } = rows[0];
296
+ return { user: await attachRoles(row), jobId };
297
+ }
270
298
  const exists = await pool.query(sql_1.VERIFY_USER_BY_ID, [id]);
271
299
  if (!exists.rows[0])
272
300
  return null;
301
+ if (record?.require_active && exists.rows[0].status !== 'active') {
302
+ throw new UserPropertyValidationError('identity bindings are issued to active users only');
303
+ }
273
304
  // The user exists, so the identity guard is what blocked the write. Name
274
305
  // the first guarded key for the caller; the row was not touched.
275
306
  throw new UserPropertyConflictError(Object.keys(guard)[0] ?? 'identity binding');
@@ -1,5 +1,6 @@
1
- export { CreateUserInput, UpdateUserInput, UserPropertyOps, VALID_ROLE_TYPES } from './types';
2
- export { createUser, getUser, getUserNames, UserNameRecord, getUserByExternalId, getUserByEmail, getUserByMetadataValue, updateUser, patchUserProperties, getIdentityPropertyKeys, UserPropertyConflictError, UserPropertyValidationError, deleteUser, listUsers, } from './crud';
1
+ export { CreateUserInput, PropertyPatchRecord, UpdateUserInput, UserPropertyOps, VALID_ROLE_TYPES } from './types';
2
+ export { redactIdentityKeys, setIdentityKeyProtection, identityKeysProtected } from './redact';
3
+ export { createUser, getUser, getUserNames, UserNameRecord, getUserByExternalId, getUserByEmail, getUserByMetadataValue, updateUser, patchUserProperties, patchUserPropertiesRecorded, identityKeysTouched, getIdentityPropertyKeys, UserPropertyConflictError, UserPropertyValidationError, deleteUser, listUsers, } from './crud';
3
4
  export { isValidRoleType, addUserRole, grantRoleIfAbsent, removeUserRole, getUserRoles, hasRole, hasRoleType, } from './roles';
4
5
  export { isSuperAdmin, isGroupAdmin, canManageRole, hasGlobalEscalationAccess, hasRolesAsAdmin, getRoleScope, getRoleWriteScope } from './rbac';
5
6
  export { READ_SCOPES, WRITE_SCOPES, DEFAULT_READ_SCOPE, DEFAULT_WRITE_SCOPE, isValidReadScope, isValidWriteScope, isValidScopePair, effectiveScope, } from './scope';
@@ -1,8 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PREFERENCES_MAX_BYTES = exports.patchPreferences = exports.getPreferences = exports.seedAdmin = exports.verifyPassword = exports.effectiveScope = exports.isValidScopePair = exports.isValidWriteScope = exports.isValidReadScope = exports.DEFAULT_WRITE_SCOPE = exports.DEFAULT_READ_SCOPE = exports.WRITE_SCOPES = exports.READ_SCOPES = exports.getRoleWriteScope = exports.getRoleScope = exports.hasRolesAsAdmin = exports.hasGlobalEscalationAccess = exports.canManageRole = exports.isGroupAdmin = exports.isSuperAdmin = exports.hasRoleType = exports.hasRole = exports.getUserRoles = exports.removeUserRole = exports.grantRoleIfAbsent = exports.addUserRole = exports.isValidRoleType = exports.listUsers = exports.deleteUser = exports.UserPropertyValidationError = exports.UserPropertyConflictError = exports.getIdentityPropertyKeys = exports.patchUserProperties = exports.updateUser = exports.getUserByMetadataValue = exports.getUserByEmail = exports.getUserByExternalId = exports.getUserNames = exports.getUser = exports.createUser = exports.VALID_ROLE_TYPES = void 0;
3
+ exports.PREFERENCES_MAX_BYTES = exports.patchPreferences = exports.getPreferences = exports.seedAdmin = exports.verifyPassword = exports.effectiveScope = exports.isValidScopePair = exports.isValidWriteScope = exports.isValidReadScope = exports.DEFAULT_WRITE_SCOPE = exports.DEFAULT_READ_SCOPE = exports.WRITE_SCOPES = exports.READ_SCOPES = exports.getRoleWriteScope = exports.getRoleScope = exports.hasRolesAsAdmin = exports.hasGlobalEscalationAccess = exports.canManageRole = exports.isGroupAdmin = exports.isSuperAdmin = exports.hasRoleType = exports.hasRole = exports.getUserRoles = exports.removeUserRole = exports.grantRoleIfAbsent = exports.addUserRole = exports.isValidRoleType = exports.listUsers = exports.deleteUser = exports.UserPropertyValidationError = exports.UserPropertyConflictError = exports.getIdentityPropertyKeys = exports.identityKeysTouched = exports.patchUserPropertiesRecorded = exports.patchUserProperties = exports.updateUser = exports.getUserByMetadataValue = exports.getUserByEmail = exports.getUserByExternalId = exports.getUserNames = exports.getUser = exports.createUser = exports.identityKeysProtected = exports.setIdentityKeyProtection = exports.redactIdentityKeys = exports.VALID_ROLE_TYPES = void 0;
4
4
  var types_1 = require("./types");
5
5
  Object.defineProperty(exports, "VALID_ROLE_TYPES", { enumerable: true, get: function () { return types_1.VALID_ROLE_TYPES; } });
6
+ var redact_1 = require("./redact");
7
+ Object.defineProperty(exports, "redactIdentityKeys", { enumerable: true, get: function () { return redact_1.redactIdentityKeys; } });
8
+ Object.defineProperty(exports, "setIdentityKeyProtection", { enumerable: true, get: function () { return redact_1.setIdentityKeyProtection; } });
9
+ Object.defineProperty(exports, "identityKeysProtected", { enumerable: true, get: function () { return redact_1.identityKeysProtected; } });
6
10
  var crud_1 = require("./crud");
7
11
  Object.defineProperty(exports, "createUser", { enumerable: true, get: function () { return crud_1.createUser; } });
8
12
  Object.defineProperty(exports, "getUser", { enumerable: true, get: function () { return crud_1.getUser; } });
@@ -12,6 +16,8 @@ Object.defineProperty(exports, "getUserByEmail", { enumerable: true, get: functi
12
16
  Object.defineProperty(exports, "getUserByMetadataValue", { enumerable: true, get: function () { return crud_1.getUserByMetadataValue; } });
13
17
  Object.defineProperty(exports, "updateUser", { enumerable: true, get: function () { return crud_1.updateUser; } });
14
18
  Object.defineProperty(exports, "patchUserProperties", { enumerable: true, get: function () { return crud_1.patchUserProperties; } });
19
+ Object.defineProperty(exports, "patchUserPropertiesRecorded", { enumerable: true, get: function () { return crud_1.patchUserPropertiesRecorded; } });
20
+ Object.defineProperty(exports, "identityKeysTouched", { enumerable: true, get: function () { return crud_1.identityKeysTouched; } });
15
21
  Object.defineProperty(exports, "getIdentityPropertyKeys", { enumerable: true, get: function () { return crud_1.getIdentityPropertyKeys; } });
16
22
  Object.defineProperty(exports, "UserPropertyConflictError", { enumerable: true, get: function () { return crud_1.UserPropertyConflictError; } });
17
23
  Object.defineProperty(exports, "UserPropertyValidationError", { enumerable: true, get: function () { return crud_1.UserPropertyValidationError; } });
@@ -0,0 +1,17 @@
1
+ import type { LTUserRecord } from '../../types';
2
+ /**
3
+ * Whether identity keys are protected: left out of user reads, refused in
4
+ * wholesale metadata writes, and written only with credentialIssuer. On by
5
+ * default; start({ labels: { protectIdentityKeys: false } }) turns it off.
6
+ */
7
+ export declare function setIdentityKeyProtection(on: boolean): void;
8
+ export declare function identityKeysProtected(): boolean;
9
+ /**
10
+ * A user record as a reader sees it. `identity_bound` names the identity keys
11
+ * the user carries; while protection is on, their values (badge tokens and
12
+ * other printed credentials) leave `metadata`, and printing a credential is
13
+ * the only path that reveals one.
14
+ */
15
+ export declare function redactIdentityKeys<T extends Pick<LTUserRecord, 'metadata'>>(user: T, identityKeys: string[]): T & {
16
+ identity_bound: string[];
17
+ };
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setIdentityKeyProtection = setIdentityKeyProtection;
4
+ exports.identityKeysProtected = identityKeysProtected;
5
+ exports.redactIdentityKeys = redactIdentityKeys;
6
+ const config_1 = require("../../modules/config");
7
+ let protectIdentityKeys = config_1.config.LT_PROTECT_IDENTITY_KEYS;
8
+ /**
9
+ * Whether identity keys are protected: left out of user reads, refused in
10
+ * wholesale metadata writes, and written only with credentialIssuer. On by
11
+ * default; start({ labels: { protectIdentityKeys: false } }) turns it off.
12
+ */
13
+ function setIdentityKeyProtection(on) {
14
+ protectIdentityKeys = on;
15
+ }
16
+ function identityKeysProtected() {
17
+ return protectIdentityKeys;
18
+ }
19
+ /**
20
+ * A user record as a reader sees it. `identity_bound` names the identity keys
21
+ * the user carries; while protection is on, their values (badge tokens and
22
+ * other printed credentials) leave `metadata`, and printing a credential is
23
+ * the only path that reveals one.
24
+ */
25
+ function redactIdentityKeys(user, identityKeys) {
26
+ const metadata = user.metadata ? { ...user.metadata } : user.metadata;
27
+ const bound = identityKeys.filter((key) => !!metadata && key in metadata);
28
+ if (metadata && protectIdentityKeys)
29
+ for (const key of bound)
30
+ delete metadata[key];
31
+ return { ...user, metadata, identity_bound: bound };
32
+ }
@@ -33,23 +33,16 @@ export declare const GET_NAMES_BY_IDS = "SELECT id, display_name, external_id, e
33
33
  */
34
34
  export declare const GET_USERS_BY_METADATA_VALUE: string;
35
35
  /** Check if a user exists by id. Lightweight — returns only the id column. */
36
- export declare const VERIFY_USER_BY_ID = "SELECT id FROM lt_users WHERE id = $1 LIMIT 1";
36
+ export declare const VERIFY_USER_BY_ID = "SELECT id, status FROM lt_users WHERE id = $1 LIMIT 1";
37
+ export declare const PATCH_USER_PROPERTIES = "\n UPDATE lt_users SET metadata = (\n (COALESCE(metadata, '{}'::jsonb) - $2::text[])\n || COALESCE((\n SELECT jsonb_object_agg(r.next, COALESCE(lt_users.metadata, '{}'::jsonb) -> r.prev)\n FROM jsonb_to_recordset($3::jsonb) AS r(prev text, next text)\n WHERE COALESCE(lt_users.metadata, '{}'::jsonb) ? r.prev\n ), '{}'::jsonb)\n || $4::jsonb\n )\n WHERE id = $1\n AND NOT EXISTS (\n SELECT 1\n FROM lt_users u2, jsonb_each_text($5::jsonb) AS g(k, v)\n WHERE u2.id <> $1 AND u2.status = 'active' AND u2.metadata ->> g.k = g.v\n )\n RETURNING *";
37
38
  /**
38
- * Atomic per-key patch of the user's properties dictionary — ONE statement,
39
- * never read-merge-write. Composition (later wins on key collision):
40
- *
41
- * base minus ($2: removed keys ∪ rename old-names)
42
- * || renames ($3: [{prev,next}] — each carries the OLD value, skipped when
43
- * the source key is absent)
44
- * || sets ($4: typed JSON values)
45
- *
46
- * $5 is the identity-binding guard: {key: value} pairs that must not already
47
- * belong to ANOTHER active user (the write-side counterpart of the
48
- * resolver's ambiguity throw in GET_USERS_BY_METADATA_VALUE). Zero rows
49
- * back means the user is missing OR the guard tripped — the caller
50
- * distinguishes with VERIFY_USER_BY_ID.
39
+ * The same patch, recorded in lt_label_jobs in the same statement: the ledger
40
+ * row exists exactly when the patch landed. $6 is the ledger row as JSON
41
+ * (action, requested_by, source, and for a reissue the template and media);
42
+ * it never carries the identity value. With `require_active`, only an active
43
+ * user is patched, checked in the same statement.
51
44
  */
52
- export declare const PATCH_USER_PROPERTIES = "\n UPDATE lt_users SET metadata = (\n (COALESCE(metadata, '{}'::jsonb) - $2::text[])\n || COALESCE((\n SELECT jsonb_object_agg(r.next, COALESCE(lt_users.metadata, '{}'::jsonb) -> r.prev)\n FROM jsonb_to_recordset($3::jsonb) AS r(prev text, next text)\n WHERE COALESCE(lt_users.metadata, '{}'::jsonb) ? r.prev\n ), '{}'::jsonb)\n || $4::jsonb\n )\n WHERE id = $1\n AND NOT EXISTS (\n SELECT 1\n FROM lt_users u2, jsonb_each_text($5::jsonb) AS g(k, v)\n WHERE u2.id <> $1 AND u2.status = 'active' AND u2.metadata ->> g.k = g.v\n )\n RETURNING *";
45
+ export declare const PATCH_USER_PROPERTIES_RECORDED: string;
53
46
  /** Fetch user + roles in a single query. Returns one row per role (or one row with nulls if no roles). */
54
47
  export declare const GET_USER_WITH_ROLES = "SELECT u.id, u.external_id, u.display_name, u.status, u.metadata,\n r.role, r.type AS role_type, r.read_scope, r.write_scope\n FROM lt_users u\n LEFT JOIN lt_user_roles r ON r.user_id = u.id\n WHERE u.external_id = $1\n ORDER BY r.created_at";
55
48
  export declare const DELETE_USER_BY_ID = "DELETE FROM lt_users WHERE id = $1";
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  // ─── Shared queries (used by multiple modules) ──────────────────────────────
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.IS_GROUP_ADMIN = exports.GET_ROLE_SCOPE = exports.HAS_ROLE_TYPE = exports.HAS_ROLE = exports.DELETE_USER_ROLE = exports.INSERT_USER_ROLE_IF_ABSENT = exports.UPSERT_USER_ROLE = exports.GET_ROLES_BY_USER_IDS = exports.DELETE_USER_BY_ID = exports.GET_USER_WITH_ROLES = exports.PATCH_USER_PROPERTIES = exports.VERIFY_USER_BY_ID = exports.GET_USERS_BY_METADATA_VALUE = exports.GET_NAMES_BY_IDS = exports.GET_USER_BY_ID = exports.GET_USER_BY_EMAIL = exports.CREATE_USER_WITH_ROLES = exports.GET_USER_FOR_AUTH = exports.GET_USER_BY_EXTERNAL_ID = exports.GET_ROLES_BY_USER_ID = exports.ENSURE_ROLE_EXISTS = exports.USER_SAFE_COLUMNS_U = exports.USER_SAFE_COLUMNS = void 0;
4
+ exports.IS_GROUP_ADMIN = exports.GET_ROLE_SCOPE = exports.HAS_ROLE_TYPE = exports.HAS_ROLE = exports.DELETE_USER_ROLE = exports.INSERT_USER_ROLE_IF_ABSENT = exports.UPSERT_USER_ROLE = exports.GET_ROLES_BY_USER_IDS = exports.DELETE_USER_BY_ID = exports.GET_USER_WITH_ROLES = exports.PATCH_USER_PROPERTIES_RECORDED = exports.PATCH_USER_PROPERTIES = exports.VERIFY_USER_BY_ID = exports.GET_USERS_BY_METADATA_VALUE = exports.GET_NAMES_BY_IDS = exports.GET_USER_BY_ID = exports.GET_USER_BY_EMAIL = exports.CREATE_USER_WITH_ROLES = exports.GET_USER_FOR_AUTH = exports.GET_USER_BY_EXTERNAL_ID = exports.GET_ROLES_BY_USER_ID = exports.ENSURE_ROLE_EXISTS = exports.USER_SAFE_COLUMNS_U = exports.USER_SAFE_COLUMNS = void 0;
5
5
  /**
6
6
  * Every lt_users column a client may see. password_hash and oauth_provider_id
7
7
  * are credentials and never appear here — no user read path selects them (the
@@ -61,7 +61,7 @@ exports.GET_NAMES_BY_IDS = 'SELECT id, display_name, external_id, email FROM lt_
61
61
  */
62
62
  exports.GET_USERS_BY_METADATA_VALUE = `SELECT ${exports.USER_SAFE_COLUMNS} FROM lt_users WHERE metadata->>$1 = $2 AND status = 'active' LIMIT 2`;
63
63
  /** Check if a user exists by id. Lightweight — returns only the id column. */
64
- exports.VERIFY_USER_BY_ID = 'SELECT id FROM lt_users WHERE id = $1 LIMIT 1';
64
+ exports.VERIFY_USER_BY_ID = 'SELECT id, status FROM lt_users WHERE id = $1 LIMIT 1';
65
65
  /**
66
66
  * Atomic per-key patch of the user's properties dictionary — ONE statement,
67
67
  * never read-merge-write. Composition (later wins on key collision):
@@ -77,7 +77,7 @@ exports.VERIFY_USER_BY_ID = 'SELECT id FROM lt_users WHERE id = $1 LIMIT 1';
77
77
  * back means the user is missing OR the guard tripped — the caller
78
78
  * distinguishes with VERIFY_USER_BY_ID.
79
79
  */
80
- exports.PATCH_USER_PROPERTIES = `
80
+ const PATCH_USER_PROPERTIES_UPDATE = `
81
81
  UPDATE lt_users SET metadata = (
82
82
  (COALESCE(metadata, '{}'::jsonb) - $2::text[])
83
83
  || COALESCE((
@@ -94,6 +94,30 @@ exports.PATCH_USER_PROPERTIES = `
94
94
  WHERE u2.id <> $1 AND u2.status = 'active' AND u2.metadata ->> g.k = g.v
95
95
  )
96
96
  RETURNING *`;
97
+ exports.PATCH_USER_PROPERTIES = PATCH_USER_PROPERTIES_UPDATE;
98
+ /**
99
+ * The same patch, recorded in lt_label_jobs in the same statement: the ledger
100
+ * row exists exactly when the patch landed. $6 is the ledger row as JSON
101
+ * (action, requested_by, source, and for a reissue the template and media);
102
+ * it never carries the identity value. With `require_active`, only an active
103
+ * user is patched, checked in the same statement.
104
+ */
105
+ exports.PATCH_USER_PROPERTIES_RECORDED = `
106
+ WITH patched AS (${PATCH_USER_PROPERTIES_UPDATE.replace('WHERE id = $1', "WHERE id = $1 AND (($6::jsonb->>'require_active')::boolean IS NOT TRUE OR status = 'active')")}),
107
+ recorded AS (
108
+ INSERT INTO lt_label_jobs (
109
+ action, requested_by, sensitive, source, subject_user_ids, label_count,
110
+ template_name, template_revision, template_snapshot, scheme_version, scheme_kind, media, output
111
+ )
112
+ SELECT $6::jsonb->>'action', ($6::jsonb->>'requested_by')::uuid, true,
113
+ COALESCE($6::jsonb->'source', '{}'::jsonb), ARRAY[patched.id],
114
+ COALESCE(($6::jsonb->>'label_count')::int, 0),
115
+ $6::jsonb->>'template_name', ($6::jsonb->>'template_revision')::int, $6::jsonb->'template_snapshot',
116
+ ($6::jsonb->>'scheme_version')::int, $6::jsonb->>'scheme_kind', $6::jsonb->'media', $6::jsonb->>'output'
117
+ FROM patched
118
+ RETURNING id
119
+ )
120
+ SELECT patched.*, (SELECT id FROM recorded) AS ledger_id FROM patched`;
97
121
  /** Fetch user + roles in a single query. Returns one row per role (or one row with nulls if no roles). */
98
122
  exports.GET_USER_WITH_ROLES = `SELECT u.id, u.external_id, u.display_name, u.status, u.metadata,
99
123
  r.role, r.type AS role_type, r.read_scope, r.write_scope
@@ -24,7 +24,10 @@ export interface UpdateUserInput {
24
24
  display_name?: string;
25
25
  password?: string;
26
26
  status?: LTUserStatus;
27
- /** Wholesale REPLACE of the properties dictionary — for per-key edits use patchUserProperties. */
27
+ /**
28
+ * Wholesale REPLACE of the properties dictionary — for per-key edits use
29
+ * patchUserProperties. Identity bindings absent from the replacement are kept.
30
+ */
28
31
  metadata?: Record<string, any>;
29
32
  }
30
33
  /**
@@ -37,3 +40,20 @@ export interface UserPropertyOps {
37
40
  remove?: string[];
38
41
  rename?: Record<string, string>;
39
42
  }
43
+ /** The lt_label_jobs row a recorded property patch writes beside the patch. */
44
+ export interface PropertyPatchRecord {
45
+ action: 'bind' | 'reissue';
46
+ requested_by: string;
47
+ /** Patch only an active user; checked in the patch statement. */
48
+ require_active?: boolean;
49
+ /** Which identity keys changed; never their values. */
50
+ source: Record<string, unknown>;
51
+ label_count?: number;
52
+ template_name?: string;
53
+ template_revision?: number;
54
+ template_snapshot?: unknown;
55
+ scheme_version?: number;
56
+ scheme_kind?: string;
57
+ media?: unknown;
58
+ output?: string;
59
+ }
@@ -0,0 +1,12 @@
1
+ import type { ParseableScheme } from '../scan-code/parse';
2
+ /** A code that cannot be composed under its scheme. */
3
+ export declare class ScanComposeError extends Error {
4
+ constructor(message: string);
5
+ }
6
+ /** Whether the scheme's codes are minted by the engine (and so printable from a template). */
7
+ export declare function isMintableScheme(scheme: Pick<ParseableScheme, 'encoding'>): boolean;
8
+ /**
9
+ * The code a scan of `target` under `category` reads. Throws ScanComposeError
10
+ * when the scheme only reads codes (gtin, pattern) or the target does not fit.
11
+ */
12
+ export declare function composeScanCode(scheme: Pick<ParseableScheme, 'version' | 'encoding' | 'delimiter' | 'target_length'>, category: string, target: string): string;
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ // The inverse of parseScanCode for the encodings the engine mints.
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.ScanComposeError = void 0;
5
+ exports.isMintableScheme = isMintableScheme;
6
+ exports.composeScanCode = composeScanCode;
7
+ /** A code that cannot be composed under its scheme. */
8
+ class ScanComposeError extends Error {
9
+ constructor(message) {
10
+ super(message);
11
+ this.name = 'ScanComposeError';
12
+ }
13
+ }
14
+ exports.ScanComposeError = ScanComposeError;
15
+ const PRINTABLE_ASCII = /^[\x21-\x7e]+$/;
16
+ /** Whether the scheme's codes are minted by the engine (and so printable from a template). */
17
+ function isMintableScheme(scheme) {
18
+ return scheme.encoding === 'fixed' || scheme.encoding === 'delimited';
19
+ }
20
+ /**
21
+ * The code a scan of `target` under `category` reads. Throws ScanComposeError
22
+ * when the scheme only reads codes (gtin, pattern) or the target does not fit.
23
+ */
24
+ function composeScanCode(scheme, category, target) {
25
+ if (!/^[0-9]$/.test(category)) {
26
+ throw new ScanComposeError(`category must be a single digit, got "${category}"`);
27
+ }
28
+ const version = String(scheme.version);
29
+ if (scheme.encoding === 'delimited') {
30
+ if (!target || !PRINTABLE_ASCII.test(target)) {
31
+ throw new ScanComposeError(`target "${target}" must be printable ASCII with no spaces`);
32
+ }
33
+ return `${version}${scheme.delimiter}${category}${scheme.delimiter}${target}`;
34
+ }
35
+ if (scheme.encoding === 'fixed') {
36
+ const length = scheme.target_length ?? 0;
37
+ if (!new RegExp(`^[0-9]{${length}}$`).test(target)) {
38
+ throw new ScanComposeError(`target "${target}" must be exactly ${length} digits`);
39
+ }
40
+ return `${version}${category}${target}`;
41
+ }
42
+ throw new ScanComposeError(`scheme ${version} reads ${scheme.encoding} codes; the engine does not mint them`);
43
+ }
@@ -0,0 +1,9 @@
1
+ export * from './types';
2
+ export { composeScanCode, isMintableScheme, ScanComposeError } from './compose';
3
+ export { renderLabelText, listLabelTokens, unknownLabelTokens, userTokenKeys, type LabelTokenContext } from './tokens';
4
+ export { LABEL_MEDIA, DEFAULT_LABEL_MEDIA_ID, LabelMediaError, assertValidMedia, resolveMedia, slotOrigin, slotsPerPage, } from './media';
5
+ export { encodeSymbol, quietZoneModules, SymbolEncodeError, type EncodedSymbol } from './symbol';
6
+ export { layoutLabelContent, GLYPH_ADVANCE, type LabelContentOptions } from './label-content';
7
+ export { buildLabelSheet, cutMarkSegments, LabelLayoutError, MAX_COPIES, type LabelSheetInput } from './layout';
8
+ export { renderSheetSvg, escapeXml, type SvgRenderOptions } from './render-svg';
9
+ export { renderSheetZpl, zplField, ZplRenderError } from './render-zpl';