@hotmeshio/long-tail 0.23.2 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (483) hide show
  1. package/build/adapters/express.d.ts +9 -1
  2. package/build/adapters/express.js +32 -41
  3. package/build/api/auth-sso.d.ts +1 -1
  4. package/build/api/bot-accounts.d.ts +2 -0
  5. package/build/api/bot-accounts.js +4 -0
  6. package/build/api/capabilities.d.ts +7 -2
  7. package/build/api/capabilities.js +13 -2
  8. package/build/api/escalations/analytics.js +5 -0
  9. package/build/api/escalations/bulk.d.ts +2 -0
  10. package/build/api/escalations/bulk.js +9 -4
  11. package/build/api/escalations/helpers.d.ts +5 -0
  12. package/build/api/escalations/helpers.js +7 -0
  13. package/build/api/escalations/metadata.js +3 -0
  14. package/build/api/escalations/single.d.ts +3 -2
  15. package/build/api/escalations/single.js +8 -3
  16. package/build/api/mcp/tools.d.ts +12 -0
  17. package/build/api/mcp/tools.js +113 -9
  18. package/build/api/scan-codes/choice.js +31 -7
  19. package/build/api/settings.js +9 -0
  20. package/build/api/tasks.d.ts +3 -3
  21. package/build/api/tasks.js +30 -7
  22. package/build/api/workflows/input-lookups.js +1 -1
  23. package/build/api/workflows/invocable.js +2 -2
  24. package/build/api/workflows/invocation.js +1 -1
  25. package/build/api/yaml-workflows/deploy.d.ts +10 -2
  26. package/build/api/yaml-workflows/deploy.js +42 -2
  27. package/build/lib/db/schemas/038_oauth_server.sql +46 -0
  28. package/build/lib/events/browser-view.d.ts +15 -0
  29. package/build/lib/events/browser-view.js +101 -0
  30. package/build/lib/events/nats-ws-filter.d.ts +29 -0
  31. package/build/lib/events/nats-ws-filter.js +94 -0
  32. package/build/lib/events/nats-ws-proxy.d.ts +2 -0
  33. package/build/lib/events/nats-ws-proxy.js +39 -5
  34. package/build/lib/events/nats-ws-server-filter.d.ts +16 -0
  35. package/build/lib/events/nats-ws-server-filter.js +56 -0
  36. package/build/lib/events/nats-ws-ticket.d.ts +10 -0
  37. package/build/lib/events/nats-ws-ticket.js +42 -0
  38. package/build/lib/events/socketio.d.ts +10 -1
  39. package/build/lib/events/socketio.js +10 -3
  40. package/build/lib/http/index.d.ts +27 -0
  41. package/build/lib/http/index.js +55 -0
  42. package/build/modules/auth.d.ts +15 -24
  43. package/build/modules/auth.js +43 -126
  44. package/build/modules/capabilities.d.ts +62 -0
  45. package/build/modules/capabilities.js +188 -0
  46. package/build/modules/config.d.ts +14 -0
  47. package/build/modules/config.js +20 -0
  48. package/build/modules/defaults.d.ts +10 -0
  49. package/build/modules/defaults.js +12 -1
  50. package/build/modules/mcp-auth.d.ts +11 -0
  51. package/build/modules/mcp-auth.js +56 -0
  52. package/build/modules/oauth-server.d.ts +18 -0
  53. package/build/modules/oauth-server.js +40 -0
  54. package/build/routes/agents.js +46 -14
  55. package/build/routes/announcements.js +2 -2
  56. package/build/routes/auth-sso.js +2 -2
  57. package/build/routes/auth.js +2 -2
  58. package/build/routes/bot-accounts.js +26 -3
  59. package/build/routes/capabilities.js +4 -4
  60. package/build/routes/controlplane.js +2 -2
  61. package/build/routes/dba.js +2 -2
  62. package/build/routes/delegation.js +2 -2
  63. package/build/routes/diagnostics.js +2 -2
  64. package/build/routes/docs.js +2 -2
  65. package/build/routes/domain.js +2 -2
  66. package/build/routes/escalations/accumulate.d.ts +1 -1
  67. package/build/routes/escalations/acting.d.ts +1 -1
  68. package/build/routes/escalations/analytics.d.ts +1 -1
  69. package/build/routes/escalations/bulk.d.ts +1 -1
  70. package/build/routes/escalations/facets.d.ts +1 -1
  71. package/build/routes/escalations/index.js +2 -2
  72. package/build/routes/escalations/list.d.ts +1 -1
  73. package/build/routes/escalations/metadata.d.ts +1 -1
  74. package/build/routes/escalations/related.d.ts +1 -1
  75. package/build/routes/escalations/resolve.d.ts +1 -1
  76. package/build/routes/escalations/single.d.ts +1 -1
  77. package/build/routes/escalations/single.js +1 -1
  78. package/build/routes/exports.js +14 -13
  79. package/build/routes/file-browser.js +9 -8
  80. package/build/routes/files.js +2 -2
  81. package/build/routes/index.js +4 -2
  82. package/build/routes/insight.js +5 -4
  83. package/build/routes/knowledge.js +2 -2
  84. package/build/routes/maintenance.js +2 -2
  85. package/build/routes/mcp-endpoint.d.ts +3 -1
  86. package/build/routes/mcp-endpoint.js +18 -8
  87. package/build/routes/mcp.js +35 -15
  88. package/build/routes/me.js +2 -2
  89. package/build/routes/namespaces.js +4 -3
  90. package/build/routes/nats-credentials.js +27 -3
  91. package/build/routes/oauth-server/authorize.d.ts +2 -0
  92. package/build/routes/oauth-server/authorize.js +108 -0
  93. package/build/routes/oauth-server/grants.d.ts +2 -0
  94. package/build/routes/oauth-server/grants.js +35 -0
  95. package/build/routes/oauth-server/index.d.ts +8 -0
  96. package/build/routes/oauth-server/index.js +52 -0
  97. package/build/routes/oauth-server/registration.d.ts +2 -0
  98. package/build/routes/oauth-server/registration.js +38 -0
  99. package/build/routes/oauth-server/token.d.ts +2 -0
  100. package/build/routes/oauth-server/token.js +100 -0
  101. package/build/routes/oauth-well-known.d.ts +8 -0
  102. package/build/routes/oauth-well-known.js +31 -0
  103. package/build/routes/oauth.js +2 -2
  104. package/build/routes/overview.js +2 -2
  105. package/build/routes/personas.js +2 -2
  106. package/build/routes/pipelines.js +6 -5
  107. package/build/routes/roles.js +2 -2
  108. package/build/routes/scan-codes.js +2 -2
  109. package/build/routes/settings.js +2 -2
  110. package/build/routes/tasks.js +5 -5
  111. package/build/routes/topics.js +21 -9
  112. package/build/routes/users.js +25 -22
  113. package/build/routes/workflow-sets.js +13 -12
  114. package/build/routes/workflows/config.js +15 -2
  115. package/build/routes/workflows/discovery.js +2 -2
  116. package/build/routes/workflows/index.js +2 -2
  117. package/build/routes/workflows/invocation.js +11 -10
  118. package/build/routes/yaml-workflows/cron.js +19 -6
  119. package/build/routes/yaml-workflows/crud.js +13 -12
  120. package/build/routes/yaml-workflows/deployment.js +11 -10
  121. package/build/routes/yaml-workflows/index.js +2 -2
  122. package/build/routes/yaml-workflows/versions.js +2 -2
  123. package/build/services/agent/authority.d.ts +14 -0
  124. package/build/services/agent/authority.js +53 -0
  125. package/build/services/auth/bot-api-key.d.ts +2 -0
  126. package/build/services/auth/bot-api-key.js +10 -0
  127. package/build/services/auth/oauth-server/access-token.d.ts +36 -0
  128. package/build/services/auth/oauth-server/access-token.js +80 -0
  129. package/build/services/auth/oauth-server/authorization.d.ts +47 -0
  130. package/build/services/auth/oauth-server/authorization.js +54 -0
  131. package/build/services/auth/oauth-server/constants.d.ts +11 -0
  132. package/build/services/auth/oauth-server/constants.js +16 -0
  133. package/build/services/auth/oauth-server/index.d.ts +3 -0
  134. package/build/services/auth/oauth-server/index.js +26 -0
  135. package/build/services/auth/oauth-server/metadata.d.ts +21 -0
  136. package/build/services/auth/oauth-server/metadata.js +53 -0
  137. package/build/services/auth/oauth-server/registration.d.ts +42 -0
  138. package/build/services/auth/oauth-server/registration.js +134 -0
  139. package/build/services/auth/oauth-server/sql.d.ts +34 -0
  140. package/build/services/auth/oauth-server/sql.js +123 -0
  141. package/build/services/auth/oauth-server/store.d.ts +74 -0
  142. package/build/services/auth/oauth-server/store.js +151 -0
  143. package/build/services/auth/sql.d.ts +1 -0
  144. package/build/services/auth/sql.js +3 -1
  145. package/build/services/escalation/queries.js +7 -2
  146. package/build/services/export/index.d.ts +10 -0
  147. package/build/services/export/index.js +27 -0
  148. package/build/services/invocation-access.d.ts +25 -4
  149. package/build/services/invocation-access.js +39 -7
  150. package/build/services/mcp/client/connection-dispatch.d.ts +6 -1
  151. package/build/services/mcp/client/connection-dispatch.js +3 -2
  152. package/build/services/mcp/client/connection-lifecycle.d.ts +10 -2
  153. package/build/services/mcp/client/connection-lifecycle.js +45 -7
  154. package/build/services/mcp/client/connection-test.js +2 -6
  155. package/build/services/mcp/client/connection.d.ts +1 -1
  156. package/build/services/mcp/client/connection.js +3 -1
  157. package/build/services/mcp/client/index.d.ts +2 -2
  158. package/build/services/mcp/client/index.js +4 -1
  159. package/build/services/mcp/client/network-transport.d.ts +12 -0
  160. package/build/services/mcp/client/network-transport.js +20 -0
  161. package/build/services/mcp/client/tools.d.ts +13 -0
  162. package/build/services/mcp/client/tools.js +18 -0
  163. package/build/services/mcp/db-server/index.js +2 -1
  164. package/build/services/mcp/external-server.d.ts +9 -4
  165. package/build/services/mcp/external-server.js +34 -11
  166. package/build/services/mcp/playwright-server/index.js +2 -1
  167. package/build/services/mcp/registered-tools.d.ts +3 -0
  168. package/build/services/mcp/registered-tools.js +7 -0
  169. package/build/services/mcp/server-lifecycle.js +2 -1
  170. package/build/services/workflow-invocation.d.ts +16 -3
  171. package/build/services/workflow-invocation.js +42 -10
  172. package/build/services/yaml-workflow/deployer.d.ts +10 -2
  173. package/build/services/yaml-workflow/deployer.js +17 -5
  174. package/build/services/yaml-workflow/invoke.js +27 -26
  175. package/build/start/config.js +7 -0
  176. package/build/start/index.js +4 -22
  177. package/build/start/server.d.ts +6 -4
  178. package/build/start/server.js +11 -35
  179. package/build/start/socket-auth.js +2 -1
  180. package/build/start/workers.js +1 -1
  181. package/build/system/mcp-servers/admin/agent-subscriptions.js +24 -1
  182. package/build/system/mcp-servers/admin/agents.js +25 -2
  183. package/build/system/mcp-servers/admin/announcements.js +3 -2
  184. package/build/system/mcp-servers/admin/bot-accounts.js +37 -5
  185. package/build/system/mcp-servers/admin/escalations.d.ts +3 -5
  186. package/build/system/mcp-servers/admin/escalations.js +74 -70
  187. package/build/system/mcp-servers/admin/exports.js +7 -1
  188. package/build/system/mcp-servers/admin/index.js +24 -25
  189. package/build/system/mcp-servers/admin/overview.d.ts +2 -2
  190. package/build/system/mcp-servers/admin/run-read.d.ts +2 -0
  191. package/build/system/mcp-servers/admin/run-read.js +5 -0
  192. package/build/system/mcp-servers/admin/scan-codes.d.ts +2 -2
  193. package/build/system/mcp-servers/admin/scan-codes.js +5 -11
  194. package/build/system/mcp-servers/admin/schemas.d.ts +20 -20
  195. package/build/system/mcp-servers/admin/tasks.js +7 -2
  196. package/build/system/mcp-servers/admin/users.js +31 -4
  197. package/build/system/mcp-servers/admin/workflow-config.js +12 -1
  198. package/build/system/mcp-servers/admin/workflows.js +27 -5
  199. package/build/system/mcp-servers/admin/yaml-workflows.js +7 -1
  200. package/build/system/mcp-servers/caller-auth.d.ts +18 -0
  201. package/build/system/mcp-servers/caller-auth.js +29 -0
  202. package/build/system/mcp-servers/claude-code.js +2 -1
  203. package/build/system/mcp-servers/db-query/index.js +2 -1
  204. package/build/system/mcp-servers/file-storage.js +2 -1
  205. package/build/system/mcp-servers/http-fetch.js +2 -1
  206. package/build/system/mcp-servers/human-queue.js +7 -3
  207. package/build/system/mcp-servers/oauth.js +31 -4
  208. package/build/system/mcp-servers/schema-exchange.js +2 -1
  209. package/build/system/mcp-servers/vision.d.ts +1 -0
  210. package/build/system/mcp-servers/vision.js +17 -7
  211. package/build/system/seed/tool-manifests-admin.d.ts +2 -17985
  212. package/build/system/seed/tool-manifests-admin.js +121 -121
  213. package/build/system/seed/tool-manifests-data.d.ts +8 -374
  214. package/build/system/seed/tool-manifests-data.js +22 -4
  215. package/build/system/seed/tool-manifests-escalation.d.ts +2 -352
  216. package/build/system/seed/tool-manifests-escalation.js +11 -1
  217. package/build/system/seed/tool-manifests-events.d.ts +2 -116
  218. package/build/system/seed/tool-manifests-events.js +6 -2
  219. package/build/system/seed/tool-manifests-knowledge.d.ts +2 -221
  220. package/build/system/seed/tool-manifests-knowledge.js +41 -1
  221. package/build/system/seed/tool-manifests-workflows.d.ts +2 -71
  222. package/build/system/seed/tool-manifests-workflows.js +3 -1
  223. package/build/system/workflows/shared/principal-tools.d.ts +20 -0
  224. package/build/system/workflows/shared/principal-tools.js +64 -0
  225. package/build/system/workflows/shared/tool-executor.js +21 -11
  226. package/build/system/workflows/shared/tool-loader.js +8 -1
  227. package/build/tsconfig.tsbuildinfo +1 -1
  228. package/build/types/auth.d.ts +1 -1
  229. package/build/types/capability.d.ts +14 -0
  230. package/build/types/capability.js +2 -0
  231. package/build/types/events.d.ts +1 -1
  232. package/build/types/index.d.ts +3 -1
  233. package/build/types/mcp.d.ts +3 -1
  234. package/build/types/oauth-server.d.ts +52 -0
  235. package/build/types/oauth-server.js +2 -0
  236. package/build/types/startup.d.ts +15 -7
  237. package/build/vitest.config.js +2 -1
  238. package/build/vitest.fast.config.d.ts +2 -0
  239. package/build/vitest.fast.config.js +20 -0
  240. package/build/vitest.llm.config.d.ts +2 -0
  241. package/build/vitest.llm.config.js +16 -0
  242. package/dashboard/dist/assets/{AdminDashboard-BPWsgMfZ.js → AdminDashboard-B3mkMIOT.js} +2 -2
  243. package/dashboard/dist/assets/{AdminDashboard-BPWsgMfZ.js.map → AdminDashboard-B3mkMIOT.js.map} +1 -1
  244. package/dashboard/dist/assets/{AgentConfigPage-De9imyo5.js → AgentConfigPage-CQj2B678.js} +2 -2
  245. package/dashboard/dist/assets/{AgentConfigPage-De9imyo5.js.map → AgentConfigPage-CQj2B678.js.map} +1 -1
  246. package/dashboard/dist/assets/{AgentDetailPage-B6o96Y5G.js → AgentDetailPage-CzrD8JJI.js} +3 -3
  247. package/dashboard/dist/assets/{AgentDetailPage-B6o96Y5G.js.map → AgentDetailPage-CzrD8JJI.js.map} +1 -1
  248. package/dashboard/dist/assets/{AgentsPage-DMEmiK_W.js → AgentsPage-jg2OFwyW.js} +2 -2
  249. package/dashboard/dist/assets/{AgentsPage-DMEmiK_W.js.map → AgentsPage-jg2OFwyW.js.map} +1 -1
  250. package/dashboard/dist/assets/{AvailableEscalationsPage-DeYMngwE.js → AvailableEscalationsPage-IS28XBRe.js} +2 -2
  251. package/dashboard/dist/assets/{AvailableEscalationsPage-DeYMngwE.js.map → AvailableEscalationsPage-IS28XBRe.js.map} +1 -1
  252. package/dashboard/dist/assets/{BotPicker-DDmpgGHZ.js → BotPicker-DvEJFpwS.js} +2 -2
  253. package/dashboard/dist/assets/{BotPicker-DDmpgGHZ.js.map → BotPicker-DvEJFpwS.js.map} +1 -1
  254. package/dashboard/dist/assets/{BulkAssignModal-BqlklomG.js → BulkAssignModal-BoQCi-YC.js} +2 -2
  255. package/dashboard/dist/assets/{BulkAssignModal-BqlklomG.js.map → BulkAssignModal-BoQCi-YC.js.map} +1 -1
  256. package/dashboard/dist/assets/{CapabilitiesPage-DOtjDTbK.js → CapabilitiesPage-kwlrcb_t.js} +2 -2
  257. package/dashboard/dist/assets/{CapabilitiesPage-DOtjDTbK.js.map → CapabilitiesPage-kwlrcb_t.js.map} +1 -1
  258. package/dashboard/dist/assets/{CollapsibleSection-CLr8LP0V.js → CollapsibleSection-UMIV4KIj.js} +2 -2
  259. package/dashboard/dist/assets/{CollapsibleSection-CLr8LP0V.js.map → CollapsibleSection-UMIV4KIj.js.map} +1 -1
  260. package/dashboard/dist/assets/ConfirmDeleteModal-C5puwMg7.js +2 -0
  261. package/dashboard/dist/assets/ConfirmDeleteModal-C5puwMg7.js.map +1 -0
  262. package/dashboard/dist/assets/ConnectedAppsPage-drZa65kP.js +2 -0
  263. package/dashboard/dist/assets/ConnectedAppsPage-drZa65kP.js.map +1 -0
  264. package/dashboard/dist/assets/{CountdownTimer-DxX72PwV.js → CountdownTimer-LG03dVgR.js} +2 -2
  265. package/dashboard/dist/assets/{CountdownTimer-DxX72PwV.js.map → CountdownTimer-LG03dVgR.js.map} +1 -1
  266. package/dashboard/dist/assets/{CredentialsPage-CObc9Rs5.js → CredentialsPage-CaFQ6vLb.js} +2 -2
  267. package/dashboard/dist/assets/{CredentialsPage-CObc9Rs5.js.map → CredentialsPage-CaFQ6vLb.js.map} +1 -1
  268. package/dashboard/dist/assets/{CronLabel-Bb8GoNY5.js → CronLabel-Co5j7tzW.js} +2 -2
  269. package/dashboard/dist/assets/{CronLabel-Bb8GoNY5.js.map → CronLabel-Co5j7tzW.js.map} +1 -1
  270. package/dashboard/dist/assets/{ElapsedCell-CmGhVlYl.js → ElapsedCell-WJyE9G0T.js} +2 -2
  271. package/dashboard/dist/assets/{ElapsedCell-CmGhVlYl.js.map → ElapsedCell-WJyE9G0T.js.map} +1 -1
  272. package/dashboard/dist/assets/{EntityTimelinePanel-B4Jwy1w3.js → EntityTimelinePanel-CDFFfX9d.js} +2 -2
  273. package/dashboard/dist/assets/{EntityTimelinePanel-B4Jwy1w3.js.map → EntityTimelinePanel-CDFFfX9d.js.map} +1 -1
  274. package/dashboard/dist/assets/{EscalationListSchemaPage-CZZbZ4Aa.js → EscalationListSchemaPage-CMrUlaKI.js} +3 -3
  275. package/dashboard/dist/assets/{EscalationListSchemaPage-CZZbZ4Aa.js.map → EscalationListSchemaPage-CMrUlaKI.js.map} +1 -1
  276. package/dashboard/dist/assets/{EscalationSchemaPage-D0ko59_S.js → EscalationSchemaPage-Dx2Lyfrz.js} +2 -2
  277. package/dashboard/dist/assets/{EscalationSchemaPage-D0ko59_S.js.map → EscalationSchemaPage-Dx2Lyfrz.js.map} +1 -1
  278. package/dashboard/dist/assets/{EscalationTimeline-BcnJEKFD.js → EscalationTimeline-d3nvshOk.js} +2 -2
  279. package/dashboard/dist/assets/{EscalationTimeline-BcnJEKFD.js.map → EscalationTimeline-d3nvshOk.js.map} +1 -1
  280. package/dashboard/dist/assets/{EscalationTitleSelect-P0q5sck4.js → EscalationTitleSelect-DWQieOM9.js} +2 -2
  281. package/dashboard/dist/assets/{EscalationTitleSelect-P0q5sck4.js.map → EscalationTitleSelect-DWQieOM9.js.map} +1 -1
  282. package/dashboard/dist/assets/{EscalationsOverview-BLPmh4AF.js → EscalationsOverview-BX8Cpi0X.js} +2 -2
  283. package/dashboard/dist/assets/{EscalationsOverview-BLPmh4AF.js.map → EscalationsOverview-BX8Cpi0X.js.map} +1 -1
  284. package/dashboard/dist/assets/{EventTable-gBzi5tIS.js → EventTable-D1-ITVXS.js} +2 -2
  285. package/dashboard/dist/assets/{EventTable-gBzi5tIS.js.map → EventTable-D1-ITVXS.js.map} +1 -1
  286. package/dashboard/dist/assets/{FilterBar-BulSsWb2.js → FilterBar-ABC9ctin.js} +2 -2
  287. package/dashboard/dist/assets/{FilterBar-BulSsWb2.js.map → FilterBar-ABC9ctin.js.map} +1 -1
  288. package/dashboard/dist/assets/{FormattedValue-BMHRrvrL.js → FormattedValue-k27T4bG7.js} +2 -2
  289. package/dashboard/dist/assets/{FormattedValue-BMHRrvrL.js.map → FormattedValue-k27T4bG7.js.map} +1 -1
  290. package/dashboard/dist/assets/{GraphInvokePage--997yNRr.js → GraphInvokePage-DKUErxWc.js} +2 -2
  291. package/dashboard/dist/assets/{GraphInvokePage--997yNRr.js.map → GraphInvokePage-DKUErxWc.js.map} +1 -1
  292. package/dashboard/dist/assets/{HomePage-CwXFz--v.js → HomePage-C6u9dIpR.js} +2 -2
  293. package/dashboard/dist/assets/{HomePage-CwXFz--v.js.map → HomePage-C6u9dIpR.js.map} +1 -1
  294. package/dashboard/dist/assets/{ListToolbar-Df4qZryJ.js → ListToolbar-gA5rFzkz.js} +2 -2
  295. package/dashboard/dist/assets/{ListToolbar-Df4qZryJ.js.map → ListToolbar-gA5rFzkz.js.map} +1 -1
  296. package/dashboard/dist/assets/{McpOverview-DrogIAKJ.js → McpOverview-BOPo3J_i.js} +2 -2
  297. package/dashboard/dist/assets/{McpOverview-DrogIAKJ.js.map → McpOverview-BOPo3J_i.js.map} +1 -1
  298. package/dashboard/dist/assets/{McpQueryDetailPage-CJmvCAE6.js → McpQueryDetailPage-BRVVi0Zh.js} +2 -2
  299. package/dashboard/dist/assets/{McpQueryDetailPage-CJmvCAE6.js.map → McpQueryDetailPage-BRVVi0Zh.js.map} +1 -1
  300. package/dashboard/dist/assets/{McpQueryPage-lygo4Yq0.js → McpQueryPage-Dmbb6SAc.js} +2 -2
  301. package/dashboard/dist/assets/{McpQueryPage-lygo4Yq0.js.map → McpQueryPage-Dmbb6SAc.js.map} +1 -1
  302. package/dashboard/dist/assets/{McpRunDetailPage-hvns2sCm.js → McpRunDetailPage-bMXNO-6V.js} +2 -2
  303. package/dashboard/dist/assets/{McpRunDetailPage-hvns2sCm.js.map → McpRunDetailPage-bMXNO-6V.js.map} +1 -1
  304. package/dashboard/dist/assets/{McpRunsPage-C2_7spTX.js → McpRunsPage-Bi9AMWja.js} +2 -2
  305. package/dashboard/dist/assets/{McpRunsPage-C2_7spTX.js.map → McpRunsPage-Bi9AMWja.js.map} +1 -1
  306. package/dashboard/dist/assets/{OperationsPage-BlK8WlsY.js → OperationsPage-CvR74ZUJ.js} +3 -3
  307. package/dashboard/dist/assets/{OperationsPage-BlK8WlsY.js.map → OperationsPage-CvR74ZUJ.js.map} +1 -1
  308. package/dashboard/dist/assets/{OperatorDashboard-BeWBiMGX.js → OperatorDashboard-DctmZw10.js} +2 -2
  309. package/dashboard/dist/assets/{OperatorDashboard-BeWBiMGX.js.map → OperatorDashboard-DctmZw10.js.map} +1 -1
  310. package/dashboard/dist/assets/{PersonaDetailPage-CNHpsX_i.js → PersonaDetailPage-Ubqm2rQH.js} +2 -2
  311. package/dashboard/dist/assets/{PersonaDetailPage-CNHpsX_i.js.map → PersonaDetailPage-Ubqm2rQH.js.map} +1 -1
  312. package/dashboard/dist/assets/{PersonasPage-ChASEZRg.js → PersonasPage-BpFL2rpo.js} +2 -2
  313. package/dashboard/dist/assets/{PersonasPage-ChASEZRg.js.map → PersonasPage-BpFL2rpo.js.map} +1 -1
  314. package/dashboard/dist/assets/{PortalPage-D5Lk-PKF.js → PortalPage-Dfc_Q02R.js} +2 -2
  315. package/dashboard/dist/assets/{PortalPage-D5Lk-PKF.js.map → PortalPage-Dfc_Q02R.js.map} +1 -1
  316. package/dashboard/dist/assets/ProcessDetailPage-liJspvQh.js +2 -0
  317. package/dashboard/dist/assets/{ProcessDetailPage-DNgCIwRl.js.map → ProcessDetailPage-liJspvQh.js.map} +1 -1
  318. package/dashboard/dist/assets/{ProcessesListPage-pRjWuWlH.js → ProcessesListPage-C3OM5ZUy.js} +2 -2
  319. package/dashboard/dist/assets/{ProcessesListPage-pRjWuWlH.js.map → ProcessesListPage-C3OM5ZUy.js.map} +1 -1
  320. package/dashboard/dist/assets/ResolverForm-B1_x8Blv.js +8 -0
  321. package/dashboard/dist/assets/ResolverForm-B1_x8Blv.js.map +1 -0
  322. package/dashboard/dist/assets/{RoleDetailPage-Bh_UcfYY.js → RoleDetailPage-CrlYCh-R.js} +2 -2
  323. package/dashboard/dist/assets/{RoleDetailPage-Bh_UcfYY.js.map → RoleDetailPage-CrlYCh-R.js.map} +1 -1
  324. package/dashboard/dist/assets/{RolesPage-CK17N7zz.js → RolesPage-BaazL_pt.js} +2 -2
  325. package/dashboard/dist/assets/{RolesPage-CK17N7zz.js.map → RolesPage-BaazL_pt.js.map} +1 -1
  326. package/dashboard/dist/assets/{RunAsSelector-BEKUP0p2.js → RunAsSelector-DxuV0fa1.js} +2 -2
  327. package/dashboard/dist/assets/{RunAsSelector-BEKUP0p2.js.map → RunAsSelector-DxuV0fa1.js.map} +1 -1
  328. package/dashboard/dist/assets/{ScanCodesPage-Bd0Pflqx.js → ScanCodesPage-C0mvmYTq.js} +2 -2
  329. package/dashboard/dist/assets/{ScanCodesPage-Bd0Pflqx.js.map → ScanCodesPage-C0mvmYTq.js.map} +1 -1
  330. package/dashboard/dist/assets/{ScanSchemeDetailPage-CnuhozmJ.js → ScanSchemeDetailPage-CiJgt5dZ.js} +2 -2
  331. package/dashboard/dist/assets/{ScanSchemeDetailPage-CnuhozmJ.js.map → ScanSchemeDetailPage-CiJgt5dZ.js.map} +1 -1
  332. package/dashboard/dist/assets/{ScanStationPage-CoLc-q3h.js → ScanStationPage-DzGaXc40.js} +2 -2
  333. package/dashboard/dist/assets/{ScanStationPage-CoLc-q3h.js.map → ScanStationPage-DzGaXc40.js.map} +1 -1
  334. package/dashboard/dist/assets/{StickyPagination-COrfvkBi.js → StickyPagination-CqbjVY6T.js} +2 -2
  335. package/dashboard/dist/assets/{StickyPagination-COrfvkBi.js.map → StickyPagination-CqbjVY6T.js.map} +1 -1
  336. package/dashboard/dist/assets/{StreamMessageDetail-Cif2egLy.js → StreamMessageDetail-wX3i0aqs.js} +2 -2
  337. package/dashboard/dist/assets/{StreamMessageDetail-Cif2egLy.js.map → StreamMessageDetail-wX3i0aqs.js.map} +1 -1
  338. package/dashboard/dist/assets/{SwimlaneTimeline-BnZYTrAh.js → SwimlaneTimeline-C50PsFoV.js} +2 -2
  339. package/dashboard/dist/assets/{SwimlaneTimeline-BnZYTrAh.js.map → SwimlaneTimeline-C50PsFoV.js.map} +1 -1
  340. package/dashboard/dist/assets/{TaskDetailPage-DEz_dqyR.js → TaskDetailPage-bbNSv4Ae.js} +2 -2
  341. package/dashboard/dist/assets/{TaskDetailPage-DEz_dqyR.js.map → TaskDetailPage-bbNSv4Ae.js.map} +1 -1
  342. package/dashboard/dist/assets/{TasksListPage-oEfEGj0_.js → TasksListPage-CDWnm_d9.js} +2 -2
  343. package/dashboard/dist/assets/{TasksListPage-oEfEGj0_.js.map → TasksListPage-CDWnm_d9.js.map} +1 -1
  344. package/dashboard/dist/assets/{TimeAgo-Dz5TgZZZ.js → TimeAgo-BLjqlfoX.js} +2 -2
  345. package/dashboard/dist/assets/{TimeAgo-Dz5TgZZZ.js.map → TimeAgo-BLjqlfoX.js.map} +1 -1
  346. package/dashboard/dist/assets/{TimestampCell-BUTgE244.js → TimestampCell-CnW0ENb5.js} +2 -2
  347. package/dashboard/dist/assets/{TimestampCell-BUTgE244.js.map → TimestampCell-CnW0ENb5.js.map} +1 -1
  348. package/dashboard/dist/assets/{ToolTestPanel-BS4g6vt-.js → ToolTestPanel-DkMgCB-k.js} +2 -2
  349. package/dashboard/dist/assets/{ToolTestPanel-BS4g6vt-.js.map → ToolTestPanel-DkMgCB-k.js.map} +1 -1
  350. package/dashboard/dist/assets/{TopicDetailPage-C_I6JIVD.js → TopicDetailPage-g3pljKKX.js} +2 -2
  351. package/dashboard/dist/assets/{TopicDetailPage-C_I6JIVD.js.map → TopicDetailPage-g3pljKKX.js.map} +1 -1
  352. package/dashboard/dist/assets/{TopicsPage-Cr6-wfhJ.js → TopicsPage-CVcCYdy-.js} +2 -2
  353. package/dashboard/dist/assets/{TopicsPage-Cr6-wfhJ.js.map → TopicsPage-CVcCYdy-.js.map} +1 -1
  354. package/dashboard/dist/assets/{UserName-ZFpWMaFF.js → UserName-D6zGIK2i.js} +2 -2
  355. package/dashboard/dist/assets/{UserName-ZFpWMaFF.js.map → UserName-D6zGIK2i.js.map} +1 -1
  356. package/dashboard/dist/assets/{WorkflowExecutionPage-ByPixDZW.js → WorkflowExecutionPage-B8g81FCJ.js} +2 -2
  357. package/dashboard/dist/assets/{WorkflowExecutionPage-ByPixDZW.js.map → WorkflowExecutionPage-B8g81FCJ.js.map} +1 -1
  358. package/dashboard/dist/assets/{WorkflowsDashboard-CWsJdMdR.js → WorkflowsDashboard-nxT3bv6W.js} +2 -2
  359. package/dashboard/dist/assets/{WorkflowsDashboard-CWsJdMdR.js.map → WorkflowsDashboard-nxT3bv6W.js.map} +1 -1
  360. package/dashboard/dist/assets/{WorkflowsOverview-Dk9gyqZN.js → WorkflowsOverview-grI-KAI2.js} +2 -2
  361. package/dashboard/dist/assets/{WorkflowsOverview-Dk9gyqZN.js.map → WorkflowsOverview-grI-KAI2.js.map} +1 -1
  362. package/dashboard/dist/assets/{YamlWorkflowDetailPage-CHwcrsaT.js → YamlWorkflowDetailPage-BoZ-hfBE.js} +2 -2
  363. package/dashboard/dist/assets/{YamlWorkflowDetailPage-CHwcrsaT.js.map → YamlWorkflowDetailPage-BoZ-hfBE.js.map} +1 -1
  364. package/dashboard/dist/assets/{YamlWorkflowsPage-B5jRX2Ph.js → YamlWorkflowsPage-Bf04rwRv.js} +2 -2
  365. package/dashboard/dist/assets/{YamlWorkflowsPage-B5jRX2Ph.js.map → YamlWorkflowsPage-Bf04rwRv.js.map} +1 -1
  366. package/dashboard/dist/assets/{agents-Dd7E-27d.js → agents-Dphpdi8l.js} +2 -2
  367. package/dashboard/dist/assets/{agents-Dd7E-27d.js.map → agents-Dphpdi8l.js.map} +1 -1
  368. package/dashboard/dist/assets/{bots-CpaYjZTk.js → bots-DIFE298x.js} +2 -2
  369. package/dashboard/dist/assets/{bots-CpaYjZTk.js.map → bots-DIFE298x.js.map} +1 -1
  370. package/dashboard/dist/assets/{capabilities-CNjg_qv1.js → capabilities-D7Y7LClY.js} +2 -2
  371. package/dashboard/dist/assets/{capabilities-CNjg_qv1.js.map → capabilities-D7Y7LClY.js.map} +1 -1
  372. package/dashboard/dist/assets/{controlplane-DgmvnAtU.js → controlplane-D1TGcYsS.js} +2 -2
  373. package/dashboard/dist/assets/{controlplane-DgmvnAtU.js.map → controlplane-D1TGcYsS.js.map} +1 -1
  374. package/dashboard/dist/assets/{escalation-columns-Uj4U9g5H.js → escalation-columns-cwZE6xyo.js} +2 -2
  375. package/dashboard/dist/assets/{escalation-columns-Uj4U9g5H.js.map → escalation-columns-cwZE6xyo.js.map} +1 -1
  376. package/dashboard/dist/assets/{index-x5z73M9N.js → index-BzYcUPdD.js} +2 -2
  377. package/dashboard/dist/assets/{index-x5z73M9N.js.map → index-BzYcUPdD.js.map} +1 -1
  378. package/dashboard/dist/assets/index-CeCtqujG.js +67 -0
  379. package/dashboard/dist/assets/index-CeCtqujG.js.map +1 -0
  380. package/dashboard/dist/assets/{index-RIFT3RlO.js → index-ChV7pBjM.js} +2 -2
  381. package/dashboard/dist/assets/{index-RIFT3RlO.js.map → index-ChV7pBjM.js.map} +1 -1
  382. package/dashboard/dist/assets/{index-OfO0173w.js → index-CniRa65p.js} +2 -2
  383. package/dashboard/dist/assets/{index-OfO0173w.js.map → index-CniRa65p.js.map} +1 -1
  384. package/dashboard/dist/assets/{index-ByBy9M3L.js → index-CxdjT1Yk.js} +2 -2
  385. package/dashboard/dist/assets/{index-ByBy9M3L.js.map → index-CxdjT1Yk.js.map} +1 -1
  386. package/dashboard/dist/assets/{index-C_K7OlzT.js → index-DAvi5_2T.js} +2 -2
  387. package/dashboard/dist/assets/{index-C_K7OlzT.js.map → index-DAvi5_2T.js.map} +1 -1
  388. package/dashboard/dist/assets/{index-BrwqtXRh.js → index-DN-kX7hL.js} +2 -2
  389. package/dashboard/dist/assets/{index-BrwqtXRh.js.map → index-DN-kX7hL.js.map} +1 -1
  390. package/dashboard/dist/assets/index-Dl_8hbYI.js +2 -0
  391. package/dashboard/dist/assets/index-Dl_8hbYI.js.map +1 -0
  392. package/dashboard/dist/assets/{index-D4Dlznn9.js → index-DpKOr311.js} +2 -2
  393. package/dashboard/dist/assets/{index-D4Dlznn9.js.map → index-DpKOr311.js.map} +1 -1
  394. package/dashboard/dist/assets/{index-CnOvJz6U.js → index-Dy1wWu2e.js} +2 -2
  395. package/dashboard/dist/assets/{index-CnOvJz6U.js.map → index-Dy1wWu2e.js.map} +1 -1
  396. package/dashboard/dist/assets/{index-BT1Ms5Q5.js → index-HLu98Sqh.js} +2 -2
  397. package/dashboard/dist/assets/{index-BT1Ms5Q5.js.map → index-HLu98Sqh.js.map} +1 -1
  398. package/dashboard/dist/assets/{index-BFASQ7_X.js → index-ag2pCAPu.js} +2 -2
  399. package/dashboard/dist/assets/{index-BFASQ7_X.js.map → index-ag2pCAPu.js.map} +1 -1
  400. package/dashboard/dist/assets/{index-BsHVgWH6.js → index-gkxPN7Vx.js} +2 -2
  401. package/dashboard/dist/assets/{index-BsHVgWH6.js.map → index-gkxPN7Vx.js.map} +1 -1
  402. package/dashboard/dist/assets/index-m9A3UYst.css +1 -0
  403. package/dashboard/dist/assets/{knowledge-Cci_r6Kl.js → knowledge-DnMs-SOJ.js} +2 -2
  404. package/dashboard/dist/assets/{knowledge-Cci_r6Kl.js.map → knowledge-DnMs-SOJ.js.map} +1 -1
  405. package/dashboard/dist/assets/{mcp-NY4iL0L-.js → mcp-CwW-K3r4.js} +2 -2
  406. package/dashboard/dist/assets/{mcp-NY4iL0L-.js.map → mcp-CwW-K3r4.js.map} +1 -1
  407. package/dashboard/dist/assets/{mcp-query-CbvZo_I_.js → mcp-query-BZt5e8_Q.js} +2 -2
  408. package/dashboard/dist/assets/{mcp-query-CbvZo_I_.js.map → mcp-query-BZt5e8_Q.js.map} +1 -1
  409. package/dashboard/dist/assets/{personas-Fy-f7QQd.js → personas-UA-Xn60f.js} +2 -2
  410. package/dashboard/dist/assets/{personas-Fy-f7QQd.js.map → personas-UA-Xn60f.js.map} +1 -1
  411. package/dashboard/dist/assets/{pipelines-DKiuozxV.js → pipelines-Cu3PARum.js} +2 -2
  412. package/dashboard/dist/assets/{pipelines-DKiuozxV.js.map → pipelines-Cu3PARum.js.map} +1 -1
  413. package/dashboard/dist/assets/{tasks-CdM1Rkk9.js → tasks-BO6h8GJE.js} +2 -2
  414. package/dashboard/dist/assets/{tasks-CdM1Rkk9.js.map → tasks-BO6h8GJE.js.map} +1 -1
  415. package/dashboard/dist/assets/{topics-XNy2mf3n.js → topics-CWjCR-17.js} +2 -2
  416. package/dashboard/dist/assets/{topics-XNy2mf3n.js.map → topics-CWjCR-17.js.map} +1 -1
  417. package/dashboard/dist/assets/{useDebouncedValue-CyGcU3_S.js → useDebouncedValue-6t0jx1RB.js} +2 -2
  418. package/dashboard/dist/assets/{useDebouncedValue-CyGcU3_S.js.map → useDebouncedValue-6t0jx1RB.js.map} +1 -1
  419. package/dashboard/dist/assets/{useNamespace-C2RIh_IN.js → useNamespace-CqpoQx6D.js} +2 -2
  420. package/dashboard/dist/assets/{useNamespace-C2RIh_IN.js.map → useNamespace-CqpoQx6D.js.map} +1 -1
  421. package/dashboard/dist/assets/{useYamlActivityEvents-CDiV5fjf.js → useYamlActivityEvents-hmCQQwzB.js} +2 -2
  422. package/dashboard/dist/assets/{useYamlActivityEvents-CDiV5fjf.js.map → useYamlActivityEvents-hmCQQwzB.js.map} +1 -1
  423. package/dashboard/dist/assets/{validate-DcGWN82Y.js → validate-BIRn4a6d.js} +2 -2
  424. package/dashboard/dist/assets/{validate-DcGWN82Y.js.map → validate-BIRn4a6d.js.map} +1 -1
  425. package/dashboard/dist/assets/{yaml-workflows-CH8UrouH.js → yaml-workflows-ziUdZhKY.js} +2 -2
  426. package/dashboard/dist/assets/{yaml-workflows-CH8UrouH.js.map → yaml-workflows-ziUdZhKY.js.map} +1 -1
  427. package/dashboard/dist/index.html +2 -2
  428. package/docs/agents.md +3 -1
  429. package/docs/api/http/agents.md +15 -1
  430. package/docs/api/http/escalations.md +3 -3
  431. package/docs/api/http/exports.md +3 -1
  432. package/docs/api/http/file-browser.md +3 -1
  433. package/docs/api/http/mcp-endpoint.md +5 -2
  434. package/docs/api/http/mcp-servers.md +34 -4
  435. package/docs/api/http/namespaces.md +2 -0
  436. package/docs/api/http/pipelines.md +2 -0
  437. package/docs/api/http/roles.md +11 -8
  438. package/docs/api/http/service-accounts.md +8 -2
  439. package/docs/api/http/settings.md +29 -2
  440. package/docs/api/http/tasks.md +3 -1
  441. package/docs/api/http/topics.md +7 -1
  442. package/docs/api/http/users.md +8 -2
  443. package/docs/api/http/workflows.md +25 -10
  444. package/docs/api/http/yaml-workflows.md +21 -0
  445. package/docs/api/mcp/admin.md +409 -49
  446. package/docs/api/mcp/file-storage.md +4 -0
  447. package/docs/api/mcp/http-fetch.md +6 -2
  448. package/docs/api/mcp/human-queue.md +53 -0
  449. package/docs/api/mcp/index.md +13 -10
  450. package/docs/api/mcp/knowledge.md +34 -0
  451. package/docs/api/mcp/oauth.md +1 -1
  452. package/docs/api/mcp/ortho.md +113 -0
  453. package/docs/api/mcp/vision.md +1 -1
  454. package/docs/api/sdk/bot-accounts.md +1 -0
  455. package/docs/api/sdk/escalations.md +2 -2
  456. package/docs/api/sdk/mcp.md +2 -2
  457. package/docs/api/sdk/settings.md +1 -1
  458. package/docs/api/sdk/tasks.md +2 -2
  459. package/docs/api/sdk/workflows.md +2 -2
  460. package/docs/api/sdk/yaml-workflows.md +1 -1
  461. package/docs/architecture.md +3 -1
  462. package/docs/auth.md +3 -2
  463. package/docs/cloud.md +7 -2
  464. package/docs/dashboard.md +16 -7
  465. package/docs/data.md +1 -1
  466. package/docs/escalation-strategies.md +9 -20
  467. package/docs/events.md +6 -0
  468. package/docs/iam.md +7 -5
  469. package/docs/mcp.md +159 -210
  470. package/docs/oauth-and-delegation.md +32 -21
  471. package/docs/topics.md +2 -0
  472. package/docs/workflows.md +14 -112
  473. package/package.json +5 -3
  474. package/dashboard/dist/assets/ConfirmDeleteModal-DW4DrPur.js +0 -2
  475. package/dashboard/dist/assets/ConfirmDeleteModal-DW4DrPur.js.map +0 -1
  476. package/dashboard/dist/assets/ProcessDetailPage-DNgCIwRl.js +0 -2
  477. package/dashboard/dist/assets/ResolverForm-CKIOAGtY.js +0 -8
  478. package/dashboard/dist/assets/ResolverForm-CKIOAGtY.js.map +0 -1
  479. package/dashboard/dist/assets/index-CtlBjl8o.js +0 -2
  480. package/dashboard/dist/assets/index-CtlBjl8o.js.map +0 -1
  481. package/dashboard/dist/assets/index-LRYC__mE.js +0 -67
  482. package/dashboard/dist/assets/index-LRYC__mE.js.map +0 -1
  483. package/dashboard/dist/assets/index-MYI2_Xb3.css +0 -1
@@ -47,7 +47,7 @@ export declare function listTasks(input: {
47
47
  origin_id?: string;
48
48
  limit?: number;
49
49
  offset?: number;
50
- }): Promise<LTApiResult>;
50
+ }, auth?: LTApiAuth): Promise<LTApiResult>;
51
51
  /**
52
52
  * Return aggregate process statistics.
53
53
  *
@@ -82,7 +82,7 @@ export declare function listProcesses(input: {
82
82
  */
83
83
  export declare function getProcess(input: {
84
84
  originId: string;
85
- }): Promise<LTApiResult>;
85
+ }, auth?: LTApiAuth): Promise<LTApiResult>;
86
86
  /**
87
87
  * Get a single task by ID.
88
88
  *
@@ -91,4 +91,4 @@ export declare function getProcess(input: {
91
91
  */
92
92
  export declare function getTask(input: {
93
93
  id: string;
94
- }): Promise<LTApiResult>;
94
+ }, auth?: LTApiAuth): Promise<LTApiResult>;
@@ -41,6 +41,24 @@ exports.getProcess = getProcess;
41
41
  exports.getTask = getTask;
42
42
  const taskService = __importStar(require("../services/task"));
43
43
  const escalationService = __importStar(require("../services/escalation"));
44
+ const helpers_1 = require("./escalations/helpers");
45
+ const capabilities_1 = require("../modules/capabilities");
46
+ /**
47
+ * How a caller sees task rows. A builder, and the person a run was started by
48
+ * or runs as, see the whole row; anyone else sees it without the run's input
49
+ * (`envelope`), output (`data`) and `metadata`. An in-process call (no auth)
50
+ * sees whole rows.
51
+ */
52
+ async function taskViewFor(auth) {
53
+ if (!auth?.userId || (await (0, capabilities_1.mayBuild)(auth)))
54
+ return (task) => task;
55
+ return (task) => {
56
+ if (task.initiated_by === auth.userId || task.executing_as === auth.userId)
57
+ return task;
58
+ const { envelope: _envelope, data: _data, metadata: _metadata, ...rest } = task;
59
+ return rest;
60
+ };
61
+ }
44
62
  /**
45
63
  * Create a task record.
46
64
  *
@@ -104,10 +122,10 @@ async function createTask(input, auth) {
104
122
  * @param input.offset — pagination offset (default: 0)
105
123
  * @returns `{ status: 200, data: { tasks, total } }`
106
124
  */
107
- async function listTasks(input) {
125
+ async function listTasks(input, auth) {
108
126
  try {
109
- const result = await taskService.listTasks(input);
110
- return { status: 200, data: result };
127
+ const [result, view] = await Promise.all([taskService.listTasks(input), taskViewFor(auth)]);
128
+ return { status: 200, data: { ...result, tasks: result.tasks.map(view) } };
111
129
  }
112
130
  catch (err) {
113
131
  return { status: 500, error: err.message };
@@ -153,12 +171,17 @@ async function listProcesses(input) {
153
171
  * @param input.originId — root process origin ID
154
172
  * @returns `{ status: 200, data: { origin_id, tasks, escalations } }`
155
173
  */
156
- async function getProcess(input) {
174
+ async function getProcess(input, auth) {
157
175
  try {
158
- const [tasks, escalations] = await Promise.all([
176
+ const [rows, all, view] = await Promise.all([
159
177
  taskService.getProcessTasks(input.originId),
160
178
  escalationService.getEscalationsByOriginId(input.originId),
179
+ taskViewFor(auth),
161
180
  ]);
181
+ const tasks = rows.map(view);
182
+ // With a caller, only the escalations that caller may read.
183
+ const scope = auth?.userId ? await (0, helpers_1.getEscalationReadScope)(auth.userId) : null;
184
+ const escalations = scope ? all.filter((e) => (0, helpers_1.scopeAdmits)(scope, auth.userId, e)) : all;
162
185
  return {
163
186
  status: 200,
164
187
  data: { origin_id: input.originId, tasks, escalations },
@@ -174,13 +197,13 @@ async function getProcess(input) {
174
197
  * @param input.id — task UUID
175
198
  * @returns `{ status: 200, data: <task record> }` or 404
176
199
  */
177
- async function getTask(input) {
200
+ async function getTask(input, auth) {
178
201
  try {
179
202
  const task = await taskService.getTask(input.id);
180
203
  if (!task) {
181
204
  return { status: 404, error: 'Task not found' };
182
205
  }
183
- return { status: 200, data: task };
206
+ return { status: 200, data: (await taskViewFor(auth))(task) };
184
207
  }
185
208
  catch (err) {
186
209
  return { status: 500, error: err.message };
@@ -57,7 +57,7 @@ async function getWorkflowInputLookups(input, auth) {
57
57
  return { status: 404, error: 'Workflow config not found' };
58
58
  }
59
59
  const user = auth.userId ? await userService.getUser(auth.userId) : null;
60
- if (!(0, invocation_access_1.canInvokeWorkflow)(config, user?.roles ?? [], auth.role)) {
60
+ if (!(0, invocation_access_1.canInvokeWorkflow)(config, user?.roles ?? [])) {
61
61
  return { status: 403, error: 'Not authorized to invoke this workflow' };
62
62
  }
63
63
  const lookups = await (0, knowledge_1.resolveLookupRefs)(config.input_lookups ?? []);
@@ -88,9 +88,9 @@ async function listInvocableWorkflows(auth) {
88
88
  ]);
89
89
  const roles = user?.roles ?? [];
90
90
  const workflows = configs
91
- .filter((c) => (0, invocation_access_1.canInvokeWorkflow)(c, roles, auth.role))
91
+ .filter((c) => (0, invocation_access_1.canInvokeWorkflow)(c, roles))
92
92
  .map((c) => ({ ...c, tier: tierOf(c) }));
93
- if ((0, invocation_access_1.hasGlobalInvocationAccess)(roles, auth.role)) {
93
+ if ((0, invocation_access_1.hasGlobalInvocationAccess)(roles)) {
94
94
  const registered = new Set(configs.map((c) => c.workflow_type));
95
95
  for (const [name, { taskQueue }] of (0, registry_1.getRegisteredWorkers)()) {
96
96
  if (registered.has(name) || registry_1.SYSTEM_WORKFLOWS.has(name))
@@ -62,7 +62,7 @@ function isResolveError(err) {
62
62
  */
63
63
  async function invokeWorkflow(input, auth) {
64
64
  try {
65
- await (0, workflow_invocation_1.checkInvocationRoles)(input.type, auth.userId, auth.role);
65
+ await (0, workflow_invocation_1.authorizeInvocation)({ workflowType: input.type, userId: auth.userId, executeAs: input.execute_as });
66
66
  const config = await configService.getWorkflowConfig(input.type);
67
67
  const violation = await (0, input_validation_1.checkInvokeInput)(config, input.data, input.metadata);
68
68
  if (violation)
@@ -1,3 +1,11 @@
1
+ import type { LTYamlWorkflowRecord } from '../../types/yaml-workflow';
2
+ /**
3
+ * A compiled workflow's tool steps run with lt-system authority. Deploying or
4
+ * activating one needs the caller to be able to call every built-in tool it
5
+ * uses: automation never does more than its author may. Null when allowed;
6
+ * without a caller (in-process), allowed.
7
+ */
8
+ export declare function deployRefusal(wf: LTYamlWorkflowRecord, auth: LTApiAuth | undefined): Promise<LTApiResult | null>;
1
9
  import type { LTApiResult, LTApiAuth } from '../../types/sdk';
2
10
  /**
3
11
  * Deploy a YAML workflow and all sibling workflows sharing its app_id namespace.
@@ -11,7 +19,7 @@ import type { LTApiResult, LTApiAuth } from '../../types/sdk';
11
19
  */
12
20
  export declare function deployYamlWorkflow(input: {
13
21
  id: string;
14
- }): Promise<LTApiResult>;
22
+ }, auth?: LTApiAuth): Promise<LTApiResult>;
15
23
  /**
16
24
  * Activate a previously deployed YAML workflow and its app_id siblings.
17
25
  *
@@ -24,7 +32,7 @@ export declare function deployYamlWorkflow(input: {
24
32
  */
25
33
  export declare function activateYamlWorkflow(input: {
26
34
  id: string;
27
- }): Promise<LTApiResult>;
35
+ }, auth?: LTApiAuth): Promise<LTApiResult>;
28
36
  /**
29
37
  * Invoke an active YAML workflow, executing its DAG pipeline.
30
38
  *
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.deployRefusal = deployRefusal;
36
37
  exports.deployYamlWorkflow = deployYamlWorkflow;
37
38
  exports.activateYamlWorkflow = activateYamlWorkflow;
38
39
  exports.invokeYamlWorkflow = invokeYamlWorkflow;
@@ -42,6 +43,32 @@ const yamlDb = __importStar(require("../../services/yaml-workflow/db"));
42
43
  const yamlDeployer = __importStar(require("../../services/yaml-workflow/deployer"));
43
44
  const yamlWorkers = __importStar(require("../../services/yaml-workflow/workers"));
44
45
  const invoke_1 = require("../../services/yaml-workflow/invoke");
46
+ const workflow_invocation_1 = require("../../services/workflow-invocation");
47
+ const capabilities_1 = require("../../modules/capabilities");
48
+ const tools_1 = require("../mcp/tools");
49
+ /**
50
+ * A compiled workflow's tool steps run with lt-system authority. Deploying or
51
+ * activating one needs the caller to be able to call every built-in tool it
52
+ * uses: automation never does more than its author may. Null when allowed;
53
+ * without a caller (in-process), allowed.
54
+ */
55
+ async function deployRefusal(wf, auth) {
56
+ if (!auth?.userId)
57
+ return null;
58
+ const access = (0, capabilities_1.capabilityAccess)({ userId: auth.userId });
59
+ // A deploy publishes every workflow sharing the app id, so every one is checked.
60
+ const siblings = await yamlDb.listYamlWorkflowsByAppId(wf.app_id);
61
+ const steps = [wf, ...siblings.filter((w) => w.id !== wf.id)].flatMap((w) => w.activity_manifest ?? []);
62
+ for (const step of steps) {
63
+ if (step.tool_source !== 'mcp' || !step.mcp_server_id || !step.mcp_tool_name)
64
+ continue;
65
+ const builtin = await (0, tools_1.builtinServerFor)(step.mcp_server_id);
66
+ if (builtin && !(await access((0, tools_1.builtinToolGate)(builtin, step.mcp_tool_name)))) {
67
+ return { status: 403, error: `Forbidden: this workflow calls ${step.mcp_tool_name}, which is not available to you` };
68
+ }
69
+ }
70
+ return null;
71
+ }
45
72
  const helpers_1 = require("./helpers");
46
73
  /**
47
74
  * Deploy a YAML workflow and all sibling workflows sharing its app_id namespace.
@@ -53,12 +80,15 @@ const helpers_1 = require("./helpers");
53
80
  * @param input.id — UUID of the workflow to deploy
54
81
  * @returns `{ status: 200, data: YamlWorkflow }` the refreshed workflow record after deployment
55
82
  */
56
- async function deployYamlWorkflow(input) {
83
+ async function deployYamlWorkflow(input, auth) {
57
84
  try {
58
85
  const wf = await yamlDb.getYamlWorkflow(input.id);
59
86
  if (!wf) {
60
87
  return { status: 404, error: 'YAML workflow not found' };
61
88
  }
89
+ const refused = await deployRefusal(wf, auth);
90
+ if (refused)
91
+ return refused;
62
92
  // Compute the next app-level version for the namespace.
63
93
  // Each deploy increments regardless of individual tool versions —
64
94
  // adding a second tool (v1 of itself) to an app already at v1 produces app v2.
@@ -99,12 +129,15 @@ async function deployYamlWorkflow(input) {
99
129
  * @param input.id — UUID of the workflow to activate
100
130
  * @returns `{ status: 200, data: YamlWorkflow }` the refreshed workflow record after activation
101
131
  */
102
- async function activateYamlWorkflow(input) {
132
+ async function activateYamlWorkflow(input, auth) {
103
133
  try {
104
134
  const wf = await yamlDb.getYamlWorkflow(input.id);
105
135
  if (!wf) {
106
136
  return { status: 404, error: 'YAML workflow not found' };
107
137
  }
138
+ const refused = await deployRefusal(wf, auth);
139
+ if (refused)
140
+ return refused;
108
141
  if (wf.status !== 'deployed' && wf.status !== 'active') {
109
142
  return { status: 400, error: 'Workflow must be deployed before activation' };
110
143
  }
@@ -151,6 +184,11 @@ async function invokeYamlWorkflow(input, auth) {
151
184
  if (wf.status !== 'active') {
152
185
  return { status: 400, error: 'Workflow must be active to invoke' };
153
186
  }
187
+ if (input.execute_as) {
188
+ if (!auth?.userId)
189
+ return { status: 403, error: 'execute_as requires an authenticated caller' };
190
+ await (0, workflow_invocation_1.assertMayActAs)(auth.userId, input.execute_as);
191
+ }
154
192
  const result = await (0, invoke_1.invokeYamlWorkflow)(wf, {
155
193
  data: input.data,
156
194
  sync: input.sync,
@@ -161,6 +199,8 @@ async function invokeYamlWorkflow(input, auth) {
161
199
  return { status: 200, data: result };
162
200
  }
163
201
  catch (err) {
202
+ if (err instanceof workflow_invocation_1.InvocationError)
203
+ return { status: err.statusCode, error: err.message };
164
204
  if ((0, helpers_1.isNotFoundError)(err)) {
165
205
  return { status: 404, error: 'YAML workflow not found' };
166
206
  }
@@ -0,0 +1,46 @@
1
+ -- Migration 038: OAuth authorization server for /mcp
2
+ --
3
+ -- MCP clients register, a person consents to a grant, and the client holds a
4
+ -- refresh token for that grant. Access tokens are self-contained JWTs and are
5
+ -- never stored. Codes and refresh tokens are stored as SHA-256 hashes.
6
+
7
+ CREATE TABLE IF NOT EXISTS lt_oauth_clients (
8
+ client_id TEXT PRIMARY KEY,
9
+ client_name TEXT,
10
+ redirect_uris TEXT[] NOT NULL,
11
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
12
+ );
13
+
14
+ -- A grant is one person's consent for one client. The policy is the rights
15
+ -- the person chose (a preset today); the scope is its coarse summary.
16
+ CREATE TABLE IF NOT EXISTS lt_oauth_grants (
17
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
18
+ user_id UUID NOT NULL REFERENCES lt_users(id) ON DELETE CASCADE,
19
+ client_id TEXT NOT NULL REFERENCES lt_oauth_clients(client_id) ON DELETE CASCADE,
20
+ policy JSONB NOT NULL,
21
+ scope TEXT NOT NULL,
22
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
23
+ revoked_at TIMESTAMPTZ
24
+ );
25
+
26
+ CREATE INDEX IF NOT EXISTS idx_lt_oauth_grants_user ON lt_oauth_grants (user_id);
27
+
28
+ CREATE TABLE IF NOT EXISTS lt_oauth_codes (
29
+ code_hash TEXT PRIMARY KEY,
30
+ grant_id UUID NOT NULL REFERENCES lt_oauth_grants(id) ON DELETE CASCADE,
31
+ redirect_uri TEXT NOT NULL,
32
+ code_challenge TEXT NOT NULL,
33
+ resource TEXT,
34
+ expires_at TIMESTAMPTZ NOT NULL,
35
+ used_at TIMESTAMPTZ
36
+ );
37
+
38
+ CREATE TABLE IF NOT EXISTS lt_oauth_refresh_tokens (
39
+ token_hash TEXT PRIMARY KEY,
40
+ grant_id UUID NOT NULL REFERENCES lt_oauth_grants(id) ON DELETE CASCADE,
41
+ expires_at TIMESTAMPTZ NOT NULL,
42
+ used_at TIMESTAMPTZ,
43
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
44
+ );
45
+
46
+ CREATE INDEX IF NOT EXISTS idx_lt_oauth_refresh_tokens_grant ON lt_oauth_refresh_tokens (grant_id);
@@ -0,0 +1,15 @@
1
+ import type { LTEvent } from '../../types';
2
+ /** Escalation event fields a browser needs to route a refresh and follow a claim. */
3
+ export declare const BROWSER_ESCALATION_FIELDS: readonly ["id", "type", "subtype", "status", "priority", "role", "assigned_to", "assigned_until", "workflow_id", "workflow_type", "origin_id", "task_id", "parent_id", "resolved_at", "claimed_at", "bulk", "from_role", "to_role", "reassigned_from"];
4
+ export interface BrowserViewer {
5
+ builder: boolean;
6
+ }
7
+ /** The event as this viewer receives it. */
8
+ export declare function eventForViewer(event: LTEvent, viewer: BrowserViewer): LTEvent;
9
+ /**
10
+ * Rewrite one serialized event for a viewer who is not a builder. A payload
11
+ * that is not an event is withheld (null).
12
+ */
13
+ export declare function payloadForViewer(payload: Buffer, viewer: BrowserViewer): Buffer | null;
14
+ /** Whether a person is a builder, looked up lazily to keep lib free of an import cycle. */
15
+ export declare function viewerFor(userId: string | null | undefined): Promise<BrowserViewer>;
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.BROWSER_ESCALATION_FIELDS = void 0;
37
+ exports.eventForViewer = eventForViewer;
38
+ exports.payloadForViewer = payloadForViewer;
39
+ exports.viewerFor = viewerFor;
40
+ /**
41
+ * What a browser receives of an event. Builders receive events whole. Anyone
42
+ * else receives enough to route and refresh: escalation events keep their
43
+ * routing fields, and every other event arrives without `data` and
44
+ * `milestones`. Full records are read through the scoped API, by id.
45
+ *
46
+ * Server-side consumers (agent triggers, callbacks) are unaffected: this view
47
+ * applies only where events leave for a browser.
48
+ */
49
+ const ESCALATION_SUBJECT = 'system.escalation.';
50
+ /** Escalation event fields a browser needs to route a refresh and follow a claim. */
51
+ exports.BROWSER_ESCALATION_FIELDS = [
52
+ 'id', 'type', 'subtype', 'status', 'priority', 'role',
53
+ 'assigned_to', 'assigned_until', 'workflow_id', 'workflow_type',
54
+ 'origin_id', 'task_id', 'parent_id', 'resolved_at', 'claimed_at',
55
+ 'bulk', 'from_role', 'to_role', 'reassigned_from',
56
+ ];
57
+ /** The event as this viewer receives it. */
58
+ function eventForViewer(event, viewer) {
59
+ if (viewer.builder)
60
+ return event;
61
+ const { data, milestones: _milestones, ...rest } = event;
62
+ if (typeof event.type === 'string' && event.type.startsWith(ESCALATION_SUBJECT) && data) {
63
+ const kept = {};
64
+ for (const key of exports.BROWSER_ESCALATION_FIELDS) {
65
+ if (data[key] !== undefined)
66
+ kept[key] = data[key];
67
+ }
68
+ return { ...rest, data: kept };
69
+ }
70
+ return rest;
71
+ }
72
+ /**
73
+ * Rewrite one serialized event for a viewer who is not a builder. A payload
74
+ * that is not an event is withheld (null).
75
+ */
76
+ function payloadForViewer(payload, viewer) {
77
+ if (viewer.builder)
78
+ return payload;
79
+ let event;
80
+ try {
81
+ event = JSON.parse(payload.toString('utf8'));
82
+ }
83
+ catch {
84
+ return null;
85
+ }
86
+ if (!event || typeof event !== 'object' || typeof event.type !== 'string')
87
+ return null;
88
+ return Buffer.from(JSON.stringify(eventForViewer(event, viewer)), 'utf8');
89
+ }
90
+ /** Whether a person is a builder, looked up lazily to keep lib free of an import cycle. */
91
+ async function viewerFor(userId) {
92
+ if (!userId)
93
+ return { builder: false };
94
+ try {
95
+ const { mayBuild } = await Promise.resolve().then(() => __importStar(require('../../modules/capabilities')));
96
+ return { builder: await mayBuild({ userId }) };
97
+ }
98
+ catch {
99
+ return { builder: false };
100
+ }
101
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * The browser's half of a NATS connection, as the WebSocket proxy forwards
3
+ * it. A browser only subscribes, so the proxy authenticates the connection
4
+ * itself and lets the browser read, never publish:
5
+ *
6
+ * - CONNECT is rewritten to carry the server's credential (the browser is
7
+ * never given it), keeping the client's other options.
8
+ * - PUB and HPUB are dropped with their payloads.
9
+ * - SUB, UNSUB, PING and PONG pass through unchanged.
10
+ *
11
+ * The NATS client protocol is line-oriented (`OP args\r\n`), and a publish is
12
+ * followed by a payload of a declared size. Operations can span WebSocket
13
+ * frames, so the filter keeps whatever it has not yet seen whole.
14
+ */
15
+ export declare class NatsClientFilter {
16
+ private readonly authToken;
17
+ private pending;
18
+ /** Payload bytes (plus the trailing CRLF) of a dropped publish still to skip. */
19
+ private skip;
20
+ private failed;
21
+ constructor(authToken: string | null);
22
+ /** Whether the stream was malformed; the proxy closes the connection. */
23
+ get malformed(): boolean;
24
+ /** The bytes to forward upstream for one chunk from the browser. */
25
+ feed(chunk: Buffer): Buffer;
26
+ /** The line to forward, or null to drop it. */
27
+ private filterLine;
28
+ private rewriteConnect;
29
+ }
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ /**
3
+ * The browser's half of a NATS connection, as the WebSocket proxy forwards
4
+ * it. A browser only subscribes, so the proxy authenticates the connection
5
+ * itself and lets the browser read, never publish:
6
+ *
7
+ * - CONNECT is rewritten to carry the server's credential (the browser is
8
+ * never given it), keeping the client's other options.
9
+ * - PUB and HPUB are dropped with their payloads.
10
+ * - SUB, UNSUB, PING and PONG pass through unchanged.
11
+ *
12
+ * The NATS client protocol is line-oriented (`OP args\r\n`), and a publish is
13
+ * followed by a payload of a declared size. Operations can span WebSocket
14
+ * frames, so the filter keeps whatever it has not yet seen whole.
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.NatsClientFilter = void 0;
18
+ const CRLF = Buffer.from('\r\n');
19
+ const MAX_LINE = 64 * 1024;
20
+ class NatsClientFilter {
21
+ constructor(authToken) {
22
+ this.authToken = authToken;
23
+ this.pending = Buffer.alloc(0);
24
+ /** Payload bytes (plus the trailing CRLF) of a dropped publish still to skip. */
25
+ this.skip = 0;
26
+ this.failed = false;
27
+ }
28
+ /** Whether the stream was malformed; the proxy closes the connection. */
29
+ get malformed() {
30
+ return this.failed;
31
+ }
32
+ /** The bytes to forward upstream for one chunk from the browser. */
33
+ feed(chunk) {
34
+ if (this.failed)
35
+ return Buffer.alloc(0);
36
+ this.pending = this.pending.length ? Buffer.concat([this.pending, chunk]) : chunk;
37
+ const out = [];
38
+ for (;;) {
39
+ if (this.skip > 0) {
40
+ const n = Math.min(this.skip, this.pending.length);
41
+ this.pending = this.pending.subarray(n);
42
+ this.skip -= n;
43
+ if (this.skip > 0)
44
+ break;
45
+ }
46
+ const end = this.pending.indexOf(CRLF);
47
+ if (end === -1) {
48
+ if (this.pending.length > MAX_LINE)
49
+ this.failed = true;
50
+ break;
51
+ }
52
+ const line = this.pending.subarray(0, end).toString('utf8');
53
+ this.pending = this.pending.subarray(end + CRLF.length);
54
+ const forwarded = this.filterLine(line);
55
+ if (this.failed)
56
+ return Buffer.alloc(0);
57
+ if (forwarded !== null)
58
+ out.push(Buffer.from(`${forwarded}\r\n`, 'utf8'));
59
+ }
60
+ return Buffer.concat(out);
61
+ }
62
+ /** The line to forward, or null to drop it. */
63
+ filterLine(line) {
64
+ const space = line.indexOf(' ');
65
+ const op = (space === -1 ? line : line.slice(0, space)).toUpperCase();
66
+ const args = space === -1 ? '' : line.slice(space + 1);
67
+ if (op === 'CONNECT')
68
+ return this.rewriteConnect(args);
69
+ if (op === 'PUB' || op === 'HPUB') {
70
+ // PUB <subject> [reply] <size>; HPUB <subject> [reply] <header size> <total size>
71
+ const size = Number(args.trim().split(/\s+/).pop());
72
+ if (!Number.isInteger(size) || size < 0) {
73
+ this.failed = true;
74
+ return null;
75
+ }
76
+ this.skip = size + CRLF.length;
77
+ return null;
78
+ }
79
+ return line;
80
+ }
81
+ rewriteConnect(json) {
82
+ let options;
83
+ try {
84
+ options = JSON.parse(json);
85
+ }
86
+ catch {
87
+ this.failed = true;
88
+ return null;
89
+ }
90
+ const { auth_token: _token, user: _user, pass: _pass, jwt: _jwt, nkey: _nkey, sig: _sig, ...rest } = options;
91
+ return `CONNECT ${JSON.stringify(this.authToken ? { ...rest, auth_token: this.authToken } : rest)}`;
92
+ }
93
+ }
94
+ exports.NatsClientFilter = NatsClientFilter;
@@ -25,4 +25,6 @@ export declare function deriveWsUrlFromRequest(req: {
25
25
  export declare function attachNatsWsProxy(server: HttpServer, target: string, options?: {
26
26
  basePath?: string;
27
27
  onWsUrlDerived?: (url: string) => void;
28
+ /** The NATS server credential, written into each browser's CONNECT by the proxy. */
29
+ authToken?: string | null;
28
30
  }): void;
@@ -5,6 +5,10 @@ exports.deriveWsUrlFromRequest = deriveWsUrlFromRequest;
5
5
  exports.attachNatsWsProxy = attachNatsWsProxy;
6
6
  const ws_1 = require("ws");
7
7
  const logger_1 = require("../logger");
8
+ const nats_ws_filter_1 = require("./nats-ws-filter");
9
+ const nats_ws_server_filter_1 = require("./nats-ws-server-filter");
10
+ const browser_view_1 = require("./browser-view");
11
+ const nats_ws_ticket_1 = require("./nats-ws-ticket");
8
12
  /** Default path for the NATS WebSocket proxy endpoint. */
9
13
  exports.NATS_WS_PROXY_PATH = '/nats-ws';
10
14
  /**
@@ -36,8 +40,21 @@ function attachNatsWsProxy(server, target, options = {}) {
36
40
  const proxyPath = `${basePath}${exports.NATS_WS_PROXY_PATH}`;
37
41
  const wss = new ws_1.WebSocketServer({ noServer: true });
38
42
  let derived = false;
39
- server.on('upgrade', (req, socket, head) => {
40
- if (req.url !== proxyPath)
43
+ server.on('upgrade', async (req, socket, head) => {
44
+ const url = new URL(req.url ?? '/', 'http://proxy');
45
+ if (url.pathname !== proxyPath)
46
+ return;
47
+ // Only a signed-in person, holding the ticket the credentials route issued.
48
+ const userId = (0, nats_ws_ticket_1.verifyNatsWsTicket)(url.searchParams.get(nats_ws_ticket_1.NATS_WS_TICKET_PARAM));
49
+ if (!userId) {
50
+ socket.write('HTTP/1.1 401 Unauthorized\r\nConnection: close\r\n\r\n');
51
+ socket.destroy();
52
+ return;
53
+ }
54
+ // Decided once per connection: a builder receives events whole, anyone
55
+ // else receives the browser view (lib/events/browser-view.ts).
56
+ const viewer = await (0, browser_view_1.viewerFor)(userId);
57
+ if (socket.destroyed)
41
58
  return;
42
59
  // Derive the public wsUrl from the first request's headers
43
60
  if (!derived && options.onWsUrlDerived) {
@@ -46,14 +63,31 @@ function attachNatsWsProxy(server, target, options = {}) {
46
63
  }
47
64
  wss.handleUpgrade(req, socket, head, (clientWs) => {
48
65
  const upstream = new ws_1.WebSocket(target);
66
+ // The browser reads; the proxy holds the credential and drops its publishes.
67
+ const filter = new nats_ws_filter_1.NatsClientFilter(options.authToken ?? null);
68
+ const inbound = viewer.builder ? null : new nats_ws_server_filter_1.NatsServerFilter((payload) => (0, browser_view_1.payloadForViewer)(payload, viewer));
49
69
  upstream.on('open', () => {
50
70
  clientWs.on('message', (data) => {
51
- if (upstream.readyState === ws_1.WebSocket.OPEN)
52
- upstream.send(data);
71
+ const chunk = Buffer.isBuffer(data) ? data : Buffer.from(data);
72
+ const forward = filter.feed(chunk);
73
+ if (filter.malformed) {
74
+ clientWs.close();
75
+ return;
76
+ }
77
+ if (forward.length && upstream.readyState === ws_1.WebSocket.OPEN)
78
+ upstream.send(forward);
53
79
  });
54
80
  upstream.on('message', (data) => {
55
- if (clientWs.readyState === ws_1.WebSocket.OPEN)
81
+ if (clientWs.readyState !== ws_1.WebSocket.OPEN)
82
+ return;
83
+ if (!inbound) {
56
84
  clientWs.send(data);
85
+ return;
86
+ }
87
+ const chunk = Buffer.isBuffer(data) ? data : Buffer.from(data);
88
+ const forward = inbound.feed(chunk);
89
+ if (forward.length)
90
+ clientWs.send(forward);
57
91
  });
58
92
  });
59
93
  const close = () => {
@@ -0,0 +1,16 @@
1
+ /**
2
+ * The server's half of a browser's NATS connection, as the WebSocket proxy
3
+ * forwards it. Message payloads (MSG and HMSG) pass through `rewrite`, which
4
+ * returns the payload to deliver or null to withhold the message; protocol
5
+ * lines (INFO, PING, PONG, +OK, -ERR) pass unchanged.
6
+ *
7
+ * Operations can span WebSocket frames, so the filter keeps whatever it has
8
+ * not yet seen whole.
9
+ */
10
+ export declare class NatsServerFilter {
11
+ private readonly rewrite;
12
+ private pending;
13
+ constructor(rewrite: (payload: Buffer) => Buffer | null);
14
+ /** The bytes to forward to the browser for one chunk from the server. */
15
+ feed(chunk: Buffer): Buffer;
16
+ }