@demiurgejs/core 0.1.1 → 0.2.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/README.md +3 -0
  2. package/bin/demiurge.mjs +51 -0
  3. package/dist/chunks/request-metadata-DwEO1EAS.js +477 -0
  4. package/dist/chunks/request-metadata-DwEO1EAS.js.map +1 -0
  5. package/dist/chunks/{streaming-DN1DnbRE.js → streaming-Ci6vf3BB.js} +117 -107
  6. package/dist/chunks/streaming-Ci6vf3BB.js.map +1 -0
  7. package/dist/chunks/{testing-DR3eQAvY.js → testing-DBjVCN5v.js} +2384 -1942
  8. package/dist/chunks/testing-DBjVCN5v.js.map +1 -0
  9. package/dist/cli.d.ts +42 -0
  10. package/dist/cli.d.ts.map +1 -0
  11. package/dist/cli.js +164 -0
  12. package/dist/cli.js.map +1 -0
  13. package/dist/document/index.d.ts +2 -2
  14. package/dist/document/index.d.ts.map +1 -1
  15. package/dist/document/render.d.ts +1 -1
  16. package/dist/document/render.d.ts.map +1 -1
  17. package/dist/document/scripts.d.ts +22 -0
  18. package/dist/document/scripts.d.ts.map +1 -1
  19. package/dist/index.d.ts +7 -7
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +817 -969
  22. package/dist/index.js.map +1 -1
  23. package/dist/internal/testing.js +15 -14
  24. package/dist/internal/testing.js.map +1 -1
  25. package/dist/node/index.js +3 -3
  26. package/dist/node/streaming.d.ts +2 -0
  27. package/dist/node/streaming.d.ts.map +1 -1
  28. package/dist/route/action.d.ts +11 -11
  29. package/dist/route/action.d.ts.map +1 -1
  30. package/dist/route/index.d.ts +2 -1
  31. package/dist/route/index.d.ts.map +1 -1
  32. package/dist/route/middleware.d.ts +7 -0
  33. package/dist/route/middleware.d.ts.map +1 -0
  34. package/dist/route/page.d.ts +2 -2
  35. package/dist/route/page.d.ts.map +1 -1
  36. package/dist/route/response.d.ts +19 -19
  37. package/dist/route/response.d.ts.map +1 -1
  38. package/dist/route/types.d.ts +55 -31
  39. package/dist/route/types.d.ts.map +1 -1
  40. package/dist/route/webhook.d.ts +1 -1
  41. package/dist/router/manifest.d.ts +1 -0
  42. package/dist/router/manifest.d.ts.map +1 -1
  43. package/dist/routing/generate.d.ts +2 -0
  44. package/dist/routing/generate.d.ts.map +1 -1
  45. package/dist/routing/index.d.ts +1 -1
  46. package/dist/routing/index.d.ts.map +1 -1
  47. package/dist/routing/types.d.ts +2 -0
  48. package/dist/routing/types.d.ts.map +1 -1
  49. package/dist/security/cors.d.ts.map +1 -1
  50. package/dist/security/index.d.ts +4 -2
  51. package/dist/security/index.d.ts.map +1 -1
  52. package/dist/security/policy.d.ts +31 -2
  53. package/dist/security/policy.d.ts.map +1 -1
  54. package/dist/security/types.d.ts +27 -13
  55. package/dist/security/types.d.ts.map +1 -1
  56. package/dist/security/verification.d.ts +8 -0
  57. package/dist/security/verification.d.ts.map +1 -0
  58. package/dist/server/errors.d.ts.map +1 -1
  59. package/dist/server/not-found.d.ts.map +1 -1
  60. package/dist/server/render-tree.d.ts +6 -1
  61. package/dist/server/render-tree.d.ts.map +1 -1
  62. package/dist/server/request-handler.d.ts +4 -1
  63. package/dist/server/request-handler.d.ts.map +1 -1
  64. package/dist/server/ssr.d.ts +1 -0
  65. package/dist/server/ssr.d.ts.map +1 -1
  66. package/dist/static/index.d.ts +10 -0
  67. package/dist/static/index.d.ts.map +1 -1
  68. package/dist/static/index.js +579 -139
  69. package/dist/static/index.js.map +1 -1
  70. package/dist/static/preview.d.ts +8 -0
  71. package/dist/static/preview.d.ts.map +1 -0
  72. package/dist/static/vercel.d.ts +31 -0
  73. package/dist/static/vercel.d.ts.map +1 -0
  74. package/dist/vite/index.d.ts +3 -2
  75. package/dist/vite/index.d.ts.map +1 -1
  76. package/dist/vite/index.js +754 -326
  77. package/dist/vite/index.js.map +1 -1
  78. package/dist/vite/plugin.d.ts +13 -0
  79. package/dist/vite/plugin.d.ts.map +1 -1
  80. package/dist/vite/policy-verification.d.ts +10 -0
  81. package/dist/vite/policy-verification.d.ts.map +1 -0
  82. package/package.json +6 -1
  83. package/dist/chunks/index-BnX9Qxbm.js +0 -44
  84. package/dist/chunks/index-BnX9Qxbm.js.map +0 -1
  85. package/dist/chunks/ssr-BJejKlkZ.js +0 -275
  86. package/dist/chunks/ssr-BJejKlkZ.js.map +0 -1
  87. package/dist/chunks/streaming-DN1DnbRE.js.map +0 -1
  88. package/dist/chunks/testing-DR3eQAvY.js.map +0 -1
@@ -1,81 +1,460 @@
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";
1
+ import { readFile as v, mkdir as E, mkdtemp as W, cp as k, writeFile as A, rm as $, rename as rt } from "node:fs/promises";
2
+ import { resolve as h, relative as w, sep as g, extname as nt, dirname as N, join as m } from "node:path";
3
+ import { d as it, S as F } from "../chunks/request-metadata-DwEO1EAS.js";
4
+ import { v as ot, c as st, a as at, h as ct, r as ut, m as ft, b as D, d as lt } from "../chunks/testing-DBjVCN5v.js";
6
5
  import "react-dom/server";
7
6
  import "react";
8
7
  import "react/jsx-runtime";
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({
8
+ import { C as _, I as dt, R as ht } from "../chunks/static-files-DUjHw-4H.js";
9
+ import { createServer as pt } from "node:http";
10
+ import { normalizeRoutes as mt, getTransformedRoutes as wt } from "@vercel/routing-utils";
11
+ const yt = "demiurge-static-manifest.json", gt = {
12
+ ".avif": "image/avif",
13
+ ".css": "text/css; charset=utf-8",
14
+ ".gif": "image/gif",
15
+ ".html": "text/html; charset=utf-8",
16
+ ".ico": "image/x-icon",
17
+ ".jpeg": "image/jpeg",
18
+ ".jpg": "image/jpeg",
19
+ ".js": "text/javascript; charset=utf-8",
20
+ ".json": "application/json; charset=utf-8",
21
+ ".mjs": "text/javascript; charset=utf-8",
22
+ ".png": "image/png",
23
+ ".svg": "image/svg+xml",
24
+ ".txt": "text/plain; charset=utf-8",
25
+ ".webmanifest": "application/manifest+json",
26
+ ".webp": "image/webp",
27
+ ".woff": "font/woff",
28
+ ".woff2": "font/woff2"
29
+ };
30
+ async function de(t) {
31
+ const e = h(t.outDir), r = Et(
32
+ await v(h(e, yt), "utf8")
33
+ ), n = new Map(
34
+ r.entries.map((o) => [o.pathname, o])
35
+ ), i = new Map(
36
+ r.entries.map((o) => [o.file, o])
37
+ ), a = r.fileHeaderRules.map((o) => ({
38
+ ...o,
39
+ expression: new RegExp(o.pattern)
40
+ })), c = pt(async (o, s) => {
41
+ try {
42
+ if (o.method !== "GET" && o.method !== "HEAD") {
43
+ s.writeHead(405, { allow: "GET, HEAD" }), s.end();
44
+ return;
45
+ }
46
+ const f = new URL(o.url ?? "/", "http://demiurge.local");
47
+ let l;
48
+ try {
49
+ l = decodeURIComponent(f.pathname);
50
+ } catch {
51
+ s.writeHead(400, {
52
+ "content-type": "text/plain; charset=utf-8"
53
+ }), s.end("The request path is not valid UTF-8.");
54
+ return;
55
+ }
56
+ const R = l.replace(/\/$/, "") || "/", y = n.get(R);
57
+ if (y) {
58
+ await T(e, y, o.method, s);
59
+ return;
60
+ }
61
+ const u = St(e, l);
62
+ if (u)
63
+ try {
64
+ const p = w(e, u).split(g).join("/"), b = i.get(p);
65
+ if (b) {
66
+ await T(e, b, o.method, s);
67
+ return;
68
+ }
69
+ const X = await v(u), j = gt[nt(u).toLowerCase()];
70
+ j && s.setHeader("content-type", j);
71
+ const Y = l.split("/").at(-1) ?? "", tt = a.find(({ expression: et }) => et.test(Y));
72
+ U(s, tt?.headers ?? {}), s.writeHead(200), s.end(o.method === "HEAD" ? void 0 : X);
73
+ return;
74
+ } catch (p) {
75
+ if (!Ot(p)) throw p;
76
+ }
77
+ const d = n.get("*");
78
+ if (!d) {
79
+ s.writeHead(404), s.end();
80
+ return;
81
+ }
82
+ await T(e, d, o.method, s);
83
+ } catch {
84
+ s.writeHead(500, {
85
+ "content-type": "text/plain; charset=utf-8"
86
+ }), s.end("Demiurge could not serve the static output.");
87
+ }
88
+ });
89
+ return await new Promise((o, s) => {
90
+ const f = (l) => s(l);
91
+ c.once("error", f), c.listen(
92
+ t.port ?? 4173,
93
+ t.host ?? "localhost",
94
+ () => {
95
+ c.off("error", f), o();
96
+ }
97
+ );
98
+ }), c;
99
+ }
100
+ async function T(t, e, r, n) {
101
+ const i = B(t, e.file), a = await v(i);
102
+ U(n, e.headers), n.writeHead(e.status), n.end(r === "HEAD" ? void 0 : a);
103
+ }
104
+ function U(t, e) {
105
+ for (const [r, n] of Object.entries(e))
106
+ t.setHeader(r, n);
107
+ }
108
+ function St(t, e) {
109
+ if (!e.endsWith("/"))
110
+ return V(t, `.${e}`);
111
+ }
112
+ function B(t, e) {
113
+ const r = V(t, e);
114
+ if (!r)
115
+ throw new Error(`Static preview file is outside the output directory: ${JSON.stringify(e)}.`);
116
+ return r;
117
+ }
118
+ function V(t, e) {
119
+ if (!e || e.startsWith("/") || e.startsWith("\\") || e.split(/[\\/]/).includes(".."))
120
+ return;
121
+ const r = h(t, e), n = w(t, r);
122
+ return n !== ".." && !n.startsWith(`..${g}`) ? r : void 0;
123
+ }
124
+ function Et(t) {
125
+ let e;
126
+ try {
127
+ e = JSON.parse(t);
128
+ } catch {
129
+ throw new Error("The static output manifest is not valid JSON.");
130
+ }
131
+ if (!O(e) || e.adapter !== "static" || e.version !== 1)
132
+ throw new Error("The static output manifest has an unsupported format.");
133
+ if (!Array.isArray(e.entries) || !Array.isArray(e.fileHeaderRules))
134
+ throw new Error("The static output manifest does not contain header rules and entries.");
135
+ const r = e.entries.map(vt), n = e.fileHeaderRules.map($t), i = /* @__PURE__ */ new Set();
136
+ for (const a of r) {
137
+ if (i.has(a.pathname))
138
+ throw new Error(`The static output manifest repeats pathname ${JSON.stringify(a.pathname)}.`);
139
+ i.add(a.pathname);
140
+ }
141
+ return { adapter: "static", entries: r, fileHeaderRules: n, version: 1 };
142
+ }
143
+ function vt(t) {
144
+ if (!O(t) || typeof t.file != "string" || typeof t.pathname != "string" || t.status !== 200 && t.status !== 404 || !q(t.headers))
145
+ throw new Error("The static output manifest contains an invalid entry.");
146
+ return B("/demiurge-manifest-root", t.file), {
147
+ file: t.file,
148
+ headers: t.headers,
149
+ pathname: t.pathname,
150
+ status: t.status
151
+ };
152
+ }
153
+ function $t(t) {
154
+ if (!O(t) || typeof t.pattern != "string" || !q(t.headers))
155
+ throw new Error("The static output manifest contains an invalid file header rule.");
156
+ try {
157
+ new RegExp(t.pattern);
158
+ } catch {
159
+ throw new Error("The static output manifest contains an invalid file header pattern.");
160
+ }
161
+ return { headers: t.headers, pattern: t.pattern };
162
+ }
163
+ function O(t) {
164
+ return !!t && typeof t == "object" && !Array.isArray(t);
165
+ }
166
+ function q(t) {
167
+ return O(t) && Object.values(t).every(
168
+ (e) => typeof e == "string"
169
+ );
170
+ }
171
+ function Ot(t) {
172
+ return t instanceof Error && "code" in t && (t.code === "EISDIR" || t.code === "ENOENT");
173
+ }
174
+ const Rt = "demiurge-manifest.json", Tt = "demiurge-static-manifest.json";
175
+ function he(t = {}) {
176
+ return {
177
+ adapter: "vercel",
178
+ cache: t.cache?.map((e) => ({
179
+ source: e.source,
180
+ value: e.value
181
+ })) ?? []
182
+ };
183
+ }
184
+ async function pe(t) {
185
+ Ft(t.deployment);
186
+ const e = h(t.projectRoot), r = h(t.outDir), n = h(e, ".vercel/output");
187
+ if (Ht(r, n))
188
+ throw new Error(
189
+ "The static output directory must not overlap the Vercel output directory."
190
+ );
191
+ const i = N(n);
192
+ await E(i, { recursive: !0 });
193
+ const a = await W(m(i, "output-demiurge-"));
194
+ try {
195
+ const c = m(a, "static");
196
+ await k(r, c, {
197
+ filter: (o) => {
198
+ const s = w(r, o).split(g).join("/");
199
+ return s !== Rt && s !== Tt;
200
+ },
201
+ recursive: !0
202
+ }), await A(
203
+ m(a, "config.json"),
204
+ `${JSON.stringify(xt(
205
+ t.manifest,
206
+ t.deployment
207
+ ), null, 2)}
208
+ `
209
+ ), await $(n, { force: !0, recursive: !0 }), await rt(a, n);
210
+ } catch (c) {
211
+ throw await $(a, { force: !0, recursive: !0 }), c;
212
+ }
213
+ return n;
214
+ }
215
+ function xt(t, e) {
216
+ const r = t.entries.find((o) => o.pathname === "*");
217
+ if (!r)
218
+ throw new Error("Vercel output requires a static fallback entry.");
219
+ const n = jt(e.cache), i = [];
220
+ for (const o of t.entries) {
221
+ if (o.pathname === "*") continue;
222
+ const s = `/${o.file}`;
223
+ s !== o.pathname && i.push({
224
+ continue: !0,
225
+ dest: o.pathname,
226
+ src: S(s)
227
+ });
228
+ }
229
+ for (const o of t.entries) {
230
+ const s = H(o.headers);
231
+ if (Object.keys(s).length === 0) continue;
232
+ const f = o.pathname === "*" ? `/${o.file}` : o.pathname;
233
+ i.push({
234
+ continue: !0,
235
+ headers: s,
236
+ src: S(f)
237
+ });
238
+ }
239
+ i.push(...n);
240
+ for (const o of t.entries) {
241
+ if (o.pathname === "*") {
242
+ i.push({
243
+ dest: `/${o.file}`,
244
+ src: S(`/${o.file}`),
245
+ status: 404
246
+ });
247
+ continue;
248
+ }
249
+ i.push({
250
+ dest: o.pathname === "/" ? `/${o.file}` : o.pathname,
251
+ src: S(o.pathname)
252
+ });
253
+ }
254
+ i.push({ handle: "hit" });
255
+ for (const o of [...t.fileHeaderRules].reverse())
256
+ i.push({
257
+ continue: !0,
258
+ headers: { ...o.headers },
259
+ src: Nt(o.pattern)
260
+ });
261
+ i.push(...n.map((o) => ({ ...o }))), i.push({ handle: "error" });
262
+ const a = H(r.headers);
263
+ Object.keys(a).length > 0 && i.push({
264
+ continue: !0,
265
+ headers: a,
266
+ src: "^/.*$"
267
+ }), i.push(...n.map((o) => ({ ...o }))), i.push({ dest: `/${r.file}`, src: "^/.*$", status: 404 });
268
+ const c = mt(i);
269
+ if (c.error || !c.routes)
270
+ throw new Error(
271
+ `Vercel rejected the generated routes: ${c.error?.message ?? "The route list is empty."}`
272
+ );
273
+ return {
274
+ overrides: Object.fromEntries(
275
+ t.entries.map((o) => [o.file, At(o)])
276
+ ),
277
+ routes: c.routes,
278
+ version: 3
279
+ };
280
+ }
281
+ function At(t) {
282
+ const e = {}, r = t.headers["content-type"];
283
+ if (r && (e.contentType = r), t.pathname !== "*") {
284
+ const n = t.file === "index.html" ? "/" : `/${t.file}`;
285
+ t.pathname !== n && (e.path = t.pathname.slice(1));
286
+ }
287
+ return e;
288
+ }
289
+ function S(t) {
290
+ const e = t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
291
+ return t === "/" ? "^/$" : `^${e}/?$`;
292
+ }
293
+ function H(t) {
294
+ return Object.fromEntries(
295
+ Object.entries(t).filter(([e]) => e.toLowerCase() !== "content-type")
296
+ );
297
+ }
298
+ function Nt(t) {
299
+ return t === ".*" ? "^/.*$" : t === _.source ? "^/(?:.*/)?[^/]*-[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9]+$" : `^/${bt(t)}$`;
300
+ }
301
+ function bt(t) {
302
+ const e = t.startsWith("^"), r = t.endsWith("$") && !t.endsWith("\\$"), n = t.slice(
303
+ e ? 1 : 0,
304
+ r ? -1 : void 0
305
+ );
306
+ return `${e ? "(?:.*/)?" : "(?:.*/)?[^/]*"}(?:${n})${r ? "" : "[^/]*"}`;
307
+ }
308
+ function jt(t) {
309
+ const e = t.map((n) => ({
310
+ headers: [{ key: "cache-control", value: n.value }],
311
+ source: n.source
312
+ })), r = wt({ headers: e });
313
+ if (r.error || !r.routes)
314
+ throw new Error(
315
+ `A Vercel static header rule is not valid: ${r.error?.message ?? "The route list is empty."}`
316
+ );
317
+ return r.routes;
318
+ }
319
+ function Ft(t) {
320
+ if (t.adapter !== "vercel" || !Array.isArray(t.cache))
321
+ throw new Error("The Vercel static adapter configuration is not valid.");
322
+ for (const e of t.cache)
323
+ if (!e || typeof e != "object" || typeof e.source != "string" || !e.source || typeof e.value != "string" || !e.value)
324
+ throw new Error("A Vercel static header rule is not valid.");
325
+ }
326
+ function Ht(t, e) {
327
+ const r = w(t, e), n = w(e, t);
328
+ return C(r) || C(n);
329
+ }
330
+ function C(t) {
331
+ return !t || t !== ".." && !t.startsWith(`..${g}`) && !t.startsWith("/");
332
+ }
333
+ const G = "demiurge-static-manifest.json", Ct = it({
11
334
  name: "static",
12
335
  capabilities: {
13
336
  staticOutput: !0
14
337
  }
15
- });
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, {
338
+ }), Pt = 8;
339
+ async function Jt(t) {
340
+ const e = Object.entries(t), r = new Array(e.length);
341
+ let n = 0;
342
+ const i = Array.from(
343
+ { length: Math.min(Pt, e.length) },
344
+ async () => {
345
+ for (; n < e.length; ) {
346
+ const a = n++, [c, o] = e[a];
347
+ try {
348
+ r[a] = [c, await o()];
349
+ } catch (s) {
350
+ throw new Error(
351
+ `Demiurge could not load route module ${JSON.stringify(c)}.`,
352
+ { cause: s }
353
+ );
354
+ }
355
+ }
356
+ }
357
+ );
358
+ return await Promise.all(i), Object.fromEntries(r);
359
+ }
360
+ async function me(t) {
361
+ const e = await Jt(t.routes), r = ot(e, {
362
+ adapter: Ct
363
+ }), n = Wt(t.origin), i = h(t.outDir), a = await Dt(r), c = await st(r, {
18
364
  includeResources: !0
19
365
  });
20
- V(
21
- n,
22
- i.filter((u) => o.get(u.file) === "document").length
366
+ kt(
367
+ r,
368
+ c.filter((u) => a.get(u.file) === "document").length
23
369
  );
24
- const c = Z(
25
- i.map((u) => ({
26
- kind: o.get(u.file) ?? "resource",
370
+ const o = Bt(
371
+ c.map((u) => ({
372
+ kind: a.get(u.file) ?? "resource",
27
373
  pathname: u.pathname
28
374
  }))
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, {
375
+ ), s = at(), f = [], l = { ...t.ssr, navigation: "document" };
376
+ for (const u of o) {
377
+ const d = J(n, u.pathname, u.kind), p = await ct(r, d, {
32
378
  onError: t.onError,
33
- rateLimitStore: a,
34
- ssr: f
379
+ rateLimitStore: s,
380
+ ssr: l
35
381
  });
36
- s.push(
37
- u.kind === "document" ? await T(u, y, 200) : await rt(u, y)
382
+ f.push(
383
+ u.kind === "document" ? await L(u, p, 200) : await Gt(u, p)
38
384
  );
39
385
  }
40
- const d = await q(
41
- n,
42
- v(e, "/404", "document"),
386
+ const R = await ut(
387
+ r,
388
+ J(n, "/404", "document"),
43
389
  {
44
- ...f,
45
- onError: (u, l) => t.onError?.(u, { pathname: "/404", site: l })
390
+ ...l,
391
+ onError: (u, d) => t.onError?.(u, { pathname: "/404", site: d })
46
392
  }
47
393
  );
48
- s.push(
49
- await T(
394
+ f.push(
395
+ await L(
50
396
  {
51
397
  file: "404.html",
52
398
  pathname: "*"
53
399
  },
54
- d,
400
+ R,
55
401
  404
56
402
  )
57
- ), s.sort((u, l) => u.file.localeCompare(l.file));
58
- const S = {
403
+ ), f.sort((u, d) => u.file.localeCompare(d.file));
404
+ const y = {
59
405
  adapter: "static",
60
- entries: s.map(({ body: u, ...l }) => l),
61
- fileHeaderRules: K(),
406
+ entries: f.map(({ body: u, ...d }) => d),
407
+ fileHeaderRules: await Lt(
408
+ r,
409
+ t.staticFileHeaders ?? []
410
+ ),
62
411
  version: 1
63
412
  };
64
- return await at(r, s, S), S;
413
+ return await te(i, f, y), y;
65
414
  }
66
- function K() {
415
+ async function Lt(t, e) {
416
+ const r = await Mt(t), n = P(r);
67
417
  return [
418
+ ...e.map((i) => (It(i.pattern), {
419
+ headers: P(
420
+ ft(r, { headers: i.headers })
421
+ ),
422
+ pattern: i.pattern
423
+ })),
68
424
  {
69
- headers: { "cache-control": B },
70
- pattern: W.source
425
+ headers: {
426
+ ...n,
427
+ "cache-control": dt
428
+ },
429
+ pattern: _.source
71
430
  },
72
431
  {
73
- headers: { "cache-control": G },
432
+ headers: {
433
+ ...n,
434
+ "cache-control": ht
435
+ },
74
436
  pattern: ".*"
75
437
  }
76
438
  ];
77
439
  }
78
- function z(t) {
440
+ async function Mt(t) {
441
+ return { headers: (await t.policies.find(
442
+ (n) => n.fileSegments.length === 0
443
+ )?.load())?.policy?.document?.headers };
444
+ }
445
+ function P(t) {
446
+ return Object.fromEntries(lt(t, {}).entries());
447
+ }
448
+ function It(t) {
449
+ try {
450
+ new RegExp(t);
451
+ } catch {
452
+ throw new Error(
453
+ `Static file header pattern is not a valid regular expression: ${JSON.stringify(t)}.`
454
+ );
455
+ }
456
+ }
457
+ function Wt(t) {
79
458
  let e;
80
459
  try {
81
460
  e = new URL(t ?? "http://demiurge.local");
@@ -90,7 +469,7 @@ function z(t) {
90
469
  );
91
470
  return e.origin;
92
471
  }
93
- function V(t, e) {
472
+ function kt(t, e) {
94
473
  if (e === 0)
95
474
  throw new Error("Static output requires at least one page route.");
96
475
  if (!t.fallbacks.notFound.some(
@@ -100,13 +479,13 @@ function V(t, e) {
100
479
  "Static output requires a root @not-found.tsx so 404.html is app-owned."
101
480
  );
102
481
  }
103
- async function Q(t) {
482
+ async function Dt(t) {
104
483
  const e = /* @__PURE__ */ new Map();
105
484
  for (const r of t.routes) {
106
- const n = await r.load(), o = X(n);
107
- if (o.length > 0)
485
+ const n = await r.load(), i = _t(n);
486
+ if (i.length > 0)
108
487
  throw new Error(
109
- `Static route ${JSON.stringify(r.file)} exports unsupported methods ${o.join(", ")}. Deploy a runtime adapter for request-time methods.`
488
+ `Static route ${JSON.stringify(r.file)} exports unsupported methods ${i.join(", ")}. Deploy a runtime adapter for request-time methods.`
110
489
  );
111
490
  if (!n.GET)
112
491
  throw new Error(
@@ -116,14 +495,14 @@ async function Q(t) {
116
495
  e.set(r.file, "document");
117
496
  continue;
118
497
  }
119
- Y(r.file, n.GET), e.set(r.file, "resource");
498
+ Ut(r.file, n.GET), e.set(r.file, "resource");
120
499
  }
121
500
  return e;
122
501
  }
123
- function X(t) {
502
+ function _t(t) {
124
503
  return ["POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"].filter((e) => t[e] !== void 0);
125
504
  }
126
- function Y(t, e) {
505
+ function Ut(t, e) {
127
506
  if ((e.kind === "text" || e.kind === "html" || e.kind === "json") && typeof e.value != "function")
128
507
  return;
129
508
  const r = "value" in e && typeof e.value == "function" ? `uses a request-dependent ${e.kind} value` : `uses the ${e.kind} response helper`;
@@ -131,23 +510,23 @@ function Y(t, e) {
131
510
  `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
511
  );
133
512
  }
134
- function Z(t) {
513
+ function Bt(t) {
135
514
  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(
515
+ return t.map(({ kind: n, pathname: i }) => {
516
+ if (r.has(i))
517
+ throw new Error(`Static output collected duplicate pathname ${JSON.stringify(i)}.`);
518
+ r.add(i);
519
+ const a = n === "document" ? z(i) : Vt(i), c = a.toLocaleLowerCase("en-US"), o = [...e.entries()].find(
141
520
  ([s]) => s === c || s.startsWith(`${c}/`) || c.startsWith(`${s}/`)
142
521
  );
143
- if (a)
522
+ if (o)
144
523
  throw new Error(
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.`
524
+ `Static paths ${JSON.stringify(o[1])} and ${JSON.stringify(i)} map to the same portable output file or to a file and directory conflict.`
146
525
  );
147
- return e.set(c, o), { file: i, kind: n, pathname: o };
526
+ return e.set(c, i), { file: a, kind: n, pathname: i };
148
527
  });
149
528
  }
150
- function J(t) {
529
+ function z(t) {
151
530
  if (!t.startsWith("/") || t.includes("?") || t.includes("#"))
152
531
  throw new Error(`Static output received invalid pathname ${JSON.stringify(t)}.`);
153
532
  return t === "/" ? "index.html" : [...t.split("/").slice(1).map((r) => {
@@ -157,27 +536,27 @@ function J(t) {
157
536
  } catch {
158
537
  throw new Error(`Static output pathname is not valid UTF-8: ${JSON.stringify(t)}.`);
159
538
  }
160
- return et(n, t), n;
539
+ return qt(n, t), n;
161
540
  }), "index.html"].join("/");
162
541
  }
163
- function tt(t) {
542
+ function Vt(t) {
164
543
  if (t === "/")
165
544
  throw new Error("A static resource route cannot own the root pathname.");
166
- return J(t).slice(0, -11);
545
+ return z(t).slice(0, -11);
167
546
  }
168
- function et(t, e) {
547
+ function qt(t, e) {
169
548
  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
549
  if (!t || t === "." || t === ".." || t.includes("/") || t.includes("\\") || r)
171
550
  throw new Error(
172
551
  `Static pathname ${JSON.stringify(e)} contains a segment that is unsafe or not portable as a file name: ${JSON.stringify(t)}.`
173
552
  );
174
553
  }
175
- function v(t, e, r) {
554
+ function J(t, e, r) {
176
555
  return new Request(`${t}${e}`, {
177
556
  headers: { accept: r === "document" ? "text/html" : "*/*" }
178
557
  });
179
558
  }
180
- async function T(t, e, r) {
559
+ async function L(t, e, r) {
181
560
  if (e.status !== r)
182
561
  throw new Error(
183
562
  `Static output for ${JSON.stringify(t.pathname)} returned status ${e.status}; expected ${r}.`
@@ -191,19 +570,19 @@ async function T(t, e, r) {
191
570
  throw new Error(
192
571
  `Static output for ${JSON.stringify(t.pathname)} attempted to set a cookie. Build artifacts cannot contain per-user response state.`
193
572
  );
194
- const o = await nt(
573
+ const i = await zt(
195
574
  await e.text(),
196
575
  e.headers
197
576
  );
198
- return await it(t.pathname, o, e.headers), {
577
+ return await Zt(t.pathname, i, e.headers), {
199
578
  file: t.file,
200
- headers: A(e.headers),
201
- body: o,
579
+ headers: Z(e.headers),
580
+ body: i,
202
581
  pathname: t.pathname,
203
582
  status: r
204
583
  };
205
584
  }
206
- async function rt(t, e) {
585
+ async function Gt(t, e) {
207
586
  if (e.status !== 200)
208
587
  throw new Error(
209
588
  `Static output for ${JSON.stringify(t.pathname)} returned status ${e.status}; expected 200.`
@@ -214,48 +593,48 @@ async function rt(t, e) {
214
593
  );
215
594
  return {
216
595
  file: t.file,
217
- headers: A(e.headers),
596
+ headers: Z(e.headers),
218
597
  body: await e.text(),
219
598
  pathname: t.pathname,
220
599
  status: 200
221
600
  };
222
601
  }
223
- async function nt(t, e) {
602
+ async function zt(t, e) {
224
603
  const r = new RegExp(
225
- `(?:^|\\s)${$}(?:\\s|$)`
226
- ), n = F(t, "script").filter((i) => r.test(i.attributes));
604
+ `(?:^|\\s)${F}(?:\\s|$)`
605
+ ), n = K(t, "script").filter((a) => r.test(a.attributes));
227
606
  if (n.length === 0)
228
607
  return t;
229
- const o = await Promise.all(
230
- n.map((i) => x(i.content))
608
+ const i = await Promise.all(
609
+ n.map((a) => D(a.content))
231
610
  );
232
- for (const i of [
611
+ for (const a of [
233
612
  "content-security-policy",
234
613
  "content-security-policy-report-only"
235
614
  ]) {
236
- const c = e.get(i);
237
- c && e.set(i, ot(c, o));
615
+ const c = e.get(a);
616
+ c && e.set(a, Kt(c, i));
238
617
  }
239
618
  return t.replace(
240
- new RegExp(`\\s${$}(?=\\s|>)`, "g"),
619
+ new RegExp(`\\s${F}(?=\\s|>)`, "g"),
241
620
  ""
242
621
  );
243
622
  }
244
- function ot(t, e) {
623
+ function Kt(t, e) {
245
624
  const r = t.split(";").map((s) => s.trim()).filter(Boolean), n = r.findIndex(
246
625
  (s) => s.split(/\s+/, 1)[0]?.toLowerCase() === "script-src"
247
- ), o = r.find(
626
+ ), i = r.find(
248
627
  (s) => s.split(/\s+/, 1)[0]?.toLowerCase() === "default-src"
249
- ), i = n === -1 ? o : r[n];
250
- if (!i)
628
+ ), a = n === -1 ? i : r[n];
629
+ if (!a)
251
630
  return t;
252
- const c = i.split(/\s+/).slice(1).filter((s) => s !== "'none'"), a = [
631
+ const c = a.split(/\s+/).slice(1).filter((s) => s !== "'none'"), o = [
253
632
  "script-src",
254
633
  .../* @__PURE__ */ new Set([...c, ...e])
255
634
  ].join(" ");
256
- return n === -1 ? r.push(a) : r[n] = a, r.join("; ");
635
+ return n === -1 ? r.push(o) : r[n] = o, r.join("; ");
257
636
  }
258
- async function it(t, e, r) {
637
+ async function Zt(t, e, r) {
259
638
  const n = r.get("content-security-policy");
260
639
  if (!n)
261
640
  return;
@@ -263,115 +642,176 @@ async function it(t, e, r) {
263
642
  throw new Error(
264
643
  `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.`
265
644
  );
266
- const o = st(n);
267
- await N(
645
+ const i = Qt(n);
646
+ await M(
268
647
  t,
269
648
  e,
270
649
  "script",
271
- h(o, "script-src")
272
- ), await N(
650
+ x(i, "script-src", "default-src")
651
+ ), await M(
273
652
  t,
274
653
  e,
275
654
  "style",
276
- h(o, "style-src")
655
+ x(
656
+ i,
657
+ "style-src-elem",
658
+ "style-src",
659
+ "default-src"
660
+ )
277
661
  );
278
- const i = h(o, "style-src");
279
- if (i && /\sstyle\s*=/i.test(e) && !i.includes("'unsafe-inline'"))
662
+ const a = x(
663
+ i,
664
+ "style-src-attr",
665
+ "style-src",
666
+ "default-src"
667
+ );
668
+ if (a && /\sstyle\s*=/i.test(e) && !a.includes("'unsafe-inline'"))
280
669
  throw new Error(
281
670
  `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.`
282
671
  );
283
672
  }
284
- function st(t) {
673
+ function Qt(t) {
285
674
  const e = /* @__PURE__ */ new Map();
286
675
  for (const r of t.split(";")) {
287
- const [n, ...o] = r.trim().split(/\s+/);
288
- n && e.set(n.toLowerCase(), o);
676
+ const [n, ...i] = r.trim().split(/\s+/);
677
+ n && e.set(n.toLowerCase(), i);
289
678
  }
290
679
  return e;
291
680
  }
292
- function h(t, e) {
293
- return t.get(e) ?? t.get("default-src");
681
+ function x(t, ...e) {
682
+ for (const r of e) {
683
+ const n = t.get(r);
684
+ if (n)
685
+ return n;
686
+ }
294
687
  }
295
- async function N(t, e, r, n) {
688
+ async function M(t, e, r, n) {
296
689
  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)
690
+ for (const i of K(e, r)) {
691
+ if (r === "script") {
692
+ const c = Xt(i.attributes, "src");
693
+ if (c) {
694
+ if (!Yt(n, c))
695
+ throw new Error(
696
+ `Static output for ${JSON.stringify(t)} contains script ${JSON.stringify(c)} that the effective script-src directive does not allow. Add its origin to security.needs.script or the route CSP policy.`
697
+ );
698
+ continue;
699
+ }
700
+ }
701
+ if (!i.content)
299
702
  continue;
300
- const i = await x(o.content);
301
- if (!n.includes(i))
703
+ const a = await D(i.content);
704
+ if (!n.includes(a))
302
705
  throw new Error(
303
- `Static output for ${JSON.stringify(t)} contains an inline ${r} without the required CSP hash ${i}.`
706
+ `Static output for ${JSON.stringify(t)} contains an inline ${r} without the required CSP hash ${a}.`
304
707
  );
305
708
  }
306
709
  }
307
- function F(t, e) {
308
- const r = t.toLowerCase(), n = [], o = `<${e}`, i = `</${e}`;
710
+ function Xt(t, e) {
711
+ return t.match(
712
+ new RegExp(`(?:^|\\s)${e}\\s*=\\s*["']([^"']+)["']`, "i")
713
+ )?.[1]?.replaceAll("&amp;", "&");
714
+ }
715
+ function Yt(t, e) {
716
+ if (!t)
717
+ return !0;
718
+ if (t.includes("'none'") || t.includes("'strict-dynamic'") && t.some(
719
+ (n) => n.startsWith("'nonce-") || /^'sha(?:256|384|512)-/.test(n)
720
+ ))
721
+ return !1;
722
+ if (t.includes("*") || t.includes("'self'") && e.startsWith("/") && !e.startsWith("//") || e.startsWith("https:") && t.includes("https:") || e.startsWith("http:") && t.includes("http:"))
723
+ return !0;
724
+ let r;
725
+ try {
726
+ r = new URL(e, "https://demiurge.invalid");
727
+ } catch {
728
+ return !1;
729
+ }
730
+ return t.some((n) => {
731
+ if (n.startsWith("'"))
732
+ return !1;
733
+ let i;
734
+ try {
735
+ i = new URL(n);
736
+ } catch {
737
+ return !1;
738
+ }
739
+ const a = i.hostname.startsWith("*.") ? r.hostname.endsWith(i.hostname.slice(1)) && r.hostname !== i.hostname.slice(2) : r.hostname === i.hostname, c = i.pathname === "/" || i.pathname.endsWith("/") ? r.pathname.startsWith(i.pathname) : r.pathname === i.pathname;
740
+ return r.protocol === i.protocol && a && r.port === i.port && c;
741
+ });
742
+ }
743
+ function K(t, e) {
744
+ const r = t.toLowerCase(), n = [], i = `<${e}`, a = `</${e}`;
309
745
  let c = 0;
310
746
  for (; c < t.length; ) {
311
- const a = r.indexOf(o, c);
312
- if (a === -1)
747
+ const o = r.indexOf(i, c);
748
+ if (o === -1)
313
749
  break;
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)
750
+ const s = r.indexOf(">", o + i.length), f = s === -1 ? -1 : r.indexOf(a, s + 1), l = f === -1 ? -1 : r.indexOf(">", f + a.length);
751
+ if (s === -1 || f === -1 || l === -1)
316
752
  throw new Error(`Static output contains an unclosed <${e}> element.`);
317
753
  n.push({
318
- attributes: t.slice(a + o.length, s),
754
+ attributes: t.slice(o + i.length, s),
319
755
  content: t.slice(s + 1, f)
320
- }), c = d + 1;
756
+ }), c = l + 1;
321
757
  }
322
758
  return n;
323
759
  }
324
- function A(t) {
760
+ function Z(t) {
325
761
  return Object.fromEntries(
326
762
  [...t.entries()].sort(([e], [r]) => e.localeCompare(r))
327
763
  );
328
764
  }
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-"));
765
+ async function te(t, e, r) {
766
+ const n = N(t);
767
+ await E(n, { recursive: !0 });
768
+ const i = await W(m(n, ".demiurge-static-"));
333
769
  try {
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);
770
+ for (const o of e) {
771
+ const s = I(i, o.file);
772
+ await E(N(s), { recursive: !0 }), await A(s, o.body);
337
773
  }
338
- await E(
339
- m(o, C),
774
+ await A(
775
+ m(i, G),
340
776
  `${JSON.stringify(r, null, 2)}
341
777
  `
342
778
  );
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 });
779
+ const a = await ee(t);
780
+ await E(t, { recursive: !0 }), await k(i, t, { recursive: !0, force: !0 });
781
+ const c = new Set(e.map((o) => o.file));
782
+ for (const o of a)
783
+ c.has(o) || await $(I(t, o), { force: !0 });
348
784
  } finally {
349
- await g(o, { force: !0, recursive: !0 });
785
+ await $(i, { force: !0, recursive: !0 });
350
786
  }
351
787
  }
352
- async function ct(t) {
788
+ async function ee(t) {
353
789
  try {
354
- const e = await b(m(t, C), "utf8"), r = JSON.parse(e);
790
+ const e = await v(m(t, G), "utf8"), r = JSON.parse(e);
355
791
  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] : []
792
+ (n) => typeof n.file == "string" && Q(n.file) ? [n.file] : []
357
793
  );
358
794
  } catch {
359
795
  return [];
360
796
  }
361
797
  }
362
- function R(t, e) {
363
- if (!L(e))
798
+ function I(t, e) {
799
+ if (!Q(e))
364
800
  throw new Error(`Static output file must stay inside the output directory: ${JSON.stringify(e)}.`);
365
- const r = w(t), n = w(r, e);
366
- if (M(r, n).split(H).includes(".."))
801
+ const r = h(t), n = h(r, e);
802
+ if (w(r, n).split(g).includes(".."))
367
803
  throw new Error(`Static output file escaped the output directory: ${JSON.stringify(e)}.`);
368
804
  return n;
369
805
  }
370
- function L(t) {
806
+ function Q(t) {
371
807
  return !!t && !t.startsWith("/") && !t.startsWith("\\") && !t.split(/[\\/]/).includes("..");
372
808
  }
373
809
  export {
374
- Et as generateStaticOutput,
375
- yt as staticAdapter
810
+ de as createStaticPreviewServer,
811
+ xt as createVercelOutputConfig,
812
+ me as generateStaticOutput,
813
+ pe as generateVercelStaticOutput,
814
+ Ct as staticAdapter,
815
+ he as vercelStatic
376
816
  };
377
817
  //# sourceMappingURL=index.js.map