@jini-ai/http-kit 0.2.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 (227) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +107 -0
  3. package/dist/active-context.d.ts +99 -0
  4. package/dist/active-context.d.ts.map +1 -0
  5. package/dist/active-context.js +77 -0
  6. package/dist/active-context.js.map +1 -0
  7. package/dist/adapter.d.ts +36 -0
  8. package/dist/adapter.d.ts.map +1 -0
  9. package/dist/adapter.js +92 -0
  10. package/dist/adapter.js.map +1 -0
  11. package/dist/agents.d.ts +55 -0
  12. package/dist/agents.d.ts.map +1 -0
  13. package/dist/agents.js +23 -0
  14. package/dist/agents.js.map +1 -0
  15. package/dist/api-security-middleware.d.ts +146 -0
  16. package/dist/api-security-middleware.d.ts.map +1 -0
  17. package/dist/api-security-middleware.js +276 -0
  18. package/dist/api-security-middleware.js.map +1 -0
  19. package/dist/attachments.d.ts +317 -0
  20. package/dist/attachments.d.ts.map +1 -0
  21. package/dist/attachments.js +664 -0
  22. package/dist/attachments.js.map +1 -0
  23. package/dist/cancel-owned-runs.d.ts +44 -0
  24. package/dist/cancel-owned-runs.d.ts.map +1 -0
  25. package/dist/cancel-owned-runs.js +35 -0
  26. package/dist/cancel-owned-runs.js.map +1 -0
  27. package/dist/compat.d.ts +22 -0
  28. package/dist/compat.d.ts.map +1 -0
  29. package/dist/compat.js +17 -0
  30. package/dist/compat.js.map +1 -0
  31. package/dist/component-catalog.d.ts +74 -0
  32. package/dist/component-catalog.d.ts.map +1 -0
  33. package/dist/component-catalog.js +74 -0
  34. package/dist/component-catalog.js.map +1 -0
  35. package/dist/connectors.d.ts +165 -0
  36. package/dist/connectors.d.ts.map +1 -0
  37. package/dist/connectors.js +474 -0
  38. package/dist/connectors.js.map +1 -0
  39. package/dist/daemon-status.d.ts +72 -0
  40. package/dist/daemon-status.d.ts.map +1 -0
  41. package/dist/daemon-status.js +60 -0
  42. package/dist/daemon-status.js.map +1 -0
  43. package/dist/db-ops.d.ts +116 -0
  44. package/dist/db-ops.d.ts.map +1 -0
  45. package/dist/db-ops.js +191 -0
  46. package/dist/db-ops.js.map +1 -0
  47. package/dist/delegated-tools.d.ts +46 -0
  48. package/dist/delegated-tools.d.ts.map +1 -0
  49. package/dist/delegated-tools.js +155 -0
  50. package/dist/delegated-tools.js.map +1 -0
  51. package/dist/express/run-stream.d.ts +15 -0
  52. package/dist/express/run-stream.d.ts.map +1 -0
  53. package/dist/express/run-stream.js +11 -0
  54. package/dist/express/run-stream.js.map +1 -0
  55. package/dist/express-index.d.ts +32 -0
  56. package/dist/express-index.d.ts.map +1 -0
  57. package/dist/express-index.js +14 -0
  58. package/dist/express-index.js.map +1 -0
  59. package/dist/fastify/adapter.d.ts +31 -0
  60. package/dist/fastify/adapter.d.ts.map +1 -0
  61. package/dist/fastify/adapter.js +64 -0
  62. package/dist/fastify/adapter.js.map +1 -0
  63. package/dist/fastify/agents.d.ts +13 -0
  64. package/dist/fastify/agents.d.ts.map +1 -0
  65. package/dist/fastify/agents.js +7 -0
  66. package/dist/fastify/agents.js.map +1 -0
  67. package/dist/fastify/api-security-middleware.d.ts +64 -0
  68. package/dist/fastify/api-security-middleware.d.ts.map +1 -0
  69. package/dist/fastify/api-security-middleware.js +139 -0
  70. package/dist/fastify/api-security-middleware.js.map +1 -0
  71. package/dist/fastify/compat.d.ts +22 -0
  72. package/dist/fastify/compat.d.ts.map +1 -0
  73. package/dist/fastify/compat.js +16 -0
  74. package/dist/fastify/compat.js.map +1 -0
  75. package/dist/fastify/daemon-status.d.ts +22 -0
  76. package/dist/fastify/daemon-status.d.ts.map +1 -0
  77. package/dist/fastify/daemon-status.js +9 -0
  78. package/dist/fastify/daemon-status.js.map +1 -0
  79. package/dist/fastify/host-tools.d.ts +13 -0
  80. package/dist/fastify/host-tools.d.ts.map +1 -0
  81. package/dist/fastify/host-tools.js +8 -0
  82. package/dist/fastify/host-tools.js.map +1 -0
  83. package/dist/fastify/index.d.ts +36 -0
  84. package/dist/fastify/index.d.ts.map +1 -0
  85. package/dist/fastify/index.js +18 -0
  86. package/dist/fastify/index.js.map +1 -0
  87. package/dist/fastify/local-daemon-request.d.ts +43 -0
  88. package/dist/fastify/local-daemon-request.d.ts.map +1 -0
  89. package/dist/fastify/local-daemon-request.js +155 -0
  90. package/dist/fastify/local-daemon-request.js.map +1 -0
  91. package/dist/fastify/origin.d.ts +21 -0
  92. package/dist/fastify/origin.d.ts.map +1 -0
  93. package/dist/fastify/origin.js +14 -0
  94. package/dist/fastify/origin.js.map +1 -0
  95. package/dist/fastify/request.d.ts +20 -0
  96. package/dist/fastify/request.d.ts.map +1 -0
  97. package/dist/fastify/request.js +25 -0
  98. package/dist/fastify/request.js.map +1 -0
  99. package/dist/fastify/response.d.ts +20 -0
  100. package/dist/fastify/response.d.ts.map +1 -0
  101. package/dist/fastify/response.js +41 -0
  102. package/dist/fastify/response.js.map +1 -0
  103. package/dist/fastify/route-registration-guard.d.ts +70 -0
  104. package/dist/fastify/route-registration-guard.d.ts.map +1 -0
  105. package/dist/fastify/route-registration-guard.js +69 -0
  106. package/dist/fastify/route-registration-guard.js.map +1 -0
  107. package/dist/fastify/run-stream.d.ts +18 -0
  108. package/dist/fastify/run-stream.d.ts.map +1 -0
  109. package/dist/fastify/run-stream.js +10 -0
  110. package/dist/fastify/run-stream.js.map +1 -0
  111. package/dist/fastify/runs.d.ts +17 -0
  112. package/dist/fastify/runs.d.ts.map +1 -0
  113. package/dist/fastify/runs.js +33 -0
  114. package/dist/fastify/runs.js.map +1 -0
  115. package/dist/frontend-control.d.ts +131 -0
  116. package/dist/frontend-control.d.ts.map +1 -0
  117. package/dist/frontend-control.js +77 -0
  118. package/dist/frontend-control.js.map +1 -0
  119. package/dist/frontend-sessions.d.ts +100 -0
  120. package/dist/frontend-sessions.d.ts.map +1 -0
  121. package/dist/frontend-sessions.js +180 -0
  122. package/dist/frontend-sessions.js.map +1 -0
  123. package/dist/health.d.ts +91 -0
  124. package/dist/health.d.ts.map +1 -0
  125. package/dist/health.js +53 -0
  126. package/dist/health.js.map +1 -0
  127. package/dist/host-tools.d.ts +174 -0
  128. package/dist/host-tools.d.ts.map +1 -0
  129. package/dist/host-tools.js +338 -0
  130. package/dist/host-tools.js.map +1 -0
  131. package/dist/index.d.ts +86 -0
  132. package/dist/index.d.ts.map +1 -0
  133. package/dist/index.js +40 -0
  134. package/dist/index.js.map +1 -0
  135. package/dist/local-daemon-request.d.ts +44 -0
  136. package/dist/local-daemon-request.d.ts.map +1 -0
  137. package/dist/local-daemon-request.js +145 -0
  138. package/dist/local-daemon-request.js.map +1 -0
  139. package/dist/media.d.ts +131 -0
  140. package/dist/media.d.ts.map +1 -0
  141. package/dist/media.js +352 -0
  142. package/dist/media.js.map +1 -0
  143. package/dist/memory.d.ts +230 -0
  144. package/dist/memory.d.ts.map +1 -0
  145. package/dist/memory.js +331 -0
  146. package/dist/memory.js.map +1 -0
  147. package/dist/model-proxy.d.ts +45 -0
  148. package/dist/model-proxy.d.ts.map +1 -0
  149. package/dist/model-proxy.js +619 -0
  150. package/dist/model-proxy.js.map +1 -0
  151. package/dist/origin-validation.d.ts +64 -0
  152. package/dist/origin-validation.d.ts.map +1 -0
  153. package/dist/origin-validation.js +226 -0
  154. package/dist/origin-validation.js.map +1 -0
  155. package/dist/origin.d.ts +32 -0
  156. package/dist/origin.d.ts.map +1 -0
  157. package/dist/origin.js +14 -0
  158. package/dist/origin.js.map +1 -0
  159. package/dist/pack-http.d.ts +30 -0
  160. package/dist/pack-http.d.ts.map +1 -0
  161. package/dist/pack-http.js +12 -0
  162. package/dist/pack-http.js.map +1 -0
  163. package/dist/raw-sse.d.ts +44 -0
  164. package/dist/raw-sse.d.ts.map +1 -0
  165. package/dist/raw-sse.js +93 -0
  166. package/dist/raw-sse.js.map +1 -0
  167. package/dist/remote-run-events.d.ts +66 -0
  168. package/dist/remote-run-events.d.ts.map +1 -0
  169. package/dist/remote-run-events.js +230 -0
  170. package/dist/remote-run-events.js.map +1 -0
  171. package/dist/request.d.ts +19 -0
  172. package/dist/request.d.ts.map +1 -0
  173. package/dist/request.js +25 -0
  174. package/dist/request.js.map +1 -0
  175. package/dist/research.d.ts +42 -0
  176. package/dist/research.d.ts.map +1 -0
  177. package/dist/research.js +316 -0
  178. package/dist/research.js.map +1 -0
  179. package/dist/response.d.ts +14 -0
  180. package/dist/response.d.ts.map +1 -0
  181. package/dist/response.js +45 -0
  182. package/dist/response.js.map +1 -0
  183. package/dist/route-manifest.d.ts +31 -0
  184. package/dist/route-manifest.d.ts.map +1 -0
  185. package/dist/route-manifest.js +103 -0
  186. package/dist/route-manifest.js.map +1 -0
  187. package/dist/route-registration-guard.d.ts +65 -0
  188. package/dist/route-registration-guard.d.ts.map +1 -0
  189. package/dist/route-registration-guard.js +71 -0
  190. package/dist/route-registration-guard.js.map +1 -0
  191. package/dist/routines.d.ts +114 -0
  192. package/dist/routines.d.ts.map +1 -0
  193. package/dist/routines.js +320 -0
  194. package/dist/routines.js.map +1 -0
  195. package/dist/run-stream.d.ts +60 -0
  196. package/dist/run-stream.d.ts.map +1 -0
  197. package/dist/run-stream.js +108 -0
  198. package/dist/run-stream.js.map +1 -0
  199. package/dist/runs.d.ts +79 -0
  200. package/dist/runs.d.ts.map +1 -0
  201. package/dist/runs.js +232 -0
  202. package/dist/runs.js.map +1 -0
  203. package/dist/sse.d.ts +139 -0
  204. package/dist/sse.d.ts.map +1 -0
  205. package/dist/sse.js +157 -0
  206. package/dist/sse.js.map +1 -0
  207. package/dist/terminals.d.ts +125 -0
  208. package/dist/terminals.d.ts.map +1 -0
  209. package/dist/terminals.js +349 -0
  210. package/dist/terminals.js.map +1 -0
  211. package/dist/tool-catalog.d.ts +68 -0
  212. package/dist/tool-catalog.d.ts.map +1 -0
  213. package/dist/tool-catalog.js +68 -0
  214. package/dist/tool-catalog.js.map +1 -0
  215. package/dist/types.d.ts +58 -0
  216. package/dist/types.d.ts.map +1 -0
  217. package/dist/types.js +5 -0
  218. package/dist/types.js.map +1 -0
  219. package/dist/workspace-root.d.ts +69 -0
  220. package/dist/workspace-root.d.ts.map +1 -0
  221. package/dist/workspace-root.js +63 -0
  222. package/dist/workspace-root.js.map +1 -0
  223. package/dist/xai.d.ts +86 -0
  224. package/dist/xai.d.ts.map +1 -0
  225. package/dist/xai.js +668 -0
  226. package/dist/xai.js.map +1 -0
  227. package/package.json +58 -0
@@ -0,0 +1,71 @@
1
+ const routeInventorySymbol = Symbol.for('jini.routeRegistrationGuard.inventory');
2
+ const GUARDED_METHODS = ['get', 'post', 'put', 'patch', 'delete', 'options', 'all', 'use'];
3
+ /**
4
+ * Builds the `METHOD PATH` key used to check `guardedRouteKeys` membership.
5
+ *
6
+ * @param method - The Express registration method name (any case; normalized to upper-case in the key).
7
+ * @param path - The first argument passed to that method. Only a string path can collide — a
8
+ * RegExp or array-of-paths route is never tracked, matching the inventory's own string-only
9
+ * recording below.
10
+ * @param guardedRouteKeys - The set of `METHOD PATH` keys this call installed a duplicate-registration
11
+ * guard for.
12
+ * @returns The matching key if `path` is a string and the key is in `guardedRouteKeys`, otherwise `null`.
13
+ * @complexity O(1) — a single `Set` lookup.
14
+ * @overallScore 100/100
15
+ */
16
+ export function guardedRouteKey(method, path, guardedRouteKeys) {
17
+ if (typeof path !== 'string')
18
+ return null;
19
+ const key = `${method.toUpperCase()} ${path}`;
20
+ return guardedRouteKeys.has(key) ? key : null;
21
+ }
22
+ /**
23
+ * Monkey-patches `app`'s route-registration methods to record every string-path registration into
24
+ * a per-app inventory (retrievable via {@link getRouteRegistrationInventory}) and to throw if any
25
+ * `options.guardedRouteKeys` entry is registered a second time.
26
+ *
27
+ * @param app - The Express app to instrument. Must not already have this guard installed (installing
28
+ * twice would double-wrap every method and double-count the inventory — not guarded against here
29
+ * since `createLocalNodeDaemon` and every other caller in this codebase calls this exactly once
30
+ * per app at composition time).
31
+ * @param options.guardedRouteKeys - See {@link InstallRouteRegistrationGuardOptions}.
32
+ * @returns Nothing — mutates `app` in place and stashes its inventory under a well-known `Symbol.for` key.
33
+ * @throws If a `guardedRouteKeys` entry is registered more than once, at the moment of the second registration.
34
+ * @complexity O(1) setup (patches 8 fixed methods); each wrapped call is O(1) beyond the wrapped original.
35
+ * @overallScore 100/100
36
+ */
37
+ export function installRouteRegistrationGuard(app, options = {}) {
38
+ const guardedRouteKeys = options.guardedRouteKeys ?? new Set();
39
+ const seen = new Set();
40
+ const inventory = [];
41
+ app[routeInventorySymbol] = inventory;
42
+ for (const method of GUARDED_METHODS) {
43
+ const original = app[method].bind(app);
44
+ app[method] = (path, ...handlers) => {
45
+ if (typeof path === 'string') {
46
+ inventory.push({ method: method.toUpperCase(), path });
47
+ }
48
+ const key = guardedRouteKey(method, path, guardedRouteKeys);
49
+ if (key) {
50
+ if (seen.has(key)) {
51
+ throw new Error(`duplicate guarded route registration: ${key}`);
52
+ }
53
+ seen.add(key);
54
+ }
55
+ return original(path, ...handlers);
56
+ };
57
+ }
58
+ }
59
+ /**
60
+ * Reads back every route {@link installRouteRegistrationGuard} recorded for `app`.
61
+ *
62
+ * @param app - An app the guard was installed on. Safe to call on an app with no guard installed
63
+ * (returns an empty array rather than throwing).
64
+ * @returns A fresh array copy each call — the caller can never mutate the guard's own internal inventory through the returned reference.
65
+ * @complexity O(n) in the number of routes registered so far.
66
+ * @overallScore 100/100
67
+ */
68
+ export function getRouteRegistrationInventory(app) {
69
+ return [...(app[routeInventorySymbol] ?? [])];
70
+ }
71
+ //# sourceMappingURL=route-registration-guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-registration-guard.js","sourceRoot":"","sources":["../src/route-registration-guard.ts"],"names":[],"mappings":"AAsBA,MAAM,oBAAoB,GAAG,MAAM,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC;AAEjF,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,CAAU,CAAC;AAEpG;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,eAAe,CAC7B,MAAc,EACd,IAAa,EACb,gBAAqC;IAErC,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC1C,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC;IAC9C,OAAO,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AAChD,CAAC;AAOD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,6BAA6B,CAC3C,GAAY,EACZ,UAAgD,EAAE;IAElD,MAAM,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,IAAI,IAAI,GAAG,EAAU,CAAC;IACvE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,SAAS,GAAwB,EAAE,CAAC;IACzC,GAAsD,CAAC,oBAAoB,CAAC,GAAG,SAAS,CAAC;IAE1F,KAAK,MAAM,MAAM,IAAI,eAAe,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAI,GAAkE,CAAC,MAAM,CAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACvG,GAAkE,CAAC,MAAM,CAAC,GAAG,CAC5E,IAAa,EACb,GAAG,QAAmB,EACtB,EAAE;YACF,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC7B,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;YACzD,CAAC;YACD,MAAM,GAAG,GAAG,eAAe,CAAC,MAAM,EAAE,IAAI,EAAE,gBAAgB,CAAC,CAAC;YAC5D,IAAI,GAAG,EAAE,CAAC;gBACR,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;oBAClB,MAAM,IAAI,KAAK,CAAC,yCAAyC,GAAG,EAAE,CAAC,CAAC;gBAClE,CAAC;gBACD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAChB,CAAC;YACD,OAAO,QAAQ,CAAC,IAAI,EAAE,GAAG,QAAQ,CAAC,CAAC;QACrC,CAAC,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,6BAA6B,CAAC,GAAY;IACxD,OAAO,CAAC,GAAG,CAAE,GAAkE,CAAC,oBAAoB,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;AAChH,CAAC"}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * @module routines
3
+ *
4
+ * Routine CRUD + run-history HTTP routes: `GET/POST /api/routines`, `GET/PATCH/DELETE
5
+ * /api/routines/:id`, `POST /api/routines/:id/run`, `GET /api/routines/:id/runs`. Calls into the
6
+ * `RoutineStore`/`RoutineService`-shaped ports `@jini-ai/daemon` ships (see that package's
7
+ * `routines/` module — `routine-store.ts` for the CRUD+history port, `scheduler.ts` for the
8
+ * scheduling engine) the same way `runs.ts` calls into `RunLifecycle` — no business logic lives
9
+ * in this file itself.
10
+ *
11
+ * Ported from OD's `apps/daemon/src/routes/routine.ts` (348 lines, `refactor/web-memory-slice`
12
+ * branch) per the decisions in `ADS-memory/reports/proposals/
13
+ * PROP-http-route-packs-automation-routines-2026-07-21.md` (Finding 2). That proposal identified
14
+ * two separable gaps blocking this route pack: (1) no scheduler existed anywhere in this repo —
15
+ * closed by porting `routines.ts` into `@jini-ai/daemon/src/routines/scheduler.ts` this same pass;
16
+ * (2) no `RoutineStore` persistence port existed for the CRUD side — closed by
17
+ * `@jini-ai/daemon/src/routines/routine-store.ts`, designed the same way `EventLog` is designed.
18
+ * This file is the third piece: the actual HTTP routes, now that both ports exist.
19
+ *
20
+ * **Confirmed bug fixed while porting** (per the proposal's own finding, not carried forward):
21
+ * OD's `GET /api/routines/:id`, `DELETE /api/routines/:id`, and `GET /api/routines/:id/runs` (OD
22
+ * source lines 236/268/292) had no try/catch, unlike every sibling handler in the same file. This
23
+ * port does not reproduce that gap — but not via a per-route try/catch either: every route here
24
+ * is mounted through `adapter.ts`'s `mountJsonRoute`, whose own top-level try/catch already wraps
25
+ * every route's `parse`/`handle` invocation (the same mechanism `runs.ts`/`memory.ts` rely on),
26
+ * so the bug is structurally impossible to reintroduce rather than merely patched at three call
27
+ * sites.
28
+ *
29
+ * **Deliberately NOT ported** (see the proposal's Finding 1 and the "built-in template scoping"
30
+ * decision it required a human call on):
31
+ * - `GET /api/automation-templates` / `GET /api/automation-templates/:id` — these depend on
32
+ * `automation-templates.ts`, which is not ported (see below); none of the routine CRUD/run-now/
33
+ * run-history routes below need it to function.
34
+ * - `POST /api/routines/:id/runs/:runId/crystallize` — depends on `ingestAutomationSource`
35
+ * (`automation-ingestions.ts`), explicitly scoped by the proposal as "a dedicated follow-up
36
+ * task the same size and shape as `@jini-ai/memory`'s own original port," not attempted here.
37
+ * - `automation-templates.ts` itself, including its CRUD-adjacent lookup machinery: the decision
38
+ * already made for this pass is to ship **zero built-in automation templates** (matching this
39
+ * repo's established precedent of keeping product-authored content host-owned — `@jini-ai/memory`'s
40
+ * prompt-composition, `@jini-ai/deploy`'s config-path resolution, etc.) and, since no route in this
41
+ * file needs any part of that module to function, none of it — content or generic shape — is
42
+ * ported this pass.
43
+ * - `automation-proposals.ts` / `automation-ingestions.ts` — untouched, per the proposal's Finding
44
+ * 1 explicit scoping and this task's brief.
45
+ *
46
+ * **Design note — why `target.mode === 'reuse'` project-existence checking is optional, injected
47
+ * DI, not a hard dependency**: OD's original unconditionally called `getProject(db, projectId)`
48
+ * to validate a reuse target. This module has no project concept of its own (matching
49
+ * `active-context.ts`'s `resolveResource` precedent for the same category of coupling), so
50
+ * `RoutineHttpDeps.projectExists` is an optional injected predicate: a host that has a project
51
+ * store supplies it and reuse targets are validated against it exactly like OD did; a host with
52
+ * no such concept (or that wants to defer the check) can omit it, and reuse targets are accepted
53
+ * without existence-checking rather than forcing every consumer to fabricate one.
54
+ *
55
+ * **Design note — why `POST /api/routines/:id/run`'s `run` field can be `null` even on success**:
56
+ * `RoutineStore` deliberately does not record runs (see `routine-store.ts`'s module doc: run
57
+ * *writing* stays the scheduler's own separately-injected `RoutinePersistence` concern, matching
58
+ * OD's own architectural split between the two). This route calls `store.getLatestRun(id)` after
59
+ * `scheduler.runNow(id)` resolves — accurate only if a host has bridged the scheduler's
60
+ * `RoutinePersistence.insertRun`/`updateRun` writes into the same store instance (documented,
61
+ * host-level integration wiring, out of this port's scope, the same way `runs.ts`'s `onStarted`
62
+ * driver is host-supplied). `projectId`/`conversationId`/`agentRunId` on the response always
63
+ * reflect the real, just-started run regardless of that wiring, since those come directly from
64
+ * `scheduler.runNow`'s own return value.
65
+ */
66
+ import type { Express } from 'express';
67
+ import { type Routine, type RoutineCreateInput, type RoutineRun, type RoutineService, type RoutineStore, type RoutineUpdateInput } from '@jini-ai/daemon';
68
+ import { type AdapterContext } from './adapter.js';
69
+ /** The scheduler surface these routes need — a structural subset of `RoutineService`, matching OD's own `RoutineRoutesService` narrowing (`Pick<RoutineService, 'nextRunAt' | 'rescheduleOne' | 'runNow' | 'unschedule'>`). Wiring a real `RoutineService` in satisfies this with zero adapter code. */
70
+ export type RoutineScheduler = Pick<RoutineService, 'nextRunAt' | 'rescheduleOne' | 'runNow' | 'unschedule'>;
71
+ export interface RoutineHttpDeps {
72
+ readonly store: RoutineStore;
73
+ readonly scheduler: RoutineScheduler;
74
+ /** Validates a `target: {mode: 'reuse', projectId}`'s `projectId` before create/update accept it. Omit to skip existence-checking entirely — see this module's doc comment. */
75
+ readonly projectExists?: (projectId: string) => boolean | Promise<boolean>;
76
+ }
77
+ interface RoutineUpdateRequest {
78
+ readonly id: string;
79
+ readonly patch: RoutineUpdateInput;
80
+ }
81
+ interface RoutineRunsQuery {
82
+ readonly id: string;
83
+ readonly limit: number;
84
+ }
85
+ export interface RoutineListResponse {
86
+ readonly routines: readonly Routine[];
87
+ }
88
+ export declare const routineListRoute: import("./types.js").JsonRouteSpec<void, RoutineListResponse, RoutineHttpDeps>;
89
+ export interface RoutineResponse {
90
+ readonly routine: Routine;
91
+ }
92
+ export declare const routineCreateRoute: import("./types.js").JsonRouteSpec<RoutineCreateInput, RoutineResponse, RoutineHttpDeps>;
93
+ export declare const routineGetRoute: import("./types.js").JsonRouteSpec<string, RoutineResponse, RoutineHttpDeps>;
94
+ export declare const routineUpdateRoute: import("./types.js").JsonRouteSpec<RoutineUpdateRequest, RoutineResponse, RoutineHttpDeps>;
95
+ export interface RoutineDeleteResponse {
96
+ readonly ok: true;
97
+ }
98
+ export declare const routineDeleteRoute: import("./types.js").JsonRouteSpec<string, RoutineDeleteResponse, RoutineHttpDeps>;
99
+ export interface RoutineRunNowResponse {
100
+ readonly routine: Routine | null;
101
+ readonly run: RoutineRun | null;
102
+ readonly projectId: string;
103
+ readonly conversationId: string;
104
+ readonly agentRunId: string;
105
+ }
106
+ export declare const routineRunNowRoute: import("./types.js").JsonRouteSpec<string, RoutineRunNowResponse, RoutineHttpDeps>;
107
+ export interface RoutineRunsResponse {
108
+ readonly runs: readonly RoutineRun[];
109
+ }
110
+ export declare const routineRunsListRoute: import("./types.js").JsonRouteSpec<RoutineRunsQuery, RoutineRunsResponse, RoutineHttpDeps>;
111
+ /** Mounts every routine route on `app`. A pack's `http(app, services)` calls this directly. */
112
+ export declare function registerRoutineRoutes(app: Express, deps: RoutineHttpDeps, adapter: AdapterContext): void;
113
+ export {};
114
+ //# sourceMappingURL=routines.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routines.d.ts","sourceRoot":"","sources":["../src/routines.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgEG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAGL,KAAK,OAAO,EAEZ,KAAK,kBAAkB,EAEvB,KAAK,UAAU,EAEf,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACxB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAmC,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAIpF,wSAAwS;AACxS,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,cAAc,EAAE,WAAW,GAAG,eAAe,GAAG,QAAQ,GAAG,YAAY,CAAC,CAAC;AAE7G,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC;IACrC,+KAA+K;IAC/K,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC5E;AA8HD,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAC;CACpC;AAuDD,UAAU,gBAAgB;IACxB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAkBD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;CACvC;AAED,eAAO,MAAM,gBAAgB,gFAQ3B,CAAC;AAEH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED,eAAO,MAAM,kBAAkB,0FAa7B,CAAC;AAMH,eAAO,MAAM,eAAe,8EAU1B,CAAC;AAEH,eAAO,MAAM,kBAAkB,4FAe7B,CAAC;AAEH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;CACnB;AAED,eAAO,MAAM,kBAAkB,oFAU7B,CAAC;AAMH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,eAAO,MAAM,kBAAkB,oFAmB7B,CAAC;AAMH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,SAAS,UAAU,EAAE,CAAC;CACtC;AAED,eAAO,MAAM,oBAAoB,4FAU/B,CAAC;AAEH,+FAA+F;AAC/F,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,cAAc,GAAG,IAAI,CAQxG"}
@@ -0,0 +1,320 @@
1
+ import { validateSchedule, validateTarget, } from '@jini-ai/daemon';
2
+ import { createApiError } from '@jini-ai/protocol';
3
+ import { defineJsonRoute, mountJsonRoute } from './adapter.js';
4
+ import { validationError } from './request.js';
5
+ import { err, ok } from './types.js';
6
+ function isRecord(value) {
7
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
8
+ }
9
+ function errorMessage(error) {
10
+ return error instanceof Error ? error.message : String(error);
11
+ }
12
+ /** Overlays the scheduler's live `nextRunAt` onto a routine fetched from the store — `RoutineStore` itself has no scheduler knowledge (see `routine-store.ts`'s module doc), matching OD's own `routineFromDb` two-step (fetch, then overlay `routineService.nextRunAt`). */
13
+ function attachNextRunAt(routine, scheduler) {
14
+ return { ...routine, nextRunAt: scheduler.nextRunAt(routine.id)?.getTime() ?? null };
15
+ }
16
+ async function checkTargetProjectExists(target, deps) {
17
+ if (target.mode !== 'reuse' || !deps.projectExists)
18
+ return null;
19
+ const exists = await deps.projectExists(target.projectId);
20
+ return exists ? null : createApiError('NOT_FOUND', `target project ${target.projectId} not found`);
21
+ }
22
+ function parseRoutineId(input) {
23
+ const id = input.params.id;
24
+ return typeof id === 'string' && id.length > 0 ? ok(id) : err(validationError('id must be a non-empty path parameter'));
25
+ }
26
+ function parseNonEmptyString(value, field) {
27
+ if (typeof value !== 'string' || value.trim().length === 0) {
28
+ return err(validationError(`${field} is required`, [{ path: field, message: 'required non-empty string' }]));
29
+ }
30
+ return ok(value.trim());
31
+ }
32
+ /** Present-but-non-string/empty is rejected; absent (`undefined`) or explicit `null` are both accepted (clearing the field on update). */
33
+ function parseOptionalNullableString(body, field) {
34
+ const value = body[field];
35
+ if (value === undefined)
36
+ return ok(undefined);
37
+ if (value === null)
38
+ return ok(null);
39
+ if (typeof value !== 'string' || value.trim().length === 0) {
40
+ return err(validationError(`${field} must be a non-empty string or null when provided`));
41
+ }
42
+ return ok(value);
43
+ }
44
+ function parseSchedule(value) {
45
+ try {
46
+ validateSchedule(value);
47
+ }
48
+ catch (error) {
49
+ return err(validationError(errorMessage(error)));
50
+ }
51
+ return ok(value);
52
+ }
53
+ function parseTarget(value) {
54
+ try {
55
+ validateTarget(value);
56
+ }
57
+ catch (error) {
58
+ return err(validationError(errorMessage(error)));
59
+ }
60
+ return ok(value);
61
+ }
62
+ /** Validates and de-duplicates one `context.*` array field, trimming entries and dropping blanks — mirrors OD's `cleanStringList`. */
63
+ function cleanStringList(value, field) {
64
+ if (!Array.isArray(value))
65
+ return err(validationError(`${field} must be an array`));
66
+ const out = [];
67
+ const seen = new Set();
68
+ for (const item of value) {
69
+ if (typeof item !== 'string')
70
+ return err(validationError(`${field} must contain strings`));
71
+ const trimmed = item.trim();
72
+ if (!trimmed || seen.has(trimmed))
73
+ continue;
74
+ seen.add(trimmed);
75
+ out.push(trimmed);
76
+ }
77
+ return ok(out);
78
+ }
79
+ const CONTEXT_FIELDS = ['skillIds', 'pluginIds', 'mcpServerIds', 'connectorIds'];
80
+ /** Mirrors OD's `normalizeRoutineContext`: an explicitly-empty array for a field is dropped entirely (not kept as `[]`) so a routine's stored context only ever carries fields that actually scope something. */
81
+ function parseContextSelection(value) {
82
+ if (value === undefined || value === null)
83
+ return ok({});
84
+ if (!isRecord(value))
85
+ return err(validationError('context must be an object'));
86
+ const context = {};
87
+ for (const field of CONTEXT_FIELDS) {
88
+ const raw = value[field];
89
+ if (raw === undefined)
90
+ continue;
91
+ const cleaned = cleanStringList(raw, `context.${field}`);
92
+ if (!cleaned.ok)
93
+ return cleaned;
94
+ if (cleaned.value.length > 0)
95
+ context[field] = cleaned.value;
96
+ }
97
+ return ok(context);
98
+ }
99
+ function parseRoutineCreate(input) {
100
+ if (!isRecord(input.body))
101
+ return err(validationError('body must be a JSON object'));
102
+ const name = parseNonEmptyString(input.body.name, 'name');
103
+ if (!name.ok)
104
+ return name;
105
+ const prompt = parseNonEmptyString(input.body.prompt, 'prompt');
106
+ if (!prompt.ok)
107
+ return prompt;
108
+ const schedule = parseSchedule(input.body.schedule);
109
+ if (!schedule.ok)
110
+ return schedule;
111
+ const target = parseTarget(input.body.target);
112
+ if (!target.ok)
113
+ return target;
114
+ const skillId = parseOptionalNullableString(input.body, 'skillId');
115
+ if (!skillId.ok)
116
+ return skillId;
117
+ const agentId = parseOptionalNullableString(input.body, 'agentId');
118
+ if (!agentId.ok)
119
+ return agentId;
120
+ const context = parseContextSelection(input.body.context);
121
+ if (!context.ok)
122
+ return context;
123
+ const enabled = input.body.enabled;
124
+ if (enabled !== undefined && typeof enabled !== 'boolean') {
125
+ return err(validationError('enabled must be a boolean when provided'));
126
+ }
127
+ return ok({
128
+ name: name.value,
129
+ prompt: prompt.value,
130
+ schedule: schedule.value,
131
+ target: target.value,
132
+ ...(skillId.value !== undefined ? { skillId: skillId.value } : {}),
133
+ ...(agentId.value !== undefined ? { agentId: agentId.value } : {}),
134
+ context: context.value,
135
+ ...(enabled !== undefined ? { enabled } : {}),
136
+ });
137
+ }
138
+ function parseRoutineUpdate(input) {
139
+ const idResult = parseRoutineId(input);
140
+ if (!idResult.ok)
141
+ return idResult;
142
+ if (!isRecord(input.body))
143
+ return err(validationError('body must be a JSON object'));
144
+ const body = input.body;
145
+ // `RoutineUpdateInput`'s fields are `readonly` (an immutable port-input contract) — built here
146
+ // as a mutable local shape field-by-field, then handed back as that readonly type, which is a
147
+ // safe widening (mutable -> readonly), not the reverse.
148
+ const patch = {};
149
+ if (body.name !== undefined) {
150
+ const name = parseNonEmptyString(body.name, 'name');
151
+ if (!name.ok)
152
+ return name;
153
+ patch.name = name.value;
154
+ }
155
+ if (body.prompt !== undefined) {
156
+ const prompt = parseNonEmptyString(body.prompt, 'prompt');
157
+ if (!prompt.ok)
158
+ return prompt;
159
+ patch.prompt = prompt.value;
160
+ }
161
+ if (body.schedule !== undefined) {
162
+ const schedule = parseSchedule(body.schedule);
163
+ if (!schedule.ok)
164
+ return schedule;
165
+ patch.schedule = schedule.value;
166
+ }
167
+ if (body.target !== undefined) {
168
+ const target = parseTarget(body.target);
169
+ if (!target.ok)
170
+ return target;
171
+ patch.target = target.value;
172
+ }
173
+ if (body.skillId !== undefined) {
174
+ const skillId = parseOptionalNullableString(body, 'skillId');
175
+ if (!skillId.ok)
176
+ return skillId;
177
+ patch.skillId = skillId.value ?? null;
178
+ }
179
+ if (body.agentId !== undefined) {
180
+ const agentId = parseOptionalNullableString(body, 'agentId');
181
+ if (!agentId.ok)
182
+ return agentId;
183
+ patch.agentId = agentId.value ?? null;
184
+ }
185
+ if (body.context !== undefined) {
186
+ const context = parseContextSelection(body.context);
187
+ if (!context.ok)
188
+ return context;
189
+ patch.context = context.value;
190
+ }
191
+ if (body.enabled !== undefined) {
192
+ if (typeof body.enabled !== 'boolean')
193
+ return err(validationError('enabled must be a boolean when provided'));
194
+ patch.enabled = body.enabled;
195
+ }
196
+ return ok({ id: idResult.value, patch });
197
+ }
198
+ function parseRoutineRunsQuery(input) {
199
+ const idResult = parseRoutineId(input);
200
+ if (!idResult.ok)
201
+ return idResult;
202
+ const raw = input.query.limit;
203
+ const rawValue = Array.isArray(raw) ? raw[0] : raw;
204
+ // Matches OD's own `Math.min(100, Math.max(1, Number(req.query.limit) || 20))` exactly,
205
+ // including the `|| 20` fallback for NaN/0/negative/absent rather than `?? 20`.
206
+ const numeric = Number(rawValue) || 20;
207
+ const limit = Math.min(100, Math.max(1, numeric));
208
+ return ok({ id: idResult.value, limit });
209
+ }
210
+ export const routineListRoute = defineJsonRoute({
211
+ method: 'get',
212
+ path: '/api/routines',
213
+ parse: () => ok(undefined),
214
+ handle: async (_input, deps) => {
215
+ const routines = await deps.store.list();
216
+ return ok({ routines: routines.map((routine) => attachNextRunAt(routine, deps.scheduler)) });
217
+ },
218
+ });
219
+ export const routineCreateRoute = defineJsonRoute({
220
+ method: 'post',
221
+ path: '/api/routines',
222
+ requireSameOrigin: true,
223
+ parse: parseRoutineCreate,
224
+ handle: async (input, deps) => {
225
+ const targetError = await checkTargetProjectExists(input.target, deps);
226
+ if (targetError)
227
+ return err(targetError);
228
+ const routine = await deps.store.create(input);
229
+ deps.scheduler.rescheduleOne(routine.id);
230
+ return ok({ routine: attachNextRunAt(routine, deps.scheduler) });
231
+ },
232
+ successStatus: 201,
233
+ });
234
+ // ---------------------------------------------------------------------------
235
+ // GET/PATCH/DELETE /api/routines/:id
236
+ // ---------------------------------------------------------------------------
237
+ export const routineGetRoute = defineJsonRoute({
238
+ method: 'get',
239
+ path: '/api/routines/:id',
240
+ parse: parseRoutineId,
241
+ handle: async (id, deps) => {
242
+ const routine = await deps.store.get(id);
243
+ return routine === null
244
+ ? err(createApiError('NOT_FOUND', 'routine not found'))
245
+ : ok({ routine: attachNextRunAt(routine, deps.scheduler) });
246
+ },
247
+ });
248
+ export const routineUpdateRoute = defineJsonRoute({
249
+ method: 'patch',
250
+ path: '/api/routines/:id',
251
+ requireSameOrigin: true,
252
+ parse: parseRoutineUpdate,
253
+ handle: async ({ id, patch }, deps) => {
254
+ if (patch.target !== undefined) {
255
+ const targetError = await checkTargetProjectExists(patch.target, deps);
256
+ if (targetError)
257
+ return err(targetError);
258
+ }
259
+ const routine = await deps.store.update(id, patch);
260
+ if (routine === null)
261
+ return err(createApiError('NOT_FOUND', 'routine not found'));
262
+ deps.scheduler.rescheduleOne(id);
263
+ return ok({ routine: attachNextRunAt(routine, deps.scheduler) });
264
+ },
265
+ });
266
+ export const routineDeleteRoute = defineJsonRoute({
267
+ method: 'delete',
268
+ path: '/api/routines/:id',
269
+ requireSameOrigin: true,
270
+ parse: parseRoutineId,
271
+ handle: async (id, deps) => {
272
+ deps.scheduler.unschedule(id);
273
+ const removed = await deps.store.delete(id);
274
+ return removed ? ok({ ok: true }) : err(createApiError('NOT_FOUND', 'routine not found'));
275
+ },
276
+ });
277
+ export const routineRunNowRoute = defineJsonRoute({
278
+ method: 'post',
279
+ path: '/api/routines/:id/run',
280
+ requireSameOrigin: true,
281
+ parse: parseRoutineId,
282
+ handle: async (id, deps) => {
283
+ const existing = await deps.store.get(id);
284
+ if (existing === null)
285
+ return err(createApiError('NOT_FOUND', 'routine not found'));
286
+ const started = await deps.scheduler.runNow(id);
287
+ const [routine, run] = await Promise.all([deps.store.get(id), deps.store.getLatestRun(id)]);
288
+ return ok({
289
+ routine: routine ? attachNextRunAt(routine, deps.scheduler) : null,
290
+ run,
291
+ projectId: started.projectId,
292
+ conversationId: started.conversationId,
293
+ agentRunId: started.agentRunId,
294
+ });
295
+ },
296
+ successStatus: 202,
297
+ });
298
+ export const routineRunsListRoute = defineJsonRoute({
299
+ method: 'get',
300
+ path: '/api/routines/:id/runs',
301
+ parse: parseRoutineRunsQuery,
302
+ handle: async ({ id, limit }, deps) => {
303
+ const existing = await deps.store.get(id);
304
+ if (existing === null)
305
+ return err(createApiError('NOT_FOUND', 'routine not found'));
306
+ const runs = await deps.store.listRuns(id, limit);
307
+ return ok({ runs });
308
+ },
309
+ });
310
+ /** Mounts every routine route on `app`. A pack's `http(app, services)` calls this directly. */
311
+ export function registerRoutineRoutes(app, deps, adapter) {
312
+ mountJsonRoute(app, routineListRoute, deps, adapter);
313
+ mountJsonRoute(app, routineCreateRoute, deps, adapter);
314
+ mountJsonRoute(app, routineGetRoute, deps, adapter);
315
+ mountJsonRoute(app, routineUpdateRoute, deps, adapter);
316
+ mountJsonRoute(app, routineDeleteRoute, deps, adapter);
317
+ mountJsonRoute(app, routineRunNowRoute, deps, adapter);
318
+ mountJsonRoute(app, routineRunsListRoute, deps, adapter);
319
+ }
320
+ //# sourceMappingURL=routines.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routines.js","sourceRoot":"","sources":["../src/routines.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * @module run-stream
3
+ *
4
+ * An encoder-driven SSE run-stream route: subscribes to a run via `@jini-ai/daemon`'s
5
+ * `RunLifecycle.stream`, pipes every event through a composition-root-supplied protocol encoder,
6
+ * and writes each non-null event to the SSE response opened by `createSseResponse`.
7
+ * `handleRunStreamRequest` is the core
8
+ * — it only ever touches `node:http`'s `IncomingMessage`/`ServerResponse` — and
9
+ * `registerRunStreamRoute` below is Express's own thin mounting glue (Express's `Request`/
10
+ * `Response` already *are* Node's raw `http.IncomingMessage`/`http.ServerResponse`, so resolving
11
+ * `req.params.runId` and handing the request/response straight through is the whole job).
12
+ */
13
+ import type { IncomingMessage, ServerResponse } from 'node:http';
14
+ import type { RunLifecycle } from '@jini-ai/daemon';
15
+ import type { RunProtocolEvent } from '@jini-ai/protocol';
16
+ import type { Express } from 'express';
17
+ /** Backward-compatible route path used by the AG-UI composition. The handler itself is encoder-agnostic. */
18
+ export declare const RUN_STREAM_ROUTE_PATH = "/api/runs/:runId/agui-stream";
19
+ export interface RunStreamEncoder {
20
+ encode(event: RunProtocolEvent, context: {
21
+ readonly runId: string;
22
+ }): unknown | null;
23
+ }
24
+ export interface RunStreamInternalErrorContext {
25
+ readonly source: 'encoder' | 'lifecycle' | 'route';
26
+ readonly runId: string;
27
+ readonly error: unknown;
28
+ }
29
+ export interface RunStreamDeps {
30
+ readonly lifecycle: RunLifecycle;
31
+ /** Protocol adapter supplied by the composition root (for example `createGenUiEncoder()`). */
32
+ readonly encoder: RunStreamEncoder;
33
+ /** Host-owned sink for failures that must not escape an async Express handler. Defaults to `console.error`. */
34
+ readonly onInternalError?: (context: RunStreamInternalErrorContext) => void;
35
+ }
36
+ /**
37
+ * Handles one encoded SSE run-stream request end to end. Opens the SSE connection immediately (an
38
+ * SSE endpoint commits to `text/event-stream` headers before it can know whether `runId` is
39
+ * valid), then subscribes to the run: a replay-then-live-subscribe `unknown-run`/`replay-gap`/
40
+ * `invalid-cursor` result is reported as one `{ error }` SSE data event before closing (there is
41
+ * no JSON-status-code channel left once SSE headers are already committed). On the happy path,
42
+ * every event `RunLifecycle` delivers is encoded and forwarded; the connection closes itself once
43
+ * the run's own terminal `'end'` event has been forwarded (a driver's contract with
44
+ * `RunLifecycle` guarantees no further events follow a run's `'end')`, so nothing is lost by
45
+ * closing right after it). If the client disconnects first, `createSseResponse`'s own
46
+ * `req.on('close', ...)` fires first, which (via `onClose` here) unsubscribes from the run so a
47
+ * disconnected client never leaves a dangling `RunLifecycle` subscriber.
48
+ *
49
+ * @param req - The raw request `createSseResponse` opens the stream against.
50
+ * @param res - The raw response `createSseResponse` opens the stream against.
51
+ * @param runId - The run to stream, already resolved by the caller's transport-specific glue.
52
+ * @param deps.lifecycle - The `RunLifecycle` to subscribe to.
53
+ * @param deps.encoder - The protocol adapter chosen by the composition root.
54
+ * @complexity O(1) plus the supplied encoder's per-event cost and `RunLifecycle.stream`'s replay cost.
55
+ * @overallScore 100/100
56
+ */
57
+ export declare function handleRunStreamRequest(req: IncomingMessage, res: ServerResponse, runId: string, deps: RunStreamDeps): Promise<void>;
58
+ /** Mounts the encoder-driven SSE run-stream route on `app`. */
59
+ export declare function registerRunStreamRoute(app: Express, deps: RunStreamDeps): void;
60
+ //# sourceMappingURL=run-stream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-stream.d.ts","sourceRoot":"","sources":["../src/run-stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAyB,MAAM,iBAAiB,CAAC;AAC3E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EAAE,OAAO,EAAqB,MAAM,SAAS,CAAC;AAG1D,4GAA4G;AAC5G,eAAO,MAAM,qBAAqB,iCAAiC,CAAC;AAEpE,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,GAAG,IAAI,CAAC;CACtF;AAED,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,OAAO,CAAC;IACnD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC;IACjC,8FAA8F;IAC9F,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;IACnC,+GAA+G;IAC/G,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,6BAA6B,KAAK,IAAI,CAAC;CAC7E;AAwBD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,IAAI,CAAC,CAuCf;AAED,+DAA+D;AAC/D,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,GAAG,IAAI,CAiB9E"}