@sapiom/harness 0.1.5 → 0.2.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 (245) hide show
  1. package/CHANGELOG.md +151 -0
  2. package/dist/cli/args.d.ts +16 -0
  3. package/dist/cli/args.d.ts.map +1 -0
  4. package/dist/cli/args.js +80 -0
  5. package/dist/cli/args.js.map +1 -0
  6. package/dist/cli/bin.js +30 -66
  7. package/dist/cli/bin.js.map +1 -1
  8. package/dist/cli/consent.js +1 -1
  9. package/dist/cli/settings.d.ts.map +1 -1
  10. package/dist/cli/settings.js +33 -1
  11. package/dist/cli/settings.js.map +1 -1
  12. package/dist/core/adapters/adapter.d.ts +2 -2
  13. package/dist/core/adapters/claude-code.d.ts +60 -2
  14. package/dist/core/adapters/claude-code.d.ts.map +1 -1
  15. package/dist/core/adapters/claude-code.js +119 -32
  16. package/dist/core/adapters/claude-code.js.map +1 -1
  17. package/dist/core/adapters/codex.d.ts +21 -2
  18. package/dist/core/adapters/codex.d.ts.map +1 -1
  19. package/dist/core/adapters/codex.js +53 -2
  20. package/dist/core/adapters/codex.js.map +1 -1
  21. package/dist/core/adapters/detect.d.ts +9 -0
  22. package/dist/core/adapters/detect.d.ts.map +1 -1
  23. package/dist/core/adapters/detect.js +9 -0
  24. package/dist/core/adapters/detect.js.map +1 -1
  25. package/dist/core/api-key-provider.d.ts +79 -0
  26. package/dist/core/api-key-provider.d.ts.map +1 -0
  27. package/dist/core/api-key-provider.js +91 -0
  28. package/dist/core/api-key-provider.js.map +1 -0
  29. package/dist/core/canvas-body.d.ts +28 -28
  30. package/dist/core/canvas-body.d.ts.map +1 -1
  31. package/dist/core/canvas-body.js +117 -55
  32. package/dist/core/canvas-body.js.map +1 -1
  33. package/dist/core/canvas-derive.d.ts +43 -0
  34. package/dist/core/canvas-derive.d.ts.map +1 -0
  35. package/dist/core/canvas-derive.js +95 -0
  36. package/dist/core/canvas-derive.js.map +1 -0
  37. package/dist/core/canvas-enrichment.d.ts +52 -127
  38. package/dist/core/canvas-enrichment.d.ts.map +1 -1
  39. package/dist/core/canvas-enrichment.js +17 -178
  40. package/dist/core/canvas-enrichment.js.map +1 -1
  41. package/dist/core/canvas-graph.d.ts +40 -1
  42. package/dist/core/canvas-graph.d.ts.map +1 -1
  43. package/dist/core/canvas-graph.js +71 -9
  44. package/dist/core/canvas-graph.js.map +1 -1
  45. package/dist/core/canvas-interconnections.d.ts +26 -8
  46. package/dist/core/canvas-interconnections.d.ts.map +1 -1
  47. package/dist/core/canvas-interconnections.js +132 -24
  48. package/dist/core/canvas-interconnections.js.map +1 -1
  49. package/dist/core/canvas-manifest-check.d.ts.map +1 -1
  50. package/dist/core/canvas-manifest-check.js +15 -2
  51. package/dist/core/canvas-manifest-check.js.map +1 -1
  52. package/dist/core/canvas-render.d.ts +8 -15
  53. package/dist/core/canvas-render.d.ts.map +1 -1
  54. package/dist/core/canvas-render.js +29 -41
  55. package/dist/core/canvas-render.js.map +1 -1
  56. package/dist/core/canvas-run-state.d.ts +50 -5
  57. package/dist/core/canvas-run-state.d.ts.map +1 -1
  58. package/dist/core/canvas-run-state.js +176 -11
  59. package/dist/core/canvas-run-state.js.map +1 -1
  60. package/dist/core/canvas-svg.d.ts +9 -4
  61. package/dist/core/canvas-svg.d.ts.map +1 -1
  62. package/dist/core/canvas-svg.js +84 -13
  63. package/dist/core/canvas-svg.js.map +1 -1
  64. package/dist/core/canvas-template.d.ts +9 -10
  65. package/dist/core/canvas-template.d.ts.map +1 -1
  66. package/dist/core/canvas-template.js +57 -20
  67. package/dist/core/canvas-template.js.map +1 -1
  68. package/dist/core/canvas-watcher.d.ts +22 -1
  69. package/dist/core/canvas-watcher.d.ts.map +1 -1
  70. package/dist/core/canvas-watcher.js +111 -30
  71. package/dist/core/canvas-watcher.js.map +1 -1
  72. package/dist/core/collector/normalizer.d.ts +8 -0
  73. package/dist/core/collector/normalizer.d.ts.map +1 -1
  74. package/dist/core/collector/normalizer.js +8 -0
  75. package/dist/core/collector/normalizer.js.map +1 -1
  76. package/dist/core/collector/store.d.ts +75 -1
  77. package/dist/core/collector/store.d.ts.map +1 -1
  78. package/dist/core/collector/store.js +334 -2
  79. package/dist/core/collector/store.js.map +1 -1
  80. package/dist/core/definition-slug-resolver.d.ts +13 -0
  81. package/dist/core/definition-slug-resolver.d.ts.map +1 -1
  82. package/dist/core/definition-slug-resolver.js +29 -0
  83. package/dist/core/definition-slug-resolver.js.map +1 -1
  84. package/dist/core/errors.d.ts +10 -4
  85. package/dist/core/errors.d.ts.map +1 -1
  86. package/dist/core/errors.js +11 -5
  87. package/dist/core/errors.js.map +1 -1
  88. package/dist/core/example-seed.d.ts +8 -0
  89. package/dist/core/example-seed.d.ts.map +1 -1
  90. package/dist/core/example-seed.js +47 -10
  91. package/dist/core/example-seed.js.map +1 -1
  92. package/dist/core/inject/system-prompt.d.ts +8 -0
  93. package/dist/core/inject/system-prompt.d.ts.map +1 -1
  94. package/dist/core/inject/system-prompt.js +3 -1
  95. package/dist/core/inject/system-prompt.js.map +1 -1
  96. package/dist/core/macros.d.ts.map +1 -1
  97. package/dist/core/macros.js +5 -6
  98. package/dist/core/macros.js.map +1 -1
  99. package/dist/core/paths.d.ts +1 -0
  100. package/dist/core/paths.d.ts.map +1 -1
  101. package/dist/core/paths.js +1 -0
  102. package/dist/core/paths.js.map +1 -1
  103. package/dist/core/record-archive.d.ts +187 -0
  104. package/dist/core/record-archive.d.ts.map +1 -0
  105. package/dist/core/record-archive.js +465 -0
  106. package/dist/core/record-archive.js.map +1 -0
  107. package/dist/core/rehydration.d.ts +72 -0
  108. package/dist/core/rehydration.d.ts.map +1 -0
  109. package/dist/core/rehydration.js +72 -0
  110. package/dist/core/rehydration.js.map +1 -0
  111. package/dist/core/render-local-run.d.ts +82 -0
  112. package/dist/core/render-local-run.d.ts.map +1 -0
  113. package/dist/core/render-local-run.js +105 -0
  114. package/dist/core/render-local-run.js.map +1 -0
  115. package/dist/core/render-log-slice.d.ts +30 -0
  116. package/dist/core/render-log-slice.d.ts.map +1 -0
  117. package/dist/core/render-log-slice.js +49 -0
  118. package/dist/core/render-log-slice.js.map +1 -0
  119. package/dist/core/render-run-state.d.ts.map +1 -1
  120. package/dist/core/render-run-state.js +30 -49
  121. package/dist/core/render-run-state.js.map +1 -1
  122. package/dist/core/resume-brief.d.ts +130 -0
  123. package/dist/core/resume-brief.d.ts.map +1 -0
  124. package/dist/core/resume-brief.js +404 -0
  125. package/dist/core/resume-brief.js.map +1 -0
  126. package/dist/core/rolling-summary.d.ts +130 -0
  127. package/dist/core/rolling-summary.d.ts.map +1 -0
  128. package/dist/core/rolling-summary.js +227 -0
  129. package/dist/core/rolling-summary.js.map +1 -0
  130. package/dist/core/run-local-bootstrap.d.ts +93 -0
  131. package/dist/core/run-local-bootstrap.d.ts.map +1 -0
  132. package/dist/core/run-local-bootstrap.js +155 -0
  133. package/dist/core/run-local-bootstrap.js.map +1 -0
  134. package/dist/core/run-state.d.ts +16 -1
  135. package/dist/core/run-state.d.ts.map +1 -1
  136. package/dist/core/run-state.js +75 -25
  137. package/dist/core/run-state.js.map +1 -1
  138. package/dist/core/session-manager.d.ts +11 -3
  139. package/dist/core/session-manager.d.ts.map +1 -1
  140. package/dist/core/session-manager.js +56 -7
  141. package/dist/core/session-manager.js.map +1 -1
  142. package/dist/core/session-record.d.ts +165 -0
  143. package/dist/core/session-record.d.ts.map +1 -0
  144. package/dist/core/session-record.js +470 -0
  145. package/dist/core/session-record.js.map +1 -0
  146. package/dist/core/spawn-target.d.ts +12 -0
  147. package/dist/core/spawn-target.d.ts.map +1 -0
  148. package/dist/core/spawn-target.js +187 -0
  149. package/dist/core/spawn-target.js.map +1 -0
  150. package/dist/core/stub-feedback.d.ts +52 -0
  151. package/dist/core/stub-feedback.d.ts.map +1 -0
  152. package/dist/core/stub-feedback.js +33 -0
  153. package/dist/core/stub-feedback.js.map +1 -0
  154. package/dist/core/task-manager.d.ts.map +1 -1
  155. package/dist/core/task-manager.js +9 -1
  156. package/dist/core/task-manager.js.map +1 -1
  157. package/dist/core/template-catalog.d.ts +48 -0
  158. package/dist/core/template-catalog.d.ts.map +1 -0
  159. package/dist/core/template-catalog.js +338 -0
  160. package/dist/core/template-catalog.js.map +1 -0
  161. package/dist/core/workflow-registry.d.ts.map +1 -1
  162. package/dist/core/workflow-registry.js +2 -2
  163. package/dist/core/workflow-registry.js.map +1 -1
  164. package/dist/core/workspace-watcher.d.ts.map +1 -1
  165. package/dist/core/workspace-watcher.js +4 -3
  166. package/dist/core/workspace-watcher.js.map +1 -1
  167. package/dist/index.d.ts +12 -0
  168. package/dist/index.d.ts.map +1 -1
  169. package/dist/index.js +21 -0
  170. package/dist/index.js.map +1 -1
  171. package/dist/profiles/default.d.ts.map +1 -1
  172. package/dist/profiles/default.js +9 -14
  173. package/dist/profiles/default.js.map +1 -1
  174. package/dist/server/actions.d.ts +139 -0
  175. package/dist/server/actions.d.ts.map +1 -0
  176. package/dist/server/actions.js +430 -0
  177. package/dist/server/actions.js.map +1 -0
  178. package/dist/server/auth-routes.d.ts +92 -0
  179. package/dist/server/auth-routes.d.ts.map +1 -0
  180. package/dist/server/auth-routes.js +151 -0
  181. package/dist/server/auth-routes.js.map +1 -0
  182. package/dist/server/canvas.d.ts.map +1 -1
  183. package/dist/server/canvas.js +7 -7
  184. package/dist/server/canvas.js.map +1 -1
  185. package/dist/server/fs.d.ts.map +1 -1
  186. package/dist/server/fs.js +17 -1
  187. package/dist/server/fs.js.map +1 -1
  188. package/dist/server/index.d.ts +12 -3
  189. package/dist/server/index.d.ts.map +1 -1
  190. package/dist/server/index.js +0 -0
  191. package/dist/server/index.js.map +1 -1
  192. package/dist/server/ingest.d.ts +11 -0
  193. package/dist/server/ingest.d.ts.map +1 -1
  194. package/dist/server/ingest.js +1 -0
  195. package/dist/server/ingest.js.map +1 -1
  196. package/dist/server/macros.d.ts +4 -6
  197. package/dist/server/macros.d.ts.map +1 -1
  198. package/dist/server/macros.js.map +1 -1
  199. package/dist/server/rest.d.ts +18 -6
  200. package/dist/server/rest.d.ts.map +1 -1
  201. package/dist/server/rest.js +185 -50
  202. package/dist/server/rest.js.map +1 -1
  203. package/dist/server/runs.d.ts +16 -15
  204. package/dist/server/runs.d.ts.map +1 -1
  205. package/dist/server/runs.js +15 -80
  206. package/dist/server/runs.js.map +1 -1
  207. package/dist/server/static.d.ts +15 -1
  208. package/dist/server/static.d.ts.map +1 -1
  209. package/dist/server/static.js +54 -4
  210. package/dist/server/static.js.map +1 -1
  211. package/dist/server/templates.d.ts +24 -0
  212. package/dist/server/templates.d.ts.map +1 -0
  213. package/dist/server/templates.js +54 -0
  214. package/dist/server/templates.js.map +1 -0
  215. package/dist/shared/types.d.ts +558 -66
  216. package/dist/shared/types.d.ts.map +1 -1
  217. package/dist/shared/types.js +19 -11
  218. package/dist/shared/types.js.map +1 -1
  219. package/dist/web/assets/index-DC65cskq.js +446 -0
  220. package/dist/web/assets/index-xtD-3FFa.css +32 -0
  221. package/dist/web/canvas/sess-boot/index.html +305 -0
  222. package/dist/web/index.html +4 -9
  223. package/package.json +8 -4
  224. package/dist/core/canvas-enrich.d.ts +0 -115
  225. package/dist/core/canvas-enrich.d.ts.map +0 -1
  226. package/dist/core/canvas-enrich.js +0 -186
  227. package/dist/core/canvas-enrich.js.map +0 -1
  228. package/dist/core/run-spend.d.ts +0 -55
  229. package/dist/core/run-spend.d.ts.map +0 -1
  230. package/dist/core/run-spend.js +0 -109
  231. package/dist/core/run-spend.js.map +0 -1
  232. package/dist/core/run-transactions.d.ts +0 -60
  233. package/dist/core/run-transactions.d.ts.map +0 -1
  234. package/dist/core/run-transactions.js +0 -129
  235. package/dist/core/run-transactions.js.map +0 -1
  236. package/dist/profiles/canvas-guidelines.d.ts +0 -20
  237. package/dist/profiles/canvas-guidelines.d.ts.map +0 -1
  238. package/dist/profiles/canvas-guidelines.js +0 -48
  239. package/dist/profiles/canvas-guidelines.js.map +0 -1
  240. package/dist/server/skills.d.ts +0 -51
  241. package/dist/server/skills.d.ts.map +0 -1
  242. package/dist/server/skills.js +0 -312
  243. package/dist/server/skills.js.map +0 -1
  244. package/dist/web/assets/index-DM84J83Y.js +0 -234
  245. package/dist/web/assets/index-DemtWW4L.css +0 -32
@@ -1,40 +1,31 @@
1
1
  /**
2
- * Runs router — backs GET /api/runs/:executionId/{state,spend,transactions}.
2
+ * Runs router — backs GET /api/runs/:executionId/state.
3
3
  *
4
- * Returns a {@link RunView} (live status), {@link RunSpend} (per-step cost), or
5
- * per-call {@link RunCall}[] (cost drill-down) for a running or finished prod
6
- * agents execution, so the web canvas can poll live status, cost, and the
7
- * "why is this costly" breakdown. The Sapiom API key is held server-side and
8
- * never forwarded to the browser — the router fetches on behalf of the canvas
9
- * via {@link createRunStateFetcher}, {@link createRunSpendFetcher}, and
10
- * {@link createRunTransactionsFetcher}.
4
+ * Returns a {@link RunView} (live status) for a running or finished prod agents
5
+ * execution, so the web canvas can poll live status. The Sapiom API key is held
6
+ * server-side and never forwarded to the browser the router fetches on behalf
7
+ * of the canvas via {@link createRunStateFetcher}.
11
8
  */
12
9
  import { Router } from "express";
13
10
  import { createRunStateFetcher } from "../core/run-state.js";
14
- import { createRunSpendFetcher } from "../core/run-spend.js";
15
- import { createRunTransactionsFetcher } from "../core/run-transactions.js";
11
+ import { staticApiKeyProvider, } from "../core/api-key-provider.js";
16
12
  /**
17
- * Create the runs router. Mounts `GET /api/runs/:executionId/state` and
18
- * `GET /api/runs/:executionId/spend`, delegating to the respective fetchers
19
- * for each upstream call.
13
+ * Create the runs router. Mounts `GET /api/runs/:executionId/state`, delegating
14
+ * to the run-state fetcher for the upstream call.
20
15
  */
21
16
  export function createRunsRouter(opts) {
22
17
  const router = Router();
18
+ // Normalize to a provider so the live-status path always authenticates with
19
+ // the held API key and can refresh + retry when that key is rejected — a
20
+ // plain string|null becomes a no-op static provider (no refresh).
21
+ const provider = opts.apiKey !== null && typeof opts.apiKey === "object"
22
+ ? opts.apiKey
23
+ : staticApiKeyProvider(opts.apiKey);
23
24
  const stateFetcher = createRunStateFetcher({
24
- apiKey: opts.apiKey,
25
+ apiKey: provider,
25
26
  baseUrl: opts.baseUrl,
26
27
  fetchImpl: opts.fetchImpl,
27
28
  });
28
- const spendFetcher = createRunSpendFetcher({
29
- apiKey: opts.apiKey,
30
- baseUrl: opts.coreBaseUrl,
31
- fetchImpl: opts.fetchImpl,
32
- });
33
- const transactionsFetcher = createRunTransactionsFetcher({
34
- apiKey: opts.apiKey,
35
- baseUrl: opts.coreBaseUrl,
36
- fetchImpl: opts.fetchImpl,
37
- });
38
29
  /**
39
30
  * GET /api/runs/:executionId/state
40
31
  *
@@ -63,62 +54,6 @@ export function createRunsRouter(opts) {
63
54
  res.status(result.status).json({ error: result.error });
64
55
  }
65
56
  });
66
- /**
67
- * GET /api/runs/:executionId/spend
68
- *
69
- * Returns a {@link RunSpend} for the given execution id, fetched from the
70
- * core surface (api.sapiom.ai). Cost settles just after a run finishes, so
71
- * the SPA polls this endpoint a few extra times after terminal state. The key
72
- * stays server-side and never reaches the browser.
73
- *
74
- * 200 RunSpend JSON — spend found and decoded
75
- * 400 executionId missing or empty
76
- * 404 spend not found on the core surface
77
- * 502 upstream error or decode failure
78
- * 503 harness is not signed in to Sapiom
79
- */
80
- router.get("/api/runs/:executionId/spend", async (req, res) => {
81
- const id = req.params.executionId;
82
- if (!id || typeof id !== "string" || id.trim() === "") {
83
- res.status(400).json({ error: "executionId is required" });
84
- return;
85
- }
86
- const result = await spendFetcher.fetch(id);
87
- if (result.ok) {
88
- res.json(result.spend);
89
- }
90
- else {
91
- res.status(result.status).json({ error: result.error });
92
- }
93
- });
94
- /**
95
- * GET /api/runs/:executionId/transactions
96
- *
97
- * Returns the per-call cost drill-down ({@link RunCall}[]) for the given
98
- * execution — the individual billable capability calls behind each step's
99
- * cost, so the canvas can answer "why is this step costly". Provider-agnostic
100
- * (capability labels only) and key-safe (fetched server-side).
101
- *
102
- * 200 RunCall[] JSON — transactions found and mapped
103
- * 400 executionId missing or empty
104
- * 404 transactions not found on the core surface
105
- * 502 upstream error or decode failure
106
- * 503 harness is not signed in to Sapiom
107
- */
108
- router.get("/api/runs/:executionId/transactions", async (req, res) => {
109
- const id = req.params.executionId;
110
- if (!id || typeof id !== "string" || id.trim() === "") {
111
- res.status(400).json({ error: "executionId is required" });
112
- return;
113
- }
114
- const result = await transactionsFetcher.fetch(id);
115
- if (result.ok) {
116
- res.json(result.calls);
117
- }
118
- else {
119
- res.status(result.status).json({ error: result.error });
120
- }
121
- });
122
57
  return router;
123
58
  }
124
59
  //# sourceMappingURL=runs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runs.js","sourceRoot":"","sources":["../../src/server/runs.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runs.js","sourceRoot":"","sources":["../../src/server/runs.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAEL,oBAAoB,GACrB,MAAM,6BAA6B,CAAC;AAqBrC;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAoB;IACnD,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IACxB,4EAA4E;IAC5E,yEAAyE;IACzE,kEAAkE;IAClE,MAAM,QAAQ,GACZ,IAAI,CAAC,MAAM,KAAK,IAAI,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ;QACrD,CAAC,CAAC,IAAI,CAAC,MAAM;QACb,CAAC,CAAC,oBAAoB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAExC,MAAM,YAAY,GAAG,qBAAqB,CAAC;QACzC,MAAM,EAAE,QAAQ;QAChB,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,SAAS,EAAE,IAAI,CAAC,SAAS;KAC1B,CAAC,CAAC;IAEH;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,GAAG,CAAC,8BAA8B,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QAC5D,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC;QAClC,IAAI,CAAC,EAAE,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACtD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC,CAAC;YAC3D,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC5C,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;YACd,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC3B,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -2,7 +2,21 @@
2
2
  * Serves the built Vite SPA from dist/web. Falls back to a placeholder page
3
3
  * when the web bundle hasn't been built yet (e.g. `pnpm dev` without a prior
4
4
  * `pnpm build:web`), so the server is still useful for API/WS-only testing.
5
+ *
6
+ * Boot-token injection: every HTML response has a `<script>` block baked in
7
+ * before `</head>` that sets `window.__HARNESS__ = { token: ${bootToken} }`.
8
+ * This lets `getBootToken()` (web/src/lib/api.ts) resolve the token without
9
+ * relying on the `?token=` query param — which is lost on navigation/reload
10
+ * and caused every /api POST to 401 after the first page load (SAP-1898).
11
+ *
12
+ * Implementation note: `express.static` serves index.html directly on `/`
13
+ * requests, bypassing any downstream handlers. To guarantee injection we:
14
+ * 1. Use `express.static` with `index: false` so it never auto-serves
15
+ * index.html itself.
16
+ * 2. Add a catch-all `GET *` that serves the pre-injected HTML string for
17
+ * any route that `express.static` didn't match (SPA deep-route fallback
18
+ * AND the root `/`).
5
19
  */
6
20
  import { Router } from "express";
7
- export declare function createStaticRouter(webDir: string): Router;
21
+ export declare function createStaticRouter(webDir: string, bootToken: string): Router;
8
22
  //# sourceMappingURL=static.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"static.d.ts","sourceRoot":"","sources":["../../src/server/static.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAgB,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAc1C,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAgBzD"}
1
+ {"version":3,"file":"static.d.ts","sourceRoot":"","sources":["../../src/server/static.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,OAAgB,EAAE,MAAM,EAA+B,MAAM,SAAS,CAAC;AA2CvE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CA2B5E"}
@@ -2,8 +2,22 @@
2
2
  * Serves the built Vite SPA from dist/web. Falls back to a placeholder page
3
3
  * when the web bundle hasn't been built yet (e.g. `pnpm dev` without a prior
4
4
  * `pnpm build:web`), so the server is still useful for API/WS-only testing.
5
+ *
6
+ * Boot-token injection: every HTML response has a `<script>` block baked in
7
+ * before `</head>` that sets `window.__HARNESS__ = { token: ${bootToken} }`.
8
+ * This lets `getBootToken()` (web/src/lib/api.ts) resolve the token without
9
+ * relying on the `?token=` query param — which is lost on navigation/reload
10
+ * and caused every /api POST to 401 after the first page load (SAP-1898).
11
+ *
12
+ * Implementation note: `express.static` serves index.html directly on `/`
13
+ * requests, bypassing any downstream handlers. To guarantee injection we:
14
+ * 1. Use `express.static` with `index: false` so it never auto-serves
15
+ * index.html itself.
16
+ * 2. Add a catch-all `GET *` that serves the pre-injected HTML string for
17
+ * any route that `express.static` didn't match (SPA deep-route fallback
18
+ * AND the root `/`).
5
19
  */
6
- import { existsSync } from "node:fs";
20
+ import { existsSync, readFileSync } from "node:fs";
7
21
  import { join } from "node:path";
8
22
  import express, { Router } from "express";
9
23
  const PLACEHOLDER_HTML = `<!doctype html>
@@ -17,13 +31,49 @@ const PLACEHOLDER_HTML = `<!doctype html>
17
31
  </body>
18
32
  </html>
19
33
  `;
20
- export function createStaticRouter(webDir) {
34
+ /**
35
+ * Builds the inline `<script>` that bakes the boot token into the page before
36
+ * any SPA JS runs. JSON.stringify ensures the token is safely escaped even if
37
+ * it contains characters that could break a bare string interpolation.
38
+ */
39
+ function buildTokenScript(bootToken) {
40
+ const safeJson = JSON.stringify({ token: bootToken }).replace(/</g, "\\u003c");
41
+ return `<script>window.__HARNESS__ = ${safeJson};</script>`;
42
+ }
43
+ /**
44
+ * Injects the boot-token `<script>` block into raw HTML. The block is
45
+ * inserted immediately before `</head>` so it executes before any SPA modules
46
+ * load. Falls back to prepending to `<body>` if `</head>` is absent (shouldn't
47
+ * happen with our Vite output, but keeps the injection unconditional).
48
+ */
49
+ function injectTokenScript(html, bootToken) {
50
+ const script = buildTokenScript(bootToken);
51
+ if (html.includes("</head>")) {
52
+ return html.replace("</head>", `${script}</head>`);
53
+ }
54
+ // Fallback: inject at the very start of <body> if </head> is missing.
55
+ if (html.includes("<body>")) {
56
+ return html.replace("<body>", `<body>${script}`);
57
+ }
58
+ // Last resort: prepend to the document.
59
+ return script + html;
60
+ }
61
+ export function createStaticRouter(webDir, bootToken) {
21
62
  const router = Router();
22
63
  const indexPath = join(webDir, "index.html");
23
64
  if (existsSync(indexPath)) {
24
- router.use(express.static(webDir));
65
+ // Read index.html once at startup. The file doesn't change at runtime
66
+ // (it's a Vite build output), so a single read is fine and avoids
67
+ // repeated disk I/O for every page navigation request.
68
+ const rawHtml = readFileSync(indexPath, "utf-8");
69
+ const injectedHtml = injectTokenScript(rawHtml, bootToken);
70
+ // Serve hashed assets (JS, CSS, images) via express.static.
71
+ // `index: false` prevents express.static from auto-serving index.html
72
+ // on GET / — we handle that (and all SPA deep routes) in the catch-all
73
+ // below so every HTML response always carries the injected token script.
74
+ router.use(express.static(webDir, { index: false }));
25
75
  router.get("*", (_req, res) => {
26
- res.sendFile(indexPath);
76
+ res.status(200).set("Content-Type", "text/html").send(injectedHtml);
27
77
  });
28
78
  }
29
79
  else {
@@ -1 +1 @@
1
- {"version":3,"file":"static.js","sourceRoot":"","sources":["../../src/server/static.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAE1C,MAAM,gBAAgB,GAAG;;;;;;;;;;CAUxB,CAAC;AAEF,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC/C,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IACxB,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAE7C,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC1B,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QACnC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;YAC5B,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;YAC5B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAC1E,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"static.js","sourceRoot":"","sources":["../../src/server/static.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,OAAO,EAAE,EAAE,MAAM,EAA+B,MAAM,SAAS,CAAC;AAEvE,MAAM,gBAAgB,GAAG;;;;;;;;;;CAUxB,CAAC;AAEF;;;;GAIG;AACH,SAAS,gBAAgB,CAAC,SAAiB;IACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAC/E,OAAO,gCAAgC,QAAQ,YAAY,CAAC;AAC9D,CAAC;AAED;;;;;GAKG;AACH,SAAS,iBAAiB,CAAC,IAAY,EAAE,SAAiB;IACxD,MAAM,MAAM,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAC3C,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,MAAM,SAAS,CAAC,CAAC;IACrD,CAAC;IACD,sEAAsE;IACtE,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC;IACnD,CAAC;IACD,wCAAwC;IACxC,OAAO,MAAM,GAAG,IAAI,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAc,EAAE,SAAiB;IAClE,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IACxB,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAE7C,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC1B,sEAAsE;QACtE,kEAAkE;QAClE,uDAAuD;QACvD,MAAM,OAAO,GAAG,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACjD,MAAM,YAAY,GAAG,iBAAiB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QAE3D,4DAA4D;QAC5D,sEAAsE;QACtE,uEAAuE;QACvE,yEAAyE;QACzE,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QAErD,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAa,EAAE,GAAa,EAAE,EAAE;YAC/C,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACtE,CAAC,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAa,EAAE,GAAa,EAAE,EAAE;YAC/C,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAC1E,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Templates router — backs GET /api/templates and GET /api/templates/:id.
3
+ *
4
+ * Relays the Sapiom core gallery (the same catalog the dashboard's Template
5
+ * library renders) to the SPA. The API key is held server-side and never
6
+ * forwarded to the browser — the router fetches on the dialog's behalf via
7
+ * {@link createTemplateCatalog}, exactly as the runs router does for live run
8
+ * state. That is also why this can't be a direct browser fetch of core: the
9
+ * `sk_…` key would have to reach the page, and core sends no CORS headers for
10
+ * the harness's origin.
11
+ */
12
+ import { Router } from "express";
13
+ import { type ApiKeyProvider } from "../core/api-key-provider.js";
14
+ export interface TemplatesRouterOpts {
15
+ /** The Sapiom API key (`sk_…`), NOT the local boot token. Pass a provider so a
16
+ * rejected key can refresh + retry instead of locking the gallery. */
17
+ apiKey: string | null | ApiKeyProvider;
18
+ /** Override the core base URL (resolved from env by default). Test seam. */
19
+ baseUrl?: string;
20
+ /** Injectable fetch. Test seam. */
21
+ fetchImpl?: typeof fetch;
22
+ }
23
+ export declare function createTemplatesRouter(opts: TemplatesRouterOpts): Router;
24
+ //# sourceMappingURL=templates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../src/server/templates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAGjC,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAElE,MAAM,WAAW,mBAAmB;IAClC;2EACuE;IACvE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,cAAc,CAAC;IACvC,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mCAAmC;IACnC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,mBAAmB,GAAG,MAAM,CA0CvE"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Templates router — backs GET /api/templates and GET /api/templates/:id.
3
+ *
4
+ * Relays the Sapiom core gallery (the same catalog the dashboard's Template
5
+ * library renders) to the SPA. The API key is held server-side and never
6
+ * forwarded to the browser — the router fetches on the dialog's behalf via
7
+ * {@link createTemplateCatalog}, exactly as the runs router does for live run
8
+ * state. That is also why this can't be a direct browser fetch of core: the
9
+ * `sk_…` key would have to reach the page, and core sends no CORS headers for
10
+ * the harness's origin.
11
+ */
12
+ import { Router } from "express";
13
+ import { createTemplateCatalog } from "../core/template-catalog.js";
14
+ export function createTemplatesRouter(opts) {
15
+ const router = Router();
16
+ const catalog = createTemplateCatalog({
17
+ apiKey: opts.apiKey,
18
+ baseUrl: opts.baseUrl,
19
+ fetchImpl: opts.fetchImpl,
20
+ });
21
+ /**
22
+ * GET /api/templates
23
+ *
24
+ * 200 always — a `TemplateListResponse`. Deliberately never an error status:
25
+ * an unreachable or signed-out catalog is a degraded gallery (the bundled
26
+ * starters still work offline), not a failed request, and core's own endpoint
27
+ * makes the same choice. `source`/`reason` carry the degradation so the dialog
28
+ * can explain itself.
29
+ */
30
+ router.get("/api/templates", async (_req, res) => {
31
+ res.json(await catalog.list());
32
+ });
33
+ /**
34
+ * GET /api/templates/:id
35
+ *
36
+ * 200 TemplateDetailView
37
+ * 404 unknown id, or the catalog could not be reached
38
+ */
39
+ router.get("/api/templates/:id", async (req, res) => {
40
+ const id = req.params.id;
41
+ if (!id || id.trim() === "") {
42
+ res.status(400).json({ error: "template id is required" });
43
+ return;
44
+ }
45
+ const detail = await catalog.detail(id);
46
+ if (!detail) {
47
+ res.status(404).json({ error: `Template not found: ${id}` });
48
+ return;
49
+ }
50
+ res.json(detail);
51
+ });
52
+ return router;
53
+ }
54
+ //# sourceMappingURL=templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/server/templates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAapE,MAAM,UAAU,qBAAqB,CAAC,IAAyB;IAC7D,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IACxB,MAAM,OAAO,GAAG,qBAAqB,CAAC;QACpC,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,SAAS,EAAE,IAAI,CAAC,SAAS;KAC1B,CAAC,CAAC;IAEH;;;;;;;;OAQG;IACH,MAAM,CAAC,GAAG,CAAC,gBAAgB,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;QAC/C,GAAG,CAAC,IAAI,CAAC,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH;;;;;OAKG;IACH,MAAM,CAAC,GAAG,CAAC,oBAAoB,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QAClD,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YAC5B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC,CAAC;YAC3D,OAAO;QACT,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACxC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,uBAAuB,EAAE,EAAE,EAAE,CAAC,CAAC;YAC7D,OAAO;QACT,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnB,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}