@hotmeshio/long-tail 0.22.0 → 0.22.2

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 (356) hide show
  1. package/build/api/escalations/accumulate.d.ts +10 -1
  2. package/build/api/escalations/accumulate.js +121 -34
  3. package/build/api/escalations/metadata.d.ts +5 -0
  4. package/build/api/escalations/metadata.js +6 -2
  5. package/build/api/escalations/resolve-batch.js +18 -11
  6. package/build/api/roles.js +4 -0
  7. package/build/api/scan-codes/badge-policy.d.ts +10 -0
  8. package/build/api/scan-codes/badge-policy.js +72 -0
  9. package/build/api/scan-codes/choice.js +18 -11
  10. package/build/api/scan-codes/context.d.ts +45 -1
  11. package/build/api/scan-codes/context.js +51 -3
  12. package/build/api/scan-codes/execute.js +73 -35
  13. package/build/api/scan-codes/grant.d.ts +27 -0
  14. package/build/api/scan-codes/grant.js +67 -0
  15. package/build/api/scan-codes/hold.d.ts +10 -0
  16. package/build/api/scan-codes/hold.js +98 -0
  17. package/build/api/scan-codes/identity.d.ts +5 -2
  18. package/build/api/scan-codes/identity.js +26 -8
  19. package/build/api/scan-codes/subject.d.ts +15 -0
  20. package/build/api/scan-codes/subject.js +68 -0
  21. package/build/api/scan-codes/verb-accumulate.d.ts +24 -0
  22. package/build/api/scan-codes/verb-accumulate.js +147 -0
  23. package/build/api/scan-codes/verb-fill.d.ts +6 -0
  24. package/build/api/scan-codes/verb-fill.js +152 -0
  25. package/build/api/scan-codes/verbs-subject.d.ts +14 -0
  26. package/build/api/scan-codes/verbs-subject.js +270 -0
  27. package/build/api/scan-codes/verbs.d.ts +7 -22
  28. package/build/api/scan-codes/verbs.js +35 -114
  29. package/build/api/workflows/invocation.d.ts +8 -4
  30. package/build/api/workflows/invocation.js +26 -9
  31. package/build/index.d.ts +1 -0
  32. package/build/index.js +8 -2
  33. package/build/lib/cli/commands/workflows.js +9 -4
  34. package/build/lib/db/schemas/037_scan_gtin_and_subject_grants.sql +27 -0
  35. package/build/routes/escalations/accumulate.js +13 -6
  36. package/build/routes/escalations/acting.d.ts +5 -0
  37. package/build/routes/escalations/acting.js +8 -1
  38. package/build/routes/scan-codes.js +3 -0
  39. package/build/sdk/index.d.ts +3 -0
  40. package/build/services/escalation/crud.d.ts +2 -2
  41. package/build/services/escalation/crud.js +4 -2
  42. package/build/services/escalation/facet-sql.js +8 -0
  43. package/build/services/escalation/sql.d.ts +4 -2
  44. package/build/services/escalation/sql.js +10 -2
  45. package/build/services/export/index.d.ts +8 -3
  46. package/build/services/export/index.js +15 -21
  47. package/build/services/iam/acting-identity.d.ts +29 -4
  48. package/build/services/iam/acting-identity.js +60 -17
  49. package/build/services/iam/ephemeral.d.ts +21 -0
  50. package/build/services/iam/ephemeral.js +32 -1
  51. package/build/services/iam/sql.d.ts +10 -0
  52. package/build/services/iam/sql.js +32 -3
  53. package/build/services/pipelines/events.js +2 -1
  54. package/build/services/pipelines/execution-builder.js +2 -1
  55. package/build/services/pipelines/queries.js +2 -1
  56. package/build/services/role/badge-grant.d.ts +5 -0
  57. package/build/services/role/badge-grant.js +36 -0
  58. package/build/services/role/seed.js +5 -0
  59. package/build/services/role/types.d.ts +14 -0
  60. package/build/services/role/types.js +5 -0
  61. package/build/services/scan-code/index.d.ts +3 -2
  62. package/build/services/scan-code/index.js +7 -1
  63. package/build/services/scan-code/parse.d.ts +23 -20
  64. package/build/services/scan-code/parse.js +45 -90
  65. package/build/services/scan-code/read.js +1 -0
  66. package/build/services/scan-code/sql.d.ts +3 -3
  67. package/build/services/scan-code/sql.js +11 -8
  68. package/build/services/scan-code/validate-subject.d.ts +7 -0
  69. package/build/services/scan-code/validate-subject.js +158 -0
  70. package/build/services/scan-code/validate.d.ts +7 -0
  71. package/build/services/scan-code/validate.js +111 -16
  72. package/build/services/scan-code/write.d.ts +1 -0
  73. package/build/services/scan-code/write.js +9 -3
  74. package/build/services/workflow-state.d.ts +21 -0
  75. package/build/services/workflow-state.js +39 -0
  76. package/build/shared/form-validation/field-validator.js +4 -0
  77. package/build/shared/form-validation/index.d.ts +1 -0
  78. package/build/shared/form-validation/index.js +1 -0
  79. package/build/shared/form-validation/x-lt-scan.d.ts +52 -0
  80. package/build/shared/form-validation/x-lt-scan.js +166 -0
  81. package/build/shared/scan-code/gtin.d.ts +5 -0
  82. package/build/shared/scan-code/gtin.js +25 -0
  83. package/build/shared/scan-code/index.d.ts +2 -0
  84. package/build/shared/scan-code/index.js +10 -0
  85. package/build/shared/scan-code/parse.d.ts +46 -0
  86. package/build/shared/scan-code/parse.js +133 -0
  87. package/build/shared/workflow-state.d.ts +17 -0
  88. package/build/shared/workflow-state.js +29 -0
  89. package/build/system/mcp-servers/admin/escalations.js +8 -4
  90. package/build/system/mcp-servers/admin/scan-codes.js +10 -4
  91. package/build/system/mcp-servers/admin/schemas.d.ts +792 -23
  92. package/build/system/mcp-servers/admin/schemas.js +61 -4
  93. package/build/system/mcp-servers/admin/workflows.js +20 -31
  94. package/build/system/mcp-servers/human-queue-schemas.d.ts +6 -6
  95. package/build/system/seed/tool-manifests-admin.d.ts +94 -0
  96. package/build/system/seed/tool-manifests-admin.js +3 -3
  97. package/build/tsconfig.tsbuildinfo +1 -1
  98. package/build/types/escalation.d.ts +2 -0
  99. package/build/types/escalation.js +3 -1
  100. package/build/types/facets.d.ts +14 -0
  101. package/build/types/index.d.ts +3 -3
  102. package/build/types/index.js +8 -1
  103. package/build/types/scan-code/constants.d.ts +182 -0
  104. package/build/types/{scan-code.js → scan-code/constants.js} +62 -12
  105. package/build/types/scan-code/index.d.ts +3 -0
  106. package/build/types/scan-code/index.js +17 -0
  107. package/build/types/scan-code/response.d.ts +140 -0
  108. package/build/types/scan-code/response.js +2 -0
  109. package/build/types/scan-code/rule.d.ts +199 -0
  110. package/build/types/scan-code/rule.js +2 -0
  111. package/build/types/startup.d.ts +3 -1
  112. package/dashboard/dist/assets/{AdminDashboard-Covdam48.js → AdminDashboard-DBW12qQt.js} +2 -2
  113. package/dashboard/dist/assets/{AdminDashboard-Covdam48.js.map → AdminDashboard-DBW12qQt.js.map} +1 -1
  114. package/dashboard/dist/assets/{AgentConfigPage-CE1k6J5r.js → AgentConfigPage-CmHv8U9M.js} +2 -2
  115. package/dashboard/dist/assets/{AgentConfigPage-CE1k6J5r.js.map → AgentConfigPage-CmHv8U9M.js.map} +1 -1
  116. package/dashboard/dist/assets/{AgentDetailPage-CWJZIZP1.js → AgentDetailPage-D1scIbz-.js} +3 -3
  117. package/dashboard/dist/assets/{AgentDetailPage-CWJZIZP1.js.map → AgentDetailPage-D1scIbz-.js.map} +1 -1
  118. package/dashboard/dist/assets/{AgentsPage---Dg5ufF.js → AgentsPage-BA_ai9HJ.js} +2 -2
  119. package/dashboard/dist/assets/{AgentsPage---Dg5ufF.js.map → AgentsPage-BA_ai9HJ.js.map} +1 -1
  120. package/dashboard/dist/assets/AvailableEscalationsPage-C2_5aEFW.js +2 -0
  121. package/dashboard/dist/assets/AvailableEscalationsPage-C2_5aEFW.js.map +1 -0
  122. package/dashboard/dist/assets/{BotPicker-D3drO3-T.js → BotPicker-BZo4Kp4a.js} +2 -2
  123. package/dashboard/dist/assets/{BotPicker-D3drO3-T.js.map → BotPicker-BZo4Kp4a.js.map} +1 -1
  124. package/dashboard/dist/assets/{BulkAssignModal-BOAWsViq.js → BulkAssignModal-BFhyxY2T.js} +2 -2
  125. package/dashboard/dist/assets/{BulkAssignModal-BOAWsViq.js.map → BulkAssignModal-BFhyxY2T.js.map} +1 -1
  126. package/dashboard/dist/assets/CapabilitiesPage-CvOX6vAc.js +2 -0
  127. package/dashboard/dist/assets/{CapabilitiesPage-RGgD3YZO.js.map → CapabilitiesPage-CvOX6vAc.js.map} +1 -1
  128. package/dashboard/dist/assets/{CollapsibleSection-DNkZn87n.js → CollapsibleSection-GCJsV9Oq.js} +2 -2
  129. package/dashboard/dist/assets/{CollapsibleSection-DNkZn87n.js.map → CollapsibleSection-GCJsV9Oq.js.map} +1 -1
  130. package/dashboard/dist/assets/{ConfirmDeleteModal-BqzOwhPr.js → ConfirmDeleteModal-CAgYLcef.js} +2 -2
  131. package/dashboard/dist/assets/{ConfirmDeleteModal-BqzOwhPr.js.map → ConfirmDeleteModal-CAgYLcef.js.map} +1 -1
  132. package/dashboard/dist/assets/CountdownTimer-Dik2z0M_.js +2 -0
  133. package/dashboard/dist/assets/{CountdownTimer-BaexQMK6.js.map → CountdownTimer-Dik2z0M_.js.map} +1 -1
  134. package/dashboard/dist/assets/{CredentialsPage-D7abp0aS.js → CredentialsPage-twd2xCOW.js} +2 -2
  135. package/dashboard/dist/assets/{CredentialsPage-D7abp0aS.js.map → CredentialsPage-twd2xCOW.js.map} +1 -1
  136. package/dashboard/dist/assets/{CronLabel-DZiWmTwJ.js → CronLabel-DdnIuudX.js} +2 -2
  137. package/dashboard/dist/assets/{CronLabel-DZiWmTwJ.js.map → CronLabel-DdnIuudX.js.map} +1 -1
  138. package/dashboard/dist/assets/{DropZone-f1o-GLM8.js → DropZone-B1Tdfddc.js} +2 -2
  139. package/dashboard/dist/assets/{DropZone-f1o-GLM8.js.map → DropZone-B1Tdfddc.js.map} +1 -1
  140. package/dashboard/dist/assets/{ElapsedCell-BdGO_w4v.js → ElapsedCell-DCctVv5R.js} +2 -2
  141. package/dashboard/dist/assets/{ElapsedCell-BdGO_w4v.js.map → ElapsedCell-DCctVv5R.js.map} +1 -1
  142. package/dashboard/dist/assets/{EntityTimelinePanel-DIDcF5Yu.js → EntityTimelinePanel-CMnskyWv.js} +2 -2
  143. package/dashboard/dist/assets/{EntityTimelinePanel-DIDcF5Yu.js.map → EntityTimelinePanel-CMnskyWv.js.map} +1 -1
  144. package/dashboard/dist/assets/{EscalationListSchemaPage-C28rn9XC.js → EscalationListSchemaPage-VfCn6WDb.js} +3 -3
  145. package/dashboard/dist/assets/{EscalationListSchemaPage-C28rn9XC.js.map → EscalationListSchemaPage-VfCn6WDb.js.map} +1 -1
  146. package/dashboard/dist/assets/{EscalationListView-CkBnkpDJ.js → EscalationListView-CGQZxcC-.js} +2 -2
  147. package/dashboard/dist/assets/{EscalationListView-CkBnkpDJ.js.map → EscalationListView-CGQZxcC-.js.map} +1 -1
  148. package/dashboard/dist/assets/EscalationSchemaPage-BX0tx-PM.js +9 -0
  149. package/dashboard/dist/assets/EscalationSchemaPage-BX0tx-PM.js.map +1 -0
  150. package/dashboard/dist/assets/EscalationTimeline-DKoSM56J.js +2 -0
  151. package/dashboard/dist/assets/EscalationTimeline-DKoSM56J.js.map +1 -0
  152. package/dashboard/dist/assets/{EscalationTitleSelect-CzKfavri.js → EscalationTitleSelect-DWGLBOmS.js} +2 -2
  153. package/dashboard/dist/assets/{EscalationTitleSelect-CzKfavri.js.map → EscalationTitleSelect-DWGLBOmS.js.map} +1 -1
  154. package/dashboard/dist/assets/{EscalationsOverview-Tdu3Yx2c.js → EscalationsOverview-C2XoguaA.js} +2 -2
  155. package/dashboard/dist/assets/{EscalationsOverview-Tdu3Yx2c.js.map → EscalationsOverview-C2XoguaA.js.map} +1 -1
  156. package/dashboard/dist/assets/{EventTable-DiIxOJwO.js → EventTable-CBUWq7--.js} +2 -2
  157. package/dashboard/dist/assets/{EventTable-DiIxOJwO.js.map → EventTable-CBUWq7--.js.map} +1 -1
  158. package/dashboard/dist/assets/{FilterBar-CvMBCVIo.js → FilterBar-8IdbleZ9.js} +2 -2
  159. package/dashboard/dist/assets/{FilterBar-CvMBCVIo.js.map → FilterBar-8IdbleZ9.js.map} +1 -1
  160. package/dashboard/dist/assets/GrantScopeField-BzWGzBfA.js +2 -0
  161. package/dashboard/dist/assets/GrantScopeField-BzWGzBfA.js.map +1 -0
  162. package/dashboard/dist/assets/{GraphInvokePage-DO-yyhi6.js → GraphInvokePage-CUvoPzsW.js} +2 -2
  163. package/dashboard/dist/assets/{GraphInvokePage-DO-yyhi6.js.map → GraphInvokePage-CUvoPzsW.js.map} +1 -1
  164. package/dashboard/dist/assets/{HomePage-DSS3eHR2.js → HomePage-BP7v9GLJ.js} +2 -2
  165. package/dashboard/dist/assets/{HomePage-DSS3eHR2.js.map → HomePage-BP7v9GLJ.js.map} +1 -1
  166. package/dashboard/dist/assets/{ListToolbar-C3-Tqqub.js → ListToolbar-Cnacuwoy.js} +2 -2
  167. package/dashboard/dist/assets/{ListToolbar-C3-Tqqub.js.map → ListToolbar-Cnacuwoy.js.map} +1 -1
  168. package/dashboard/dist/assets/{McpOverview-DEJmsdVi.js → McpOverview-C2JoNoDA.js} +2 -2
  169. package/dashboard/dist/assets/{McpOverview-DEJmsdVi.js.map → McpOverview-C2JoNoDA.js.map} +1 -1
  170. package/dashboard/dist/assets/McpQueryDetailPage-C_nih0w-.js +5 -0
  171. package/dashboard/dist/assets/McpQueryDetailPage-C_nih0w-.js.map +1 -0
  172. package/dashboard/dist/assets/{McpQueryPage-BBcG_UuU.js → McpQueryPage-U_wNXow2.js} +2 -2
  173. package/dashboard/dist/assets/{McpQueryPage-BBcG_UuU.js.map → McpQueryPage-U_wNXow2.js.map} +1 -1
  174. package/dashboard/dist/assets/{McpRunDetailPage-C6xw0kBg.js → McpRunDetailPage-DtKoJq6J.js} +2 -2
  175. package/dashboard/dist/assets/{McpRunDetailPage-C6xw0kBg.js.map → McpRunDetailPage-DtKoJq6J.js.map} +1 -1
  176. package/dashboard/dist/assets/{McpRunsPage-CRQqrF4Q.js → McpRunsPage-CnYtfGhf.js} +2 -2
  177. package/dashboard/dist/assets/{McpRunsPage-CRQqrF4Q.js.map → McpRunsPage-CnYtfGhf.js.map} +1 -1
  178. package/dashboard/dist/assets/{NamespacePill-DADRJOUl.js → NamespacePill-DwM5pNA4.js} +2 -2
  179. package/dashboard/dist/assets/{NamespacePill-DADRJOUl.js.map → NamespacePill-DwM5pNA4.js.map} +1 -1
  180. package/dashboard/dist/assets/{OperationsPage-Dlfwzf-0.js → OperationsPage-C7hupIer.js} +2 -2
  181. package/dashboard/dist/assets/{OperationsPage-Dlfwzf-0.js.map → OperationsPage-C7hupIer.js.map} +1 -1
  182. package/dashboard/dist/assets/{OperatorDashboard-DoiDGZ9R.js → OperatorDashboard-fVuLn2D5.js} +2 -2
  183. package/dashboard/dist/assets/{OperatorDashboard-DoiDGZ9R.js.map → OperatorDashboard-fVuLn2D5.js.map} +1 -1
  184. package/dashboard/dist/assets/{PageHeader-Csq434-v.js → PageHeader-CMd3f4bz.js} +2 -2
  185. package/dashboard/dist/assets/{PageHeader-Csq434-v.js.map → PageHeader-CMd3f4bz.js.map} +1 -1
  186. package/dashboard/dist/assets/{PageHeaderWithStats-CSnk1p5A.js → PageHeaderWithStats-DHj8Mqox.js} +2 -2
  187. package/dashboard/dist/assets/{PageHeaderWithStats-CSnk1p5A.js.map → PageHeaderWithStats-DHj8Mqox.js.map} +1 -1
  188. package/dashboard/dist/assets/{PersonaDetailPage-BzbA4Prr.js → PersonaDetailPage-C-4o8lPw.js} +2 -2
  189. package/dashboard/dist/assets/{PersonaDetailPage-BzbA4Prr.js.map → PersonaDetailPage-C-4o8lPw.js.map} +1 -1
  190. package/dashboard/dist/assets/{PersonasPage-B36yn4hU.js → PersonasPage-BL1FwLmv.js} +2 -2
  191. package/dashboard/dist/assets/{PersonasPage-B36yn4hU.js.map → PersonasPage-BL1FwLmv.js.map} +1 -1
  192. package/dashboard/dist/assets/{PortalPage-BkD4YfDf.js → PortalPage-tJG5sgb1.js} +2 -2
  193. package/dashboard/dist/assets/{PortalPage-BkD4YfDf.js.map → PortalPage-tJG5sgb1.js.map} +1 -1
  194. package/dashboard/dist/assets/{ProcessDetailPage-BT0eiBWY.js → ProcessDetailPage-Dz_jY4Yt.js} +2 -2
  195. package/dashboard/dist/assets/{ProcessDetailPage-BT0eiBWY.js.map → ProcessDetailPage-Dz_jY4Yt.js.map} +1 -1
  196. package/dashboard/dist/assets/{ProcessesListPage-BEqeeNae.js → ProcessesListPage-Cbn9cter.js} +2 -2
  197. package/dashboard/dist/assets/{ProcessesListPage-BEqeeNae.js.map → ProcessesListPage-Cbn9cter.js.map} +1 -1
  198. package/dashboard/dist/assets/ResolverForm-Bk8iXQ6-.js +8 -0
  199. package/dashboard/dist/assets/ResolverForm-Bk8iXQ6-.js.map +1 -0
  200. package/dashboard/dist/assets/RoleDetailPage-owPi6gI9.js +8 -0
  201. package/dashboard/dist/assets/RoleDetailPage-owPi6gI9.js.map +1 -0
  202. package/dashboard/dist/assets/{RolePill-BafrASDX.js → RolePill-Di2CAHuD.js} +2 -2
  203. package/dashboard/dist/assets/{RolePill-BafrASDX.js.map → RolePill-Di2CAHuD.js.map} +1 -1
  204. package/dashboard/dist/assets/{RolesPage-80quJU5-.js → RolesPage-NwmMvZFa.js} +2 -2
  205. package/dashboard/dist/assets/{RolesPage-80quJU5-.js.map → RolesPage-NwmMvZFa.js.map} +1 -1
  206. package/dashboard/dist/assets/{RunAsSelector-BoePhWVD.js → RunAsSelector-tgEooTyU.js} +2 -2
  207. package/dashboard/dist/assets/{RunAsSelector-BoePhWVD.js.map → RunAsSelector-tgEooTyU.js.map} +1 -1
  208. package/dashboard/dist/assets/ScanCodesPage-CUv_8ic6.js +2 -0
  209. package/dashboard/dist/assets/ScanCodesPage-CUv_8ic6.js.map +1 -0
  210. package/dashboard/dist/assets/ScanSchemeDetailPage-YHqbu7oK.js +2 -0
  211. package/dashboard/dist/assets/ScanSchemeDetailPage-YHqbu7oK.js.map +1 -0
  212. package/dashboard/dist/assets/ScanStationPage-B275l6r_.js +2 -0
  213. package/dashboard/dist/assets/ScanStationPage-B275l6r_.js.map +1 -0
  214. package/dashboard/dist/assets/{ScopeBadge-b6MIBiYD.js → ScopeBadge-CSItPVOH.js} +2 -2
  215. package/dashboard/dist/assets/{ScopeBadge-b6MIBiYD.js.map → ScopeBadge-CSItPVOH.js.map} +1 -1
  216. package/dashboard/dist/assets/{StickyPagination-9ITrei_d.js → StickyPagination-CsTI_gvJ.js} +2 -2
  217. package/dashboard/dist/assets/{StickyPagination-9ITrei_d.js.map → StickyPagination-CsTI_gvJ.js.map} +1 -1
  218. package/dashboard/dist/assets/{StreamMessageDetail-BkYvEHFY.js → StreamMessageDetail-auRlvjTh.js} +2 -2
  219. package/dashboard/dist/assets/{StreamMessageDetail-BkYvEHFY.js.map → StreamMessageDetail-auRlvjTh.js.map} +1 -1
  220. package/dashboard/dist/assets/{SwimlaneTimeline-B1rotFix.js → SwimlaneTimeline-BLoVHYAd.js} +2 -2
  221. package/dashboard/dist/assets/{SwimlaneTimeline-B1rotFix.js.map → SwimlaneTimeline-BLoVHYAd.js.map} +1 -1
  222. package/dashboard/dist/assets/{TagInput-ZrIIrEUP.js → TagInput-CAgdLN_b.js} +2 -2
  223. package/dashboard/dist/assets/{TagInput-ZrIIrEUP.js.map → TagInput-CAgdLN_b.js.map} +1 -1
  224. package/dashboard/dist/assets/{TaskDetailPage-zhn_U_eC.js → TaskDetailPage-BPsZ1bK_.js} +2 -2
  225. package/dashboard/dist/assets/{TaskDetailPage-zhn_U_eC.js.map → TaskDetailPage-BPsZ1bK_.js.map} +1 -1
  226. package/dashboard/dist/assets/{TaskQueuePill-DkQ1uc6y.js → TaskQueuePill-h0oorVMe.js} +2 -2
  227. package/dashboard/dist/assets/{TaskQueuePill-DkQ1uc6y.js.map → TaskQueuePill-h0oorVMe.js.map} +1 -1
  228. package/dashboard/dist/assets/{TasksListPage-CNbNeagx.js → TasksListPage-BNGM74yT.js} +2 -2
  229. package/dashboard/dist/assets/{TasksListPage-CNbNeagx.js.map → TasksListPage-BNGM74yT.js.map} +1 -1
  230. package/dashboard/dist/assets/{TimeAgo-0YVMBwls.js → TimeAgo-BnAHXGK7.js} +2 -2
  231. package/dashboard/dist/assets/{TimeAgo-0YVMBwls.js.map → TimeAgo-BnAHXGK7.js.map} +1 -1
  232. package/dashboard/dist/assets/{TimestampCell-DB7r3np8.js → TimestampCell-J4yae6mc.js} +2 -2
  233. package/dashboard/dist/assets/{TimestampCell-DB7r3np8.js.map → TimestampCell-J4yae6mc.js.map} +1 -1
  234. package/dashboard/dist/assets/{ToolPill-Baxm02L6.js → ToolPill-CQCsVdzD.js} +2 -2
  235. package/dashboard/dist/assets/{ToolPill-Baxm02L6.js.map → ToolPill-CQCsVdzD.js.map} +1 -1
  236. package/dashboard/dist/assets/{ToolTestPanel-BLfA02wv.js → ToolTestPanel-BdzzgXDu.js} +2 -2
  237. package/dashboard/dist/assets/{ToolTestPanel-BLfA02wv.js.map → ToolTestPanel-BdzzgXDu.js.map} +1 -1
  238. package/dashboard/dist/assets/{TopicDetailPage-eAqPKShq.js → TopicDetailPage-DJKg8lb7.js} +4 -4
  239. package/dashboard/dist/assets/{TopicDetailPage-eAqPKShq.js.map → TopicDetailPage-DJKg8lb7.js.map} +1 -1
  240. package/dashboard/dist/assets/{TopicsPage-BNNWD-zl.js → TopicsPage-DQV0WxG6.js} +2 -2
  241. package/dashboard/dist/assets/{TopicsPage-BNNWD-zl.js.map → TopicsPage-DQV0WxG6.js.map} +1 -1
  242. package/dashboard/dist/assets/{UserName-Pw46tO_k.js → UserName-Ct09nGh5.js} +2 -2
  243. package/dashboard/dist/assets/{UserName-Pw46tO_k.js.map → UserName-Ct09nGh5.js.map} +1 -1
  244. package/dashboard/dist/assets/{WorkflowExecutionPage-DvA51lT3.js → WorkflowExecutionPage-B5WJOsee.js} +2 -2
  245. package/dashboard/dist/assets/{WorkflowExecutionPage-DvA51lT3.js.map → WorkflowExecutionPage-B5WJOsee.js.map} +1 -1
  246. package/dashboard/dist/assets/{WorkflowPill-ZepbO_ny.js → WorkflowPill-Dg7BDTyM.js} +2 -2
  247. package/dashboard/dist/assets/{WorkflowPill-ZepbO_ny.js.map → WorkflowPill-Dg7BDTyM.js.map} +1 -1
  248. package/dashboard/dist/assets/{WorkflowsDashboard-DFDTwnhn.js → WorkflowsDashboard-Hc87TRgD.js} +2 -2
  249. package/dashboard/dist/assets/{WorkflowsDashboard-DFDTwnhn.js.map → WorkflowsDashboard-Hc87TRgD.js.map} +1 -1
  250. package/dashboard/dist/assets/{WorkflowsOverview-5i2Tcy-p.js → WorkflowsOverview-CJQbyOj-.js} +2 -2
  251. package/dashboard/dist/assets/{WorkflowsOverview-5i2Tcy-p.js.map → WorkflowsOverview-CJQbyOj-.js.map} +1 -1
  252. package/dashboard/dist/assets/{YamlWorkflowDetailPage-p4VEYZS0.js → YamlWorkflowDetailPage-BMeED677.js} +8 -8
  253. package/dashboard/dist/assets/{YamlWorkflowDetailPage-p4VEYZS0.js.map → YamlWorkflowDetailPage-BMeED677.js.map} +1 -1
  254. package/dashboard/dist/assets/{YamlWorkflowsPage-Cq-hMVxl.js → YamlWorkflowsPage-BMMg0Id6.js} +2 -2
  255. package/dashboard/dist/assets/{YamlWorkflowsPage-Cq-hMVxl.js.map → YamlWorkflowsPage-BMMg0Id6.js.map} +1 -1
  256. package/dashboard/dist/assets/{agents-EyBPJMYa.js → agents-CdFkgFvg.js} +2 -2
  257. package/dashboard/dist/assets/{agents-EyBPJMYa.js.map → agents-CdFkgFvg.js.map} +1 -1
  258. package/dashboard/dist/assets/{bots-DX6jjqtF.js → bots-Mj3LHWWg.js} +2 -2
  259. package/dashboard/dist/assets/{bots-DX6jjqtF.js.map → bots-Mj3LHWWg.js.map} +1 -1
  260. package/dashboard/dist/assets/{capabilities-ZdLv9xBQ.js → capabilities-Dw1ObK2-.js} +2 -2
  261. package/dashboard/dist/assets/{capabilities-ZdLv9xBQ.js.map → capabilities-Dw1ObK2-.js.map} +1 -1
  262. package/dashboard/dist/assets/{controlplane-CpvZaJuw.js → controlplane-DcNE1APv.js} +2 -2
  263. package/dashboard/dist/assets/{controlplane-CpvZaJuw.js.map → controlplane-DcNE1APv.js.map} +1 -1
  264. package/dashboard/dist/assets/{escalation-columns-Mvsze5eV.js → escalation-columns-D364Trpy.js} +2 -2
  265. package/dashboard/dist/assets/{escalation-columns-Mvsze5eV.js.map → escalation-columns-D364Trpy.js.map} +1 -1
  266. package/dashboard/dist/assets/{index-Cn8uJsd7.js → index-B3veJ698.js} +2 -2
  267. package/dashboard/dist/assets/{index-Cn8uJsd7.js.map → index-B3veJ698.js.map} +1 -1
  268. package/dashboard/dist/assets/index-BQeHJHYN.js +67 -0
  269. package/dashboard/dist/assets/index-BQeHJHYN.js.map +1 -0
  270. package/dashboard/dist/assets/{index-D-Xs4rAW.js → index-BRGTmoYY.js} +2 -2
  271. package/dashboard/dist/assets/{index-D-Xs4rAW.js.map → index-BRGTmoYY.js.map} +1 -1
  272. package/dashboard/dist/assets/{index-DkrBFFSO.js → index-Bd6-KmBE.js} +3 -3
  273. package/dashboard/dist/assets/{index-DkrBFFSO.js.map → index-Bd6-KmBE.js.map} +1 -1
  274. package/dashboard/dist/assets/{index-Bhb89oHH.js → index-BiVce3n0.js} +2 -2
  275. package/dashboard/dist/assets/{index-Bhb89oHH.js.map → index-BiVce3n0.js.map} +1 -1
  276. package/dashboard/dist/assets/{index-z5Hpeidu.js → index-BmNAVd4s.js} +2 -2
  277. package/dashboard/dist/assets/{index-z5Hpeidu.js.map → index-BmNAVd4s.js.map} +1 -1
  278. package/dashboard/dist/assets/{index-BbCjGO3M.js → index-Bq5XNEzD.js} +2 -2
  279. package/dashboard/dist/assets/{index-BbCjGO3M.js.map → index-Bq5XNEzD.js.map} +1 -1
  280. package/dashboard/dist/assets/{index-DGmzBY9D.js → index-DPStdq4T.js} +2 -2
  281. package/dashboard/dist/assets/{index-DGmzBY9D.js.map → index-DPStdq4T.js.map} +1 -1
  282. package/dashboard/dist/assets/index-DcppjzP5.css +1 -0
  283. package/dashboard/dist/assets/{index-PfSRKerc.js → index-DkcI4V_H.js} +2 -2
  284. package/dashboard/dist/assets/{index-PfSRKerc.js.map → index-DkcI4V_H.js.map} +1 -1
  285. package/dashboard/dist/assets/{index-oFKUFGQL.js → index-Dyotfa_k.js} +2 -2
  286. package/dashboard/dist/assets/{index-oFKUFGQL.js.map → index-Dyotfa_k.js.map} +1 -1
  287. package/dashboard/dist/assets/{index-Eo-l3Lqo.js → index-MDD4JYtu.js} +2 -2
  288. package/dashboard/dist/assets/{index-Eo-l3Lqo.js.map → index-MDD4JYtu.js.map} +1 -1
  289. package/dashboard/dist/assets/index-WSm8bgE7.js +3 -0
  290. package/dashboard/dist/assets/index-WSm8bgE7.js.map +1 -0
  291. package/dashboard/dist/assets/{index-DZhtP2Ok.js → index-eDm6cz0F.js} +2 -2
  292. package/dashboard/dist/assets/{index-DZhtP2Ok.js.map → index-eDm6cz0F.js.map} +1 -1
  293. package/dashboard/dist/assets/{knowledge-CgloEkaf.js → knowledge-Bafewjxk.js} +2 -2
  294. package/dashboard/dist/assets/{knowledge-CgloEkaf.js.map → knowledge-Bafewjxk.js.map} +1 -1
  295. package/dashboard/dist/assets/{mcp-query-o-sGX2ST.js → mcp-query-BzTtIG90.js} +2 -2
  296. package/dashboard/dist/assets/{mcp-query-o-sGX2ST.js.map → mcp-query-BzTtIG90.js.map} +1 -1
  297. package/dashboard/dist/assets/{mcp-Bix7QYO7.js → mcp-vLIutbnc.js} +2 -2
  298. package/dashboard/dist/assets/{mcp-Bix7QYO7.js.map → mcp-vLIutbnc.js.map} +1 -1
  299. package/dashboard/dist/assets/{personas-30azkJ_s.js → personas-WD40EDS_.js} +2 -2
  300. package/dashboard/dist/assets/{personas-30azkJ_s.js.map → personas-WD40EDS_.js.map} +1 -1
  301. package/dashboard/dist/assets/{pipelines-Bfk2GFK7.js → pipelines-DFwULWs3.js} +2 -2
  302. package/dashboard/dist/assets/{pipelines-Bfk2GFK7.js.map → pipelines-DFwULWs3.js.map} +1 -1
  303. package/dashboard/dist/assets/{tasks-CpdopewW.js → tasks-La_-WAUn.js} +2 -2
  304. package/dashboard/dist/assets/{tasks-CpdopewW.js.map → tasks-La_-WAUn.js.map} +1 -1
  305. package/dashboard/dist/assets/{topics--bvCV9Yp.js → topics-CzYMlvqm.js} +2 -2
  306. package/dashboard/dist/assets/{topics--bvCV9Yp.js.map → topics-CzYMlvqm.js.map} +1 -1
  307. package/dashboard/dist/assets/{useDebouncedValue-Da0lPmj3.js → useDebouncedValue-C0FQyANW.js} +2 -2
  308. package/dashboard/dist/assets/{useDebouncedValue-Da0lPmj3.js.map → useDebouncedValue-C0FQyANW.js.map} +1 -1
  309. package/dashboard/dist/assets/{useNamespace-DD_Esl6n.js → useNamespace-WW_XjAb3.js} +2 -2
  310. package/dashboard/dist/assets/{useNamespace-DD_Esl6n.js.map → useNamespace-WW_XjAb3.js.map} +1 -1
  311. package/dashboard/dist/assets/{useYamlActivityEvents-AeAhZJJk.js → useYamlActivityEvents-B3YxPeFt.js} +2 -2
  312. package/dashboard/dist/assets/{useYamlActivityEvents-AeAhZJJk.js.map → useYamlActivityEvents-B3YxPeFt.js.map} +1 -1
  313. package/dashboard/dist/assets/{vendor-icons-B7OcUM6b.js → vendor-icons-CeVtUKyP.js} +2 -2
  314. package/dashboard/dist/assets/{vendor-icons-B7OcUM6b.js.map → vendor-icons-CeVtUKyP.js.map} +1 -1
  315. package/dashboard/dist/assets/{yaml-workflows-BHAOOGvn.js → yaml-workflows-COHOjdhF.js} +2 -2
  316. package/dashboard/dist/assets/{yaml-workflows-BHAOOGvn.js.map → yaml-workflows-COHOjdhF.js.map} +1 -1
  317. package/dashboard/dist/index.html +3 -3
  318. package/docs/accumulator.md +37 -1
  319. package/docs/api/mcp/admin.md +3 -2
  320. package/docs/api/sdk/escalations.md +6 -0
  321. package/docs/api/sdk/exports.md +1 -1
  322. package/docs/api/sdk/workflows.md +23 -4
  323. package/docs/cli.md +1 -1
  324. package/docs/dashboard.md +2 -2
  325. package/docs/faceted-routing.md +2 -0
  326. package/docs/hitl/x-lt-scan.md +51 -0
  327. package/docs/hitl/x-lt-widget.md +5 -0
  328. package/docs/hitl-guide.md +2 -0
  329. package/docs/scan-codes.md +252 -19
  330. package/package.json +1 -1
  331. package/build/types/scan-code.d.ts +0 -308
  332. package/dashboard/dist/assets/AvailableEscalationsPage-CpbC8oTN.js +0 -2
  333. package/dashboard/dist/assets/AvailableEscalationsPage-CpbC8oTN.js.map +0 -1
  334. package/dashboard/dist/assets/CapabilitiesPage-RGgD3YZO.js +0 -2
  335. package/dashboard/dist/assets/CountdownTimer-BaexQMK6.js +0 -2
  336. package/dashboard/dist/assets/EscalationSchemaPage-W5r0A1kj.js +0 -9
  337. package/dashboard/dist/assets/EscalationSchemaPage-W5r0A1kj.js.map +0 -1
  338. package/dashboard/dist/assets/EscalationTimeline-DKyTz6sM.js +0 -2
  339. package/dashboard/dist/assets/EscalationTimeline-DKyTz6sM.js.map +0 -1
  340. package/dashboard/dist/assets/McpQueryDetailPage-DYJr16l7.js +0 -5
  341. package/dashboard/dist/assets/McpQueryDetailPage-DYJr16l7.js.map +0 -1
  342. package/dashboard/dist/assets/ResolverForm-BwgjIX97.js +0 -7
  343. package/dashboard/dist/assets/ResolverForm-BwgjIX97.js.map +0 -1
  344. package/dashboard/dist/assets/RoleDetailPage-BFuLNJXa.js +0 -8
  345. package/dashboard/dist/assets/RoleDetailPage-BFuLNJXa.js.map +0 -1
  346. package/dashboard/dist/assets/ScanCodesPage-Cu1bKEix.js +0 -2
  347. package/dashboard/dist/assets/ScanCodesPage-Cu1bKEix.js.map +0 -1
  348. package/dashboard/dist/assets/ScanSchemeDetailPage-D9AbS6UY.js +0 -2
  349. package/dashboard/dist/assets/ScanSchemeDetailPage-D9AbS6UY.js.map +0 -1
  350. package/dashboard/dist/assets/ScanStationPage-gcZGefvT.js +0 -2
  351. package/dashboard/dist/assets/ScanStationPage-gcZGefvT.js.map +0 -1
  352. package/dashboard/dist/assets/index-B_GT23TE.js +0 -3
  353. package/dashboard/dist/assets/index-B_GT23TE.js.map +0 -1
  354. package/dashboard/dist/assets/index-CgUcYveM.js +0 -67
  355. package/dashboard/dist/assets/index-CgUcYveM.js.map +0 -1
  356. package/dashboard/dist/assets/index-Dh8MJl3L.css +0 -1
@@ -33,28 +33,71 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.ACTING_ERRORS = void 0;
37
+ exports.peekActingAuth = peekActingAuth;
38
+ exports.consumeActingGrant = consumeActingGrant;
39
+ exports.refundActingGrant = refundActingGrant;
36
40
  exports.resolveActingAuth = resolveActingAuth;
37
41
  const userService = __importStar(require("../user"));
38
42
  const ephemeral_1 = require("./ephemeral");
39
43
  const types_1 = require("../../types");
44
+ exports.ACTING_ERRORS = {
45
+ NOT_A_GRANT: 'actingToken is not an acting-identity grant',
46
+ EXPIRED: 'acting identity expired — scan your badge again',
47
+ INACTIVE: 'acting identity is no longer an active user',
48
+ OTHER_SUBJECT: 'this badge already acted on another item; scan your badge again',
49
+ };
50
+ function isActingGrant(actingToken) {
51
+ const parsed = (0, ephemeral_1.parseEphemeralToken)(actingToken);
52
+ return parsed && parsed.label === types_1.ACTING_IDENTITY_LABEL ? parsed.uuid : null;
53
+ }
54
+ async function toAuth(grant, consumed) {
55
+ const user = await userService.getUser(grant.value);
56
+ if (!user || user.status !== 'active')
57
+ return { ok: false, error: exports.ACTING_ERRORS.INACTIVE };
58
+ return {
59
+ ok: true,
60
+ auth: { userId: user.id },
61
+ grant: { consumed, remaining: grant.remaining, bound: grant.bound },
62
+ };
63
+ }
40
64
  /**
41
- * Exchange a supplied acting grant for the person it names. A supplied token
42
- * that fails — wrong label, expired, exhausted, or a vanished user — is a
43
- * terminal error, never a silent fall-back to the session identity: that
44
- * would misattribute whatever follows.
65
+ * Read a supplied acting grant without spending it. A token that fails
66
+ * (wrong label, expired, exhausted, or a vanished user) is a terminal error,
67
+ * never a silent fall-back to the session identity: that would misattribute
68
+ * whatever follows.
45
69
  */
46
- async function resolveActingAuth(actingToken) {
47
- const parsed = (0, ephemeral_1.parseEphemeralToken)(actingToken);
48
- if (!parsed || parsed.label !== types_1.ACTING_IDENTITY_LABEL) {
49
- return { ok: false, error: 'actingToken is not an acting-identity grant' };
50
- }
51
- const userId = await (0, ephemeral_1.exchangeEphemeralToken)(actingToken);
52
- if (!userId) {
53
- return { ok: false, error: 'acting identity expired — scan your badge again' };
54
- }
55
- const user = await userService.getUser(userId);
56
- if (!user || user.status !== 'active') {
57
- return { ok: false, error: 'acting identity is no longer an active user' };
70
+ async function peekActingAuth(actingToken) {
71
+ const uuid = isActingGrant(actingToken);
72
+ if (!uuid)
73
+ return { ok: false, error: exports.ACTING_ERRORS.NOT_A_GRANT };
74
+ const grant = await (0, ephemeral_1.peekEphemeral)(uuid);
75
+ if (!grant)
76
+ return { ok: false, error: exports.ACTING_ERRORS.EXPIRED };
77
+ return toAuth(grant, false);
78
+ }
79
+ /**
80
+ * Spend one use of the grant for an act. `ref` names the subject the act
81
+ * lands on; a subject-scoped grant binds to it on first spend.
82
+ */
83
+ async function consumeActingGrant(actingToken, ref = null) {
84
+ const uuid = isActingGrant(actingToken);
85
+ if (!uuid)
86
+ return { ok: false, error: exports.ACTING_ERRORS.NOT_A_GRANT };
87
+ const grant = await (0, ephemeral_1.consumeEphemeral)(uuid, ref);
88
+ if (!grant) {
89
+ const live = ref ? await (0, ephemeral_1.peekEphemeral)(uuid) : null;
90
+ return { ok: false, error: live?.bound ? exports.ACTING_ERRORS.OTHER_SUBJECT : exports.ACTING_ERRORS.EXPIRED };
58
91
  }
59
- return { ok: true, auth: { userId: user.id } };
92
+ return toAuth(grant, true);
93
+ }
94
+ /** Return a use whose act missed. `unbind` when that spend bound the grant. */
95
+ async function refundActingGrant(actingToken, unbind) {
96
+ const uuid = isActingGrant(actingToken);
97
+ if (uuid)
98
+ await (0, ephemeral_1.refundEphemeral)(uuid, unbind);
99
+ }
100
+ /** Spend the grant up front: the escalation work routes always act. */
101
+ async function resolveActingAuth(actingToken) {
102
+ return consumeActingGrant(actingToken);
60
103
  }
@@ -21,6 +21,8 @@ export interface StoreEphemeralOptions {
21
21
  ttlSeconds?: number;
22
22
  /** Human-readable label for debugging. */
23
23
  label?: string;
24
+ /** The first ref-carrying spend binds the token to that ref (see consumeEphemeral). */
25
+ bindOnUse?: boolean;
24
26
  }
25
27
  /**
26
28
  * Store a sensitive value. Returns the raw token UUID.
@@ -40,6 +42,25 @@ export declare function storeEphemeral(value: string, opts?: StoreEphemeralOptio
40
42
  * - Row is deleted when use_count reaches max_uses (if max_uses > 0)
41
43
  */
42
44
  export declare function exchangeEphemeral(token: string): Promise<string | null>;
45
+ /** A live token's value and how many uses it has left (null = unbounded). */
46
+ export interface EphemeralGrant {
47
+ value: string;
48
+ remaining: number | null;
49
+ /** True once the token is bound to a ref; it then acts only on that ref. */
50
+ bound: boolean;
51
+ }
52
+ /** Read a live token without spending a use. */
53
+ export declare function peekEphemeral(token: string): Promise<EphemeralGrant | null>;
54
+ /**
55
+ * Spend one use of a token. A token stored with `bindOnUse` binds to `ref`
56
+ * on its first ref-carrying spend; after that it spends freely on that ref
57
+ * and never on another. Returns null when expired, exhausted, or bound
58
+ * elsewhere. An exhausted row stays until its TTL so a spend whose act
59
+ * missed can be refunded.
60
+ */
61
+ export declare function consumeEphemeral(token: string, ref?: string | null): Promise<EphemeralGrant | null>;
62
+ /** Undo one spend whose act did not land. `unbind` undoes the binding that spend made. */
63
+ export declare function refundEphemeral(token: string, unbind: boolean): Promise<void>;
43
64
  /**
44
65
  * Explicitly revoke a token before expiry/exhaustion.
45
66
  */
@@ -7,6 +7,9 @@ exports.exchangeEphemeralToken = exchangeEphemeralToken;
7
7
  exports.exchangeTokensInArgs = exchangeTokensInArgs;
8
8
  exports.storeEphemeral = storeEphemeral;
9
9
  exports.exchangeEphemeral = exchangeEphemeral;
10
+ exports.peekEphemeral = peekEphemeral;
11
+ exports.consumeEphemeral = consumeEphemeral;
12
+ exports.refundEphemeral = refundEphemeral;
10
13
  exports.revokeEphemeral = revokeEphemeral;
11
14
  exports.cleanupExpired = cleanupExpired;
12
15
  const db_1 = require("../../lib/db");
@@ -81,7 +84,7 @@ async function storeEphemeral(value, opts = {}) {
81
84
  const expiresAt = opts.ttlSeconds
82
85
  ? `NOW() + ${opts.ttlSeconds} * INTERVAL '1 second'`
83
86
  : 'NULL';
84
- const { rows } = await pool.query((0, sql_1.INSERT_EPHEMERAL)(expiresAt), [Buffer.from(encrypted, 'base64'), opts.label || null, maxUses]);
87
+ const { rows } = await pool.query((0, sql_1.INSERT_EPHEMERAL)(expiresAt), [Buffer.from(encrypted, 'base64'), opts.label || null, maxUses, opts.bindOnUse ?? false]);
85
88
  return rows[0].token;
86
89
  }
87
90
  /**
@@ -106,6 +109,34 @@ async function exchangeEphemeral(token) {
106
109
  }
107
110
  return (0, crypto_1.decrypt)(buf.toString('base64'));
108
111
  }
112
+ function toGrant(row) {
113
+ const bound = row.bound_ref !== null;
114
+ return {
115
+ value: (0, crypto_1.decrypt)(row.value.toString('base64')),
116
+ remaining: bound || row.max_uses === 0 ? null : Math.max(0, row.max_uses - row.use_count),
117
+ bound,
118
+ };
119
+ }
120
+ /** Read a live token without spending a use. */
121
+ async function peekEphemeral(token) {
122
+ const { rows } = await (0, db_1.getPool)().query(sql_1.PEEK_EPHEMERAL, [token]);
123
+ return rows.length ? toGrant(rows[0]) : null;
124
+ }
125
+ /**
126
+ * Spend one use of a token. A token stored with `bindOnUse` binds to `ref`
127
+ * on its first ref-carrying spend; after that it spends freely on that ref
128
+ * and never on another. Returns null when expired, exhausted, or bound
129
+ * elsewhere. An exhausted row stays until its TTL so a spend whose act
130
+ * missed can be refunded.
131
+ */
132
+ async function consumeEphemeral(token, ref = null) {
133
+ const { rows } = await (0, db_1.getPool)().query(sql_1.CONSUME_EPHEMERAL, [token, ref]);
134
+ return rows.length ? toGrant(rows[0]) : null;
135
+ }
136
+ /** Undo one spend whose act did not land. `unbind` undoes the binding that spend made. */
137
+ async function refundEphemeral(token, unbind) {
138
+ await (0, db_1.getPool)().query(sql_1.REFUND_EPHEMERAL, [token, unbind]);
139
+ }
109
140
  /**
110
141
  * Explicitly revoke a token before expiry/exhaustion.
111
142
  */
@@ -1,6 +1,16 @@
1
1
  /** Build INSERT for ephemeral credentials. expiresExpr is a SQL expression like 'NULL' or "NOW() + N * INTERVAL '1 second'". */
2
2
  export declare const INSERT_EPHEMERAL: (expiresExpr: string) => string;
3
3
  export declare const EXCHANGE_EPHEMERAL = "\n UPDATE lt_ephemeral_credentials\n SET use_count = use_count + 1\n WHERE token = $1\n AND (expires_at IS NULL OR expires_at > NOW())\n AND (max_uses = 0 OR use_count < max_uses)\n RETURNING value, use_count, max_uses";
4
+ /** Validity check without spending a use. A bound grant stays live until its TTL. */
5
+ export declare const PEEK_EPHEMERAL = "\n SELECT value, use_count, max_uses, bound_ref\n FROM lt_ephemeral_credentials\n WHERE token = $1\n AND (expires_at IS NULL OR expires_at > NOW())\n AND (bound_ref IS NOT NULL OR max_uses = 0 OR use_count < max_uses)";
6
+ /**
7
+ * Spend one use, binding a bind_on_use grant to $2 on its first spend.
8
+ * A bound grant acts again on its own ref without counting, and never on
9
+ * another ref. Without a ref ($2 NULL) the grant counts like any other.
10
+ */
11
+ export declare const CONSUME_EPHEMERAL = "\n UPDATE lt_ephemeral_credentials\n SET use_count = CASE WHEN bound_ref IS NOT NULL THEN use_count ELSE use_count + 1 END,\n bound_ref = CASE WHEN bind_on_use AND bound_ref IS NULL THEN $2::text ELSE bound_ref END\n WHERE token = $1\n AND (expires_at IS NULL OR expires_at > NOW())\n AND (\n (bound_ref IS NOT NULL AND bound_ref = $2::text)\n OR (bound_ref IS NULL AND (max_uses = 0 OR use_count < max_uses))\n )\n RETURNING value, use_count, max_uses, bound_ref";
12
+ /** Return a use an act spent but did not land; $2 also undoes the binding that spend made. */
13
+ export declare const REFUND_EPHEMERAL = "\n UPDATE lt_ephemeral_credentials\n SET use_count = GREATEST(use_count - 1, 0),\n bound_ref = CASE WHEN $2::boolean THEN NULL ELSE bound_ref END\n WHERE token = $1";
4
14
  export declare const DELETE_EPHEMERAL = "\n DELETE FROM lt_ephemeral_credentials WHERE token = $1";
5
15
  export declare const CLEANUP_EXPIRED_EPHEMERAL = "\n DELETE FROM lt_ephemeral_credentials\n WHERE expires_at IS NOT NULL AND expires_at < NOW()";
6
16
  export declare const LIST_BOTS = "\n SELECT * FROM lt_users\n WHERE account_type = 'bot'\n AND ($3::text IS NULL OR status = $3)\n AND ($4::text IS NULL\n OR display_name ILIKE '%' || $4 || '%'\n OR external_id ILIKE '%' || $4 || '%'\n OR metadata->>'description' ILIKE '%' || $4 || '%')\n ORDER BY created_at DESC\n LIMIT $1 OFFSET $2";
@@ -1,11 +1,11 @@
1
1
  "use strict";
2
2
  // ─── Ephemeral credentials ──────────────────────────────────────────────────
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.GET_USER_WITH_ROLES_FLEXIBLE = exports.GET_USER_BY_EXTERNAL_ID = exports.SET_ACCOUNT_TYPE_BOT = exports.COUNT_BOTS = exports.LIST_BOTS = exports.CLEANUP_EXPIRED_EPHEMERAL = exports.DELETE_EPHEMERAL = exports.EXCHANGE_EPHEMERAL = exports.INSERT_EPHEMERAL = void 0;
4
+ exports.GET_USER_WITH_ROLES_FLEXIBLE = exports.GET_USER_BY_EXTERNAL_ID = exports.SET_ACCOUNT_TYPE_BOT = exports.COUNT_BOTS = exports.LIST_BOTS = exports.CLEANUP_EXPIRED_EPHEMERAL = exports.DELETE_EPHEMERAL = exports.REFUND_EPHEMERAL = exports.CONSUME_EPHEMERAL = exports.PEEK_EPHEMERAL = exports.EXCHANGE_EPHEMERAL = exports.INSERT_EPHEMERAL = void 0;
5
5
  /** Build INSERT for ephemeral credentials. expiresExpr is a SQL expression like 'NULL' or "NOW() + N * INTERVAL '1 second'". */
6
6
  const INSERT_EPHEMERAL = (expiresExpr) => `
7
- INSERT INTO lt_ephemeral_credentials (value, label, max_uses, expires_at)
8
- VALUES ($1, $2, $3, ${expiresExpr})
7
+ INSERT INTO lt_ephemeral_credentials (value, label, max_uses, bind_on_use, expires_at)
8
+ VALUES ($1, $2, $3, $4, ${expiresExpr})
9
9
  RETURNING token`;
10
10
  exports.INSERT_EPHEMERAL = INSERT_EPHEMERAL;
11
11
  exports.EXCHANGE_EPHEMERAL = `
@@ -15,6 +15,35 @@ exports.EXCHANGE_EPHEMERAL = `
15
15
  AND (expires_at IS NULL OR expires_at > NOW())
16
16
  AND (max_uses = 0 OR use_count < max_uses)
17
17
  RETURNING value, use_count, max_uses`;
18
+ /** Validity check without spending a use. A bound grant stays live until its TTL. */
19
+ exports.PEEK_EPHEMERAL = `
20
+ SELECT value, use_count, max_uses, bound_ref
21
+ FROM lt_ephemeral_credentials
22
+ WHERE token = $1
23
+ AND (expires_at IS NULL OR expires_at > NOW())
24
+ AND (bound_ref IS NOT NULL OR max_uses = 0 OR use_count < max_uses)`;
25
+ /**
26
+ * Spend one use, binding a bind_on_use grant to $2 on its first spend.
27
+ * A bound grant acts again on its own ref without counting, and never on
28
+ * another ref. Without a ref ($2 NULL) the grant counts like any other.
29
+ */
30
+ exports.CONSUME_EPHEMERAL = `
31
+ UPDATE lt_ephemeral_credentials
32
+ SET use_count = CASE WHEN bound_ref IS NOT NULL THEN use_count ELSE use_count + 1 END,
33
+ bound_ref = CASE WHEN bind_on_use AND bound_ref IS NULL THEN $2::text ELSE bound_ref END
34
+ WHERE token = $1
35
+ AND (expires_at IS NULL OR expires_at > NOW())
36
+ AND (
37
+ (bound_ref IS NOT NULL AND bound_ref = $2::text)
38
+ OR (bound_ref IS NULL AND (max_uses = 0 OR use_count < max_uses))
39
+ )
40
+ RETURNING value, use_count, max_uses, bound_ref`;
41
+ /** Return a use an act spent but did not land; $2 also undoes the binding that spend made. */
42
+ exports.REFUND_EPHEMERAL = `
43
+ UPDATE lt_ephemeral_credentials
44
+ SET use_count = GREATEST(use_count - 1, 0),
45
+ bound_ref = CASE WHEN $2::boolean THEN NULL ELSE bound_ref END
46
+ WHERE token = $1`;
18
47
  exports.DELETE_EPHEMERAL = `
19
48
  DELETE FROM lt_ephemeral_credentials WHERE token = $1`;
20
49
  exports.CLEANUP_EXPIRED_EPHEMERAL = `
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.buildEvents = buildEvents;
4
4
  const hotmesh_utils_1 = require("../hotmesh-utils");
5
+ const workflow_state_1 = require("../workflow-state");
5
6
  /**
6
7
  * Transform raw activities + job context into a chronological event list
7
8
  * with back-references linking completions to their scheduled events.
@@ -84,7 +85,7 @@ function completionEvent(id, act, input, timelineKey, index) {
84
85
  };
85
86
  }
86
87
  function appendWorkflowTerminalEvent(events, nextId, ctx) {
87
- const status = ctx.job.status > 0 ? 'running' : ctx.job.status === 0 ? 'completed' : 'failed';
88
+ const status = (0, workflow_state_1.workflowStateFromStatus)(ctx.job.status);
88
89
  if (status === 'completed') {
89
90
  events.push({
90
91
  event_id: nextId,
@@ -6,6 +6,7 @@ const hotmesh_utils_1 = require("../hotmesh-utils");
6
6
  const enrichment_1 = require("./enrichment");
7
7
  const events_1 = require("./events");
8
8
  const sql_1 = require("./sql");
9
+ const workflow_state_1 = require("../workflow-state");
9
10
  /**
10
11
  * Build a complete execution export for a YAML engine workflow job.
11
12
  *
@@ -88,7 +89,7 @@ function assembleExport(ctx, events, activities) {
88
89
  workflow_type: ctx.workflowTopic,
89
90
  workflow_name: ctx.workflowName,
90
91
  task_queue: ctx.appId,
91
- status: ctx.job.status > 0 ? 'running' : ctx.job.status === 0 ? 'completed' : 'failed',
92
+ status: (0, workflow_state_1.workflowStateFromStatus)(ctx.job.status),
92
93
  start_time: startTime,
93
94
  close_time: closeTime,
94
95
  duration_ms: durationMs,
@@ -5,6 +5,7 @@ exports.listJobs = listJobs;
5
5
  const db_1 = require("../../lib/db");
6
6
  const hotmesh_utils_1 = require("../hotmesh-utils");
7
7
  const sql_1 = require("./sql");
8
+ const workflow_state_1 = require("../workflow-state");
8
9
  const SORTABLE_COLUMNS = new Set(['created_at', 'updated_at', 'entity', 'status']);
9
10
  function buildOrderBy(sortBy, order) {
10
11
  if (!sortBy || !SORTABLE_COLUMNS.has(sortBy)) {
@@ -75,7 +76,7 @@ async function listJobs(params) {
75
76
  const jobs = dataResult.rows.map((row) => ({
76
77
  workflow_id: row.key.startsWith(keyPrefix) ? row.key.slice(keyPrefix.length) : row.key,
77
78
  entity: row.entity,
78
- status: row.status > 0 ? 'running' : row.status === 0 ? 'completed' : 'failed',
79
+ status: (0, workflow_state_1.workflowStateFromStatus)(row.status),
79
80
  is_live: row.is_live,
80
81
  created_at: row.created_at,
81
82
  updated_at: row.updated_at,
@@ -0,0 +1,5 @@
1
+ import { type RoleBadgeGrant } from './types';
2
+ /** The problem with a `properties.badge_grant` value, or null when it is usable (or absent). */
3
+ export declare function badgeGrantError(value: unknown): string | null;
4
+ /** The role's badge policy from its properties bag, or null when it declares none (or an unusable one). */
5
+ export declare function readBadgeGrant(properties: Record<string, unknown> | null | undefined): RoleBadgeGrant | null;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.badgeGrantError = badgeGrantError;
4
+ exports.readBadgeGrant = readBadgeGrant;
5
+ const types_1 = require("./types");
6
+ const SCOPES = ['action', 'subject'];
7
+ /** The problem with a `properties.badge_grant` value, or null when it is usable (or absent). */
8
+ function badgeGrantError(value) {
9
+ if (value === undefined || value === null)
10
+ return null;
11
+ if (typeof value !== 'object' || Array.isArray(value))
12
+ return 'properties.badge_grant must be an object';
13
+ const grant = value;
14
+ const known = new Set(['ttl_seconds', 'max_uses', 'scope']);
15
+ const extra = Object.keys(grant).filter((k) => !known.has(k));
16
+ if (extra.length)
17
+ return `properties.badge_grant has unknown key(s): ${extra.join(', ')}`;
18
+ if (grant.ttl_seconds !== undefined
19
+ && (!Number.isInteger(grant.ttl_seconds) || grant.ttl_seconds < 1 || grant.ttl_seconds > 86_400)) {
20
+ return 'properties.badge_grant.ttl_seconds must be an integer from 1 to 86400';
21
+ }
22
+ if (grant.max_uses !== undefined && (!Number.isInteger(grant.max_uses) || grant.max_uses < 0)) {
23
+ return 'properties.badge_grant.max_uses must be a non-negative integer';
24
+ }
25
+ if (grant.scope !== undefined && !SCOPES.includes(grant.scope)) {
26
+ return `properties.badge_grant.scope must be one of ${SCOPES.join(', ')}`;
27
+ }
28
+ return null;
29
+ }
30
+ /** The role's badge policy from its properties bag, or null when it declares none (or an unusable one). */
31
+ function readBadgeGrant(properties) {
32
+ const value = properties?.[types_1.ROLE_PROPERTY_KEYS.BADGE_GRANT];
33
+ if (value === undefined || value === null || badgeGrantError(value))
34
+ return null;
35
+ return value;
36
+ }
@@ -8,6 +8,8 @@ const db_1 = require("../../lib/db");
8
8
  const logger_1 = require("../../lib/logger");
9
9
  const index_1 = require("./index");
10
10
  const sql_1 = require("./sql");
11
+ const badge_grant_1 = require("./badge-grant");
12
+ const types_1 = require("./types");
11
13
  /** Recorded on schema snapshots written by the startup apply. */
12
14
  exports.STARTUP_CHANGE_SUMMARY = 'startup apply (code)';
13
15
  /** Metadata fields shared 1:1 between LTRoleConfig and UpdateRoleInput. */
@@ -79,6 +81,9 @@ async function listConfiguredRoles() {
79
81
  * Escalation targets use replace semantics when declared.
80
82
  */
81
83
  async function applyRoleConfig(cfg, codeOwned) {
84
+ const grantError = (0, badge_grant_1.badgeGrantError)(cfg.properties?.[types_1.ROLE_PROPERTY_KEYS.BADGE_GRANT]);
85
+ if (grantError)
86
+ throw new Error(`role ${cfg.role}: ${grantError}`);
82
87
  const created = await (0, index_1.createRole)(cfg.role);
83
88
  const pool = (0, db_1.getPool)();
84
89
  const { rows } = await pool.query(sql_1.GET_ROLE_ROW, [cfg.role]);
@@ -15,6 +15,10 @@ export interface EscalationChain {
15
15
  * MEMBER of exactly this one role, the dashboard drops the left nav, the
16
16
  * role's escalation list becomes home, and navigation is held to the list,
17
17
  * the detail page, and the scan screens. Multi-role users get full chrome.
18
+ * - BADGE_GRANT: RoleBadgeGrant — the badge policy at this role's stations.
19
+ * A badge scanned on a device signed in as a member of this role mints
20
+ * its acting grant under this policy instead of the badge scheme's own
21
+ * (see api/scan-codes/badge-policy.ts).
18
22
  * - LINK_VARIABLES: RoleLinkVariable[] — metadata facet names members bind
19
23
  * per device. Pins may reference `{lt:name}` as a whole facet value
20
24
  * (e.g. `facets={"region":"{lt:region}"}`); the dashboard substitutes
@@ -27,7 +31,17 @@ export declare const ROLE_PROPERTY_KEYS: {
27
31
  readonly WORKED_BY: "worked_by";
28
32
  readonly KIOSK: "kiosk";
29
33
  readonly LINK_VARIABLES: "link_variables";
34
+ readonly BADGE_GRANT: "badge_grant";
30
35
  };
36
+ /** A station role's badge policy. Absent fields keep the badge scheme's value. */
37
+ export interface RoleBadgeGrant {
38
+ /** How long a badge scan stays primed (1-86400 s). */
39
+ ttl_seconds?: number;
40
+ /** 0 = TTL-bound; n = the grant covers n acts. */
41
+ max_uses?: number;
42
+ /** 'action' spends a use per act; 'subject' binds to one held item. */
43
+ scope?: 'action' | 'subject';
44
+ }
31
45
  /**
32
46
  * One link-variable declaration inside `properties.link_variables`. `name` is
33
47
  * the metadata facet key (facet-key charset); `label` is the human annotation
@@ -14,6 +14,10 @@ exports.PORTAL_KEY = exports.PORTAL_LIMITS = exports.ROLE_PROPERTY_KEYS = void 0
14
14
  * MEMBER of exactly this one role, the dashboard drops the left nav, the
15
15
  * role's escalation list becomes home, and navigation is held to the list,
16
16
  * the detail page, and the scan screens. Multi-role users get full chrome.
17
+ * - BADGE_GRANT: RoleBadgeGrant — the badge policy at this role's stations.
18
+ * A badge scanned on a device signed in as a member of this role mints
19
+ * its acting grant under this policy instead of the badge scheme's own
20
+ * (see api/scan-codes/badge-policy.ts).
17
21
  * - LINK_VARIABLES: RoleLinkVariable[] — metadata facet names members bind
18
22
  * per device. Pins may reference `{lt:name}` as a whole facet value
19
23
  * (e.g. `facets={"region":"{lt:region}"}`); the dashboard substitutes
@@ -26,6 +30,7 @@ exports.ROLE_PROPERTY_KEYS = {
26
30
  WORKED_BY: 'worked_by',
27
31
  KIOSK: 'kiosk',
28
32
  LINK_VARIABLES: 'link_variables',
33
+ BADGE_GRANT: 'badge_grant',
29
34
  };
30
35
  /** Bounds for a role's portals: how many, and the matrix of each (rows of cells, each cell a pin). */
31
36
  exports.PORTAL_LIMITS = {
@@ -1,4 +1,5 @@
1
1
  export { listScanSchemes, getScanScheme, listScanRules, getScanRule, } from './read';
2
2
  export { upsertScanScheme, deleteScanScheme, upsertScanRule, deleteScanRule, seedScanScheme, seedScanRule, applyScanScheme, applyScanRule, type ScanSchemeInput, type ScanRuleInput, } from './write';
3
- export { parseScanCode, interpolateScanTemplate, mentionsClaimToken, ScanTemplateError, type ScanParseResult, type ScanParseFailure, type ScanTemplateContext, } from './parse';
4
- export { assertValidScheme, assertValidSteps } from './validate';
3
+ export { parseScanCode, interpolateScanTemplate, mentionsClaimToken, renderScanCopy, ScanTemplateError, type ScanParseResult, type ScanParseFailure, type ScanTemplateContext, } from './parse';
4
+ export { assertValidScheme, assertValidSteps, assertValidIdentityRule, assertSchemesCoexist, } from './validate';
5
+ export { isValidGtin, normalizeGtin } from '../../shared/scan-code';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.assertValidSteps = exports.assertValidScheme = exports.ScanTemplateError = exports.mentionsClaimToken = exports.interpolateScanTemplate = exports.parseScanCode = exports.applyScanRule = exports.applyScanScheme = exports.seedScanRule = exports.seedScanScheme = exports.deleteScanRule = exports.upsertScanRule = exports.deleteScanScheme = exports.upsertScanScheme = exports.getScanRule = exports.listScanRules = exports.getScanScheme = exports.listScanSchemes = void 0;
3
+ exports.normalizeGtin = exports.isValidGtin = exports.assertSchemesCoexist = exports.assertValidIdentityRule = exports.assertValidSteps = exports.assertValidScheme = exports.ScanTemplateError = exports.renderScanCopy = exports.mentionsClaimToken = exports.interpolateScanTemplate = exports.parseScanCode = exports.applyScanRule = exports.applyScanScheme = exports.seedScanRule = exports.seedScanScheme = exports.deleteScanRule = exports.upsertScanRule = exports.deleteScanScheme = exports.upsertScanScheme = exports.getScanRule = exports.listScanRules = exports.getScanScheme = exports.listScanSchemes = void 0;
4
4
  var read_1 = require("./read");
5
5
  Object.defineProperty(exports, "listScanSchemes", { enumerable: true, get: function () { return read_1.listScanSchemes; } });
6
6
  Object.defineProperty(exports, "getScanScheme", { enumerable: true, get: function () { return read_1.getScanScheme; } });
@@ -19,7 +19,13 @@ var parse_1 = require("./parse");
19
19
  Object.defineProperty(exports, "parseScanCode", { enumerable: true, get: function () { return parse_1.parseScanCode; } });
20
20
  Object.defineProperty(exports, "interpolateScanTemplate", { enumerable: true, get: function () { return parse_1.interpolateScanTemplate; } });
21
21
  Object.defineProperty(exports, "mentionsClaimToken", { enumerable: true, get: function () { return parse_1.mentionsClaimToken; } });
22
+ Object.defineProperty(exports, "renderScanCopy", { enumerable: true, get: function () { return parse_1.renderScanCopy; } });
22
23
  Object.defineProperty(exports, "ScanTemplateError", { enumerable: true, get: function () { return parse_1.ScanTemplateError; } });
23
24
  var validate_1 = require("./validate");
24
25
  Object.defineProperty(exports, "assertValidScheme", { enumerable: true, get: function () { return validate_1.assertValidScheme; } });
25
26
  Object.defineProperty(exports, "assertValidSteps", { enumerable: true, get: function () { return validate_1.assertValidSteps; } });
27
+ Object.defineProperty(exports, "assertValidIdentityRule", { enumerable: true, get: function () { return validate_1.assertValidIdentityRule; } });
28
+ Object.defineProperty(exports, "assertSchemesCoexist", { enumerable: true, get: function () { return validate_1.assertSchemesCoexist; } });
29
+ var scan_code_1 = require("../../shared/scan-code");
30
+ Object.defineProperty(exports, "isValidGtin", { enumerable: true, get: function () { return scan_code_1.isValidGtin; } });
31
+ Object.defineProperty(exports, "normalizeGtin", { enumerable: true, get: function () { return scan_code_1.normalizeGtin; } });
@@ -1,9 +1,6 @@
1
+ import { type ScanParseFailure } from '../../shared/scan-code';
1
2
  import { type ParsedScanCode, type ScanScheme } from '../../types';
2
- export interface ScanParseFailure {
3
- /** Why the code did not parse. */
4
- reason: 'empty' | 'unknown_version' | 'scheme_disabled' | 'malformed';
5
- detail: string;
6
- }
3
+ export type { ScanParseFailure };
7
4
  export type ScanParseResult = {
8
5
  ok: true;
9
6
  parsed: ParsedScanCode;
@@ -12,26 +9,26 @@ export type ScanParseResult = {
12
9
  ok: false;
13
10
  failure: ScanParseFailure;
14
11
  };
15
- /**
16
- * Parse a raw scan string against the configured schemes. Pure — no I/O.
17
- *
18
- * The leading TWO digits pick the scheme (10-99, so a code never starts with a
19
- * leading zero); the scheme then defines how the remainder splits into a
20
- * single-digit category (0-9) and the target:
21
- * - delimited: `10:1:ABC-123` (delimiter from the scheme row)
22
- * - fixed: `1017554332` (one category digit, then target_length digits)
23
- */
12
+ /** Parse a raw scan string against the configured schemes. Pure; see shared/scan-code. */
24
13
  export declare function parseScanCode(raw: string, schemes: ScanScheme[]): ScanParseResult;
25
14
  export interface ScanTemplateContext {
26
15
  target: string;
27
16
  category: string;
28
17
  scannedAt: string;
18
+ /** The code as scanned; defaults to the target. */
19
+ code?: string;
29
20
  /** The acting user's single live claim, its metadata; absent when none or ambiguous. */
30
21
  claim?: Record<string, unknown>;
31
- /** The row an item-mode accumulate step located, its metadata. */
22
+ /** The row the step located (item-mode accumulate, hold), its metadata. */
32
23
  item?: Record<string, unknown>;
24
+ /** The held subject's row: its metadata plus `id`. */
25
+ subject?: Record<string, unknown>;
26
+ /** The container a subject step located, its metadata. */
27
+ container?: Record<string, unknown>;
28
+ /** The batch a fill step read: `pending`, `total`, `filled`. */
29
+ fill?: Record<string, unknown>;
33
30
  }
34
- /** A `{claim.x}` or `{item.x}` token the context cannot resolve. */
31
+ /** A bag token the context cannot resolve. */
35
32
  export declare class ScanTemplateError extends Error {
36
33
  readonly token: string;
37
34
  readonly reason: string;
@@ -41,9 +38,15 @@ export declare class ScanTemplateError extends Error {
41
38
  export declare function mentionsClaimToken(value: unknown): boolean;
42
39
  /**
43
40
  * Replace the template tokens inside string values of a params object.
44
- * Deep, pure, non-mutating. The three scan tokens are plain text
45
- * replacement; `{claim.<facet>}` and `{item.<facet>}` read the context's
46
- * facet bags and throw {@link ScanTemplateError} when they cannot resolve,
47
- * so a literal token never reaches a row. No expression language.
41
+ * Deep, pure, non-mutating. The scan tokens are plain text replacement; the
42
+ * bag tokens (`{claim.x}`, `{item.x}`, `{subject.x}`, `{container.x}`,
43
+ * `{fill.x}`) read the context's facet bags and throw
44
+ * {@link ScanTemplateError} when they cannot resolve, so a literal token
45
+ * never reaches a row. No expression language.
48
46
  */
49
47
  export declare function interpolateScanTemplate<T>(value: T, ctx: ScanTemplateContext): T;
48
+ /**
49
+ * Render refusal copy, degrading instead of failing: a token with nothing to
50
+ * read becomes an empty string, so a refusal always has words to show.
51
+ */
52
+ export declare function renderScanCopy(markdown: string, ctx: ScanTemplateContext): string;