@hotmeshio/long-tail 0.27.0 → 0.28.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 (386) hide show
  1. package/README.md +9 -2
  2. package/build/api/files.d.ts +5 -0
  3. package/build/api/files.js +19 -2
  4. package/build/api/knowledge.d.ts +3 -1
  5. package/build/api/settings.d.ts +4 -1
  6. package/build/api/settings.js +7 -1
  7. package/build/index.js +9 -4
  8. package/build/lib/db/config-lock.d.ts +10 -0
  9. package/build/lib/db/config-lock.js +28 -0
  10. package/build/lib/db/schemas/041_machine_lines.sql +26 -0
  11. package/build/lib/db/schemas/042_knowledge_edition_labels.sql +9 -0
  12. package/build/lib/events/browser-view.js +8 -2
  13. package/build/lib/events/publish.d.ts +33 -0
  14. package/build/lib/events/publish.js +52 -1
  15. package/build/lib/machines/line.d.ts +7 -1
  16. package/build/lib/machines/line.js +25 -2
  17. package/build/lib/machines/protocol/codec.d.ts +14 -0
  18. package/build/lib/machines/protocol/codec.js +10 -1
  19. package/build/lib/machines/protocol/constants.d.ts +1 -1
  20. package/build/lib/machines/protocol/constants.js +1 -1
  21. package/build/lib/machines/protocol/contract.d.ts +2 -0
  22. package/build/lib/machines/protocol/contract.js +13 -8
  23. package/build/lib/machines/site/mosquitto-conf.d.ts +9 -4
  24. package/build/lib/machines/site/mosquitto-conf.js +32 -22
  25. package/build/lib/machines/site/site-conf.d.ts +13 -3
  26. package/build/lib/machines/site/site-conf.js +31 -8
  27. package/build/lib/machines/transport/callback-feed.d.ts +1 -0
  28. package/build/lib/machines/transport/callback-feed.js +4 -1
  29. package/build/lib/machines/transport/memory.d.ts +2 -0
  30. package/build/lib/machines/transport/memory.js +6 -0
  31. package/build/lib/machines/transport/mqtt-bus.d.ts +2 -0
  32. package/build/lib/machines/transport/mqtt-bus.js +4 -0
  33. package/build/lib/machines/transport/nats-bus.d.ts +3 -0
  34. package/build/lib/machines/transport/nats-bus.js +3 -0
  35. package/build/lib/machines/transport/nats-feed.d.ts +1 -0
  36. package/build/lib/machines/transport/nats-feed.js +4 -1
  37. package/build/lib/machines/transport/pubsub-feed.d.ts +1 -0
  38. package/build/lib/machines/transport/pubsub-feed.js +4 -1
  39. package/build/lib/machines/transport/stream-bus.d.ts +7 -1
  40. package/build/lib/machines/transport/stream-bus.js +17 -5
  41. package/build/lib/machines/transport/streams.d.ts +10 -2
  42. package/build/lib/machines/transport/streams.js +32 -5
  43. package/build/lib/messaging/memory.js +3 -0
  44. package/build/lib/messaging/nats/streams.d.ts +3 -0
  45. package/build/lib/messaging/nats/streams.js +16 -0
  46. package/build/lib/storage/local.d.ts +2 -0
  47. package/build/lib/storage/local.js +3 -0
  48. package/build/lib/storage/s3.d.ts +3 -2
  49. package/build/lib/storage/s3.js +6 -1
  50. package/build/lib/storage/types.d.ts +7 -1
  51. package/build/modules/machines.d.ts +8 -0
  52. package/build/modules/machines.js +16 -0
  53. package/build/routes/file-browser.js +3 -1
  54. package/build/routes/index.js +2 -0
  55. package/build/routes/knowledge.js +6 -5
  56. package/build/routes/machines.d.ts +2 -0
  57. package/build/routes/machines.js +253 -0
  58. package/build/services/knowledge/index.d.ts +4 -2
  59. package/build/services/knowledge/index.js +8 -2
  60. package/build/services/knowledge/lookup-cache.d.ts +8 -0
  61. package/build/services/knowledge/lookup-cache.js +30 -3
  62. package/build/services/knowledge/lookup-refs.js +1 -1
  63. package/build/services/knowledge/sql.d.ts +4 -2
  64. package/build/services/knowledge/sql.js +8 -3
  65. package/build/services/machines/commands.d.ts +5 -5
  66. package/build/services/machines/commands.js +3 -2
  67. package/build/services/machines/config.d.ts +4 -1
  68. package/build/services/machines/config.js +2 -1
  69. package/build/services/machines/contracts.d.ts +28 -0
  70. package/build/services/machines/contracts.js +15 -1
  71. package/build/services/machines/forms.d.ts +26 -1
  72. package/build/services/machines/forms.js +17 -1
  73. package/build/services/machines/gateway/actions.d.ts +14 -1
  74. package/build/services/machines/gateway/admission.d.ts +30 -4
  75. package/build/services/machines/gateway/admission.js +76 -14
  76. package/build/services/machines/gateway/api-escalations.js +4 -0
  77. package/build/services/machines/gateway/dispatcher.d.ts +12 -4
  78. package/build/services/machines/gateway/dispatcher.js +53 -17
  79. package/build/services/machines/gateway/executor.d.ts +13 -2
  80. package/build/services/machines/gateway/executor.js +84 -29
  81. package/build/services/machines/gateway/gateway.d.ts +21 -1
  82. package/build/services/machines/gateway/gateway.js +65 -25
  83. package/build/services/machines/gateway/index.d.ts +3 -0
  84. package/build/services/machines/gateway/index.js +3 -0
  85. package/build/services/machines/gateway/inspect.d.ts +17 -0
  86. package/build/services/machines/gateway/inspect.js +68 -0
  87. package/build/services/machines/gateway/log.d.ts +10 -0
  88. package/build/services/machines/gateway/log.js +20 -0
  89. package/build/services/machines/gateway/lt-http.js +11 -2
  90. package/build/services/machines/gateway/pacing.js +2 -1
  91. package/build/services/machines/gateway/plan-escalation.js +8 -3
  92. package/build/services/machines/gateway/plan-machine.js +41 -16
  93. package/build/services/machines/gateway/plan-shared.d.ts +5 -3
  94. package/build/services/machines/gateway/plan-shared.js +6 -4
  95. package/build/services/machines/gateway/project.d.ts +9 -0
  96. package/build/services/machines/gateway/project.js +55 -0
  97. package/build/services/machines/gateway/receipts.d.ts +3 -0
  98. package/build/services/machines/gateway/receipts.js +3 -1
  99. package/build/services/machines/gateway/reconcile.js +3 -3
  100. package/build/services/machines/gateway/registration.js +1 -1
  101. package/build/services/machines/gateway/reply-waiter.d.ts +8 -3
  102. package/build/services/machines/gateway/reply-waiter.js +37 -16
  103. package/build/services/machines/gateway/state.d.ts +53 -4
  104. package/build/services/machines/gateway/state.js +128 -13
  105. package/build/services/machines/gateway/wire-window.d.ts +21 -0
  106. package/build/services/machines/gateway/wire-window.js +61 -0
  107. package/build/services/machines/gateway/wire.d.ts +58 -0
  108. package/build/services/machines/gateway/wire.js +172 -0
  109. package/build/services/machines/index.d.ts +3 -0
  110. package/build/services/machines/index.js +2 -0
  111. package/build/services/machines/line-index.d.ts +16 -0
  112. package/build/services/machines/line-index.js +39 -0
  113. package/build/services/machines/registry-sql.d.ts +31 -0
  114. package/build/services/machines/registry-sql.js +110 -0
  115. package/build/services/machines/registry-sync.d.ts +31 -0
  116. package/build/services/machines/registry-sync.js +81 -0
  117. package/build/services/machines/registry.d.ts +77 -0
  118. package/build/services/machines/registry.js +158 -0
  119. package/build/services/machines/roles.d.ts +5 -4
  120. package/build/services/machines/roles.js +13 -4
  121. package/build/services/machines/rows.js +10 -1
  122. package/build/services/machines/select.d.ts +3 -2
  123. package/build/services/machines/select.js +4 -3
  124. package/build/services/machines/surface.d.ts +54 -5
  125. package/build/services/machines/surface.js +113 -17
  126. package/build/start/apply-report.d.ts +1 -1
  127. package/build/start/apply-report.js +3 -25
  128. package/build/start/index.js +16 -4
  129. package/build/system/activities/knowledge.d.ts +4 -0
  130. package/build/system/activities/knowledge.js +15 -0
  131. package/build/system/activities/sql.d.ts +2 -0
  132. package/build/system/activities/sql.js +6 -1
  133. package/build/system/index.js +13 -0
  134. package/build/system/mcp-servers/admin/schemas.d.ts +22 -22
  135. package/build/system/mcp-servers/human-queue-schemas.d.ts +7 -7
  136. package/build/system/mcp-servers/knowledge.js +4 -2
  137. package/build/system/mcp-servers/machines-schemas.d.ts +35 -0
  138. package/build/system/mcp-servers/machines-schemas.js +35 -0
  139. package/build/system/mcp-servers/machines.d.ts +20 -0
  140. package/build/system/mcp-servers/machines.js +154 -0
  141. package/build/system/seed/tool-manifests-machines.d.ts +2 -0
  142. package/build/system/seed/tool-manifests-machines.js +88 -0
  143. package/build/tsconfig.tsbuildinfo +1 -1
  144. package/build/types/escalation.d.ts +9 -6
  145. package/build/types/escalation.js +8 -2
  146. package/build/types/events.d.ts +6 -1
  147. package/build/types/index.d.ts +1 -0
  148. package/build/types/machines-view.d.ts +175 -0
  149. package/build/types/machines-view.js +7 -0
  150. package/build/types/machines.d.ts +5 -0
  151. package/build/types/messaging.d.ts +2 -0
  152. package/build/types/startup.d.ts +2 -0
  153. package/dashboard/dist/assets/{AdminDashboard-DlItqxFS.js → AdminDashboard-Bm7VG65H.js} +2 -2
  154. package/dashboard/dist/assets/{AdminDashboard-DlItqxFS.js.map → AdminDashboard-Bm7VG65H.js.map} +1 -1
  155. package/dashboard/dist/assets/{AgentConfigPage-BUmT4a7n.js → AgentConfigPage-aJF7Sdbc.js} +6 -6
  156. package/dashboard/dist/assets/{AgentConfigPage-BUmT4a7n.js.map → AgentConfigPage-aJF7Sdbc.js.map} +1 -1
  157. package/dashboard/dist/assets/{AgentDetailPage-Cww8rlBi.js → AgentDetailPage-GwwghhxT.js} +3 -3
  158. package/dashboard/dist/assets/{AgentDetailPage-Cww8rlBi.js.map → AgentDetailPage-GwwghhxT.js.map} +1 -1
  159. package/dashboard/dist/assets/AgentsPage-DVvCzZyg.js +2 -0
  160. package/dashboard/dist/assets/{AgentsPage-C9UuUKhr.js.map → AgentsPage-DVvCzZyg.js.map} +1 -1
  161. package/dashboard/dist/assets/AvailableEscalationsPage-Cxmcji_K.js +2 -0
  162. package/dashboard/dist/assets/{AvailableEscalationsPage-DrvfXz70.js.map → AvailableEscalationsPage-Cxmcji_K.js.map} +1 -1
  163. package/dashboard/dist/assets/{BotPicker-CDq9XRMp.js → BotPicker-CofRxk4L.js} +2 -2
  164. package/dashboard/dist/assets/{BotPicker-CDq9XRMp.js.map → BotPicker-CofRxk4L.js.map} +1 -1
  165. package/dashboard/dist/assets/{BulkAssignModal-jsvqtrEA.js → BulkAssignModal-BARWuz4L.js} +2 -2
  166. package/dashboard/dist/assets/{BulkAssignModal-jsvqtrEA.js.map → BulkAssignModal-BARWuz4L.js.map} +1 -1
  167. package/dashboard/dist/assets/{CapabilitiesPage-CSCrI6B1.js → CapabilitiesPage-BJAWVNEx.js} +2 -2
  168. package/dashboard/dist/assets/{CapabilitiesPage-CSCrI6B1.js.map → CapabilitiesPage-BJAWVNEx.js.map} +1 -1
  169. package/dashboard/dist/assets/{CollapsibleSection-uD9mn-CQ.js → CollapsibleSection-CtgoaG75.js} +2 -2
  170. package/dashboard/dist/assets/{CollapsibleSection-uD9mn-CQ.js.map → CollapsibleSection-CtgoaG75.js.map} +1 -1
  171. package/dashboard/dist/assets/{ConfirmDeleteModal-BRmx2hA4.js → ConfirmDeleteModal-BYXXBWs6.js} +2 -2
  172. package/dashboard/dist/assets/{ConfirmDeleteModal-BRmx2hA4.js.map → ConfirmDeleteModal-BYXXBWs6.js.map} +1 -1
  173. package/dashboard/dist/assets/{ConnectedAppsPage-DlMzE5a-.js → ConnectedAppsPage-D0JkzWa7.js} +2 -2
  174. package/dashboard/dist/assets/{ConnectedAppsPage-DlMzE5a-.js.map → ConnectedAppsPage-D0JkzWa7.js.map} +1 -1
  175. package/dashboard/dist/assets/{CountdownTimer-sRuM4eM5.js → CountdownTimer-BcFxdZYN.js} +2 -2
  176. package/dashboard/dist/assets/{CountdownTimer-sRuM4eM5.js.map → CountdownTimer-BcFxdZYN.js.map} +1 -1
  177. package/dashboard/dist/assets/{CredentialsPage-bLYydwqa.js → CredentialsPage-DPSY20rV.js} +2 -2
  178. package/dashboard/dist/assets/{CredentialsPage-bLYydwqa.js.map → CredentialsPage-DPSY20rV.js.map} +1 -1
  179. package/dashboard/dist/assets/{CronLabel-D_ATDL2N.js → CronLabel-Dg_Oew_Y.js} +2 -2
  180. package/dashboard/dist/assets/{CronLabel-D_ATDL2N.js.map → CronLabel-Dg_Oew_Y.js.map} +1 -1
  181. package/dashboard/dist/assets/{DropZone-u1JGfR9G.js → DropZone-Cl_Flb16.js} +2 -2
  182. package/dashboard/dist/assets/{DropZone-u1JGfR9G.js.map → DropZone-Cl_Flb16.js.map} +1 -1
  183. package/dashboard/dist/assets/{ElapsedCell-groSMfqB.js → ElapsedCell-Dm3G5fK2.js} +2 -2
  184. package/dashboard/dist/assets/{ElapsedCell-groSMfqB.js.map → ElapsedCell-Dm3G5fK2.js.map} +1 -1
  185. package/dashboard/dist/assets/{EntityTimelinePanel-D-F3_A9m.js → EntityTimelinePanel-CrEEP04e.js} +2 -2
  186. package/dashboard/dist/assets/{EntityTimelinePanel-D-F3_A9m.js.map → EntityTimelinePanel-CrEEP04e.js.map} +1 -1
  187. package/dashboard/dist/assets/{EscalationListSchemaPage-Bad6Jrmr.js → EscalationListSchemaPage-wOInXcjs.js} +3 -3
  188. package/dashboard/dist/assets/{EscalationListSchemaPage-Bad6Jrmr.js.map → EscalationListSchemaPage-wOInXcjs.js.map} +1 -1
  189. package/dashboard/dist/assets/{EscalationSchemaPage-BKi_npI9.js → EscalationSchemaPage-CrIj_g9d.js} +3 -3
  190. package/dashboard/dist/assets/{EscalationSchemaPage-BKi_npI9.js.map → EscalationSchemaPage-CrIj_g9d.js.map} +1 -1
  191. package/dashboard/dist/assets/{EscalationTimeline-DQUUm3b1.js → EscalationTimeline-CeAsl5IT.js} +2 -2
  192. package/dashboard/dist/assets/{EscalationTimeline-DQUUm3b1.js.map → EscalationTimeline-CeAsl5IT.js.map} +1 -1
  193. package/dashboard/dist/assets/{EscalationTitleSelect-3mhXh77a.js → EscalationTitleSelect-D8qpCYiy.js} +2 -2
  194. package/dashboard/dist/assets/{EscalationTitleSelect-3mhXh77a.js.map → EscalationTitleSelect-D8qpCYiy.js.map} +1 -1
  195. package/dashboard/dist/assets/{EscalationsOverview-Qaov-uML.js → EscalationsOverview-CvaqVPsr.js} +2 -2
  196. package/dashboard/dist/assets/{EscalationsOverview-Qaov-uML.js.map → EscalationsOverview-CvaqVPsr.js.map} +1 -1
  197. package/dashboard/dist/assets/{EventTable-V4RF_n58.js → EventTable-Be0JuEl6.js} +2 -2
  198. package/dashboard/dist/assets/{EventTable-V4RF_n58.js.map → EventTable-Be0JuEl6.js.map} +1 -1
  199. package/dashboard/dist/assets/FilterBar-BVyAjIgv.js +2 -0
  200. package/dashboard/dist/assets/FilterBar-BVyAjIgv.js.map +1 -0
  201. package/dashboard/dist/assets/{GraphInvokePage-Djslhf96.js → GraphInvokePage-D_QigJeD.js} +2 -2
  202. package/dashboard/dist/assets/{GraphInvokePage-Djslhf96.js.map → GraphInvokePage-D_QigJeD.js.map} +1 -1
  203. package/dashboard/dist/assets/{HomePage-EjcNxlKx.js → HomePage-C1haeuNy.js} +2 -2
  204. package/dashboard/dist/assets/{HomePage-EjcNxlKx.js.map → HomePage-C1haeuNy.js.map} +1 -1
  205. package/dashboard/dist/assets/LinePage-CWD5pv1g.js +5 -0
  206. package/dashboard/dist/assets/LinePage-CWD5pv1g.js.map +1 -0
  207. package/dashboard/dist/assets/LinesPage-NqChsKcO.js +3 -0
  208. package/dashboard/dist/assets/LinesPage-NqChsKcO.js.map +1 -0
  209. package/dashboard/dist/assets/{ListToolbar-RrEAePOX.js → ListToolbar-BZCNrTh6.js} +2 -2
  210. package/dashboard/dist/assets/{ListToolbar-RrEAePOX.js.map → ListToolbar-BZCNrTh6.js.map} +1 -1
  211. package/dashboard/dist/assets/{McpOverview-8gqiL3Vj.js → McpOverview-yJTYnh1z.js} +2 -2
  212. package/dashboard/dist/assets/{McpOverview-8gqiL3Vj.js.map → McpOverview-yJTYnh1z.js.map} +1 -1
  213. package/dashboard/dist/assets/{McpQueryDetailPage-COyn6Ak5.js → McpQueryDetailPage-ChuLpJ4u.js} +3 -3
  214. package/dashboard/dist/assets/{McpQueryDetailPage-COyn6Ak5.js.map → McpQueryDetailPage-ChuLpJ4u.js.map} +1 -1
  215. package/dashboard/dist/assets/{McpQueryPage-Dj6Qj72w.js → McpQueryPage-9S-v9soF.js} +2 -2
  216. package/dashboard/dist/assets/{McpQueryPage-Dj6Qj72w.js.map → McpQueryPage-9S-v9soF.js.map} +1 -1
  217. package/dashboard/dist/assets/McpRunDetailPage-BhrcfxD5.js +2 -0
  218. package/dashboard/dist/assets/{McpRunDetailPage-80fQn9iX.js.map → McpRunDetailPage-BhrcfxD5.js.map} +1 -1
  219. package/dashboard/dist/assets/{McpRunsPage-DaSsI-EM.js → McpRunsPage-C5_i8_Zx.js} +2 -2
  220. package/dashboard/dist/assets/{McpRunsPage-DaSsI-EM.js.map → McpRunsPage-C5_i8_Zx.js.map} +1 -1
  221. package/dashboard/dist/assets/{NamespacePill-C5epAgq6.js → NamespacePill-OTZD2hzt.js} +2 -2
  222. package/dashboard/dist/assets/{NamespacePill-C5epAgq6.js.map → NamespacePill-OTZD2hzt.js.map} +1 -1
  223. package/dashboard/dist/assets/{OperationsPage-BSu1o2gB.js → OperationsPage-C03CeU5P.js} +2 -2
  224. package/dashboard/dist/assets/{OperationsPage-BSu1o2gB.js.map → OperationsPage-C03CeU5P.js.map} +1 -1
  225. package/dashboard/dist/assets/{OperatorDashboard-HFI4WGIV.js → OperatorDashboard-BzC134Jt.js} +2 -2
  226. package/dashboard/dist/assets/{OperatorDashboard-HFI4WGIV.js.map → OperatorDashboard-BzC134Jt.js.map} +1 -1
  227. package/dashboard/dist/assets/{PageHeader-BSWIspNB.js → PageHeader-Hx8APPwE.js} +2 -2
  228. package/dashboard/dist/assets/{PageHeader-BSWIspNB.js.map → PageHeader-Hx8APPwE.js.map} +1 -1
  229. package/dashboard/dist/assets/{PageHeaderWithStats-DDjopQ-k.js → PageHeaderWithStats-BEQYYBJv.js} +2 -2
  230. package/dashboard/dist/assets/{PageHeaderWithStats-DDjopQ-k.js.map → PageHeaderWithStats-BEQYYBJv.js.map} +1 -1
  231. package/dashboard/dist/assets/{PersonaDetailPage-D0qlBuGi.js → PersonaDetailPage-D0mY9L6j.js} +2 -2
  232. package/dashboard/dist/assets/{PersonaDetailPage-D0qlBuGi.js.map → PersonaDetailPage-D0mY9L6j.js.map} +1 -1
  233. package/dashboard/dist/assets/{PersonasPage-BJClu-5H.js → PersonasPage-FFlm5Eug.js} +2 -2
  234. package/dashboard/dist/assets/{PersonasPage-BJClu-5H.js.map → PersonasPage-FFlm5Eug.js.map} +1 -1
  235. package/dashboard/dist/assets/{PortalPage-CucNZn_w.js → PortalPage-Cpc25uO-.js} +2 -2
  236. package/dashboard/dist/assets/{PortalPage-CucNZn_w.js.map → PortalPage-Cpc25uO-.js.map} +1 -1
  237. package/dashboard/dist/assets/{ProcessDetailPage-B9wMw0RV.js → ProcessDetailPage-Di2J7KwY.js} +2 -2
  238. package/dashboard/dist/assets/{ProcessDetailPage-B9wMw0RV.js.map → ProcessDetailPage-Di2J7KwY.js.map} +1 -1
  239. package/dashboard/dist/assets/{ProcessesListPage-B6k4RpmR.js → ProcessesListPage-BEXwU3Z0.js} +2 -2
  240. package/dashboard/dist/assets/{ProcessesListPage-B6k4RpmR.js.map → ProcessesListPage-BEXwU3Z0.js.map} +1 -1
  241. package/dashboard/dist/assets/{ResolverForm-ZVufJ4G-.js → ResolverForm-2ks-3jXC.js} +6 -6
  242. package/dashboard/dist/assets/{ResolverForm-ZVufJ4G-.js.map → ResolverForm-2ks-3jXC.js.map} +1 -1
  243. package/dashboard/dist/assets/{RoleDetailPage-CTbq0mz4.js → RoleDetailPage-DqoOk0xc.js} +3 -3
  244. package/dashboard/dist/assets/{RoleDetailPage-CTbq0mz4.js.map → RoleDetailPage-DqoOk0xc.js.map} +1 -1
  245. package/dashboard/dist/assets/{RolePill-CoETDpjF.js → RolePill-R5_ctGFy.js} +2 -2
  246. package/dashboard/dist/assets/{RolePill-CoETDpjF.js.map → RolePill-R5_ctGFy.js.map} +1 -1
  247. package/dashboard/dist/assets/{RolesPage-DBKxeam4.js → RolesPage-CPmo8Srr.js} +2 -2
  248. package/dashboard/dist/assets/{RolesPage-DBKxeam4.js.map → RolesPage-CPmo8Srr.js.map} +1 -1
  249. package/dashboard/dist/assets/{RosterWidget-BkLAwEYB.js → RosterWidget-D2yovCKw.js} +2 -2
  250. package/dashboard/dist/assets/{RosterWidget-BkLAwEYB.js.map → RosterWidget-D2yovCKw.js.map} +1 -1
  251. package/dashboard/dist/assets/{RunAsSelector-D2DC4iDf.js → RunAsSelector-CMv96On6.js} +2 -2
  252. package/dashboard/dist/assets/{RunAsSelector-D2DC4iDf.js.map → RunAsSelector-CMv96On6.js.map} +1 -1
  253. package/dashboard/dist/assets/{ScanCodesPage-BlKleaT0.js → ScanCodesPage-CA6cTT-M.js} +2 -2
  254. package/dashboard/dist/assets/{ScanCodesPage-BlKleaT0.js.map → ScanCodesPage-CA6cTT-M.js.map} +1 -1
  255. package/dashboard/dist/assets/{ScanSchemeDetailPage-CTW6gofi.js → ScanSchemeDetailPage-DnctN5-H.js} +2 -2
  256. package/dashboard/dist/assets/{ScanSchemeDetailPage-CTW6gofi.js.map → ScanSchemeDetailPage-DnctN5-H.js.map} +1 -1
  257. package/dashboard/dist/assets/{ScanStationPage-DPRjSPyT.js → ScanStationPage-Bk8RwkKL.js} +2 -2
  258. package/dashboard/dist/assets/{ScanStationPage-DPRjSPyT.js.map → ScanStationPage-Bk8RwkKL.js.map} +1 -1
  259. package/dashboard/dist/assets/{ScopeBadge-CGsTtqFr.js → ScopeBadge-BXZ084nD.js} +2 -2
  260. package/dashboard/dist/assets/{ScopeBadge-CGsTtqFr.js.map → ScopeBadge-BXZ084nD.js.map} +1 -1
  261. package/dashboard/dist/assets/{StickyPagination-CkmX3-Gu.js → StickyPagination-B0FSuUgs.js} +2 -2
  262. package/dashboard/dist/assets/{StickyPagination-CkmX3-Gu.js.map → StickyPagination-B0FSuUgs.js.map} +1 -1
  263. package/dashboard/dist/assets/{StreamMessageDetail-Xm_n510s.js → StreamMessageDetail-BwZEvMpP.js} +2 -2
  264. package/dashboard/dist/assets/{StreamMessageDetail-Xm_n510s.js.map → StreamMessageDetail-BwZEvMpP.js.map} +1 -1
  265. package/dashboard/dist/assets/{SwimlaneTimeline-De48aJan.js → SwimlaneTimeline-BDVQEaMw.js} +2 -2
  266. package/dashboard/dist/assets/{SwimlaneTimeline-De48aJan.js.map → SwimlaneTimeline-BDVQEaMw.js.map} +1 -1
  267. package/dashboard/dist/assets/{TagInput-S7UuVT_M.js → TagInput-DjPUDp2M.js} +2 -2
  268. package/dashboard/dist/assets/{TagInput-S7UuVT_M.js.map → TagInput-DjPUDp2M.js.map} +1 -1
  269. package/dashboard/dist/assets/{TaskDetailPage-HycMx3O9.js → TaskDetailPage-BOlv3iGB.js} +2 -2
  270. package/dashboard/dist/assets/{TaskDetailPage-HycMx3O9.js.map → TaskDetailPage-BOlv3iGB.js.map} +1 -1
  271. package/dashboard/dist/assets/{TaskQueuePill-BlHNpYiZ.js → TaskQueuePill-D-4Ynf3K.js} +2 -2
  272. package/dashboard/dist/assets/{TaskQueuePill-BlHNpYiZ.js.map → TaskQueuePill-D-4Ynf3K.js.map} +1 -1
  273. package/dashboard/dist/assets/{TasksListPage-OIcFFp1C.js → TasksListPage-e2teY0bD.js} +2 -2
  274. package/dashboard/dist/assets/{TasksListPage-OIcFFp1C.js.map → TasksListPage-e2teY0bD.js.map} +1 -1
  275. package/dashboard/dist/assets/{TimeAgo-OTC_55oZ.js → TimeAgo-Cvkpf_b3.js} +2 -2
  276. package/dashboard/dist/assets/{TimeAgo-OTC_55oZ.js.map → TimeAgo-Cvkpf_b3.js.map} +1 -1
  277. package/dashboard/dist/assets/{TimestampCell-CAwIj_AI.js → TimestampCell-B3btAV0N.js} +2 -2
  278. package/dashboard/dist/assets/{TimestampCell-CAwIj_AI.js.map → TimestampCell-B3btAV0N.js.map} +1 -1
  279. package/dashboard/dist/assets/{ToolPill-D40uLM_v.js → ToolPill-GsKQ80CO.js} +2 -2
  280. package/dashboard/dist/assets/{ToolPill-D40uLM_v.js.map → ToolPill-GsKQ80CO.js.map} +1 -1
  281. package/dashboard/dist/assets/{ToolTestPanel-8Vf6pfw4.js → ToolTestPanel-B03nebR7.js} +2 -2
  282. package/dashboard/dist/assets/{ToolTestPanel-8Vf6pfw4.js.map → ToolTestPanel-B03nebR7.js.map} +1 -1
  283. package/dashboard/dist/assets/{TopicDetailPage-iZW8rK9L.js → TopicDetailPage-DBRWne3O.js} +3 -3
  284. package/dashboard/dist/assets/{TopicDetailPage-iZW8rK9L.js.map → TopicDetailPage-DBRWne3O.js.map} +1 -1
  285. package/dashboard/dist/assets/{TopicsPage-CqiEcj-W.js → TopicsPage-CVe2M9HD.js} +2 -2
  286. package/dashboard/dist/assets/{TopicsPage-CqiEcj-W.js.map → TopicsPage-CVe2M9HD.js.map} +1 -1
  287. package/dashboard/dist/assets/{UserName-DQFjuoib.js → UserName-B_q_qp6V.js} +2 -2
  288. package/dashboard/dist/assets/{UserName-DQFjuoib.js.map → UserName-B_q_qp6V.js.map} +1 -1
  289. package/dashboard/dist/assets/WorkflowExecutionPage-Bh_dr9tM.js +2 -0
  290. package/dashboard/dist/assets/{WorkflowExecutionPage-Di08wCbs.js.map → WorkflowExecutionPage-Bh_dr9tM.js.map} +1 -1
  291. package/dashboard/dist/assets/{WorkflowPill-DJLcK_CM.js → WorkflowPill-D7244fKp.js} +2 -2
  292. package/dashboard/dist/assets/{WorkflowPill-DJLcK_CM.js.map → WorkflowPill-D7244fKp.js.map} +1 -1
  293. package/dashboard/dist/assets/{WorkflowsDashboard-Bb8HlrTJ.js → WorkflowsDashboard-DA6Mj7qH.js} +2 -2
  294. package/dashboard/dist/assets/{WorkflowsDashboard-Bb8HlrTJ.js.map → WorkflowsDashboard-DA6Mj7qH.js.map} +1 -1
  295. package/dashboard/dist/assets/{WorkflowsOverview-Dta1kurk.js → WorkflowsOverview-B1kBLj-a.js} +2 -2
  296. package/dashboard/dist/assets/{WorkflowsOverview-Dta1kurk.js.map → WorkflowsOverview-B1kBLj-a.js.map} +1 -1
  297. package/dashboard/dist/assets/{YamlWorkflowDetailPage-CfAajg68.js → YamlWorkflowDetailPage-6GJM8QIX.js} +8 -8
  298. package/dashboard/dist/assets/{YamlWorkflowDetailPage-CfAajg68.js.map → YamlWorkflowDetailPage-6GJM8QIX.js.map} +1 -1
  299. package/dashboard/dist/assets/{YamlWorkflowsPage-CQFUzT4t.js → YamlWorkflowsPage-Bu811C7f.js} +2 -2
  300. package/dashboard/dist/assets/{YamlWorkflowsPage-CQFUzT4t.js.map → YamlWorkflowsPage-Bu811C7f.js.map} +1 -1
  301. package/dashboard/dist/assets/{agents-PuftRTB2.js → agents-MPk_GnYz.js} +2 -2
  302. package/dashboard/dist/assets/{agents-PuftRTB2.js.map → agents-MPk_GnYz.js.map} +1 -1
  303. package/dashboard/dist/assets/{bots-BmEiPAWY.js → bots-2RihE2Tc.js} +2 -2
  304. package/dashboard/dist/assets/{bots-BmEiPAWY.js.map → bots-2RihE2Tc.js.map} +1 -1
  305. package/dashboard/dist/assets/{capabilities-CRii4Soa.js → capabilities-CC4iwJ1P.js} +2 -2
  306. package/dashboard/dist/assets/{capabilities-CRii4Soa.js.map → capabilities-CC4iwJ1P.js.map} +1 -1
  307. package/dashboard/dist/assets/{controlplane-DO_czaYo.js → controlplane-Bmkic8BH.js} +2 -2
  308. package/dashboard/dist/assets/{controlplane-DO_czaYo.js.map → controlplane-Bmkic8BH.js.map} +1 -1
  309. package/dashboard/dist/assets/{escalation-columns-CzCquCPh.js → escalation-columns-B0lhUUrQ.js} +2 -2
  310. package/dashboard/dist/assets/{escalation-columns-CzCquCPh.js.map → escalation-columns-B0lhUUrQ.js.map} +1 -1
  311. package/dashboard/dist/assets/{escalation-items-Cy0ZgJqV.js → escalation-items-7WFpPo46.js} +2 -2
  312. package/dashboard/dist/assets/{escalation-items-Cy0ZgJqV.js.map → escalation-items-7WFpPo46.js.map} +1 -1
  313. package/dashboard/dist/assets/index-B9uv-euR.css +1 -0
  314. package/dashboard/dist/assets/{index-DhSCCpqM.js → index-B_XV1rwu.js} +2 -2
  315. package/dashboard/dist/assets/{index-DhSCCpqM.js.map → index-B_XV1rwu.js.map} +1 -1
  316. package/dashboard/dist/assets/{index-Cx8xb-oU.js → index-C2CLfGwL.js} +2 -2
  317. package/dashboard/dist/assets/{index-Cx8xb-oU.js.map → index-C2CLfGwL.js.map} +1 -1
  318. package/dashboard/dist/assets/{index-Cga5IW3D.js → index-C3AeFihz.js} +2 -2
  319. package/dashboard/dist/assets/{index-Cga5IW3D.js.map → index-C3AeFihz.js.map} +1 -1
  320. package/dashboard/dist/assets/{index-DiaRlFYI.js → index-CBri8fYM.js} +2 -2
  321. package/dashboard/dist/assets/{index-DiaRlFYI.js.map → index-CBri8fYM.js.map} +1 -1
  322. package/dashboard/dist/assets/{index-CL_1VpGb.js → index-CRWsB7ZC.js} +2 -2
  323. package/dashboard/dist/assets/{index-CL_1VpGb.js.map → index-CRWsB7ZC.js.map} +1 -1
  324. package/dashboard/dist/assets/{index-XntldBd0.js → index-CTOv3G7a.js} +2 -2
  325. package/dashboard/dist/assets/{index-XntldBd0.js.map → index-CTOv3G7a.js.map} +1 -1
  326. package/dashboard/dist/assets/{index-CfP2nKRc.js → index-CcArGkzI.js} +3 -3
  327. package/dashboard/dist/assets/{index-CfP2nKRc.js.map → index-CcArGkzI.js.map} +1 -1
  328. package/dashboard/dist/assets/{index-Dz6R8-Dw.js → index-CkMHS-hG.js} +25 -25
  329. package/dashboard/dist/assets/index-CkMHS-hG.js.map +1 -0
  330. package/dashboard/dist/assets/index-CmsmwCyv.js +2 -0
  331. package/dashboard/dist/assets/{index-4YaDUcKd.js.map → index-CmsmwCyv.js.map} +1 -1
  332. package/dashboard/dist/assets/{index-2SM2_onB.js → index-CvJsvqIc.js} +2 -2
  333. package/dashboard/dist/assets/{index-2SM2_onB.js.map → index-CvJsvqIc.js.map} +1 -1
  334. package/dashboard/dist/assets/{index-Rwqrflm-.js → index-D-ilRyfy.js} +2 -2
  335. package/dashboard/dist/assets/{index-Rwqrflm-.js.map → index-D-ilRyfy.js.map} +1 -1
  336. package/dashboard/dist/assets/{index-CZ7A3AcD.js → index-DSUtfDXx.js} +2 -2
  337. package/dashboard/dist/assets/{index-CZ7A3AcD.js.map → index-DSUtfDXx.js.map} +1 -1
  338. package/dashboard/dist/assets/{index-jL2K6us4.js → index-Da6ycKyf.js} +2 -2
  339. package/dashboard/dist/assets/{index-jL2K6us4.js.map → index-Da6ycKyf.js.map} +1 -1
  340. package/dashboard/dist/assets/{knowledge-CeUqGPuo.js → knowledge-Bpbg20DC.js} +2 -2
  341. package/dashboard/dist/assets/{knowledge-CeUqGPuo.js.map → knowledge-Bpbg20DC.js.map} +1 -1
  342. package/dashboard/dist/assets/machines-BqOZZU-3.js +2 -0
  343. package/dashboard/dist/assets/machines-BqOZZU-3.js.map +1 -0
  344. package/dashboard/dist/assets/{mcp-Cx96NTeD.js → mcp-CmcUXYce.js} +2 -2
  345. package/dashboard/dist/assets/{mcp-Cx96NTeD.js.map → mcp-CmcUXYce.js.map} +1 -1
  346. package/dashboard/dist/assets/{mcp-query-XAzWl0gm.js → mcp-query-C8buQxN9.js} +2 -2
  347. package/dashboard/dist/assets/{mcp-query-XAzWl0gm.js.map → mcp-query-C8buQxN9.js.map} +1 -1
  348. package/dashboard/dist/assets/{personas--4kjwyOw.js → personas-C2n5oDmY.js} +2 -2
  349. package/dashboard/dist/assets/{personas--4kjwyOw.js.map → personas-C2n5oDmY.js.map} +1 -1
  350. package/dashboard/dist/assets/{pipelines-PgkwvG7f.js → pipelines-RKpSkFz7.js} +2 -2
  351. package/dashboard/dist/assets/{pipelines-PgkwvG7f.js.map → pipelines-RKpSkFz7.js.map} +1 -1
  352. package/dashboard/dist/assets/{tasks-CcYxdBa3.js → tasks-Dab4hExW.js} +2 -2
  353. package/dashboard/dist/assets/{tasks-CcYxdBa3.js.map → tasks-Dab4hExW.js.map} +1 -1
  354. package/dashboard/dist/assets/{topics-_lik7cNY.js → topics-FTMNP7r3.js} +2 -2
  355. package/dashboard/dist/assets/{topics-_lik7cNY.js.map → topics-FTMNP7r3.js.map} +1 -1
  356. package/dashboard/dist/assets/{useDebouncedValue-Bm_AoxVx.js → useDebouncedValue-B_1u1YIk.js} +2 -2
  357. package/dashboard/dist/assets/{useDebouncedValue-Bm_AoxVx.js.map → useDebouncedValue-B_1u1YIk.js.map} +1 -1
  358. package/dashboard/dist/assets/{useNamespace-DgXXKdx5.js → useNamespace-HUeAI7Qb.js} +2 -2
  359. package/dashboard/dist/assets/{useNamespace-DgXXKdx5.js.map → useNamespace-HUeAI7Qb.js.map} +1 -1
  360. package/dashboard/dist/assets/{useYamlActivityEvents-Dj2qtGSd.js → useYamlActivityEvents-Cax54qHH.js} +2 -2
  361. package/dashboard/dist/assets/{useYamlActivityEvents-Dj2qtGSd.js.map → useYamlActivityEvents-Cax54qHH.js.map} +1 -1
  362. package/dashboard/dist/assets/{validate-FlXCBBT6.js → validate-DxOaV7QS.js} +2 -2
  363. package/dashboard/dist/assets/{validate-FlXCBBT6.js.map → validate-DxOaV7QS.js.map} +1 -1
  364. package/dashboard/dist/assets/{vendor-icons-DUYcKTjP.js → vendor-icons-fxBvvHBi.js} +187 -182
  365. package/dashboard/dist/assets/vendor-icons-fxBvvHBi.js.map +1 -0
  366. package/dashboard/dist/assets/{yaml-workflows-B0_JxRYQ.js → yaml-workflows-BgY1XHJx.js} +2 -2
  367. package/dashboard/dist/assets/{yaml-workflows-B0_JxRYQ.js.map → yaml-workflows-BgY1XHJx.js.map} +1 -1
  368. package/dashboard/dist/index.html +3 -3
  369. package/docs/architecture.md +1 -0
  370. package/docs/code-owned-configuration.md +6 -0
  371. package/docs/dashboard.md +2 -1
  372. package/docs/events.md +34 -1
  373. package/docs/hitl/lookups.md +6 -4
  374. package/docs/machines.md +114 -28
  375. package/docs/mcp.md +19 -0
  376. package/package.json +1 -1
  377. package/dashboard/dist/assets/AgentsPage-C9UuUKhr.js +0 -2
  378. package/dashboard/dist/assets/AvailableEscalationsPage-DrvfXz70.js +0 -2
  379. package/dashboard/dist/assets/FilterBar-BygWrnB1.js +0 -2
  380. package/dashboard/dist/assets/FilterBar-BygWrnB1.js.map +0 -1
  381. package/dashboard/dist/assets/McpRunDetailPage-80fQn9iX.js +0 -2
  382. package/dashboard/dist/assets/WorkflowExecutionPage-Di08wCbs.js +0 -2
  383. package/dashboard/dist/assets/index-4YaDUcKd.js +0 -2
  384. package/dashboard/dist/assets/index-CnU7Jjz3.css +0 -1
  385. package/dashboard/dist/assets/index-Dz6R8-Dw.js.map +0 -1
  386. package/dashboard/dist/assets/vendor-icons-DUYcKTjP.js.map +0 -1
package/README.md CHANGED
@@ -63,6 +63,12 @@ The `reviewer` role owns a versioned form schema. The platform renders it as the
63
63
 
64
64
  Two surfaces, one model. A `proxyActivity` targets a machine: call it, get a result. `conditional` targets the external world — a reviewer, an operator, a factory cell. It suspends the workflow and writes a single escalation row carrying everything needed to route the work: the `role` that should act, its `type` and `priority`, and any `metadata` to display or filter on. People work that row through an RBAC-scoped surface — find it, claim it, resolve it — from the dashboard, the API, or MCP, and resolving it resumes the workflow exactly where it paused.
65
65
 
66
+ Three kinds of resolver answer the same row:
67
+
68
+ - **People**, on the [dashboard](https://github.com/hotmeshio/long-tail/blob/main/docs/dashboard.md): the role's versioned form is their UI.
69
+ - **Systems and agents**, over the [API](https://github.com/hotmeshio/long-tail/blob/main/docs/api/http/escalations.md) and MCP: the same find, claim and resolve verbs, as a service account.
70
+ - **Machines**, over [MQTT](https://github.com/hotmeshio/long-tail/blob/main/docs/machines.md): a line's gateway claims and resolves as each machine, and the protocol lands on the row as data; the dashboard's Lines view watches the wire, and lines are declared in code or through the API.
71
+
66
72
  Activities are plain functions:
67
73
 
68
74
  ```typescript
@@ -76,7 +82,7 @@ export async function analyzeContent(content: string) {
76
82
 
77
83
  The non-deterministic queue has qualities the deterministic one never needed:
78
84
 
79
- - **RBAC is intrinsic.** The queue is a role; permission lives in the queue itself. Any member answers — a person in the dashboard, a service account through the API — and the workflow is indifferent to which.
85
+ - **RBAC is intrinsic.** The queue is a role; permission lives in the queue itself. Any member answers — a person in the dashboard, a service account through the API, a machine over MQTT — and the workflow is indifferent to which.
80
86
  - **The form is data.** A versioned JSON Schema on the role renders the resolver's UI — fields, validation, conditionals, layout — with zero frontend code. Assign an escalation to one named user with self scope and you have a just-in-time form: one person, one item, one auditable edition.
81
87
  - **Claims are locks.** A claim is a TTL window with an extend prompt before it lapses and a resolve guard behind it — the platform rejects a submission against an expired claim atomically, in the same statement that settles the row. Stale work cannot land.
82
88
  - **Cancel is home.** Cancellation is a first-class settlement, not an exception. When the pressure no longer applies, the waiting flow sees `null` and reconciles to a modeled resting state. Handled is broader than resolved — timeout, cancel, and hop-onward are all endings the loop was built to reach.
@@ -170,6 +176,7 @@ const lt = await start({
170
176
  telemetry: { honeycomb: { apiKey: process.env.HNY } },
171
177
  logging: { pino: { level: 'info' } },
172
178
  maintenance: true,
179
+ machines: { lines: [Machines.loadLine('/etc/line.json')] }, // rows resolved over MQTT; the dashboard gains a Lines view
173
180
  });
174
181
  ```
175
182
 
@@ -246,7 +253,7 @@ All modes share PostgreSQL and scale independently. See [Cloud Deployment](https
246
253
  | [Schema Enforcement](https://github.com/hotmeshio/long-tail/blob/main/docs/schema-enforcement.md) | form_schema as an enforced API contract on every resolve surface |
247
254
  | [Code-Owned Configuration](https://github.com/hotmeshio/long-tail/blob/main/docs/code-owned-configuration.md) | `configSource` — declared config compared and applied at every boot |
248
255
  | [Faceted Routing](https://github.com/hotmeshio/long-tail/blob/main/docs/faceted-routing.md) | Query and atomically claim the queue by facets; dispatcher pattern |
249
- | [Machines](https://github.com/hotmeshio/long-tail/blob/main/docs/machines.md) | `start({ machines })`: machines resolve escalation rows over MQTT, as people do with forms |
256
+ | [Machines](https://github.com/hotmeshio/long-tail/blob/main/docs/machines.md) | `start({ machines })`: machines resolve escalation rows over MQTT, as people do with forms; the Lines view, the line registry API and the machines MCP server |
250
257
  | [SDK](https://github.com/hotmeshio/long-tail/blob/main/docs/sdk.md) | Embedded usage, `createClient`, event subscriptions |
251
258
  | [Architecture](https://github.com/hotmeshio/long-tail/blob/main/docs/architecture.md) | Project structure, conventions, discovery |
252
259
  | [Cloud](https://github.com/hotmeshio/long-tail/blob/main/docs/cloud.md) | AWS ECS, GCP Cloud Run, Docker |
@@ -10,9 +10,14 @@ export declare function getFileMetadata(input: {
10
10
  export declare function deleteFile(input: {
11
11
  filePath: string;
12
12
  }): Promise<LTApiResult>;
13
+ /**
14
+ * Stores the bytes with their SHA-256. A caller that names the digest it
15
+ * expects gets 422 when the bytes received differ, and nothing is stored.
16
+ */
13
17
  export declare function uploadFile(input: {
14
18
  path: string;
15
19
  buffer: Buffer;
20
+ sha256?: string;
16
21
  }): Promise<LTApiResult>;
17
22
  export declare function generateSignedUrl(input: {
18
23
  filePath: string;
@@ -5,6 +5,7 @@ exports.getFileMetadata = getFileMetadata;
5
5
  exports.deleteFile = deleteFile;
6
6
  exports.uploadFile = uploadFile;
7
7
  exports.generateSignedUrl = generateSignedUrl;
8
+ const crypto_1 = require("crypto");
8
9
  const storage_1 = require("../lib/storage");
9
10
  const mime_1 = require("../lib/storage/mime");
10
11
  const publish_1 = require("../lib/events/publish");
@@ -46,9 +47,25 @@ async function deleteFile(input) {
46
47
  return { status: 500, error: err.message };
47
48
  }
48
49
  }
50
+ const SHA256_HEX = /^[0-9a-f]{64}$/i;
51
+ /**
52
+ * Stores the bytes with their SHA-256. A caller that names the digest it
53
+ * expects gets 422 when the bytes received differ, and nothing is stored.
54
+ */
49
55
  async function uploadFile(input) {
56
+ if (input.sha256 !== undefined && !SHA256_HEX.test(input.sha256)) {
57
+ return { status: 400, error: 'sha256 must be 64 hex characters' };
58
+ }
59
+ const sha256 = (0, crypto_1.createHash)('sha256').update(input.buffer).digest('hex');
60
+ if (input.sha256 && input.sha256.toLowerCase() !== sha256) {
61
+ return {
62
+ status: 422,
63
+ error: 'sha256 does not match the bytes received',
64
+ data: { error: 'sha256 does not match the bytes received', path: input.path, expected: input.sha256.toLowerCase(), actual: sha256 },
65
+ };
66
+ }
50
67
  try {
51
- const result = await (0, storage_1.getStorageBackend)().write(input.path, input.buffer);
68
+ const result = await (0, storage_1.getStorageBackend)().write(input.path, input.buffer, { sha256 });
52
69
  const contentType = (0, mime_1.mimeFromPath)(input.path);
53
70
  (0, publish_1.publishFileEvent)({
54
71
  type: 'file.stored',
@@ -58,7 +75,7 @@ async function uploadFile(input) {
58
75
  });
59
76
  return {
60
77
  status: 200,
61
- data: { path: input.path, size: result.size, content_type: contentType },
78
+ data: { path: input.path, size: result.size, content_type: contentType, sha256 },
62
79
  };
63
80
  }
64
81
  catch (err) {
@@ -14,7 +14,8 @@ export declare function getEntry(input: {
14
14
  export declare function getEntryVersion(input: {
15
15
  domain: string;
16
16
  key: string;
17
- version: number;
17
+ /** An edition number, or the label an edition carries. */
18
+ version: number | string;
18
19
  }): Promise<LTApiResult>;
19
20
  export declare function listEntryVersions(input: {
20
21
  domain: string;
@@ -26,6 +27,7 @@ export declare function storeEntry(input: {
26
27
  data: Record<string, any>;
27
28
  tags?: string[];
28
29
  replace?: boolean;
30
+ label?: string;
29
31
  }): Promise<LTApiResult>;
30
32
  export declare function setField(input: {
31
33
  domain: string;
@@ -8,6 +8,9 @@ import type { LTApiResult } from '../types/sdk';
8
8
  * environment block (long-tail + HotMesh versions, Node env/version).
9
9
  *
10
10
  * @param req — the incoming HTTP request, used to derive NATS WS URL from headers when proxying
11
- * @returns `{ status: 200, data: { telemetry, escalation, events, auth, ai, features, search, branding, display, environment } }`
11
+ * `machines` is present only when `start({ machines })` runs a surface; it carries the
12
+ * number of lines this replica runs and nothing else, since the settings are public.
13
+ *
14
+ * @returns `{ status: 200, data: { telemetry, escalation, events, auth, ai, features, search, branding, display, environment, machines? } }`
12
15
  */
13
16
  export declare function getSettings(req?: IncomingMessage): Promise<LTApiResult>;
@@ -12,6 +12,7 @@ const search_1 = require("../modules/search");
12
12
  const branding_1 = require("../modules/branding");
13
13
  const oauth_server_1 = require("../modules/oauth-server");
14
14
  const display_1 = require("../modules/display");
15
+ const machines_1 = require("../modules/machines");
15
16
  const version_1 = require("../modules/version");
16
17
  const sso_1 = require("../modules/sso");
17
18
  const defaults_1 = require("../modules/defaults");
@@ -43,7 +44,10 @@ function resolveNatsWsUrl(adapter, req) {
43
44
  * environment block (long-tail + HotMesh versions, Node env/version).
44
45
  *
45
46
  * @param req — the incoming HTTP request, used to derive NATS WS URL from headers when proxying
46
- * @returns `{ status: 200, data: { telemetry, escalation, events, auth, ai, features, search, branding, display, environment } }`
47
+ * `machines` is present only when `start({ machines })` runs a surface; it carries the
48
+ * number of lines this replica runs and nothing else, since the settings are public.
49
+ *
50
+ * @returns `{ status: 200, data: { telemetry, escalation, events, auth, ai, features, search, branding, display, environment, machines? } }`
47
51
  */
48
52
  async function getSettings(req) {
49
53
  try {
@@ -55,6 +59,7 @@ async function getSettings(req) {
55
59
  // connect via NATS instead of Socket.IO.
56
60
  const forceNats = config_1.config.EVENT_TRANSPORT === 'nats';
57
61
  const transport = forceNats && natsAdapter ? 'nats' : hasSocketIO ? 'socketio' : natsAdapter ? 'nats' : 'none';
62
+ const machines = (0, machines_1.getMachineSurface)();
58
63
  return {
59
64
  status: 200,
60
65
  data: {
@@ -97,6 +102,7 @@ async function getSettings(req) {
97
102
  nodeVersion: process.version,
98
103
  eventTransport: transport,
99
104
  },
105
+ ...(machines ? { machines: { declared: machines.describeLines().length } } : {}),
100
106
  },
101
107
  };
102
108
  }
package/build/index.js CHANGED
@@ -283,15 +283,20 @@ async function main() {
283
283
  : undefined,
284
284
  });
285
285
  }
286
- /** The configured line, spoken to by the codec MACHINE_CODEC_MODULE names (its `createCodec(line)`), or the generic one. */
286
+ /**
287
+ * The configured lines (MACHINE_LINE_CONFIG, one path or several), spoken to by
288
+ * the generic codec, or for one line by the codec MACHINE_CODEC_MODULE names (its `createCodec(line)`).
289
+ */
287
290
  function machinesFromEnv(lineConfig, codecModule) {
288
- const line = (0, line_1.loadLine)(lineConfig);
291
+ const lines = (0, line_1.loadLines)(lineConfig);
289
292
  if (!codecModule)
290
- return { lines: [line] };
293
+ return { lines };
294
+ if (lines.length > 1)
295
+ throw new Error('MACHINE_CODEC_MODULE speaks for one line; MACHINE_LINE_CONFIG names several');
291
296
  const { createCodec } = require(path.resolve(codecModule));
292
297
  if (typeof createCodec !== 'function')
293
298
  throw new Error(`MACHINE_CODEC_MODULE=${codecModule} exports no createCodec(line)`);
294
- return { lines: [line], codec: createCodec(line) };
299
+ return { lines, codec: createCodec(lines[0]) };
295
300
  }
296
301
  // Run server when executed directly
297
302
  if (require.main === module) {
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Serializes multi-statement config writes (role-list replaces, escalation
3
+ * target replaces, line declarations) across concurrently booting containers
4
+ * and live API writes. Single-statement upserts are individually race-safe;
5
+ * the lock exists for the replace transactions and keeps boot reports
6
+ * coherent. Distinct from the migration lock so a slow migration on one
7
+ * container never blocks another's config pass behind two locks at once.
8
+ */
9
+ export declare const CONFIG_APPLY_LOCK_ID = 8675310;
10
+ export declare function withConfigLock<T>(fn: () => Promise<T>): Promise<T>;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CONFIG_APPLY_LOCK_ID = void 0;
4
+ exports.withConfigLock = withConfigLock;
5
+ const index_1 = require("./index");
6
+ /**
7
+ * Serializes multi-statement config writes (role-list replaces, escalation
8
+ * target replaces, line declarations) across concurrently booting containers
9
+ * and live API writes. Single-statement upserts are individually race-safe;
10
+ * the lock exists for the replace transactions and keeps boot reports
11
+ * coherent. Distinct from the migration lock so a slow migration on one
12
+ * container never blocks another's config pass behind two locks at once.
13
+ */
14
+ exports.CONFIG_APPLY_LOCK_ID = 8675310;
15
+ async function withConfigLock(fn) {
16
+ const pool = (0, index_1.getPool)();
17
+ const client = await pool.connect();
18
+ try {
19
+ await client.query(`SELECT pg_advisory_lock(${exports.CONFIG_APPLY_LOCK_ID})`);
20
+ return await fn();
21
+ }
22
+ finally {
23
+ await client
24
+ .query(`SELECT pg_advisory_unlock(${exports.CONFIG_APPLY_LOCK_ID})`)
25
+ .catch(() => { });
26
+ client.release();
27
+ }
28
+ }
@@ -0,0 +1,26 @@
1
+ -- Migration 041: The machine line registry
2
+ --
3
+ -- One row per line a deployment controls: the line definition as the
4
+ -- gateway reads it (site, line, machines in route order), who declared it,
5
+ -- and a version that advances on every change. Lines declared in code
6
+ -- (start({ machines })) are applied here at boot under the configSource
7
+ -- rules; lines declared through PUT /api/machines/lines live here alone.
8
+ -- Every replica reads the registry to know which lines to contend for, and
9
+ -- the Lines index reads it with the pending rows that say how each line is.
10
+ -- search_text is the service's lowercase projection of site, line, machine
11
+ -- ids, processes, roles and addresses, for the index's search.
12
+
13
+ CREATE TABLE IF NOT EXISTS lt_machine_lines (
14
+ site_id TEXT NOT NULL,
15
+ line_id TEXT NOT NULL,
16
+ definition JSONB NOT NULL,
17
+ source TEXT NOT NULL CHECK (source IN ('code', 'api')),
18
+ version INT NOT NULL DEFAULT 1,
19
+ enabled BOOLEAN NOT NULL DEFAULT true,
20
+ search_text TEXT NOT NULL,
21
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
22
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
23
+ PRIMARY KEY (site_id, line_id)
24
+ );
25
+
26
+ CREATE INDEX IF NOT EXISTS lt_machine_lines_site_idx ON lt_machine_lines (site_id, line_id);
@@ -0,0 +1,9 @@
1
+ -- An edition may carry a label: a name a lookup ref pins instead of the
2
+ -- version number (a catalog revision, say). A label names one edition of an
3
+ -- entry; editions without one are reached by number or as current.
4
+ ALTER TABLE lt_knowledge_versions
5
+ ADD COLUMN IF NOT EXISTS label TEXT;
6
+
7
+ CREATE UNIQUE INDEX IF NOT EXISTS lt_knowledge_versions_label_idx
8
+ ON lt_knowledge_versions (domain, key, label)
9
+ WHERE label IS NOT NULL;
@@ -41,13 +41,15 @@ exports.holderView = holderView;
41
41
  /**
42
42
  * What a browser receives of an event. Builders receive events whole. Anyone
43
43
  * else receives enough to route and refresh: escalation events keep their
44
- * routing fields, and every other event arrives without `data` and
45
- * `milestones`. Full records are read through the scoped API, by id.
44
+ * routing fields, machine wire events keep everything but the raw payload,
45
+ * and every other event arrives without `data` and `milestones`. Full
46
+ * records are read through the scoped API, by id.
46
47
  *
47
48
  * Server-side consumers (agent triggers, callbacks) are unaffected: this view
48
49
  * applies only where events leave for a browser.
49
50
  */
50
51
  const ESCALATION_SUBJECT = 'system.escalation.';
52
+ const MACHINE_WIRE_SUBJECT = 'machine.wire.';
51
53
  const ACTIVE_ACCOUNT = 'active';
52
54
  /** Escalation event fields a browser needs to route a refresh and follow a claim. */
53
55
  exports.BROWSER_ESCALATION_FIELDS = [
@@ -69,6 +71,10 @@ function eventForViewer(event, viewer) {
69
71
  }
70
72
  return { ...rest, data: kept };
71
73
  }
74
+ if (typeof event.type === 'string' && event.type.startsWith(MACHINE_WIRE_SUBJECT) && data) {
75
+ const { payload: _payload, ...wire } = data;
76
+ return { ...rest, data: wire };
77
+ }
72
78
  return rest;
73
79
  }
74
80
  /**
@@ -1,4 +1,5 @@
1
1
  import type { LTMilestone } from '../../types';
2
+ import type { WireEvent } from '../../types/machines-view';
2
3
  /**
3
4
  * Publish a milestone event. Called from handleCompletion (workflow
4
5
  * interceptor), ltCompleteTask (orchestrator activity), and the
@@ -124,3 +125,35 @@ export declare function publishWorkflowEvent(params: {
124
125
  status: string;
125
126
  data?: Record<string, any>;
126
127
  }): Promise<void>;
128
+ /** The subject family of every message a line's gateway reads or sends. */
129
+ export declare const MACHINE_WIRE_TYPE = "machine.wire";
130
+ /** The subject family of the gateway log. */
131
+ export declare const MACHINE_LOG_TYPE = "machine.log";
132
+ /** The machine token of a wire event from an address no station claims. */
133
+ export declare const MACHINE_UNKNOWN_TOKEN = "unknown";
134
+ /**
135
+ * Publish one wire record from a line's gateway.
136
+ * Subject: machine.wire.{site}.{line}.{machineId|unknown}.{in|out}
137
+ */
138
+ export declare function publishMachineWireEvent(event: WireEvent): Promise<void>;
139
+ /** The log event as one subject token: `machine_gateway.dispatch.accepted` becomes `dispatch-accepted`. */
140
+ export declare function machineLogToken(event: string): string;
141
+ /**
142
+ * Publish one gateway log entry.
143
+ * Subject: machine.log.{site}.{line}.{event}
144
+ */
145
+ export declare function publishMachineLogEvent(params: {
146
+ siteId: string;
147
+ lineId: string;
148
+ level: 'info' | 'warn' | 'error';
149
+ event: string;
150
+ context?: Record<string, unknown>;
151
+ }): Promise<void>;
152
+ /** A line declared or retired in the registry; every replica reads the row again and follows. */
153
+ export declare function publishMachineLineEvent(params: {
154
+ siteId: string;
155
+ lineId: string;
156
+ source: 'code' | 'api';
157
+ version: number;
158
+ action: 'declared' | 'retired';
159
+ }): Promise<void>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ANNOUNCEMENT_TOPIC = void 0;
3
+ exports.MACHINE_UNKNOWN_TOKEN = exports.MACHINE_LOG_TYPE = exports.MACHINE_WIRE_TYPE = exports.ANNOUNCEMENT_TOPIC = void 0;
4
4
  exports.publishMilestoneEvent = publishMilestoneEvent;
5
5
  exports.publishTaskEvent = publishTaskEvent;
6
6
  exports.publishEscalationEvent = publishEscalationEvent;
@@ -10,6 +10,10 @@ exports.publishKnowledgeEvent = publishKnowledgeEvent;
10
10
  exports.publishFileEvent = publishFileEvent;
11
11
  exports.publishAgentEvent = publishAgentEvent;
12
12
  exports.publishWorkflowEvent = publishWorkflowEvent;
13
+ exports.publishMachineWireEvent = publishMachineWireEvent;
14
+ exports.machineLogToken = machineLogToken;
15
+ exports.publishMachineLogEvent = publishMachineLogEvent;
16
+ exports.publishMachineLineEvent = publishMachineLineEvent;
13
17
  const index_1 = require("./index");
14
18
  const matching_1 = require("./matching");
15
19
  const logger_1 = require("../logger");
@@ -202,3 +206,50 @@ function publishWorkflowEvent(params) {
202
206
  timestamp: new Date().toISOString(),
203
207
  });
204
208
  }
209
+ /** The subject family of every message a line's gateway reads or sends. */
210
+ exports.MACHINE_WIRE_TYPE = 'machine.wire';
211
+ /** The subject family of the gateway log. */
212
+ exports.MACHINE_LOG_TYPE = 'machine.log';
213
+ /** The machine token of a wire event from an address no station claims. */
214
+ exports.MACHINE_UNKNOWN_TOKEN = 'unknown';
215
+ const MACHINE_SOURCE = 'machine-gateway';
216
+ /**
217
+ * Publish one wire record from a line's gateway.
218
+ * Subject: machine.wire.{site}.{line}.{machineId|unknown}.{in|out}
219
+ */
220
+ function publishMachineWireEvent(event) {
221
+ const machine = event.machineId ? (0, matching_1.sanitizeSubjectToken)(event.machineId) : exports.MACHINE_UNKNOWN_TOKEN;
222
+ return fireAndForget({
223
+ type: `${exports.MACHINE_WIRE_TYPE}.${(0, matching_1.sanitizeSubjectToken)(event.siteId)}.${(0, matching_1.sanitizeSubjectToken)(event.lineId)}.${machine}.${event.direction}`,
224
+ source: MACHINE_SOURCE,
225
+ data: event,
226
+ timestamp: event.at,
227
+ });
228
+ }
229
+ const GATEWAY_LOG_PREFIX = 'machine_gateway.';
230
+ /** The log event as one subject token: `machine_gateway.dispatch.accepted` becomes `dispatch-accepted`. */
231
+ function machineLogToken(event) {
232
+ return (0, matching_1.sanitizeSubjectToken)(event.startsWith(GATEWAY_LOG_PREFIX) ? event.slice(GATEWAY_LOG_PREFIX.length) : event);
233
+ }
234
+ /**
235
+ * Publish one gateway log entry.
236
+ * Subject: machine.log.{site}.{line}.{event}
237
+ */
238
+ function publishMachineLogEvent(params) {
239
+ return fireAndForget({
240
+ type: `${exports.MACHINE_LOG_TYPE}.${(0, matching_1.sanitizeSubjectToken)(params.siteId)}.${(0, matching_1.sanitizeSubjectToken)(params.lineId)}.${machineLogToken(params.event)}`,
241
+ source: MACHINE_SOURCE,
242
+ data: { level: params.level, event: params.event, siteId: params.siteId, lineId: params.lineId, ...(params.context ?? {}) },
243
+ timestamp: new Date().toISOString(),
244
+ });
245
+ }
246
+ const MACHINE_LINE_TYPE = 'machine.line';
247
+ /** A line declared or retired in the registry; every replica reads the row again and follows. */
248
+ function publishMachineLineEvent(params) {
249
+ return fireAndForget({
250
+ type: `${MACHINE_LINE_TYPE}.${(0, matching_1.sanitizeSubjectToken)(params.siteId)}.${(0, matching_1.sanitizeSubjectToken)(params.lineId)}.${params.action}`,
251
+ source: MACHINE_SOURCE,
252
+ data: { ...params },
253
+ timestamp: new Date().toISOString(),
254
+ });
255
+ }
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * The line: site, line and the machines on it, in route order, read from a
3
- * JSON file (MACHINE_LINE_CONFIG) or passed in by the host.
3
+ * JSON file or passed in by the host. MACHINE_LINE_CONFIG names one file, or
4
+ * several separated by commas.
4
5
  */
5
6
  import type { LineDef, MachineDef, MachineIdent, MaterialDef, MeasurementDef } from '../../types/machines';
6
7
  export type { LineDef, MachineDef, MaterialDef, MeasurementDef };
@@ -22,6 +23,8 @@ export type CarrierRole = typeof CARRIER_ROLE[keyof typeof CARRIER_ROLE];
22
23
  export declare function validateLine(line: LineDef): LineDef;
23
24
  /** The line at `path` (JSON), or `fallback` when no path is given. */
24
25
  export declare function loadLine(path: string | undefined, fallback?: LineDef): LineDef;
26
+ /** Every line in `paths`, a comma-separated list of JSON files (MACHINE_LINE_CONFIG); each site and line once. */
27
+ export declare function loadLines(paths: string | undefined, fallback?: LineDef): LineDef[];
25
28
  export declare function identOf(line: LineDef, machineId: string): MachineIdent;
26
29
  export declare function machineById(line: LineDef, machineId: string): MachineDef;
27
30
  /** The broker identity of each machine whose address the line declares, {site}-{line}-{address}. */
@@ -32,6 +35,7 @@ export declare function controllerId(line: LineDef): string;
32
35
  export declare function stationRole(process: string): string;
33
36
  export declare const DEFAULT_EXIT_ROLE = "line-exit";
34
37
  export declare const DEFAULT_OPERATOR_ROLE = "line-operator";
38
+ export declare const DEFAULT_QUALITY_ROLE = "line-quality";
35
39
  /** The Long Tail role a machine resolves handoffs under. */
36
40
  export declare function machineRole(def: Pick<MachineDef, 'role' | 'process'>): string;
37
41
  /** Every station role on the line, once each, in route order. */
@@ -42,3 +46,5 @@ export declare function exitRole(line: LineDef): string;
42
46
  export declare function receiverRoles(line: LineDef): string[];
43
47
  /** The role of the person who decides failed handoffs and closes alarm and machine rows. */
44
48
  export declare function operatorRole(line: LineDef): string;
49
+ /** The role of the people who decide units a machine finished on hold: release, rework or scrap. */
50
+ export declare function qualityRole(line: LineDef): string;
@@ -1,13 +1,15 @@
1
1
  "use strict";
2
2
  /**
3
3
  * The line: site, line and the machines on it, in route order, read from a
4
- * JSON file (MACHINE_LINE_CONFIG) or passed in by the host.
4
+ * JSON file or passed in by the host. MACHINE_LINE_CONFIG names one file, or
5
+ * several separated by commas.
5
6
  */
6
7
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.DEFAULT_OPERATOR_ROLE = exports.DEFAULT_EXIT_ROLE = exports.CARRIER_ROLE = exports.ADDRESSING = void 0;
8
+ exports.DEFAULT_QUALITY_ROLE = exports.DEFAULT_OPERATOR_ROLE = exports.DEFAULT_EXIT_ROLE = exports.CARRIER_ROLE = exports.ADDRESSING = void 0;
8
9
  exports.learnsAddress = learnsAddress;
9
10
  exports.validateLine = validateLine;
10
11
  exports.loadLine = loadLine;
12
+ exports.loadLines = loadLines;
11
13
  exports.identOf = identOf;
12
14
  exports.machineById = machineById;
13
15
  exports.clientIds = clientIds;
@@ -18,6 +20,7 @@ exports.stationRoles = stationRoles;
18
20
  exports.exitRole = exitRole;
19
21
  exports.receiverRoles = receiverRoles;
20
22
  exports.operatorRole = operatorRole;
23
+ exports.qualityRole = qualityRole;
21
24
  const fs_1 = require("fs");
22
25
  const protocol_1 = require("./protocol");
23
26
  /** How a line knows its machines' addresses (`LineDef.addressing`). */
@@ -68,6 +71,21 @@ function loadLine(path, fallback) {
68
71
  }
69
72
  return validateLine(JSON.parse((0, fs_1.readFileSync)(path, 'utf8')));
70
73
  }
74
+ /** Every line in `paths`, a comma-separated list of JSON files (MACHINE_LINE_CONFIG); each site and line once. */
75
+ function loadLines(paths, fallback) {
76
+ const list = (paths ?? '').split(',').map((p) => p.trim()).filter(Boolean);
77
+ if (!list.length)
78
+ return [loadLine(undefined, fallback)];
79
+ const lines = list.map((p) => loadLine(p));
80
+ const seen = new Set();
81
+ for (const line of lines) {
82
+ const key = `${line.siteId}/${line.lineId}`;
83
+ if (seen.has(key))
84
+ throw new Error(`line ${key} is declared twice in MACHINE_LINE_CONFIG`);
85
+ seen.add(key);
86
+ }
87
+ return lines;
88
+ }
71
89
  function identOf(line, machineId) {
72
90
  const address = line.machines.find((m) => m.machineId === machineId)?.address;
73
91
  return { siteId: line.siteId, lineId: line.lineId, machineId, ...(address ? { address } : {}) };
@@ -92,6 +110,7 @@ function stationRole(process) {
92
110
  }
93
111
  exports.DEFAULT_EXIT_ROLE = 'line-exit';
94
112
  exports.DEFAULT_OPERATOR_ROLE = 'line-operator';
113
+ exports.DEFAULT_QUALITY_ROLE = 'line-quality';
95
114
  /** The Long Tail role a machine resolves handoffs under. */
96
115
  function machineRole(def) {
97
116
  return def.role ?? stationRole(def.process);
@@ -112,3 +131,7 @@ function receiverRoles(line) {
112
131
  function operatorRole(line) {
113
132
  return line.roles?.operator ?? exports.DEFAULT_OPERATOR_ROLE;
114
133
  }
134
+ /** The role of the people who decide units a machine finished on hold: release, rework or scrap. */
135
+ function qualityRole(line) {
136
+ return line.roles?.quality ?? exports.DEFAULT_QUALITY_ROLE;
137
+ }
@@ -20,6 +20,12 @@ export interface MachineCommand {
20
20
  attempt?: number;
21
21
  /** The command may have reached the machine before: sent earlier, or its row predates this gateway's takeover. */
22
22
  retry?: boolean;
23
+ /**
24
+ * When the command was issued, ISO 8601: the same on every send of this `cmdId`, by this gateway or the
25
+ * next, so a protocol that stamps a time repeats the first attempt. A dispatch or a command row takes the
26
+ * start of its validity round; any other command the time of its first send.
27
+ */
28
+ issuedAt?: string;
23
29
  }
24
30
  /** MQTT filters under each machine's topic, e.g. `job` or `alarm/+`. */
25
31
  export interface CodecChannels {
@@ -71,6 +77,12 @@ export interface LineCodec {
71
77
  * no longer lists has cleared.
72
78
  */
73
79
  readonly retainedAlarms?: boolean;
80
+ /**
81
+ * Commands of the machines' own, beyond the line protocol's control ops, that a machine-command row
82
+ * may ask for. Each is sent through `encode` and the row resolves with the reply. Every entry is a
83
+ * non-empty string; the gateway refuses a codec whose entries are not.
84
+ */
85
+ readonly rowOps?: readonly string[];
74
86
  /** One wire message as zero or more line-protocol messages; empty when the topic is not a machine's. */
75
87
  decode(topic: string, payload: string, retained?: boolean): Inspection[];
76
88
  /** The command as wire messages; none when the machines have no such command, and the gateway then sends nothing. */
@@ -81,6 +93,8 @@ export interface LineCodec {
81
93
  */
82
94
  receipt?(ident: MachineIdent, messageIds: string[]): WireMessage[];
83
95
  }
96
+ /** The codec's own row ops, each a non-empty string; anything else is a misconfigured codec and throws. */
97
+ export declare function declaredRowOps(codec: Pick<LineCodec, 'rowOps'>): readonly string[];
84
98
  export declare const DISPATCH_ON: {
85
99
  readonly CREATED: "created";
86
100
  readonly ARRIVAL: "arrival";
@@ -8,12 +8,21 @@
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.GENERIC_CHANNELS = exports.RECEIPT_FROM = exports.DISPATCH_ON = void 0;
11
+ exports.declaredRowOps = declaredRowOps;
11
12
  exports.topicOf = topicOf;
12
13
  exports.genericCodec = genericCodec;
13
14
  const constants_1 = require("./constants");
14
15
  const contract_1 = require("./contract");
15
16
  const envelope_1 = require("./envelope");
16
17
  const topics_1 = require("./topics");
18
+ /** The codec's own row ops, each a non-empty string; anything else is a misconfigured codec and throws. */
19
+ function declaredRowOps(codec) {
20
+ const ops = codec.rowOps ?? [];
21
+ if (!Array.isArray(ops) || ops.some((op) => typeof op !== 'string' || !op)) {
22
+ throw new Error('codec.rowOps must be a list of non-empty strings');
23
+ }
24
+ return ops;
25
+ }
17
26
  exports.DISPATCH_ON = { CREATED: 'created', ARRIVAL: 'arrival' };
18
27
  /** Which job event counts as the receiver's receipt. */
19
28
  exports.RECEIPT_FROM = { ARRIVED: 'arrived', BOUND: 'bound', STARTED: 'started' };
@@ -74,7 +83,7 @@ function genericCodec(opts) {
74
83
  return receiptFrom === exports.RECEIPT_FROM.ARRIVED ? [seen] : inferReceipt(seen, receiptFrom);
75
84
  },
76
85
  encode(ident, command) {
77
- return [{ topic: (0, topics_1.machineTopic)(opts.root, ident, constants_1.CHANNEL.CMD), payload: JSON.stringify((0, envelope_1.buildEnvelope)(ident, command)) }];
86
+ return [{ topic: (0, topics_1.machineTopic)(opts.root, ident, constants_1.CHANNEL.CMD), payload: JSON.stringify((0, envelope_1.buildEnvelope)(ident, command, { at: command.issuedAt })) }];
78
87
  },
79
88
  };
80
89
  }
@@ -93,7 +93,7 @@ export declare const OP: {
93
93
  readonly CANCEL: "cancel";
94
94
  /** Take work: begin or continue the queue. */
95
95
  readonly START: "start";
96
- /** Finish the current unit, then take no more; the queue is kept. */
96
+ /** Finish the current unit, then take no more; the queue is kept. With `args.jobId`, stop that job at a safe point and hold its units. */
97
97
  readonly STOP: "stop";
98
98
  /** Halt at the next safe point, holding the current unit; nothing new starts. */
99
99
  readonly PAUSE: "pause";
@@ -77,7 +77,7 @@ exports.OP = {
77
77
  CANCEL: 'cancel',
78
78
  /** Take work: begin or continue the queue. */
79
79
  START: 'start',
80
- /** Finish the current unit, then take no more; the queue is kept. */
80
+ /** Finish the current unit, then take no more; the queue is kept. With `args.jobId`, stop that job at a safe point and hold its units. */
81
81
  STOP: 'stop',
82
82
  /** Halt at the next safe point, holding the current unit; nothing new starts. */
83
83
  PAUSE: 'pause',
@@ -17,3 +17,5 @@ export interface Inspection {
17
17
  }
18
18
  /** Validate one message. `retained` is the publisher's flag when the transport reports it. */
19
19
  export declare function inspectMessage(root: string, topic: string, raw: string | Buffer, retained?: boolean): Inspection;
20
+ /** A receiver's report that it could read no id at all: a transfer failure on the read, naming no unit and no carrier. */
21
+ export declare function isUnreadableRead(b: Record<string, any>): boolean;