@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.
- package/CHANGELOG.md +151 -0
- package/dist/cli/args.d.ts +16 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +80 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/bin.js +30 -66
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/consent.js +1 -1
- package/dist/cli/settings.d.ts.map +1 -1
- package/dist/cli/settings.js +33 -1
- package/dist/cli/settings.js.map +1 -1
- package/dist/core/adapters/adapter.d.ts +2 -2
- package/dist/core/adapters/claude-code.d.ts +60 -2
- package/dist/core/adapters/claude-code.d.ts.map +1 -1
- package/dist/core/adapters/claude-code.js +119 -32
- package/dist/core/adapters/claude-code.js.map +1 -1
- package/dist/core/adapters/codex.d.ts +21 -2
- package/dist/core/adapters/codex.d.ts.map +1 -1
- package/dist/core/adapters/codex.js +53 -2
- package/dist/core/adapters/codex.js.map +1 -1
- package/dist/core/adapters/detect.d.ts +9 -0
- package/dist/core/adapters/detect.d.ts.map +1 -1
- package/dist/core/adapters/detect.js +9 -0
- package/dist/core/adapters/detect.js.map +1 -1
- package/dist/core/api-key-provider.d.ts +79 -0
- package/dist/core/api-key-provider.d.ts.map +1 -0
- package/dist/core/api-key-provider.js +91 -0
- package/dist/core/api-key-provider.js.map +1 -0
- package/dist/core/canvas-body.d.ts +28 -28
- package/dist/core/canvas-body.d.ts.map +1 -1
- package/dist/core/canvas-body.js +117 -55
- package/dist/core/canvas-body.js.map +1 -1
- package/dist/core/canvas-derive.d.ts +43 -0
- package/dist/core/canvas-derive.d.ts.map +1 -0
- package/dist/core/canvas-derive.js +95 -0
- package/dist/core/canvas-derive.js.map +1 -0
- package/dist/core/canvas-enrichment.d.ts +52 -127
- package/dist/core/canvas-enrichment.d.ts.map +1 -1
- package/dist/core/canvas-enrichment.js +17 -178
- package/dist/core/canvas-enrichment.js.map +1 -1
- package/dist/core/canvas-graph.d.ts +40 -1
- package/dist/core/canvas-graph.d.ts.map +1 -1
- package/dist/core/canvas-graph.js +71 -9
- package/dist/core/canvas-graph.js.map +1 -1
- package/dist/core/canvas-interconnections.d.ts +26 -8
- package/dist/core/canvas-interconnections.d.ts.map +1 -1
- package/dist/core/canvas-interconnections.js +132 -24
- package/dist/core/canvas-interconnections.js.map +1 -1
- package/dist/core/canvas-manifest-check.d.ts.map +1 -1
- package/dist/core/canvas-manifest-check.js +15 -2
- package/dist/core/canvas-manifest-check.js.map +1 -1
- package/dist/core/canvas-render.d.ts +8 -15
- package/dist/core/canvas-render.d.ts.map +1 -1
- package/dist/core/canvas-render.js +29 -41
- package/dist/core/canvas-render.js.map +1 -1
- package/dist/core/canvas-run-state.d.ts +50 -5
- package/dist/core/canvas-run-state.d.ts.map +1 -1
- package/dist/core/canvas-run-state.js +176 -11
- package/dist/core/canvas-run-state.js.map +1 -1
- package/dist/core/canvas-svg.d.ts +9 -4
- package/dist/core/canvas-svg.d.ts.map +1 -1
- package/dist/core/canvas-svg.js +84 -13
- package/dist/core/canvas-svg.js.map +1 -1
- package/dist/core/canvas-template.d.ts +9 -10
- package/dist/core/canvas-template.d.ts.map +1 -1
- package/dist/core/canvas-template.js +57 -20
- package/dist/core/canvas-template.js.map +1 -1
- package/dist/core/canvas-watcher.d.ts +22 -1
- package/dist/core/canvas-watcher.d.ts.map +1 -1
- package/dist/core/canvas-watcher.js +111 -30
- package/dist/core/canvas-watcher.js.map +1 -1
- package/dist/core/collector/normalizer.d.ts +8 -0
- package/dist/core/collector/normalizer.d.ts.map +1 -1
- package/dist/core/collector/normalizer.js +8 -0
- package/dist/core/collector/normalizer.js.map +1 -1
- package/dist/core/collector/store.d.ts +75 -1
- package/dist/core/collector/store.d.ts.map +1 -1
- package/dist/core/collector/store.js +334 -2
- package/dist/core/collector/store.js.map +1 -1
- package/dist/core/definition-slug-resolver.d.ts +13 -0
- package/dist/core/definition-slug-resolver.d.ts.map +1 -1
- package/dist/core/definition-slug-resolver.js +29 -0
- package/dist/core/definition-slug-resolver.js.map +1 -1
- package/dist/core/errors.d.ts +10 -4
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +11 -5
- package/dist/core/errors.js.map +1 -1
- package/dist/core/example-seed.d.ts +8 -0
- package/dist/core/example-seed.d.ts.map +1 -1
- package/dist/core/example-seed.js +47 -10
- package/dist/core/example-seed.js.map +1 -1
- package/dist/core/inject/system-prompt.d.ts +8 -0
- package/dist/core/inject/system-prompt.d.ts.map +1 -1
- package/dist/core/inject/system-prompt.js +3 -1
- package/dist/core/inject/system-prompt.js.map +1 -1
- package/dist/core/macros.d.ts.map +1 -1
- package/dist/core/macros.js +5 -6
- package/dist/core/macros.js.map +1 -1
- package/dist/core/paths.d.ts +1 -0
- package/dist/core/paths.d.ts.map +1 -1
- package/dist/core/paths.js +1 -0
- package/dist/core/paths.js.map +1 -1
- package/dist/core/record-archive.d.ts +187 -0
- package/dist/core/record-archive.d.ts.map +1 -0
- package/dist/core/record-archive.js +465 -0
- package/dist/core/record-archive.js.map +1 -0
- package/dist/core/rehydration.d.ts +72 -0
- package/dist/core/rehydration.d.ts.map +1 -0
- package/dist/core/rehydration.js +72 -0
- package/dist/core/rehydration.js.map +1 -0
- package/dist/core/render-local-run.d.ts +82 -0
- package/dist/core/render-local-run.d.ts.map +1 -0
- package/dist/core/render-local-run.js +105 -0
- package/dist/core/render-local-run.js.map +1 -0
- package/dist/core/render-log-slice.d.ts +30 -0
- package/dist/core/render-log-slice.d.ts.map +1 -0
- package/dist/core/render-log-slice.js +49 -0
- package/dist/core/render-log-slice.js.map +1 -0
- package/dist/core/render-run-state.d.ts.map +1 -1
- package/dist/core/render-run-state.js +30 -49
- package/dist/core/render-run-state.js.map +1 -1
- package/dist/core/resume-brief.d.ts +130 -0
- package/dist/core/resume-brief.d.ts.map +1 -0
- package/dist/core/resume-brief.js +404 -0
- package/dist/core/resume-brief.js.map +1 -0
- package/dist/core/rolling-summary.d.ts +130 -0
- package/dist/core/rolling-summary.d.ts.map +1 -0
- package/dist/core/rolling-summary.js +227 -0
- package/dist/core/rolling-summary.js.map +1 -0
- package/dist/core/run-local-bootstrap.d.ts +93 -0
- package/dist/core/run-local-bootstrap.d.ts.map +1 -0
- package/dist/core/run-local-bootstrap.js +155 -0
- package/dist/core/run-local-bootstrap.js.map +1 -0
- package/dist/core/run-state.d.ts +16 -1
- package/dist/core/run-state.d.ts.map +1 -1
- package/dist/core/run-state.js +75 -25
- package/dist/core/run-state.js.map +1 -1
- package/dist/core/session-manager.d.ts +11 -3
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +56 -7
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-record.d.ts +165 -0
- package/dist/core/session-record.d.ts.map +1 -0
- package/dist/core/session-record.js +470 -0
- package/dist/core/session-record.js.map +1 -0
- package/dist/core/spawn-target.d.ts +12 -0
- package/dist/core/spawn-target.d.ts.map +1 -0
- package/dist/core/spawn-target.js +187 -0
- package/dist/core/spawn-target.js.map +1 -0
- package/dist/core/stub-feedback.d.ts +52 -0
- package/dist/core/stub-feedback.d.ts.map +1 -0
- package/dist/core/stub-feedback.js +33 -0
- package/dist/core/stub-feedback.js.map +1 -0
- package/dist/core/task-manager.d.ts.map +1 -1
- package/dist/core/task-manager.js +9 -1
- package/dist/core/task-manager.js.map +1 -1
- package/dist/core/template-catalog.d.ts +48 -0
- package/dist/core/template-catalog.d.ts.map +1 -0
- package/dist/core/template-catalog.js +338 -0
- package/dist/core/template-catalog.js.map +1 -0
- package/dist/core/workflow-registry.d.ts.map +1 -1
- package/dist/core/workflow-registry.js +2 -2
- package/dist/core/workflow-registry.js.map +1 -1
- package/dist/core/workspace-watcher.d.ts.map +1 -1
- package/dist/core/workspace-watcher.js +4 -3
- package/dist/core/workspace-watcher.js.map +1 -1
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -1
- package/dist/profiles/default.d.ts.map +1 -1
- package/dist/profiles/default.js +9 -14
- package/dist/profiles/default.js.map +1 -1
- package/dist/server/actions.d.ts +139 -0
- package/dist/server/actions.d.ts.map +1 -0
- package/dist/server/actions.js +430 -0
- package/dist/server/actions.js.map +1 -0
- package/dist/server/auth-routes.d.ts +92 -0
- package/dist/server/auth-routes.d.ts.map +1 -0
- package/dist/server/auth-routes.js +151 -0
- package/dist/server/auth-routes.js.map +1 -0
- package/dist/server/canvas.d.ts.map +1 -1
- package/dist/server/canvas.js +7 -7
- package/dist/server/canvas.js.map +1 -1
- package/dist/server/fs.d.ts.map +1 -1
- package/dist/server/fs.js +17 -1
- package/dist/server/fs.js.map +1 -1
- package/dist/server/index.d.ts +12 -3
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +0 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/ingest.d.ts +11 -0
- package/dist/server/ingest.d.ts.map +1 -1
- package/dist/server/ingest.js +1 -0
- package/dist/server/ingest.js.map +1 -1
- package/dist/server/macros.d.ts +4 -6
- package/dist/server/macros.d.ts.map +1 -1
- package/dist/server/macros.js.map +1 -1
- package/dist/server/rest.d.ts +18 -6
- package/dist/server/rest.d.ts.map +1 -1
- package/dist/server/rest.js +185 -50
- package/dist/server/rest.js.map +1 -1
- package/dist/server/runs.d.ts +16 -15
- package/dist/server/runs.d.ts.map +1 -1
- package/dist/server/runs.js +15 -80
- package/dist/server/runs.js.map +1 -1
- package/dist/server/static.d.ts +15 -1
- package/dist/server/static.d.ts.map +1 -1
- package/dist/server/static.js +54 -4
- package/dist/server/static.js.map +1 -1
- package/dist/server/templates.d.ts +24 -0
- package/dist/server/templates.d.ts.map +1 -0
- package/dist/server/templates.js +54 -0
- package/dist/server/templates.js.map +1 -0
- package/dist/shared/types.d.ts +558 -66
- package/dist/shared/types.d.ts.map +1 -1
- package/dist/shared/types.js +19 -11
- package/dist/shared/types.js.map +1 -1
- package/dist/web/assets/index-DC65cskq.js +446 -0
- package/dist/web/assets/index-xtD-3FFa.css +32 -0
- package/dist/web/canvas/sess-boot/index.html +305 -0
- package/dist/web/index.html +4 -9
- package/package.json +8 -4
- package/dist/core/canvas-enrich.d.ts +0 -115
- package/dist/core/canvas-enrich.d.ts.map +0 -1
- package/dist/core/canvas-enrich.js +0 -186
- package/dist/core/canvas-enrich.js.map +0 -1
- package/dist/core/run-spend.d.ts +0 -55
- package/dist/core/run-spend.d.ts.map +0 -1
- package/dist/core/run-spend.js +0 -109
- package/dist/core/run-spend.js.map +0 -1
- package/dist/core/run-transactions.d.ts +0 -60
- package/dist/core/run-transactions.d.ts.map +0 -1
- package/dist/core/run-transactions.js +0 -129
- package/dist/core/run-transactions.js.map +0 -1
- package/dist/profiles/canvas-guidelines.d.ts +0 -20
- package/dist/profiles/canvas-guidelines.d.ts.map +0 -1
- package/dist/profiles/canvas-guidelines.js +0 -48
- package/dist/profiles/canvas-guidelines.js.map +0 -1
- package/dist/server/skills.d.ts +0 -51
- package/dist/server/skills.d.ts.map +0 -1
- package/dist/server/skills.js +0 -312
- package/dist/server/skills.js.map +0 -1
- package/dist/web/assets/index-DM84J83Y.js +0 -234
- package/dist/web/assets/index-DemtWW4L.css +0 -32
package/dist/server/runs.js
CHANGED
|
@@ -1,40 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Runs router — backs GET /api/runs/:executionId/
|
|
2
|
+
* Runs router — backs GET /api/runs/:executionId/state.
|
|
3
3
|
*
|
|
4
|
-
* Returns a {@link RunView} (live status)
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
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 {
|
|
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
|
|
18
|
-
*
|
|
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:
|
|
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
|
package/dist/server/runs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runs.js","sourceRoot":"","sources":["../../src/server/runs.ts"],"names":[],"mappings":"AAAA
|
|
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"}
|
package/dist/server/static.d.ts
CHANGED
|
@@ -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
|
|
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"}
|
package/dist/server/static.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
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"}
|