@demiurgejs/core 0.1.0 → 0.1.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.
@@ -1,54 +1,81 @@
1
- import { mkdir as d, mkdtemp as b, writeFile as m, cp as C, rm as y, readFile as R } from "node:fs/promises";
2
- import { resolve as w, dirname as g, join as S, relative as x, sep as P } from "node:path";
3
- import { d as T } from "../chunks/index-BnX9Qxbm.js";
4
- import { c as L, a as M, b as q, h as A, r as k, d as W } from "../chunks/testing-BBnJ5WUR.js";
1
+ import { mkdir as p, mkdtemp as k, writeFile as E, cp as P, rm as g, readFile as b } from "node:fs/promises";
2
+ import { resolve as w, dirname as O, join as m, relative as M, sep as H } from "node:path";
3
+ import { d as I } from "../chunks/index-BnX9Qxbm.js";
4
+ import { S as $ } from "../chunks/ssr-BJejKlkZ.js";
5
+ import { c as _, a as D, b as U, h as j, r as q, d as x } from "../chunks/testing-DR3eQAvY.js";
5
6
  import "react-dom/server";
6
7
  import "react";
7
8
  import "react/jsx-runtime";
8
- const N = "demiurge-static-manifest.json", it = T({
9
+ import { C as W, I as B, R as G } from "../chunks/static-files-DUjHw-4H.js";
10
+ const C = "demiurge-static-manifest.json", yt = I({
9
11
  name: "static",
10
12
  capabilities: {
11
13
  staticOutput: !0
12
14
  }
13
15
  });
14
- async function nt(t) {
15
- const e = j(t.origin), i = w(t.outDir), r = L(t.routes), n = await M(r);
16
- H(r, n.length);
17
- const s = I(n.map((u) => u.pathname)), c = q(), o = [], a = { ...t.ssr, navigation: "document" };
18
- for (const u of s) {
19
- const l = O(e, u.pathname), F = await A(r, l, {
16
+ async function Et(t) {
17
+ const e = z(t.origin), r = w(t.outDir), n = _(t.routes), o = await Q(n), i = await D(n, {
18
+ includeResources: !0
19
+ });
20
+ V(
21
+ n,
22
+ i.filter((u) => o.get(u.file) === "document").length
23
+ );
24
+ const c = Z(
25
+ i.map((u) => ({
26
+ kind: o.get(u.file) ?? "resource",
27
+ pathname: u.pathname
28
+ }))
29
+ ), a = U(), s = [], f = { ...t.ssr, navigation: "document" };
30
+ for (const u of c) {
31
+ const l = v(e, u.pathname, u.kind), y = await j(n, l, {
20
32
  onError: t.onError,
21
- rateLimitStore: c,
22
- ssr: a
33
+ rateLimitStore: a,
34
+ ssr: f
23
35
  });
24
- o.push(await E(u, F, 200));
36
+ s.push(
37
+ u.kind === "document" ? await T(u, y, 200) : await rt(u, y)
38
+ );
25
39
  }
26
- const f = await k(
27
- r,
28
- O(e, "/404"),
40
+ const d = await q(
41
+ n,
42
+ v(e, "/404", "document"),
29
43
  {
30
- ...a,
44
+ ...f,
31
45
  onError: (u, l) => t.onError?.(u, { pathname: "/404", site: l })
32
46
  }
33
47
  );
34
- o.push(
35
- await E(
48
+ s.push(
49
+ await T(
36
50
  {
37
51
  file: "404.html",
38
52
  pathname: "*"
39
53
  },
40
- f,
54
+ d,
41
55
  404
42
56
  )
43
- ), o.sort((u, l) => u.file.localeCompare(l.file));
44
- const p = {
57
+ ), s.sort((u, l) => u.file.localeCompare(l.file));
58
+ const S = {
45
59
  adapter: "static",
46
- entries: o.map(({ html: u, ...l }) => l),
60
+ entries: s.map(({ body: u, ...l }) => l),
61
+ fileHeaderRules: K(),
47
62
  version: 1
48
63
  };
49
- return await K(i, o, p), p;
64
+ return await at(r, s, S), S;
50
65
  }
51
- function j(t) {
66
+ function K() {
67
+ return [
68
+ {
69
+ headers: { "cache-control": B },
70
+ pattern: W.source
71
+ },
72
+ {
73
+ headers: { "cache-control": G },
74
+ pattern: ".*"
75
+ }
76
+ ];
77
+ }
78
+ function z(t) {
52
79
  let e;
53
80
  try {
54
81
  e = new URL(t ?? "http://demiurge.local");
@@ -63,194 +90,288 @@ function j(t) {
63
90
  );
64
91
  return e.origin;
65
92
  }
66
- function H(t, e) {
93
+ function V(t, e) {
67
94
  if (e === 0)
68
95
  throw new Error("Static output requires at least one page route.");
69
96
  if (!t.fallbacks.notFound.some(
70
- (r) => r.fileSegments.length === 0
97
+ (n) => n.fileSegments.length === 0
71
98
  ))
72
99
  throw new Error(
73
100
  "Static output requires a root @not-found.tsx so 404.html is app-owned."
74
101
  );
75
102
  }
76
- function I(t) {
77
- const e = /* @__PURE__ */ new Map(), i = /* @__PURE__ */ new Set();
78
- return t.map((r) => {
79
- if (i.has(r))
80
- throw new Error(`Static output collected duplicate pathname ${JSON.stringify(r)}.`);
81
- i.add(r);
82
- const n = U(r), s = n.toLocaleLowerCase("en-US"), c = e.get(s);
83
- if (c)
103
+ async function Q(t) {
104
+ const e = /* @__PURE__ */ new Map();
105
+ for (const r of t.routes) {
106
+ const n = await r.load(), o = X(n);
107
+ if (o.length > 0)
108
+ throw new Error(
109
+ `Static route ${JSON.stringify(r.file)} exports unsupported methods ${o.join(", ")}. Deploy a runtime adapter for request-time methods.`
110
+ );
111
+ if (!n.GET)
112
+ throw new Error(
113
+ `Static route ${JSON.stringify(r.file)} does not export GET and cannot produce an output file.`
114
+ );
115
+ if (n.GET.kind === "page") {
116
+ e.set(r.file, "document");
117
+ continue;
118
+ }
119
+ Y(r.file, n.GET), e.set(r.file, "resource");
120
+ }
121
+ return e;
122
+ }
123
+ function X(t) {
124
+ return ["POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"].filter((e) => t[e] !== void 0);
125
+ }
126
+ function Y(t, e) {
127
+ if ((e.kind === "text" || e.kind === "html" || e.kind === "json") && typeof e.value != "function")
128
+ return;
129
+ const r = "value" in e && typeof e.value == "function" ? `uses a request-dependent ${e.kind} value` : `uses the ${e.kind} response helper`;
130
+ throw new Error(
131
+ `Static route ${JSON.stringify(t)} ${r} and cannot produce a fixed output file. Use a fixed text, html, or json value, or deploy a runtime adapter.`
132
+ );
133
+ }
134
+ function Z(t) {
135
+ const e = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Set();
136
+ return t.map(({ kind: n, pathname: o }) => {
137
+ if (r.has(o))
138
+ throw new Error(`Static output collected duplicate pathname ${JSON.stringify(o)}.`);
139
+ r.add(o);
140
+ const i = n === "document" ? J(o) : tt(o), c = i.toLocaleLowerCase("en-US"), a = [...e.entries()].find(
141
+ ([s]) => s === c || s.startsWith(`${c}/`) || c.startsWith(`${s}/`)
142
+ );
143
+ if (a)
84
144
  throw new Error(
85
- `Static paths ${JSON.stringify(c)} and ${JSON.stringify(r)} map to the same portable output file ${JSON.stringify(n)}.`
145
+ `Static paths ${JSON.stringify(a[1])} and ${JSON.stringify(o)} map to the same portable output file or to a file and directory conflict.`
86
146
  );
87
- return e.set(s, r), { file: n, pathname: r };
147
+ return e.set(c, o), { file: i, kind: n, pathname: o };
88
148
  });
89
149
  }
90
- function U(t) {
150
+ function J(t) {
91
151
  if (!t.startsWith("/") || t.includes("?") || t.includes("#"))
92
152
  throw new Error(`Static output received invalid pathname ${JSON.stringify(t)}.`);
93
- return t === "/" ? "index.html" : [...t.split("/").slice(1).map((i) => {
94
- let r;
153
+ return t === "/" ? "index.html" : [...t.split("/").slice(1).map((r) => {
154
+ let n;
95
155
  try {
96
- r = decodeURIComponent(i);
156
+ n = decodeURIComponent(r);
97
157
  } catch {
98
158
  throw new Error(`Static output pathname is not valid UTF-8: ${JSON.stringify(t)}.`);
99
159
  }
100
- return _(r, t), r;
160
+ return et(n, t), n;
101
161
  }), "index.html"].join("/");
102
162
  }
103
- function _(t, e) {
104
- const i = /[<>:"|?*]/.test(t) || [...t].some((r) => r.charCodeAt(0) <= 31) || /[. ]$/.test(t) || /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i.test(t);
105
- if (!t || t === "." || t === ".." || t.includes("/") || t.includes("\\") || i)
163
+ function tt(t) {
164
+ if (t === "/")
165
+ throw new Error("A static resource route cannot own the root pathname.");
166
+ return J(t).slice(0, -11);
167
+ }
168
+ function et(t, e) {
169
+ const r = /[<>:"|?*]/.test(t) || [...t].some((n) => n.charCodeAt(0) <= 31) || /[. ]$/.test(t) || /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i.test(t);
170
+ if (!t || t === "." || t === ".." || t.includes("/") || t.includes("\\") || r)
106
171
  throw new Error(
107
172
  `Static pathname ${JSON.stringify(e)} contains a segment that is unsafe or not portable as a file name: ${JSON.stringify(t)}.`
108
173
  );
109
174
  }
110
- function O(t, e) {
175
+ function v(t, e, r) {
111
176
  return new Request(`${t}${e}`, {
112
- headers: { accept: "text/html" }
177
+ headers: { accept: r === "document" ? "text/html" : "*/*" }
113
178
  });
114
179
  }
115
- async function E(t, e, i) {
116
- if (e.status !== i)
180
+ async function T(t, e, r) {
181
+ if (e.status !== r)
182
+ throw new Error(
183
+ `Static output for ${JSON.stringify(t.pathname)} returned status ${e.status}; expected ${r}.`
184
+ );
185
+ const n = e.headers.get("content-type");
186
+ if (!n?.toLowerCase().startsWith("text/html"))
117
187
  throw new Error(
118
- `Static output for ${JSON.stringify(t.pathname)} returned status ${e.status}; expected ${i}.`
188
+ `Static output for ${JSON.stringify(t.pathname)} returned ${JSON.stringify(n)} instead of text/html.`
119
189
  );
120
- const r = e.headers.get("content-type");
121
- if (!r?.toLowerCase().startsWith("text/html"))
190
+ if (e.headers.has("set-cookie"))
191
+ throw new Error(
192
+ `Static output for ${JSON.stringify(t.pathname)} attempted to set a cookie. Build artifacts cannot contain per-user response state.`
193
+ );
194
+ const o = await nt(
195
+ await e.text(),
196
+ e.headers
197
+ );
198
+ return await it(t.pathname, o, e.headers), {
199
+ file: t.file,
200
+ headers: A(e.headers),
201
+ body: o,
202
+ pathname: t.pathname,
203
+ status: r
204
+ };
205
+ }
206
+ async function rt(t, e) {
207
+ if (e.status !== 200)
122
208
  throw new Error(
123
- `Static output for ${JSON.stringify(t.pathname)} returned ${JSON.stringify(r)} instead of text/html.`
209
+ `Static output for ${JSON.stringify(t.pathname)} returned status ${e.status}; expected 200.`
124
210
  );
125
211
  if (e.headers.has("set-cookie"))
126
212
  throw new Error(
127
213
  `Static output for ${JSON.stringify(t.pathname)} attempted to set a cookie. Build artifacts cannot contain per-user response state.`
128
214
  );
129
- const n = await e.text();
130
- return await B(t.pathname, n, e.headers), {
131
- ...t,
132
- headers: G(e.headers),
133
- html: n,
134
- status: i
215
+ return {
216
+ file: t.file,
217
+ headers: A(e.headers),
218
+ body: await e.text(),
219
+ pathname: t.pathname,
220
+ status: 200
135
221
  };
136
222
  }
137
- async function B(t, e, i) {
138
- const r = i.get("content-security-policy");
139
- if (!r)
223
+ async function nt(t, e) {
224
+ const r = new RegExp(
225
+ `(?:^|\\s)${$}(?:\\s|$)`
226
+ ), n = F(t, "script").filter((i) => r.test(i.attributes));
227
+ if (n.length === 0)
228
+ return t;
229
+ const o = await Promise.all(
230
+ n.map((i) => x(i.content))
231
+ );
232
+ for (const i of [
233
+ "content-security-policy",
234
+ "content-security-policy-report-only"
235
+ ]) {
236
+ const c = e.get(i);
237
+ c && e.set(i, ot(c, o));
238
+ }
239
+ return t.replace(
240
+ new RegExp(`\\s${$}(?=\\s|>)`, "g"),
241
+ ""
242
+ );
243
+ }
244
+ function ot(t, e) {
245
+ const r = t.split(";").map((s) => s.trim()).filter(Boolean), n = r.findIndex(
246
+ (s) => s.split(/\s+/, 1)[0]?.toLowerCase() === "script-src"
247
+ ), o = r.find(
248
+ (s) => s.split(/\s+/, 1)[0]?.toLowerCase() === "default-src"
249
+ ), i = n === -1 ? o : r[n];
250
+ if (!i)
251
+ return t;
252
+ const c = i.split(/\s+/).slice(1).filter((s) => s !== "'none'"), a = [
253
+ "script-src",
254
+ .../* @__PURE__ */ new Set([...c, ...e])
255
+ ].join(" ");
256
+ return n === -1 ? r.push(a) : r[n] = a, r.join("; ");
257
+ }
258
+ async function it(t, e, r) {
259
+ const n = r.get("content-security-policy");
260
+ if (!n)
140
261
  return;
141
- if (/'nonce-[^']+'/i.test(r) || /\snonce\s*=/i.test(e))
262
+ if (/'nonce-[^']+'/i.test(n) || /\snonce\s*=/i.test(e))
142
263
  throw new Error(
143
264
  `Static output for ${JSON.stringify(t)} uses a nonce-backed CSP. Use security.static() with stable hashes or a runtime adapter that injects a fresh nonce.`
144
265
  );
145
- const n = z(r);
146
- await $(
266
+ const o = st(n);
267
+ await N(
147
268
  t,
148
269
  e,
149
270
  "script",
150
- h(n, "script-src")
151
- ), await $(
271
+ h(o, "script-src")
272
+ ), await N(
152
273
  t,
153
274
  e,
154
275
  "style",
155
- h(n, "style-src")
276
+ h(o, "style-src")
156
277
  );
157
- const s = h(n, "style-src");
158
- if (/\sstyle\s*=/i.test(e) && !s.includes("'unsafe-inline'"))
278
+ const i = h(o, "style-src");
279
+ if (i && /\sstyle\s*=/i.test(e) && !i.includes("'unsafe-inline'"))
159
280
  throw new Error(
160
281
  `Static output for ${JSON.stringify(t)} contains an inline style attribute that its CSP does not allow. Move the style into a stylesheet or explicitly allow inline styles.`
161
282
  );
162
283
  }
163
- function z(t) {
284
+ function st(t) {
164
285
  const e = /* @__PURE__ */ new Map();
165
- for (const i of t.split(";")) {
166
- const [r, ...n] = i.trim().split(/\s+/);
167
- r && e.set(r.toLowerCase(), n);
286
+ for (const r of t.split(";")) {
287
+ const [n, ...o] = r.trim().split(/\s+/);
288
+ n && e.set(n.toLowerCase(), o);
168
289
  }
169
290
  return e;
170
291
  }
171
292
  function h(t, e) {
172
- return t.get(e) ?? t.get("default-src") ?? [];
293
+ return t.get(e) ?? t.get("default-src");
173
294
  }
174
- async function $(t, e, i, r) {
175
- if (!r.includes("'unsafe-inline'"))
176
- for (const n of D(e, i)) {
177
- if (i === "script" && /(?:^|\s)src\s*=/i.test(n.attributes) || !n.content)
295
+ async function N(t, e, r, n) {
296
+ if (!(!n || n.includes("'unsafe-inline'")))
297
+ for (const o of F(e, r)) {
298
+ if (r === "script" && /(?:^|\s)src\s*=/i.test(o.attributes) || !o.content)
178
299
  continue;
179
- const s = await W(n.content);
180
- if (!r.includes(s))
300
+ const i = await x(o.content);
301
+ if (!n.includes(i))
181
302
  throw new Error(
182
- `Static output for ${JSON.stringify(t)} contains an inline ${i} without the required CSP hash ${s}.`
303
+ `Static output for ${JSON.stringify(t)} contains an inline ${r} without the required CSP hash ${i}.`
183
304
  );
184
305
  }
185
306
  }
186
- function D(t, e) {
187
- const i = t.toLowerCase(), r = [], n = `<${e}`, s = `</${e}`;
307
+ function F(t, e) {
308
+ const r = t.toLowerCase(), n = [], o = `<${e}`, i = `</${e}`;
188
309
  let c = 0;
189
310
  for (; c < t.length; ) {
190
- const o = i.indexOf(n, c);
191
- if (o === -1)
311
+ const a = r.indexOf(o, c);
312
+ if (a === -1)
192
313
  break;
193
- const a = i.indexOf(">", o + n.length), f = a === -1 ? -1 : i.indexOf(s, a + 1), p = f === -1 ? -1 : i.indexOf(">", f + s.length);
194
- if (a === -1 || f === -1 || p === -1)
314
+ const s = r.indexOf(">", a + o.length), f = s === -1 ? -1 : r.indexOf(i, s + 1), d = f === -1 ? -1 : r.indexOf(">", f + i.length);
315
+ if (s === -1 || f === -1 || d === -1)
195
316
  throw new Error(`Static output contains an unclosed <${e}> element.`);
196
- r.push({
197
- attributes: t.slice(o + n.length, a),
198
- content: t.slice(a + 1, f)
199
- }), c = p + 1;
317
+ n.push({
318
+ attributes: t.slice(a + o.length, s),
319
+ content: t.slice(s + 1, f)
320
+ }), c = d + 1;
200
321
  }
201
- return r;
322
+ return n;
202
323
  }
203
- function G(t) {
324
+ function A(t) {
204
325
  return Object.fromEntries(
205
- [...t.entries()].sort(([e], [i]) => e.localeCompare(i))
326
+ [...t.entries()].sort(([e], [r]) => e.localeCompare(r))
206
327
  );
207
328
  }
208
- async function K(t, e, i) {
209
- const r = g(t);
210
- await d(r, { recursive: !0 });
211
- const n = await b(S(r, ".demiurge-static-"));
329
+ async function at(t, e, r) {
330
+ const n = O(t);
331
+ await p(n, { recursive: !0 });
332
+ const o = await k(m(n, ".demiurge-static-"));
212
333
  try {
213
- for (const o of e) {
214
- const a = v(n, o.file);
215
- await d(g(a), { recursive: !0 }), await m(a, o.html);
334
+ for (const a of e) {
335
+ const s = R(o, a.file);
336
+ await p(O(s), { recursive: !0 }), await E(s, a.body);
216
337
  }
217
- await m(
218
- S(n, N),
219
- `${JSON.stringify(i, null, 2)}
338
+ await E(
339
+ m(o, C),
340
+ `${JSON.stringify(r, null, 2)}
220
341
  `
221
342
  );
222
- const s = await Q(t);
223
- await d(t, { recursive: !0 }), await C(n, t, { recursive: !0, force: !0 });
224
- const c = new Set(e.map((o) => o.file));
225
- for (const o of s)
226
- c.has(o) || await y(v(t, o), { force: !0 });
343
+ const i = await ct(t);
344
+ await p(t, { recursive: !0 }), await P(o, t, { recursive: !0, force: !0 });
345
+ const c = new Set(e.map((a) => a.file));
346
+ for (const a of i)
347
+ c.has(a) || await g(R(t, a), { force: !0 });
227
348
  } finally {
228
- await y(n, { force: !0, recursive: !0 });
349
+ await g(o, { force: !0, recursive: !0 });
229
350
  }
230
351
  }
231
- async function Q(t) {
352
+ async function ct(t) {
232
353
  try {
233
- const e = await R(S(t, N), "utf8"), i = JSON.parse(e);
234
- return i.adapter !== "static" || i.version !== 1 || !Array.isArray(i.entries) ? [] : i.entries.flatMap(
235
- (r) => typeof r.file == "string" && r.file.endsWith(".html") && J(r.file) ? [r.file] : []
354
+ const e = await b(m(t, C), "utf8"), r = JSON.parse(e);
355
+ return r.adapter !== "static" || r.version !== 1 || !Array.isArray(r.entries) ? [] : r.entries.flatMap(
356
+ (n) => typeof n.file == "string" && L(n.file) ? [n.file] : []
236
357
  );
237
358
  } catch {
238
359
  return [];
239
360
  }
240
361
  }
241
- function v(t, e) {
242
- if (!J(e))
362
+ function R(t, e) {
363
+ if (!L(e))
243
364
  throw new Error(`Static output file must stay inside the output directory: ${JSON.stringify(e)}.`);
244
- const i = w(t), r = w(i, e);
245
- if (x(i, r).split(P).includes(".."))
365
+ const r = w(t), n = w(r, e);
366
+ if (M(r, n).split(H).includes(".."))
246
367
  throw new Error(`Static output file escaped the output directory: ${JSON.stringify(e)}.`);
247
- return r;
368
+ return n;
248
369
  }
249
- function J(t) {
370
+ function L(t) {
250
371
  return !!t && !t.startsWith("/") && !t.startsWith("\\") && !t.split(/[\\/]/).includes("..");
251
372
  }
252
373
  export {
253
- nt as generateStaticOutput,
254
- it as staticAdapter
374
+ Et as generateStaticOutput,
375
+ yt as staticAdapter
255
376
  };
256
377
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/static/index.ts"],"sourcesContent":["import {\n cp,\n mkdir,\n mkdtemp,\n readFile,\n rm,\n writeFile,\n} from \"node:fs/promises\";\nimport { dirname, join, relative, resolve, sep } from \"node:path\";\nimport { defineAdapter } from \"../adapter\";\nimport {\n collectStaticRoutePaths,\n createRouteManifest,\n type RouteManifest,\n} from \"../router\";\nimport type { RouteImporter } from \"../route\";\nimport {\n handleRequestWithManifest,\n renderNotFoundResponse,\n type RequestErrorReporter,\n type SsrOptions,\n} from \"../server\";\nimport { createMemoryRateLimitStore, cspHash } from \"../security\";\n\nconst STATIC_MANIFEST_FILE = \"demiurge-static-manifest.json\";\n\nexport const staticAdapter = defineAdapter({\n name: \"static\",\n capabilities: {\n staticOutput: true,\n },\n});\n\nexport type StaticOutputEntry = {\n file: string;\n headers: Record<string, string>;\n pathname: string;\n status: 200 | 404;\n};\n\nexport type StaticOutputManifest = {\n adapter: \"static\";\n entries: StaticOutputEntry[];\n version: 1;\n};\n\nexport type GenerateStaticOutputOptions = {\n onError?: RequestErrorReporter;\n origin?: string;\n outDir: string;\n routes: Record<string, RouteImporter>;\n ssr?: SsrOptions;\n};\n\ntype PendingOutput = StaticOutputEntry & {\n html: string;\n};\n\nexport async function generateStaticOutput(\n options: GenerateStaticOutputOptions,\n): Promise<StaticOutputManifest> {\n const origin = normalizeOrigin(options.origin);\n const outDir = resolve(options.outDir);\n const manifest = createRouteManifest(options.routes);\n const paths = await collectStaticRoutePaths(manifest);\n\n assertStaticPageApp(manifest, paths.length);\n\n const outputEntries = planOutputEntries(paths.map((path) => path.pathname));\n const rateLimitStore = createMemoryRateLimitStore();\n const pending: PendingOutput[] = [];\n const ssr = { ...options.ssr, navigation: \"document\" as const };\n\n for (const entry of outputEntries) {\n const request = createDocumentRequest(origin, entry.pathname);\n const response = await handleRequestWithManifest(manifest, request, {\n onError: options.onError,\n rateLimitStore,\n ssr,\n });\n\n pending.push(await prepareOutput(entry, response, 200));\n }\n\n const notFoundResponse = await renderNotFoundResponse(\n manifest,\n createDocumentRequest(origin, \"/404\"),\n {\n ...ssr,\n onError: (error, site) =>\n options.onError?.(error, { pathname: \"/404\", site }),\n },\n );\n pending.push(\n await prepareOutput(\n {\n file: \"404.html\",\n pathname: \"*\",\n },\n notFoundResponse,\n 404,\n ),\n );\n\n pending.sort((left, right) => left.file.localeCompare(right.file));\n\n const outputManifest: StaticOutputManifest = {\n adapter: \"static\",\n entries: pending.map(({ html: _html, ...entry }) => entry),\n version: 1,\n };\n\n await writeOutput(outDir, pending, outputManifest);\n\n return outputManifest;\n}\n\nfunction normalizeOrigin(value: string | undefined) {\n let origin: URL;\n\n try {\n origin = new URL(value ?? \"http://demiurge.local\");\n } catch {\n throw new Error(\n `Static output origin must be an absolute HTTP(S) origin: ${JSON.stringify(value)}.`,\n );\n }\n\n if (\n (origin.protocol !== \"http:\" && origin.protocol !== \"https:\") ||\n origin.username ||\n origin.password ||\n origin.pathname !== \"/\" ||\n origin.search ||\n origin.hash\n ) {\n throw new Error(\n `Static output origin must be an HTTP(S) origin without credentials, a path, query, or hash: ${JSON.stringify(value)}.`,\n );\n }\n\n return origin.origin;\n}\n\nfunction assertStaticPageApp(manifest: RouteManifest, pageCount: number) {\n if (pageCount === 0) {\n throw new Error(\"Static output requires at least one page route.\");\n }\n\n const hasRootNotFound = manifest.fallbacks.notFound.some(\n (fallback) => fallback.fileSegments.length === 0,\n );\n\n if (!hasRootNotFound) {\n throw new Error(\n \"Static output requires a root @not-found.tsx so 404.html is app-owned.\",\n );\n }\n}\n\nfunction planOutputEntries(pathnames: string[]) {\n const seenFiles = new Map<string, string>();\n const seenPathnames = new Set<string>();\n\n return pathnames.map((pathname) => {\n if (seenPathnames.has(pathname)) {\n throw new Error(`Static output collected duplicate pathname ${JSON.stringify(pathname)}.`);\n }\n\n seenPathnames.add(pathname);\n\n const file = pathnameToFile(pathname);\n const portableFile = file.toLocaleLowerCase(\"en-US\");\n const conflictingPathname = seenFiles.get(portableFile);\n\n if (conflictingPathname) {\n throw new Error(\n `Static paths ${JSON.stringify(conflictingPathname)} and ${JSON.stringify(pathname)} map to the same portable output file ${JSON.stringify(file)}.`,\n );\n }\n\n seenFiles.set(portableFile, pathname);\n\n return { file, pathname };\n });\n}\n\nfunction pathnameToFile(pathname: string) {\n if (!pathname.startsWith(\"/\") || pathname.includes(\"?\") || pathname.includes(\"#\")) {\n throw new Error(`Static output received invalid pathname ${JSON.stringify(pathname)}.`);\n }\n\n if (pathname === \"/\") {\n return \"index.html\";\n }\n\n const segments = pathname.split(\"/\").slice(1).map((segment) => {\n let decoded: string;\n\n try {\n decoded = decodeURIComponent(segment);\n } catch {\n throw new Error(`Static output pathname is not valid UTF-8: ${JSON.stringify(pathname)}.`);\n }\n\n assertPortableSegment(decoded, pathname);\n return decoded;\n });\n\n return [...segments, \"index.html\"].join(\"/\");\n}\n\nfunction assertPortableSegment(segment: string, pathname: string) {\n const invalidWindowsName = /[<>:\"|?*]/.test(segment) ||\n [...segment].some((character) => character.charCodeAt(0) <= 31) ||\n /[. ]$/.test(segment) ||\n /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\\.|$)/i.test(segment);\n\n if (\n !segment ||\n segment === \".\" ||\n segment === \"..\" ||\n segment.includes(\"/\") ||\n segment.includes(\"\\\\\") ||\n invalidWindowsName\n ) {\n throw new Error(\n `Static pathname ${JSON.stringify(pathname)} contains a segment that is unsafe or not portable as a file name: ${JSON.stringify(segment)}.`,\n );\n }\n}\n\nfunction createDocumentRequest(origin: string, pathname: string) {\n return new Request(`${origin}${pathname}`, {\n headers: { accept: \"text/html\" },\n });\n}\n\nasync function prepareOutput(\n entry: { file: string; pathname: string },\n response: Response,\n expectedStatus: 200 | 404,\n): Promise<PendingOutput> {\n if (response.status !== expectedStatus) {\n throw new Error(\n `Static output for ${JSON.stringify(entry.pathname)} returned status ${response.status}; expected ${expectedStatus}.`,\n );\n }\n\n const contentType = response.headers.get(\"content-type\");\n\n if (!contentType?.toLowerCase().startsWith(\"text/html\")) {\n throw new Error(\n `Static output for ${JSON.stringify(entry.pathname)} returned ${JSON.stringify(contentType)} instead of text/html.`,\n );\n }\n\n if (response.headers.has(\"set-cookie\")) {\n throw new Error(\n `Static output for ${JSON.stringify(entry.pathname)} attempted to set a cookie. Build artifacts cannot contain per-user response state.`,\n );\n }\n\n const html = await response.text();\n await validateStaticCsp(entry.pathname, html, response.headers);\n\n return {\n ...entry,\n headers: sortedHeaders(response.headers),\n html,\n status: expectedStatus,\n };\n}\n\nasync function validateStaticCsp(\n pathname: string,\n html: string,\n headers: Headers,\n) {\n const csp = headers.get(\"content-security-policy\");\n\n if (!csp) {\n return;\n }\n\n if (/'nonce-[^']+'/i.test(csp) || /\\snonce\\s*=/i.test(html)) {\n throw new Error(\n `Static output for ${JSON.stringify(pathname)} uses a nonce-backed CSP. Use security.static() with stable hashes or a runtime adapter that injects a fresh nonce.`,\n );\n }\n\n const directives = parseCsp(csp);\n\n await validateInlineElements(\n pathname,\n html,\n \"script\",\n effectiveSources(directives, \"script-src\"),\n );\n await validateInlineElements(\n pathname,\n html,\n \"style\",\n effectiveSources(directives, \"style-src\"),\n );\n\n const styleSources = effectiveSources(directives, \"style-src\");\n\n if (/\\sstyle\\s*=/i.test(html) && !styleSources.includes(\"'unsafe-inline'\")) {\n throw new Error(\n `Static output for ${JSON.stringify(pathname)} contains an inline style attribute that its CSP does not allow. Move the style into a stylesheet or explicitly allow inline styles.`,\n );\n }\n}\n\nfunction parseCsp(value: string) {\n const directives = new Map<string, string[]>();\n\n for (const rawDirective of value.split(\";\")) {\n const [name, ...sources] = rawDirective.trim().split(/\\s+/);\n\n if (name) {\n directives.set(name.toLowerCase(), sources);\n }\n }\n\n return directives;\n}\n\nfunction effectiveSources(directives: Map<string, string[]>, name: string) {\n return directives.get(name) ?? directives.get(\"default-src\") ?? [];\n}\n\nasync function validateInlineElements(\n pathname: string,\n html: string,\n tagName: \"script\" | \"style\",\n sources: string[],\n) {\n if (sources.includes(\"'unsafe-inline'\")) {\n return;\n }\n\n for (const element of findRawTextElements(html, tagName)) {\n if (tagName === \"script\" && /(?:^|\\s)src\\s*=/i.test(element.attributes)) {\n continue;\n }\n\n if (!element.content) {\n continue;\n }\n\n const hash = await cspHash(element.content);\n\n if (!sources.includes(hash)) {\n throw new Error(\n `Static output for ${JSON.stringify(pathname)} contains an inline ${tagName} without the required CSP hash ${hash}.`,\n );\n }\n }\n}\n\nfunction findRawTextElements(html: string, tagName: \"script\" | \"style\") {\n const lowerHtml = html.toLowerCase();\n const elements: Array<{ attributes: string; content: string }> = [];\n const opening = `<${tagName}`;\n const closing = `</${tagName}`;\n let cursor = 0;\n\n while (cursor < html.length) {\n const start = lowerHtml.indexOf(opening, cursor);\n\n if (start === -1) {\n break;\n }\n\n const openEnd = lowerHtml.indexOf(\">\", start + opening.length);\n const closeStart = openEnd === -1\n ? -1\n : lowerHtml.indexOf(closing, openEnd + 1);\n const closeEnd = closeStart === -1\n ? -1\n : lowerHtml.indexOf(\">\", closeStart + closing.length);\n\n if (openEnd === -1 || closeStart === -1 || closeEnd === -1) {\n throw new Error(`Static output contains an unclosed <${tagName}> element.`);\n }\n\n elements.push({\n attributes: html.slice(start + opening.length, openEnd),\n content: html.slice(openEnd + 1, closeStart),\n });\n cursor = closeEnd + 1;\n }\n\n return elements;\n}\n\nfunction sortedHeaders(headers: Headers) {\n return Object.fromEntries(\n [...headers.entries()].sort(([left], [right]) => left.localeCompare(right)),\n );\n}\n\nasync function writeOutput(\n outDir: string,\n entries: PendingOutput[],\n manifest: StaticOutputManifest,\n) {\n const parent = dirname(outDir);\n await mkdir(parent, { recursive: true });\n const staging = await mkdtemp(join(parent, \".demiurge-static-\"));\n\n try {\n for (const entry of entries) {\n const file = resolveContained(staging, entry.file);\n await mkdir(dirname(file), { recursive: true });\n await writeFile(file, entry.html);\n }\n\n await writeFile(\n join(staging, STATIC_MANIFEST_FILE),\n `${JSON.stringify(manifest, null, 2)}\\n`,\n );\n\n const previousFiles = await readPreviousOutputFiles(outDir);\n await mkdir(outDir, { recursive: true });\n await cp(staging, outDir, { recursive: true, force: true });\n\n const currentFiles = new Set(entries.map((entry) => entry.file));\n\n for (const file of previousFiles) {\n if (!currentFiles.has(file)) {\n await rm(resolveContained(outDir, file), { force: true });\n }\n }\n } finally {\n await rm(staging, { force: true, recursive: true });\n }\n}\n\nasync function readPreviousOutputFiles(outDir: string) {\n try {\n const source = await readFile(join(outDir, STATIC_MANIFEST_FILE), \"utf8\");\n const value = JSON.parse(source) as {\n adapter?: unknown;\n entries?: Array<{ file?: unknown }>;\n version?: unknown;\n };\n\n if (\n value.adapter !== \"static\" ||\n value.version !== 1 ||\n !Array.isArray(value.entries)\n ) {\n return [];\n }\n\n return value.entries.flatMap((entry) =>\n typeof entry.file === \"string\" &&\n entry.file.endsWith(\".html\") &&\n isSafeRelativeFile(entry.file)\n ? [entry.file]\n : []\n );\n } catch {\n return [];\n }\n}\n\nfunction resolveContained(root: string, file: string) {\n if (!isSafeRelativeFile(file)) {\n throw new Error(`Static output file must stay inside the output directory: ${JSON.stringify(file)}.`);\n }\n\n const resolvedRoot = resolve(root);\n const resolvedFile = resolve(resolvedRoot, file);\n\n if (relative(resolvedRoot, resolvedFile).split(sep).includes(\"..\")) {\n throw new Error(`Static output file escaped the output directory: ${JSON.stringify(file)}.`);\n }\n\n return resolvedFile;\n}\n\nfunction isSafeRelativeFile(file: string) {\n return Boolean(file) &&\n !file.startsWith(\"/\") &&\n !file.startsWith(\"\\\\\") &&\n !file.split(/[\\\\/]/).includes(\"..\");\n}\n"],"names":["STATIC_MANIFEST_FILE","staticAdapter","defineAdapter","generateStaticOutput","options","origin","normalizeOrigin","outDir","resolve","manifest","createRouteManifest","paths","collectStaticRoutePaths","assertStaticPageApp","outputEntries","planOutputEntries","path","rateLimitStore","createMemoryRateLimitStore","pending","ssr","entry","request","createDocumentRequest","response","handleRequestWithManifest","prepareOutput","notFoundResponse","renderNotFoundResponse","error","site","left","right","outputManifest","_html","writeOutput","value","pageCount","fallback","pathnames","seenFiles","seenPathnames","pathname","file","pathnameToFile","portableFile","conflictingPathname","segment","decoded","assertPortableSegment","invalidWindowsName","character","expectedStatus","contentType","html","validateStaticCsp","sortedHeaders","headers","csp","directives","parseCsp","validateInlineElements","effectiveSources","styleSources","rawDirective","name","sources","tagName","element","findRawTextElements","hash","cspHash","lowerHtml","elements","opening","closing","cursor","start","openEnd","closeStart","closeEnd","entries","parent","dirname","mkdir","staging","mkdtemp","join","resolveContained","writeFile","previousFiles","readPreviousOutputFiles","cp","currentFiles","rm","source","readFile","isSafeRelativeFile","root","resolvedRoot","resolvedFile","relative","sep"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/static/index.ts"],"sourcesContent":["import {\n cp,\n mkdir,\n mkdtemp,\n readFile,\n rm,\n writeFile,\n} from \"node:fs/promises\";\nimport { dirname, join, relative, resolve, sep } from \"node:path\";\nimport { defineAdapter } from \"../adapter\";\nimport { STRUCTURED_DATA_ATTRIBUTE } from \"../document/render\";\nimport {\n collectStaticRoutePaths,\n createRouteManifest,\n type RouteManifest,\n} from \"../router\";\nimport type { RouteCapability, RouteImporter, RouteModule } from \"../route\";\nimport {\n handleRequestWithManifest,\n renderNotFoundResponse,\n type RequestErrorReporter,\n type SsrOptions,\n} from \"../server\";\nimport { createMemoryRateLimitStore, cspHash } from \"../security\";\nimport {\n CONTENT_HASHED_FILE_NAME_PATTERN,\n IMMUTABLE_FILE_CACHE_CONTROL,\n REVALIDATED_FILE_CACHE_CONTROL,\n} from \"../static-files\";\n\nconst STATIC_MANIFEST_FILE = \"demiurge-static-manifest.json\";\n\nexport const staticAdapter = defineAdapter({\n name: \"static\",\n capabilities: {\n staticOutput: true,\n },\n});\n\nexport type StaticOutputEntry = {\n file: string;\n headers: Record<string, string>;\n pathname: string;\n status: 200 | 404;\n};\n\nexport type StaticOutputManifest = {\n adapter: \"static\";\n entries: StaticOutputEntry[];\n fileHeaderRules: StaticOutputFileHeaderRule[];\n version: 1;\n};\n\nexport type StaticOutputFileHeaderRule = {\n headers: Record<string, string>;\n pattern: string;\n};\n\nexport type GenerateStaticOutputOptions = {\n onError?: RequestErrorReporter;\n origin?: string;\n outDir: string;\n routes: Record<string, RouteImporter>;\n ssr?: SsrOptions;\n};\n\ntype PendingOutput = StaticOutputEntry & {\n body: string;\n};\n\ntype OutputKind = \"document\" | \"resource\";\n\ntype PlannedOutput = {\n file: string;\n kind: OutputKind;\n pathname: string;\n};\n\nexport async function generateStaticOutput(\n options: GenerateStaticOutputOptions,\n): Promise<StaticOutputManifest> {\n const origin = normalizeOrigin(options.origin);\n const outDir = resolve(options.outDir);\n const manifest = createRouteManifest(options.routes);\n const routeKinds = await validateStaticRoutes(manifest);\n const paths = await collectStaticRoutePaths(manifest, {\n includeResources: true,\n });\n\n assertStaticPageApp(\n manifest,\n paths.filter((path) => routeKinds.get(path.file) === \"document\").length,\n );\n\n const outputEntries = planOutputEntries(\n paths.map((path) => ({\n kind: routeKinds.get(path.file) ?? \"resource\",\n pathname: path.pathname,\n })),\n );\n const rateLimitStore = createMemoryRateLimitStore();\n const pending: PendingOutput[] = [];\n const ssr = { ...options.ssr, navigation: \"document\" as const };\n\n for (const entry of outputEntries) {\n const request = createStaticRequest(origin, entry.pathname, entry.kind);\n const response = await handleRequestWithManifest(manifest, request, {\n onError: options.onError,\n rateLimitStore,\n ssr,\n });\n\n pending.push(\n entry.kind === \"document\"\n ? await prepareDocumentOutput(entry, response, 200)\n : await prepareResourceOutput(entry, response),\n );\n }\n\n const notFoundResponse = await renderNotFoundResponse(\n manifest,\n createStaticRequest(origin, \"/404\", \"document\"),\n {\n ...ssr,\n onError: (error, site) =>\n options.onError?.(error, { pathname: \"/404\", site }),\n },\n );\n pending.push(\n await prepareDocumentOutput(\n {\n file: \"404.html\",\n pathname: \"*\",\n },\n notFoundResponse,\n 404,\n ),\n );\n\n pending.sort((left, right) => left.file.localeCompare(right.file));\n\n const outputManifest: StaticOutputManifest = {\n adapter: \"static\",\n entries: pending.map(({ body: _body, ...entry }) => entry),\n fileHeaderRules: createStaticFileHeaderRules(),\n version: 1,\n };\n\n await writeOutput(outDir, pending, outputManifest);\n\n return outputManifest;\n}\n\nfunction createStaticFileHeaderRules(): StaticOutputFileHeaderRule[] {\n return [\n {\n headers: { \"cache-control\": IMMUTABLE_FILE_CACHE_CONTROL },\n pattern: CONTENT_HASHED_FILE_NAME_PATTERN.source,\n },\n {\n headers: { \"cache-control\": REVALIDATED_FILE_CACHE_CONTROL },\n pattern: \".*\",\n },\n ];\n}\n\nfunction normalizeOrigin(value: string | undefined) {\n let origin: URL;\n\n try {\n origin = new URL(value ?? \"http://demiurge.local\");\n } catch {\n throw new Error(\n `Static output origin must be an absolute HTTP(S) origin: ${JSON.stringify(value)}.`,\n );\n }\n\n if (\n (origin.protocol !== \"http:\" && origin.protocol !== \"https:\") ||\n origin.username ||\n origin.password ||\n origin.pathname !== \"/\" ||\n origin.search ||\n origin.hash\n ) {\n throw new Error(\n `Static output origin must be an HTTP(S) origin without credentials, a path, query, or hash: ${JSON.stringify(value)}.`,\n );\n }\n\n return origin.origin;\n}\n\nfunction assertStaticPageApp(manifest: RouteManifest, pageCount: number) {\n if (pageCount === 0) {\n throw new Error(\"Static output requires at least one page route.\");\n }\n\n const hasRootNotFound = manifest.fallbacks.notFound.some(\n (fallback) => fallback.fileSegments.length === 0,\n );\n\n if (!hasRootNotFound) {\n throw new Error(\n \"Static output requires a root @not-found.tsx so 404.html is app-owned.\",\n );\n }\n}\n\nasync function validateStaticRoutes(manifest: RouteManifest) {\n const routeKinds = new Map<string, OutputKind>();\n\n for (const route of manifest.routes) {\n const routeModule = await route.load();\n const unsupportedMethods = staticUnsupportedMethods(routeModule);\n\n if (unsupportedMethods.length > 0) {\n throw new Error(\n `Static route ${JSON.stringify(route.file)} exports unsupported methods ${unsupportedMethods.join(\", \")}. Deploy a runtime adapter for request-time methods.`,\n );\n }\n\n if (!routeModule.GET) {\n throw new Error(\n `Static route ${JSON.stringify(route.file)} does not export GET and cannot produce an output file.`,\n );\n }\n\n if (routeModule.GET.kind === \"page\") {\n routeKinds.set(route.file, \"document\");\n continue;\n }\n\n assertStaticResource(route.file, routeModule.GET);\n routeKinds.set(route.file, \"resource\");\n }\n\n return routeKinds;\n}\n\nfunction staticUnsupportedMethods(routeModule: RouteModule) {\n return ([\"POST\", \"PUT\", \"PATCH\", \"DELETE\", \"OPTIONS\", \"HEAD\"] as const)\n .filter((method) => routeModule[method] !== undefined);\n}\n\nfunction assertStaticResource(file: string, capability: RouteCapability) {\n if (\n (capability.kind === \"text\" ||\n capability.kind === \"html\" ||\n capability.kind === \"json\") &&\n typeof capability.value !== \"function\"\n ) {\n return;\n }\n\n const reason = \"value\" in capability && typeof capability.value === \"function\"\n ? `uses a request-dependent ${capability.kind} value`\n : `uses the ${capability.kind} response helper`;\n\n throw new Error(\n `Static route ${JSON.stringify(file)} ${reason} and cannot produce a fixed output file. Use a fixed text, html, or json value, or deploy a runtime adapter.`,\n );\n}\n\nfunction planOutputEntries(\n outputs: Array<{ kind: OutputKind; pathname: string }>,\n) {\n const seenFiles = new Map<string, string>();\n const seenPathnames = new Set<string>();\n\n return outputs.map(({ kind, pathname }) => {\n if (seenPathnames.has(pathname)) {\n throw new Error(`Static output collected duplicate pathname ${JSON.stringify(pathname)}.`);\n }\n\n seenPathnames.add(pathname);\n\n const file = kind === \"document\"\n ? pathnameToDocumentFile(pathname)\n : pathnameToResourceFile(pathname);\n const portableFile = file.toLocaleLowerCase(\"en-US\");\n const conflict = [...seenFiles.entries()].find(([seenFile]) =>\n seenFile === portableFile ||\n seenFile.startsWith(`${portableFile}/`) ||\n portableFile.startsWith(`${seenFile}/`)\n );\n\n if (conflict) {\n throw new Error(\n `Static paths ${JSON.stringify(conflict[1])} and ${JSON.stringify(pathname)} map to the same portable output file or to a file and directory conflict.`,\n );\n }\n\n seenFiles.set(portableFile, pathname);\n\n return { file, kind, pathname };\n });\n}\n\nfunction pathnameToDocumentFile(pathname: string) {\n if (!pathname.startsWith(\"/\") || pathname.includes(\"?\") || pathname.includes(\"#\")) {\n throw new Error(`Static output received invalid pathname ${JSON.stringify(pathname)}.`);\n }\n\n if (pathname === \"/\") {\n return \"index.html\";\n }\n\n const segments = pathname.split(\"/\").slice(1).map((segment) => {\n let decoded: string;\n\n try {\n decoded = decodeURIComponent(segment);\n } catch {\n throw new Error(`Static output pathname is not valid UTF-8: ${JSON.stringify(pathname)}.`);\n }\n\n assertPortableSegment(decoded, pathname);\n return decoded;\n });\n\n return [...segments, \"index.html\"].join(\"/\");\n}\n\nfunction pathnameToResourceFile(pathname: string) {\n if (pathname === \"/\") {\n throw new Error(\"A static resource route cannot own the root pathname.\");\n }\n\n const documentFile = pathnameToDocumentFile(pathname);\n return documentFile.slice(0, -\"/index.html\".length);\n}\n\nfunction assertPortableSegment(segment: string, pathname: string) {\n const invalidWindowsName = /[<>:\"|?*]/.test(segment) ||\n [...segment].some((character) => character.charCodeAt(0) <= 31) ||\n /[. ]$/.test(segment) ||\n /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\\.|$)/i.test(segment);\n\n if (\n !segment ||\n segment === \".\" ||\n segment === \"..\" ||\n segment.includes(\"/\") ||\n segment.includes(\"\\\\\") ||\n invalidWindowsName\n ) {\n throw new Error(\n `Static pathname ${JSON.stringify(pathname)} contains a segment that is unsafe or not portable as a file name: ${JSON.stringify(segment)}.`,\n );\n }\n}\n\nfunction createStaticRequest(\n origin: string,\n pathname: string,\n kind: OutputKind,\n) {\n return new Request(`${origin}${pathname}`, {\n headers: { accept: kind === \"document\" ? \"text/html\" : \"*/*\" },\n });\n}\n\nasync function prepareDocumentOutput(\n entry: { file: string; pathname: string },\n response: Response,\n expectedStatus: 200 | 404,\n): Promise<PendingOutput> {\n if (response.status !== expectedStatus) {\n throw new Error(\n `Static output for ${JSON.stringify(entry.pathname)} returned status ${response.status}; expected ${expectedStatus}.`,\n );\n }\n\n const contentType = response.headers.get(\"content-type\");\n\n if (!contentType?.toLowerCase().startsWith(\"text/html\")) {\n throw new Error(\n `Static output for ${JSON.stringify(entry.pathname)} returned ${JSON.stringify(contentType)} instead of text/html.`,\n );\n }\n\n if (response.headers.has(\"set-cookie\")) {\n throw new Error(\n `Static output for ${JSON.stringify(entry.pathname)} attempted to set a cookie. Build artifacts cannot contain per-user response state.`,\n );\n }\n\n const html = await coverStructuredDataHashes(\n await response.text(),\n response.headers,\n );\n await validateStaticCsp(entry.pathname, html, response.headers);\n\n return {\n file: entry.file,\n headers: sortedHeaders(response.headers),\n body: html,\n pathname: entry.pathname,\n status: expectedStatus,\n };\n}\n\nasync function prepareResourceOutput(\n entry: PlannedOutput,\n response: Response,\n): Promise<PendingOutput> {\n if (response.status !== 200) {\n throw new Error(\n `Static output for ${JSON.stringify(entry.pathname)} returned status ${response.status}; expected 200.`,\n );\n }\n\n if (response.headers.has(\"set-cookie\")) {\n throw new Error(\n `Static output for ${JSON.stringify(entry.pathname)} attempted to set a cookie. Build artifacts cannot contain per-user response state.`,\n );\n }\n\n return {\n file: entry.file,\n headers: sortedHeaders(response.headers),\n body: await response.text(),\n pathname: entry.pathname,\n status: 200,\n };\n}\n\nasync function coverStructuredDataHashes(html: string, headers: Headers) {\n const markerPattern = new RegExp(\n `(?:^|\\\\s)${STRUCTURED_DATA_ATTRIBUTE}(?:\\\\s|$)`,\n );\n const elements = findRawTextElements(html, \"script\")\n .filter((element) => markerPattern.test(element.attributes));\n\n if (elements.length === 0) {\n return html;\n }\n\n const hashes = await Promise.all(\n elements.map((element) => cspHash(element.content)),\n );\n\n for (const headerName of [\n \"content-security-policy\",\n \"content-security-policy-report-only\",\n ]) {\n const csp = headers.get(headerName);\n if (csp) {\n headers.set(headerName, addScriptHashes(csp, hashes));\n }\n }\n\n return html.replace(\n new RegExp(`\\\\s${STRUCTURED_DATA_ATTRIBUTE}(?=\\\\s|>)`, \"g\"),\n \"\",\n );\n}\n\nfunction addScriptHashes(csp: string, hashes: readonly string[]) {\n const directives = csp.split(\";\")\n .map((directive) => directive.trim())\n .filter(Boolean);\n const scriptIndex = directives.findIndex((directive) =>\n directive.split(/\\s+/, 1)[0]?.toLowerCase() === \"script-src\"\n );\n const defaultDirective = directives.find((directive) =>\n directive.split(/\\s+/, 1)[0]?.toLowerCase() === \"default-src\"\n );\n const current = scriptIndex === -1 ? defaultDirective : directives[scriptIndex];\n\n if (!current) {\n return csp;\n }\n\n const sources = current.split(/\\s+/).slice(1)\n .filter((source) => source !== \"'none'\");\n const scriptDirective = [\n \"script-src\",\n ...new Set([...sources, ...hashes]),\n ].join(\" \");\n\n if (scriptIndex === -1) {\n directives.push(scriptDirective);\n } else {\n directives[scriptIndex] = scriptDirective;\n }\n\n return directives.join(\"; \");\n}\n\nasync function validateStaticCsp(\n pathname: string,\n html: string,\n headers: Headers,\n) {\n const csp = headers.get(\"content-security-policy\");\n\n if (!csp) {\n return;\n }\n\n if (/'nonce-[^']+'/i.test(csp) || /\\snonce\\s*=/i.test(html)) {\n throw new Error(\n `Static output for ${JSON.stringify(pathname)} uses a nonce-backed CSP. Use security.static() with stable hashes or a runtime adapter that injects a fresh nonce.`,\n );\n }\n\n const directives = parseCsp(csp);\n\n await validateInlineElements(\n pathname,\n html,\n \"script\",\n effectiveSources(directives, \"script-src\"),\n );\n await validateInlineElements(\n pathname,\n html,\n \"style\",\n effectiveSources(directives, \"style-src\"),\n );\n\n const styleSources = effectiveSources(directives, \"style-src\");\n\n if (\n styleSources &&\n /\\sstyle\\s*=/i.test(html) &&\n !styleSources.includes(\"'unsafe-inline'\")\n ) {\n throw new Error(\n `Static output for ${JSON.stringify(pathname)} contains an inline style attribute that its CSP does not allow. Move the style into a stylesheet or explicitly allow inline styles.`,\n );\n }\n}\n\nfunction parseCsp(value: string) {\n const directives = new Map<string, string[]>();\n\n for (const rawDirective of value.split(\";\")) {\n const [name, ...sources] = rawDirective.trim().split(/\\s+/);\n\n if (name) {\n directives.set(name.toLowerCase(), sources);\n }\n }\n\n return directives;\n}\n\nfunction effectiveSources(directives: Map<string, string[]>, name: string) {\n return directives.get(name) ?? directives.get(\"default-src\");\n}\n\nasync function validateInlineElements(\n pathname: string,\n html: string,\n tagName: \"script\" | \"style\",\n sources: string[] | undefined,\n) {\n if (!sources || sources.includes(\"'unsafe-inline'\")) {\n return;\n }\n\n for (const element of findRawTextElements(html, tagName)) {\n if (tagName === \"script\" && /(?:^|\\s)src\\s*=/i.test(element.attributes)) {\n continue;\n }\n\n if (!element.content) {\n continue;\n }\n\n const hash = await cspHash(element.content);\n\n if (!sources.includes(hash)) {\n throw new Error(\n `Static output for ${JSON.stringify(pathname)} contains an inline ${tagName} without the required CSP hash ${hash}.`,\n );\n }\n }\n}\n\nfunction findRawTextElements(html: string, tagName: \"script\" | \"style\") {\n const lowerHtml = html.toLowerCase();\n const elements: Array<{ attributes: string; content: string }> = [];\n const opening = `<${tagName}`;\n const closing = `</${tagName}`;\n let cursor = 0;\n\n while (cursor < html.length) {\n const start = lowerHtml.indexOf(opening, cursor);\n\n if (start === -1) {\n break;\n }\n\n const openEnd = lowerHtml.indexOf(\">\", start + opening.length);\n const closeStart = openEnd === -1\n ? -1\n : lowerHtml.indexOf(closing, openEnd + 1);\n const closeEnd = closeStart === -1\n ? -1\n : lowerHtml.indexOf(\">\", closeStart + closing.length);\n\n if (openEnd === -1 || closeStart === -1 || closeEnd === -1) {\n throw new Error(`Static output contains an unclosed <${tagName}> element.`);\n }\n\n elements.push({\n attributes: html.slice(start + opening.length, openEnd),\n content: html.slice(openEnd + 1, closeStart),\n });\n cursor = closeEnd + 1;\n }\n\n return elements;\n}\n\nfunction sortedHeaders(headers: Headers) {\n return Object.fromEntries(\n [...headers.entries()].sort(([left], [right]) => left.localeCompare(right)),\n );\n}\n\nasync function writeOutput(\n outDir: string,\n entries: PendingOutput[],\n manifest: StaticOutputManifest,\n) {\n const parent = dirname(outDir);\n await mkdir(parent, { recursive: true });\n const staging = await mkdtemp(join(parent, \".demiurge-static-\"));\n\n try {\n for (const entry of entries) {\n const file = resolveContained(staging, entry.file);\n await mkdir(dirname(file), { recursive: true });\n await writeFile(file, entry.body);\n }\n\n await writeFile(\n join(staging, STATIC_MANIFEST_FILE),\n `${JSON.stringify(manifest, null, 2)}\\n`,\n );\n\n const previousFiles = await readPreviousOutputFiles(outDir);\n await mkdir(outDir, { recursive: true });\n await cp(staging, outDir, { recursive: true, force: true });\n\n const currentFiles = new Set(entries.map((entry) => entry.file));\n\n for (const file of previousFiles) {\n if (!currentFiles.has(file)) {\n await rm(resolveContained(outDir, file), { force: true });\n }\n }\n } finally {\n await rm(staging, { force: true, recursive: true });\n }\n}\n\nasync function readPreviousOutputFiles(outDir: string) {\n try {\n const source = await readFile(join(outDir, STATIC_MANIFEST_FILE), \"utf8\");\n const value = JSON.parse(source) as {\n adapter?: unknown;\n entries?: Array<{ file?: unknown }>;\n version?: unknown;\n };\n\n if (\n value.adapter !== \"static\" ||\n value.version !== 1 ||\n !Array.isArray(value.entries)\n ) {\n return [];\n }\n\n return value.entries.flatMap((entry) =>\n typeof entry.file === \"string\" &&\n isSafeRelativeFile(entry.file)\n ? [entry.file]\n : []\n );\n } catch {\n return [];\n }\n}\n\nfunction resolveContained(root: string, file: string) {\n if (!isSafeRelativeFile(file)) {\n throw new Error(`Static output file must stay inside the output directory: ${JSON.stringify(file)}.`);\n }\n\n const resolvedRoot = resolve(root);\n const resolvedFile = resolve(resolvedRoot, file);\n\n if (relative(resolvedRoot, resolvedFile).split(sep).includes(\"..\")) {\n throw new Error(`Static output file escaped the output directory: ${JSON.stringify(file)}.`);\n }\n\n return resolvedFile;\n}\n\nfunction isSafeRelativeFile(file: string) {\n return Boolean(file) &&\n !file.startsWith(\"/\") &&\n !file.startsWith(\"\\\\\") &&\n !file.split(/[\\\\/]/).includes(\"..\");\n}\n"],"names":["STATIC_MANIFEST_FILE","staticAdapter","defineAdapter","generateStaticOutput","options","origin","normalizeOrigin","outDir","resolve","manifest","createRouteManifest","routeKinds","validateStaticRoutes","paths","collectStaticRoutePaths","assertStaticPageApp","path","outputEntries","planOutputEntries","rateLimitStore","createMemoryRateLimitStore","pending","ssr","entry","request","createStaticRequest","response","handleRequestWithManifest","prepareDocumentOutput","prepareResourceOutput","notFoundResponse","renderNotFoundResponse","error","site","left","right","outputManifest","_body","createStaticFileHeaderRules","writeOutput","IMMUTABLE_FILE_CACHE_CONTROL","CONTENT_HASHED_FILE_NAME_PATTERN","REVALIDATED_FILE_CACHE_CONTROL","value","pageCount","fallback","route","routeModule","unsupportedMethods","staticUnsupportedMethods","assertStaticResource","method","file","capability","reason","outputs","seenFiles","seenPathnames","kind","pathname","pathnameToDocumentFile","pathnameToResourceFile","portableFile","conflict","seenFile","segment","decoded","assertPortableSegment","invalidWindowsName","character","expectedStatus","contentType","html","coverStructuredDataHashes","validateStaticCsp","sortedHeaders","headers","markerPattern","STRUCTURED_DATA_ATTRIBUTE","elements","findRawTextElements","element","hashes","cspHash","headerName","csp","addScriptHashes","directives","directive","scriptIndex","defaultDirective","current","sources","source","scriptDirective","parseCsp","validateInlineElements","effectiveSources","styleSources","rawDirective","name","tagName","hash","lowerHtml","opening","closing","cursor","start","openEnd","closeStart","closeEnd","entries","parent","dirname","mkdir","staging","mkdtemp","join","resolveContained","writeFile","previousFiles","readPreviousOutputFiles","cp","currentFiles","rm","readFile","isSafeRelativeFile","root","resolvedRoot","resolvedFile","relative","sep"],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare const CONTENT_HASHED_FILE_NAME_PATTERN: RegExp;
2
+ export declare const IMMUTABLE_FILE_CACHE_CONTROL = "public, max-age=31536000, immutable";
3
+ export declare const REVALIDATED_FILE_CACHE_CONTROL = "public, max-age=0, must-revalidate";
4
+ export declare function isContentHashedFileName(fileName: string): boolean;
5
+ //# sourceMappingURL=static-files.d.ts.map