@mesofact/runtime 0.8.29
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/README.md +19 -0
- package/dist/adapters/r2.d.ts +24 -0
- package/dist/adapters/r2.d.ts.map +1 -0
- package/dist/adapters/r2.js +136 -0
- package/dist/adapters/r2.js.map +1 -0
- package/dist/adapters/sqlite.d.ts +25 -0
- package/dist/adapters/sqlite.d.ts.map +1 -0
- package/dist/adapters/sqlite.js +131 -0
- package/dist/adapters/sqlite.js.map +1 -0
- package/dist/config.d.ts +29 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +139 -0
- package/dist/config.js.map +1 -0
- package/dist/contract.d.ts +40 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +5 -0
- package/dist/contract.js.map +1 -0
- package/dist/errors.d.ts +29 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +40 -0
- package/dist/errors.js.map +1 -0
- package/dist/head.d.ts +32 -0
- package/dist/head.d.ts.map +1 -0
- package/dist/head.js +93 -0
- package/dist/head.js.map +1 -0
- package/dist/health.d.ts +14 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +85 -0
- package/dist/health.js.map +1 -0
- package/dist/hooks.d.ts +28 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +64 -0
- package/dist/hooks.js.map +1 -0
- package/dist/hydration.d.ts +6 -0
- package/dist/hydration.d.ts.map +1 -0
- package/dist/hydration.js +68 -0
- package/dist/hydration.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest.d.ts +68 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +9 -0
- package/dist/manifest.js.map +1 -0
- package/dist/routes.d.ts +67 -0
- package/dist/routes.d.ts.map +1 -0
- package/dist/routes.js +130 -0
- package/dist/routes.js.map +1 -0
- package/dist/source.d.ts +36 -0
- package/dist/source.d.ts.map +1 -0
- package/dist/source.js +52 -0
- package/dist/source.js.map +1 -0
- package/dist/track-ctx.d.ts +13 -0
- package/dist/track-ctx.d.ts.map +1 -0
- package/dist/track-ctx.js +15 -0
- package/dist/track-ctx.js.map +1 -0
- package/dist/validate.d.ts +20 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +333 -0
- package/dist/validate.js.map +1 -0
- package/package.json +40 -0
- package/src/adapters/r2.ts +163 -0
- package/src/adapters/sqlite.ts +182 -0
- package/src/config.ts +213 -0
- package/src/contract.ts +82 -0
- package/src/errors.ts +52 -0
- package/src/head.ts +130 -0
- package/src/health.ts +99 -0
- package/src/hooks.ts +72 -0
- package/src/hydration.ts +72 -0
- package/src/index.ts +113 -0
- package/src/manifest.ts +104 -0
- package/src/routes.ts +320 -0
- package/src/source.ts +91 -0
- package/src/track-ctx.ts +29 -0
- package/src/validate.ts +388 -0
package/dist/validate.js
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
// Manifest validator — structural shape + semantic rules. Used by the build
|
|
2
|
+
// (fail before bad HTML hits R2) and mirrored in `crates/mesofact/src/validate.rs`
|
|
3
|
+
// for the proxy. Shared fixtures live at `tests/fixtures/manifests/`.
|
|
4
|
+
//
|
|
5
|
+
// Semantic rules:
|
|
6
|
+
// R1. Mode 1 (static) + `source_reads` referencing a non-`global` source
|
|
7
|
+
// is rejected. Mode 1 builds can't enumerate per-user/per-project keys.
|
|
8
|
+
// R2. Mode 1 + `requires` containing "user" is rejected. The build can't
|
|
9
|
+
// know who the user is.
|
|
10
|
+
//
|
|
11
|
+
// See `.yah/docs/architecture/mesofact.md` §"Render axis × source axis".
|
|
12
|
+
import { MANIFEST_VERSION } from "./manifest.js";
|
|
13
|
+
import { HOOK_NAMES, isHookName } from "./hooks.js";
|
|
14
|
+
const MODES = new Set(["static", "ssr", "spa"]);
|
|
15
|
+
const REQUIRES = new Set(["user", "project", "region"]);
|
|
16
|
+
const RESOLVED_PLACEMENTS = new Set(["host", "edge"]);
|
|
17
|
+
function isObject(x) {
|
|
18
|
+
return typeof x === "object" && x !== null && !Array.isArray(x);
|
|
19
|
+
}
|
|
20
|
+
function shape(path, message) {
|
|
21
|
+
return { kind: "shape", path, message };
|
|
22
|
+
}
|
|
23
|
+
function checkRoute(idx, raw, errs) {
|
|
24
|
+
const base = `routes[${idx}]`;
|
|
25
|
+
if (!isObject(raw)) {
|
|
26
|
+
errs.push(shape(base, "expected object"));
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
const out = {};
|
|
30
|
+
if (typeof raw.route !== "string")
|
|
31
|
+
errs.push(shape(`${base}.route`, "expected string"));
|
|
32
|
+
else
|
|
33
|
+
out.route = raw.route;
|
|
34
|
+
if (typeof raw.mode !== "string" || !MODES.has(raw.mode)) {
|
|
35
|
+
errs.push(shape(`${base}.mode`, "expected 'static' | 'ssr' | 'spa'"));
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
out.mode = raw.mode;
|
|
39
|
+
}
|
|
40
|
+
if (typeof raw.render_entrypoint !== "string") {
|
|
41
|
+
errs.push(shape(`${base}.render_entrypoint`, "expected string"));
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
out.render_entrypoint = raw.render_entrypoint;
|
|
45
|
+
}
|
|
46
|
+
if (raw.requires !== undefined) {
|
|
47
|
+
if (!Array.isArray(raw.requires) || raw.requires.some((r) => typeof r !== "string" || !REQUIRES.has(r))) {
|
|
48
|
+
errs.push(shape(`${base}.requires`, "expected ('user' | 'project' | 'region')[]"));
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
out.requires = raw.requires;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (raw.source_reads !== undefined) {
|
|
55
|
+
if (!Array.isArray(raw.source_reads) || raw.source_reads.some((s) => typeof s !== "string")) {
|
|
56
|
+
errs.push(shape(`${base}.source_reads`, "expected string[]"));
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
out.source_reads = raw.source_reads;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (raw.data_inputs !== undefined) {
|
|
63
|
+
if (!Array.isArray(raw.data_inputs) || raw.data_inputs.some((s) => typeof s !== "string")) {
|
|
64
|
+
errs.push(shape(`${base}.data_inputs`, "expected string[]"));
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
out.data_inputs = raw.data_inputs;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (!isObject(raw.cache_policy) || typeof raw.cache_policy.ttl !== "number") {
|
|
71
|
+
errs.push(shape(`${base}.cache_policy`, "expected { ttl: number, ... }"));
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
out.cache_policy = raw.cache_policy;
|
|
75
|
+
}
|
|
76
|
+
if (raw.concurrency !== undefined) {
|
|
77
|
+
if (typeof raw.concurrency !== "number") {
|
|
78
|
+
errs.push(shape(`${base}.concurrency`, "expected number"));
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
out.concurrency = raw.concurrency;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (raw.hydration !== undefined) {
|
|
85
|
+
const h = raw.hydration;
|
|
86
|
+
if (!isObject(h) || typeof h.script !== "string" || !Array.isArray(h.code_split)) {
|
|
87
|
+
errs.push(shape(`${base}.hydration`, "expected { script: string, code_split: string[] }"));
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
out.hydration = h;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (raw.prerender !== undefined) {
|
|
94
|
+
if (!isObject(raw.prerender)) {
|
|
95
|
+
errs.push(shape(`${base}.prerender`, "expected object"));
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
out.prerender = raw.prerender;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (raw.placement !== undefined) {
|
|
102
|
+
if (typeof raw.placement !== "string" || !RESOLVED_PLACEMENTS.has(raw.placement)) {
|
|
103
|
+
// The build resolves `"auto"` to a concrete value before emission, so
|
|
104
|
+
// the manifest only ever carries `"host"` or `"edge"`.
|
|
105
|
+
errs.push(shape(`${base}.placement`, "expected 'host' | 'edge'"));
|
|
106
|
+
}
|
|
107
|
+
else if (out.mode !== undefined && out.mode !== "ssr") {
|
|
108
|
+
errs.push(shape(`${base}.placement`, "placement is only valid on mode:'ssr'"));
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
out.placement = raw.placement;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (raw.resilience !== undefined) {
|
|
115
|
+
const res = checkResilience(base, raw.resilience, out.mode, errs);
|
|
116
|
+
if (res)
|
|
117
|
+
out.resilience = res;
|
|
118
|
+
}
|
|
119
|
+
if (errs.length && errs.some((e) => e.path.startsWith(base)))
|
|
120
|
+
return null;
|
|
121
|
+
return out;
|
|
122
|
+
}
|
|
123
|
+
const RETRY_ON_VALUES = new Set(["connection", "5xx", "any"]);
|
|
124
|
+
// Structural check for the W181 resilience block as carried in the manifest.
|
|
125
|
+
// `defineRoutes` already enforced the semantic rules (ssr-only, queue
|
|
126
|
+
// reserved, backoff length); this pass keeps a hand-written manifest honest
|
|
127
|
+
// and — like data_inputs before it (R014) — prevents the field from being
|
|
128
|
+
// silently stripped when the validator rebuilds the route object.
|
|
129
|
+
function checkResilience(base, raw, mode, errs) {
|
|
130
|
+
const path = `${base}.resilience`;
|
|
131
|
+
if (!isObject(raw)) {
|
|
132
|
+
errs.push(shape(path, "expected object"));
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
if (mode !== undefined && mode !== "ssr") {
|
|
136
|
+
errs.push(shape(path, "resilience is only valid on mode:'ssr'"));
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
if (raw.queue !== undefined) {
|
|
140
|
+
errs.push(shape(`${path}.queue`, "queue policy is reserved for v2 (W181) and must not be emitted"));
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
if (raw.timeout_ms !== undefined && typeof raw.timeout_ms !== "number") {
|
|
144
|
+
errs.push(shape(`${path}.timeout_ms`, "expected number"));
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
if (raw.retry !== undefined) {
|
|
148
|
+
const retry = raw.retry;
|
|
149
|
+
if (!isObject(retry) ||
|
|
150
|
+
typeof retry.attempts !== "number" ||
|
|
151
|
+
!Array.isArray(retry.backoff_ms) ||
|
|
152
|
+
retry.backoff_ms.some((b) => typeof b !== "number") ||
|
|
153
|
+
retry.backoff_ms.length !== retry.attempts - 1) {
|
|
154
|
+
errs.push(shape(`${path}.retry`, "expected { attempts: number, backoff_ms: number[attempts - 1], ... }"));
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
if (retry.retry_on !== undefined && (typeof retry.retry_on !== "string" || !RETRY_ON_VALUES.has(retry.retry_on))) {
|
|
158
|
+
errs.push(shape(`${path}.retry.retry_on`, "expected 'connection' | '5xx' | 'any'"));
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
if (retry.budget_ms !== undefined && typeof retry.budget_ms !== "number") {
|
|
162
|
+
errs.push(shape(`${path}.retry.budget_ms`, "expected number"));
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return raw;
|
|
167
|
+
}
|
|
168
|
+
function checkStaticAsset(idx, raw, errs) {
|
|
169
|
+
const base = `static_assets[${idx}]`;
|
|
170
|
+
if (!isObject(raw)) {
|
|
171
|
+
errs.push(shape(base, "expected object"));
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
if (typeof raw.key !== "string" ||
|
|
175
|
+
typeof raw.content_hash !== "string" ||
|
|
176
|
+
typeof raw.content_type !== "string" ||
|
|
177
|
+
typeof raw.immutable !== "boolean") {
|
|
178
|
+
errs.push(shape(base, "expected { key, content_hash, content_type, immutable }"));
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
return {
|
|
182
|
+
key: raw.key,
|
|
183
|
+
content_hash: raw.content_hash,
|
|
184
|
+
content_type: raw.content_type,
|
|
185
|
+
immutable: raw.immutable,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
function checkErrorRoutes(raw, errs) {
|
|
189
|
+
if (raw === undefined)
|
|
190
|
+
return undefined;
|
|
191
|
+
if (!isObject(raw)) {
|
|
192
|
+
errs.push(shape("error_routes", "expected object"));
|
|
193
|
+
return undefined;
|
|
194
|
+
}
|
|
195
|
+
const out = {};
|
|
196
|
+
if (raw["404"] !== undefined) {
|
|
197
|
+
if (typeof raw["404"] !== "string")
|
|
198
|
+
errs.push(shape("error_routes.404", "expected string"));
|
|
199
|
+
else
|
|
200
|
+
out["404"] = raw["404"];
|
|
201
|
+
}
|
|
202
|
+
if (raw["5xx"] !== undefined) {
|
|
203
|
+
if (typeof raw["5xx"] !== "string")
|
|
204
|
+
errs.push(shape("error_routes.5xx", "expected string"));
|
|
205
|
+
else
|
|
206
|
+
out["5xx"] = raw["5xx"];
|
|
207
|
+
}
|
|
208
|
+
return out;
|
|
209
|
+
}
|
|
210
|
+
// Mode 2 hooks (R756-F6). The name set is closed — only the engine invokes a
|
|
211
|
+
// hook, so an unrecognised name in a manifest is a build that emitted
|
|
212
|
+
// something nothing will ever call, not a forward-compatible extension.
|
|
213
|
+
function checkHooks(raw, errs) {
|
|
214
|
+
if (raw === undefined)
|
|
215
|
+
return undefined;
|
|
216
|
+
if (!isObject(raw)) {
|
|
217
|
+
errs.push(shape("hooks", "expected object"));
|
|
218
|
+
return undefined;
|
|
219
|
+
}
|
|
220
|
+
const out = {};
|
|
221
|
+
for (const [name, value] of Object.entries(raw)) {
|
|
222
|
+
if (!isHookName(name)) {
|
|
223
|
+
errs.push({
|
|
224
|
+
kind: "unknown_hook",
|
|
225
|
+
path: `hooks.${name}`,
|
|
226
|
+
message: `unknown hook '${name}' (known: ${HOOK_NAMES.join(", ")})`,
|
|
227
|
+
});
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
if (!isObject(value) || typeof value.entrypoint !== "string") {
|
|
231
|
+
errs.push(shape(`hooks.${name}`, "expected { entrypoint: string }"));
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
out[name] = { entrypoint: value.entrypoint };
|
|
235
|
+
}
|
|
236
|
+
return out;
|
|
237
|
+
}
|
|
238
|
+
function checkRules(manifest, catalog, errs) {
|
|
239
|
+
manifest.routes.forEach((route, idx) => {
|
|
240
|
+
if (route.mode !== "static")
|
|
241
|
+
return;
|
|
242
|
+
if (route.source_reads) {
|
|
243
|
+
for (const name of route.source_reads) {
|
|
244
|
+
const entry = catalog[name];
|
|
245
|
+
if (!entry) {
|
|
246
|
+
errs.push({
|
|
247
|
+
kind: "shape",
|
|
248
|
+
path: `routes[${idx}].source_reads`,
|
|
249
|
+
message: `route ${route.route}: source '${name}' not declared in catalog`,
|
|
250
|
+
});
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
if (entry.scope !== "global") {
|
|
254
|
+
errs.push({
|
|
255
|
+
kind: "mode1_scoped_source",
|
|
256
|
+
path: `routes[${idx}].source_reads`,
|
|
257
|
+
message: `route ${route.route}: Mode 1 cannot read from non-'global' source '${name}' (scope='${entry.scope}')`,
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
if (route.requires?.includes("user")) {
|
|
263
|
+
errs.push({
|
|
264
|
+
kind: "mode1_requires_user",
|
|
265
|
+
path: `routes[${idx}].requires`,
|
|
266
|
+
message: `route ${route.route}: Mode 1 cannot require 'user' (the build can't enumerate users)`,
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
export function validate(input, catalog = {}) {
|
|
272
|
+
const errs = [];
|
|
273
|
+
if (!isObject(input)) {
|
|
274
|
+
return { ok: false, errors: [shape("$", "expected object")] };
|
|
275
|
+
}
|
|
276
|
+
if (input.version !== MANIFEST_VERSION) {
|
|
277
|
+
errs.push({
|
|
278
|
+
kind: "unsupported_version",
|
|
279
|
+
path: "version",
|
|
280
|
+
message: `unsupported manifest version '${String(input.version)}' (expected '${MANIFEST_VERSION}')`,
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
if (typeof input.build_id !== "string")
|
|
284
|
+
errs.push(shape("build_id", "expected string"));
|
|
285
|
+
if (!Array.isArray(input.routes)) {
|
|
286
|
+
errs.push(shape("routes", "expected array"));
|
|
287
|
+
return { ok: false, errors: errs };
|
|
288
|
+
}
|
|
289
|
+
const routes = [];
|
|
290
|
+
input.routes.forEach((r, i) => {
|
|
291
|
+
const route = checkRoute(i, r, errs);
|
|
292
|
+
if (route)
|
|
293
|
+
routes.push(route);
|
|
294
|
+
});
|
|
295
|
+
const staticAssetsRaw = input.static_assets ?? [];
|
|
296
|
+
if (!Array.isArray(staticAssetsRaw)) {
|
|
297
|
+
errs.push(shape("static_assets", "expected array"));
|
|
298
|
+
return { ok: false, errors: errs };
|
|
299
|
+
}
|
|
300
|
+
const staticAssets = [];
|
|
301
|
+
staticAssetsRaw.forEach((a, i) => {
|
|
302
|
+
const asset = checkStaticAsset(i, a, errs);
|
|
303
|
+
if (asset)
|
|
304
|
+
staticAssets.push(asset);
|
|
305
|
+
});
|
|
306
|
+
const errorRoutes = checkErrorRoutes(input.error_routes, errs);
|
|
307
|
+
let ssrPrefixes;
|
|
308
|
+
if (input.ssr_prefixes !== undefined) {
|
|
309
|
+
if (!Array.isArray(input.ssr_prefixes) || input.ssr_prefixes.some((s) => typeof s !== "string")) {
|
|
310
|
+
errs.push(shape("ssr_prefixes", "expected string[]"));
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
ssrPrefixes = input.ssr_prefixes;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
const hooks = checkHooks(input.hooks, errs);
|
|
317
|
+
if (errs.length)
|
|
318
|
+
return { ok: false, errors: errs };
|
|
319
|
+
const manifest = {
|
|
320
|
+
version: input.version,
|
|
321
|
+
build_id: input.build_id,
|
|
322
|
+
routes,
|
|
323
|
+
static_assets: staticAssets,
|
|
324
|
+
...(errorRoutes ? { error_routes: errorRoutes } : {}),
|
|
325
|
+
...(ssrPrefixes !== undefined ? { ssr_prefixes: ssrPrefixes } : {}),
|
|
326
|
+
...(hooks !== undefined ? { hooks } : {}),
|
|
327
|
+
};
|
|
328
|
+
checkRules(manifest, catalog, errs);
|
|
329
|
+
if (errs.length)
|
|
330
|
+
return { ok: false, errors: errs };
|
|
331
|
+
return { ok: true, manifest };
|
|
332
|
+
}
|
|
333
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mesofact/runtime",
|
|
3
|
+
"version": "0.8.29",
|
|
4
|
+
"description": "Render contract types and adapter API for mesofact (RenderRequest, RenderResult, Source, error taxonomy)",
|
|
5
|
+
"license": "MIT OR Apache-2.0",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"main": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./hydration": {
|
|
18
|
+
"types": "./dist/hydration.d.ts",
|
|
19
|
+
"import": "./dist/hydration.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"src"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsc",
|
|
28
|
+
"typecheck": "tsc --noEmit",
|
|
29
|
+
"test": "bun test",
|
|
30
|
+
"clean": "rm -rf dist"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/node": "^22.0.0",
|
|
34
|
+
"typescript": "^5.8.3"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"aws4fetch": "^1.0.20",
|
|
38
|
+
"smol-toml": "^1.6.1"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
// `r2` adapter — read-only BlobSource over Cloudflare R2 (or any S3-compatible
|
|
2
|
+
// endpoint). Signs requests with SigV4 via `aws4fetch`, emits `r2:<bucket>:<key>`
|
|
3
|
+
// tags into the ambient trackCtx, honors per-call `.noTrack()` / `.timeout(ms)`.
|
|
4
|
+
//
|
|
5
|
+
// See `.yah/docs/architecture/mesofact.md` §"Adapter API surface" + §"Adapter
|
|
6
|
+
// read-set provenance".
|
|
7
|
+
|
|
8
|
+
import { AwsClient } from "aws4fetch";
|
|
9
|
+
import { BaseSource, type BlobSource, type ListOpts, type R2Object } from "../source.js";
|
|
10
|
+
import { SourceQueryError, SourceTimeoutError, SourceUnavailableError } from "../errors.js";
|
|
11
|
+
|
|
12
|
+
const DEFAULT_TIMEOUT_MS = 2000;
|
|
13
|
+
|
|
14
|
+
export type R2Config = {
|
|
15
|
+
// Logical source name from `mesofact.config.toml` (e.g. "assets"). Used as
|
|
16
|
+
// the registry key and surfaced in errors.
|
|
17
|
+
name: string;
|
|
18
|
+
// R2 bucket — also the `r2:<bucket>:...` tag prefix, per the design's tag
|
|
19
|
+
// taxonomy.
|
|
20
|
+
bucket: string;
|
|
21
|
+
// Endpoint root. For Cloudflare R2 this is
|
|
22
|
+
// `https://<account_id>.r2.cloudflarestorage.com`. No trailing slash.
|
|
23
|
+
endpoint: string;
|
|
24
|
+
accessKeyId: string;
|
|
25
|
+
secretAccessKey: string;
|
|
26
|
+
// Test seam — swap `fetch` to inject a stub. Defaults to `globalThis.fetch`,
|
|
27
|
+
// which aws4fetch already uses internally; passing a custom fn lets tests
|
|
28
|
+
// observe the signed request without hitting the network.
|
|
29
|
+
httpFetch?: typeof fetch;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export class R2Adapter extends BaseSource implements BlobSource {
|
|
33
|
+
readonly bucket: string;
|
|
34
|
+
private readonly client: AwsClient;
|
|
35
|
+
private readonly endpoint: string;
|
|
36
|
+
private readonly httpFetch: typeof fetch;
|
|
37
|
+
|
|
38
|
+
constructor(config: R2Config) {
|
|
39
|
+
super(config.name);
|
|
40
|
+
this.bucket = config.bucket;
|
|
41
|
+
this.endpoint = config.endpoint.replace(/\/$/, "");
|
|
42
|
+
this.client = new AwsClient({
|
|
43
|
+
accessKeyId: config.accessKeyId,
|
|
44
|
+
secretAccessKey: config.secretAccessKey,
|
|
45
|
+
service: "s3",
|
|
46
|
+
region: "auto",
|
|
47
|
+
});
|
|
48
|
+
// aws4fetch always uses globalThis.fetch internally; we sign manually and
|
|
49
|
+
// dispatch through `httpFetch` so tests can swap it without touching the
|
|
50
|
+
// global. Calling `globalThis.fetch.bind(globalThis)` preserves the
|
|
51
|
+
// expected receiver for fetch implementations that check it.
|
|
52
|
+
this.httpFetch = config.httpFetch ?? globalThis.fetch.bind(globalThis);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async fetch(key: string): Promise<Uint8Array | null> {
|
|
56
|
+
const { track, timeout_ms } = this.consumeOverrides(DEFAULT_TIMEOUT_MS);
|
|
57
|
+
this.emitTag(`r2:${this.bucket}:${key}`, track);
|
|
58
|
+
const url = `${this.endpoint}/${this.bucket}/${encodeKey(key)}`;
|
|
59
|
+
const res = await this.send(url, { method: "GET" }, timeout_ms);
|
|
60
|
+
if (res.status === 404) return null;
|
|
61
|
+
if (!res.ok) {
|
|
62
|
+
throw new SourceQueryError(this.name, `r2 GET ${key} → HTTP ${res.status}`);
|
|
63
|
+
}
|
|
64
|
+
const buf = await res.arrayBuffer();
|
|
65
|
+
return new Uint8Array(buf);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async list(prefix: string, opts: ListOpts = {}): Promise<R2Object[]> {
|
|
69
|
+
const { track, timeout_ms } = this.consumeOverrides(DEFAULT_TIMEOUT_MS);
|
|
70
|
+
this.emitTag(`r2:${this.bucket}:${prefix}*`, track);
|
|
71
|
+
const params = new URLSearchParams({ "list-type": "2", prefix });
|
|
72
|
+
if (opts.limit !== undefined) params.set("max-keys", String(opts.limit));
|
|
73
|
+
if (opts.cursor) params.set("continuation-token", opts.cursor);
|
|
74
|
+
if (opts.delimiter) params.set("delimiter", opts.delimiter);
|
|
75
|
+
const url = `${this.endpoint}/${this.bucket}?${params.toString()}`;
|
|
76
|
+
const res = await this.send(url, { method: "GET" }, timeout_ms);
|
|
77
|
+
if (!res.ok) {
|
|
78
|
+
throw new SourceQueryError(this.name, `r2 LIST ${prefix} → HTTP ${res.status}`);
|
|
79
|
+
}
|
|
80
|
+
return parseListV2(await res.text());
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private async send(url: string, init: RequestInit, timeout_ms: number): Promise<Response> {
|
|
84
|
+
const signed = await this.client.sign(url, init);
|
|
85
|
+
return this.race(() => this.httpFetch(signed), timeout_ms);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
private async race(call: () => Promise<Response>, timeout_ms: number): Promise<Response> {
|
|
89
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
90
|
+
try {
|
|
91
|
+
return await Promise.race<Response>([
|
|
92
|
+
call().catch((err) => {
|
|
93
|
+
throw new SourceUnavailableError(this.name, { cause: err });
|
|
94
|
+
}),
|
|
95
|
+
new Promise<Response>((_, reject) => {
|
|
96
|
+
timer = setTimeout(() => reject(new SourceTimeoutError(this.name, timeout_ms)), timeout_ms);
|
|
97
|
+
}),
|
|
98
|
+
]);
|
|
99
|
+
} finally {
|
|
100
|
+
if (timer) clearTimeout(timer);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// `encodeURIComponent` re-encodes `/`, which we want to preserve so S3 sees
|
|
106
|
+
// path-style keys correctly. Other reserved chars stay percent-encoded.
|
|
107
|
+
function encodeKey(key: string): string {
|
|
108
|
+
return key
|
|
109
|
+
.split("/")
|
|
110
|
+
.map((segment) => encodeURIComponent(segment))
|
|
111
|
+
.join("/");
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Minimal ListBucketResult v2 parser. S3's XML is a fixed shape; a regex over
|
|
115
|
+
// the `<Contents>` blocks is faster and dep-free than pulling in a full XML
|
|
116
|
+
// parser, and the only fields the contract exposes are key/size/last_modified/
|
|
117
|
+
// etag (per `R2Object`).
|
|
118
|
+
function parseListV2(xml: string): R2Object[] {
|
|
119
|
+
const out: R2Object[] = [];
|
|
120
|
+
for (const match of xml.matchAll(/<Contents>([\s\S]*?)<\/Contents>/g)) {
|
|
121
|
+
const inner = match[1]!;
|
|
122
|
+
const key = pick(inner, "Key");
|
|
123
|
+
const sizeStr = pick(inner, "Size");
|
|
124
|
+
const last_modified = pick(inner, "LastModified");
|
|
125
|
+
const etagRaw = pick(inner, "ETag");
|
|
126
|
+
if (key === undefined || sizeStr === undefined || last_modified === undefined) continue;
|
|
127
|
+
out.push({
|
|
128
|
+
key,
|
|
129
|
+
size: Number.parseInt(sizeStr, 10),
|
|
130
|
+
last_modified,
|
|
131
|
+
...(etagRaw ? { etag: etagRaw.replace(/^"|"$/g, "") } : {}),
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
return out;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function pick(haystack: string, tag: string): string | undefined {
|
|
138
|
+
const m = haystack.match(new RegExp(`<${tag}>([\\s\\S]*?)</${tag}>`));
|
|
139
|
+
return m?.[1];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Per-process registry. Configuration in T4 loads `mesofact.config.toml` and
|
|
143
|
+
// calls `registerR2()` for each `[sources.*]` of `kind = "r2"`. Render code
|
|
144
|
+
// looks up by name via `r2(name)`.
|
|
145
|
+
const registry = new Map<string, R2Adapter>();
|
|
146
|
+
|
|
147
|
+
export function registerR2(adapter: R2Adapter): void {
|
|
148
|
+
registry.set(adapter.name, adapter);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function clearR2Registry(): void {
|
|
152
|
+
registry.clear();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function r2(name: string): BlobSource {
|
|
156
|
+
const adapter = registry.get(name);
|
|
157
|
+
if (!adapter) {
|
|
158
|
+
throw new Error(
|
|
159
|
+
`r2 source not registered: ${name} (declare it in mesofact.config.toml under [sources.${name}])`,
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
return adapter;
|
|
163
|
+
}
|