@demiurgejs/core 0.1.0 → 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 (96) hide show
  1. package/README.md +3 -0
  2. package/bin/demiurge.mjs +51 -0
  3. package/dist/browser/file-router.d.ts +5 -0
  4. package/dist/browser/file-router.d.ts.map +1 -1
  5. package/dist/chunks/request-metadata-DwEO1EAS.js +477 -0
  6. package/dist/chunks/request-metadata-DwEO1EAS.js.map +1 -0
  7. package/dist/chunks/static-files-DUjHw-4H.js +11 -0
  8. package/dist/chunks/static-files-DUjHw-4H.js.map +1 -0
  9. package/dist/chunks/{streaming-27pwhjGC.js → streaming-Ci6vf3BB.js} +117 -107
  10. package/dist/chunks/streaming-Ci6vf3BB.js.map +1 -0
  11. package/dist/chunks/{testing-BBnJ5WUR.js → testing-DBjVCN5v.js} +2384 -1941
  12. package/dist/chunks/testing-DBjVCN5v.js.map +1 -0
  13. package/dist/cli.d.ts +42 -0
  14. package/dist/cli.d.ts.map +1 -0
  15. package/dist/cli.js +164 -0
  16. package/dist/cli.js.map +1 -0
  17. package/dist/document/index.d.ts +2 -2
  18. package/dist/document/index.d.ts.map +1 -1
  19. package/dist/document/render.d.ts +2 -1
  20. package/dist/document/render.d.ts.map +1 -1
  21. package/dist/document/scripts.d.ts +22 -0
  22. package/dist/document/scripts.d.ts.map +1 -1
  23. package/dist/index.d.ts +7 -7
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +893 -1035
  26. package/dist/index.js.map +1 -1
  27. package/dist/internal/testing.js +15 -14
  28. package/dist/internal/testing.js.map +1 -1
  29. package/dist/node/index.js +86 -85
  30. package/dist/node/index.js.map +1 -1
  31. package/dist/node/static.d.ts.map +1 -1
  32. package/dist/node/streaming.d.ts +2 -0
  33. package/dist/node/streaming.d.ts.map +1 -1
  34. package/dist/route/action.d.ts +11 -11
  35. package/dist/route/action.d.ts.map +1 -1
  36. package/dist/route/index.d.ts +2 -1
  37. package/dist/route/index.d.ts.map +1 -1
  38. package/dist/route/middleware.d.ts +7 -0
  39. package/dist/route/middleware.d.ts.map +1 -0
  40. package/dist/route/page.d.ts +2 -2
  41. package/dist/route/page.d.ts.map +1 -1
  42. package/dist/route/response.d.ts +19 -19
  43. package/dist/route/response.d.ts.map +1 -1
  44. package/dist/route/types.d.ts +55 -31
  45. package/dist/route/types.d.ts.map +1 -1
  46. package/dist/route/webhook.d.ts +1 -1
  47. package/dist/router/manifest.d.ts +4 -1
  48. package/dist/router/manifest.d.ts.map +1 -1
  49. package/dist/routing/generate.d.ts +2 -0
  50. package/dist/routing/generate.d.ts.map +1 -1
  51. package/dist/routing/index.d.ts +1 -1
  52. package/dist/routing/index.d.ts.map +1 -1
  53. package/dist/routing/types.d.ts +2 -0
  54. package/dist/routing/types.d.ts.map +1 -1
  55. package/dist/security/cors.d.ts.map +1 -1
  56. package/dist/security/index.d.ts +4 -2
  57. package/dist/security/index.d.ts.map +1 -1
  58. package/dist/security/policy.d.ts +31 -2
  59. package/dist/security/policy.d.ts.map +1 -1
  60. package/dist/security/types.d.ts +27 -13
  61. package/dist/security/types.d.ts.map +1 -1
  62. package/dist/security/verification.d.ts +8 -0
  63. package/dist/security/verification.d.ts.map +1 -0
  64. package/dist/server/errors.d.ts.map +1 -1
  65. package/dist/server/not-found.d.ts.map +1 -1
  66. package/dist/server/render-tree.d.ts +6 -1
  67. package/dist/server/render-tree.d.ts.map +1 -1
  68. package/dist/server/request-handler.d.ts +4 -1
  69. package/dist/server/request-handler.d.ts.map +1 -1
  70. package/dist/server/ssr.d.ts +1 -0
  71. package/dist/server/ssr.d.ts.map +1 -1
  72. package/dist/static/index.d.ts +15 -0
  73. package/dist/static/index.d.ts.map +1 -1
  74. package/dist/static/index.js +684 -123
  75. package/dist/static/index.js.map +1 -1
  76. package/dist/static/preview.d.ts +8 -0
  77. package/dist/static/preview.d.ts.map +1 -0
  78. package/dist/static/vercel.d.ts +31 -0
  79. package/dist/static/vercel.d.ts.map +1 -0
  80. package/dist/static-files.d.ts +5 -0
  81. package/dist/static-files.d.ts.map +1 -0
  82. package/dist/vite/index.d.ts +3 -2
  83. package/dist/vite/index.d.ts.map +1 -1
  84. package/dist/vite/index.js +882 -288
  85. package/dist/vite/index.js.map +1 -1
  86. package/dist/vite/plugin.d.ts +13 -0
  87. package/dist/vite/plugin.d.ts.map +1 -1
  88. package/dist/vite/policy-verification.d.ts +10 -0
  89. package/dist/vite/policy-verification.d.ts.map +1 -0
  90. package/package.json +9 -1
  91. package/dist/chunks/index-BnX9Qxbm.js +0 -44
  92. package/dist/chunks/index-BnX9Qxbm.js.map +0 -1
  93. package/dist/chunks/ssr-O3d7Q73U.js +0 -273
  94. package/dist/chunks/ssr-O3d7Q73U.js.map +0 -1
  95. package/dist/chunks/streaming-27pwhjGC.js.map +0 -1
  96. package/dist/chunks/testing-BBnJ5WUR.js.map +0 -1
@@ -1,54 +1,460 @@
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 { 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";
5
5
  import "react-dom/server";
6
6
  import "react";
7
7
  import "react/jsx-runtime";
8
- const N = "demiurge-static-manifest.json", it = T({
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({
9
334
  name: "static",
10
335
  capabilities: {
11
336
  staticOutput: !0
12
337
  }
13
- });
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, {
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, {
364
+ includeResources: !0
365
+ });
366
+ kt(
367
+ r,
368
+ c.filter((u) => a.get(u.file) === "document").length
369
+ );
370
+ const o = Bt(
371
+ c.map((u) => ({
372
+ kind: a.get(u.file) ?? "resource",
373
+ pathname: u.pathname
374
+ }))
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, {
20
378
  onError: t.onError,
21
- rateLimitStore: c,
22
- ssr: a
379
+ rateLimitStore: s,
380
+ ssr: l
23
381
  });
24
- o.push(await E(u, F, 200));
382
+ f.push(
383
+ u.kind === "document" ? await L(u, p, 200) : await Gt(u, p)
384
+ );
25
385
  }
26
- const f = await k(
386
+ const R = await ut(
27
387
  r,
28
- O(e, "/404"),
388
+ J(n, "/404", "document"),
29
389
  {
30
- ...a,
31
- onError: (u, l) => t.onError?.(u, { pathname: "/404", site: l })
390
+ ...l,
391
+ onError: (u, d) => t.onError?.(u, { pathname: "/404", site: d })
32
392
  }
33
393
  );
34
- o.push(
35
- await E(
394
+ f.push(
395
+ await L(
36
396
  {
37
397
  file: "404.html",
38
398
  pathname: "*"
39
399
  },
40
- f,
400
+ R,
41
401
  404
42
402
  )
43
- ), o.sort((u, l) => u.file.localeCompare(l.file));
44
- const p = {
403
+ ), f.sort((u, d) => u.file.localeCompare(d.file));
404
+ const y = {
45
405
  adapter: "static",
46
- entries: o.map(({ html: u, ...l }) => l),
406
+ entries: f.map(({ body: u, ...d }) => d),
407
+ fileHeaderRules: await Lt(
408
+ r,
409
+ t.staticFileHeaders ?? []
410
+ ),
47
411
  version: 1
48
412
  };
49
- return await K(i, o, p), p;
413
+ return await te(i, f, y), y;
414
+ }
415
+ async function Lt(t, e) {
416
+ const r = await Mt(t), n = P(r);
417
+ return [
418
+ ...e.map((i) => (It(i.pattern), {
419
+ headers: P(
420
+ ft(r, { headers: i.headers })
421
+ ),
422
+ pattern: i.pattern
423
+ })),
424
+ {
425
+ headers: {
426
+ ...n,
427
+ "cache-control": dt
428
+ },
429
+ pattern: _.source
430
+ },
431
+ {
432
+ headers: {
433
+ ...n,
434
+ "cache-control": ht
435
+ },
436
+ pattern: ".*"
437
+ }
438
+ ];
439
+ }
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
+ }
50
456
  }
51
- function j(t) {
457
+ function Wt(t) {
52
458
  let e;
53
459
  try {
54
460
  e = new URL(t ?? "http://demiurge.local");
@@ -63,194 +469,349 @@ function j(t) {
63
469
  );
64
470
  return e.origin;
65
471
  }
66
- function H(t, e) {
472
+ function kt(t, e) {
67
473
  if (e === 0)
68
474
  throw new Error("Static output requires at least one page route.");
69
475
  if (!t.fallbacks.notFound.some(
70
- (r) => r.fileSegments.length === 0
476
+ (n) => n.fileSegments.length === 0
71
477
  ))
72
478
  throw new Error(
73
479
  "Static output requires a root @not-found.tsx so 404.html is app-owned."
74
480
  );
75
481
  }
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)
482
+ async function Dt(t) {
483
+ const e = /* @__PURE__ */ new Map();
484
+ for (const r of t.routes) {
485
+ const n = await r.load(), i = _t(n);
486
+ if (i.length > 0)
487
+ throw new Error(
488
+ `Static route ${JSON.stringify(r.file)} exports unsupported methods ${i.join(", ")}. Deploy a runtime adapter for request-time methods.`
489
+ );
490
+ if (!n.GET)
491
+ throw new Error(
492
+ `Static route ${JSON.stringify(r.file)} does not export GET and cannot produce an output file.`
493
+ );
494
+ if (n.GET.kind === "page") {
495
+ e.set(r.file, "document");
496
+ continue;
497
+ }
498
+ Ut(r.file, n.GET), e.set(r.file, "resource");
499
+ }
500
+ return e;
501
+ }
502
+ function _t(t) {
503
+ return ["POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"].filter((e) => t[e] !== void 0);
504
+ }
505
+ function Ut(t, e) {
506
+ if ((e.kind === "text" || e.kind === "html" || e.kind === "json") && typeof e.value != "function")
507
+ return;
508
+ const r = "value" in e && typeof e.value == "function" ? `uses a request-dependent ${e.kind} value` : `uses the ${e.kind} response helper`;
509
+ throw new Error(
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.`
511
+ );
512
+ }
513
+ function Bt(t) {
514
+ const e = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Set();
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(
520
+ ([s]) => s === c || s.startsWith(`${c}/`) || c.startsWith(`${s}/`)
521
+ );
522
+ if (o)
84
523
  throw new Error(
85
- `Static paths ${JSON.stringify(c)} and ${JSON.stringify(r)} map to the same portable output file ${JSON.stringify(n)}.`
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.`
86
525
  );
87
- return e.set(s, r), { file: n, pathname: r };
526
+ return e.set(c, i), { file: a, kind: n, pathname: i };
88
527
  });
89
528
  }
90
- function U(t) {
529
+ function z(t) {
91
530
  if (!t.startsWith("/") || t.includes("?") || t.includes("#"))
92
531
  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;
532
+ return t === "/" ? "index.html" : [...t.split("/").slice(1).map((r) => {
533
+ let n;
95
534
  try {
96
- r = decodeURIComponent(i);
535
+ n = decodeURIComponent(r);
97
536
  } catch {
98
537
  throw new Error(`Static output pathname is not valid UTF-8: ${JSON.stringify(t)}.`);
99
538
  }
100
- return _(r, t), r;
539
+ return qt(n, t), n;
101
540
  }), "index.html"].join("/");
102
541
  }
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)
542
+ function Vt(t) {
543
+ if (t === "/")
544
+ throw new Error("A static resource route cannot own the root pathname.");
545
+ return z(t).slice(0, -11);
546
+ }
547
+ function qt(t, e) {
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);
549
+ if (!t || t === "." || t === ".." || t.includes("/") || t.includes("\\") || r)
106
550
  throw new Error(
107
551
  `Static pathname ${JSON.stringify(e)} contains a segment that is unsafe or not portable as a file name: ${JSON.stringify(t)}.`
108
552
  );
109
553
  }
110
- function O(t, e) {
554
+ function J(t, e, r) {
111
555
  return new Request(`${t}${e}`, {
112
- headers: { accept: "text/html" }
556
+ headers: { accept: r === "document" ? "text/html" : "*/*" }
113
557
  });
114
558
  }
115
- async function E(t, e, i) {
116
- if (e.status !== i)
559
+ async function L(t, e, r) {
560
+ if (e.status !== r)
117
561
  throw new Error(
118
- `Static output for ${JSON.stringify(t.pathname)} returned status ${e.status}; expected ${i}.`
562
+ `Static output for ${JSON.stringify(t.pathname)} returned status ${e.status}; expected ${r}.`
119
563
  );
120
- const r = e.headers.get("content-type");
121
- if (!r?.toLowerCase().startsWith("text/html"))
564
+ const n = e.headers.get("content-type");
565
+ if (!n?.toLowerCase().startsWith("text/html"))
122
566
  throw new Error(
123
- `Static output for ${JSON.stringify(t.pathname)} returned ${JSON.stringify(r)} instead of text/html.`
567
+ `Static output for ${JSON.stringify(t.pathname)} returned ${JSON.stringify(n)} instead of text/html.`
124
568
  );
125
569
  if (e.headers.has("set-cookie"))
126
570
  throw new Error(
127
571
  `Static output for ${JSON.stringify(t.pathname)} attempted to set a cookie. Build artifacts cannot contain per-user response state.`
128
572
  );
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
573
+ const i = await zt(
574
+ await e.text(),
575
+ e.headers
576
+ );
577
+ return await Zt(t.pathname, i, e.headers), {
578
+ file: t.file,
579
+ headers: Z(e.headers),
580
+ body: i,
581
+ pathname: t.pathname,
582
+ status: r
135
583
  };
136
584
  }
137
- async function B(t, e, i) {
138
- const r = i.get("content-security-policy");
139
- if (!r)
585
+ async function Gt(t, e) {
586
+ if (e.status !== 200)
587
+ throw new Error(
588
+ `Static output for ${JSON.stringify(t.pathname)} returned status ${e.status}; expected 200.`
589
+ );
590
+ if (e.headers.has("set-cookie"))
591
+ throw new Error(
592
+ `Static output for ${JSON.stringify(t.pathname)} attempted to set a cookie. Build artifacts cannot contain per-user response state.`
593
+ );
594
+ return {
595
+ file: t.file,
596
+ headers: Z(e.headers),
597
+ body: await e.text(),
598
+ pathname: t.pathname,
599
+ status: 200
600
+ };
601
+ }
602
+ async function zt(t, e) {
603
+ const r = new RegExp(
604
+ `(?:^|\\s)${F}(?:\\s|$)`
605
+ ), n = K(t, "script").filter((a) => r.test(a.attributes));
606
+ if (n.length === 0)
607
+ return t;
608
+ const i = await Promise.all(
609
+ n.map((a) => D(a.content))
610
+ );
611
+ for (const a of [
612
+ "content-security-policy",
613
+ "content-security-policy-report-only"
614
+ ]) {
615
+ const c = e.get(a);
616
+ c && e.set(a, Kt(c, i));
617
+ }
618
+ return t.replace(
619
+ new RegExp(`\\s${F}(?=\\s|>)`, "g"),
620
+ ""
621
+ );
622
+ }
623
+ function Kt(t, e) {
624
+ const r = t.split(";").map((s) => s.trim()).filter(Boolean), n = r.findIndex(
625
+ (s) => s.split(/\s+/, 1)[0]?.toLowerCase() === "script-src"
626
+ ), i = r.find(
627
+ (s) => s.split(/\s+/, 1)[0]?.toLowerCase() === "default-src"
628
+ ), a = n === -1 ? i : r[n];
629
+ if (!a)
630
+ return t;
631
+ const c = a.split(/\s+/).slice(1).filter((s) => s !== "'none'"), o = [
632
+ "script-src",
633
+ .../* @__PURE__ */ new Set([...c, ...e])
634
+ ].join(" ");
635
+ return n === -1 ? r.push(o) : r[n] = o, r.join("; ");
636
+ }
637
+ async function Zt(t, e, r) {
638
+ const n = r.get("content-security-policy");
639
+ if (!n)
140
640
  return;
141
- if (/'nonce-[^']+'/i.test(r) || /\snonce\s*=/i.test(e))
641
+ if (/'nonce-[^']+'/i.test(n) || /\snonce\s*=/i.test(e))
142
642
  throw new Error(
143
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.`
144
644
  );
145
- const n = z(r);
146
- await $(
645
+ const i = Qt(n);
646
+ await M(
147
647
  t,
148
648
  e,
149
649
  "script",
150
- h(n, "script-src")
151
- ), await $(
650
+ x(i, "script-src", "default-src")
651
+ ), await M(
152
652
  t,
153
653
  e,
154
654
  "style",
155
- h(n, "style-src")
655
+ x(
656
+ i,
657
+ "style-src-elem",
658
+ "style-src",
659
+ "default-src"
660
+ )
661
+ );
662
+ const a = x(
663
+ i,
664
+ "style-src-attr",
665
+ "style-src",
666
+ "default-src"
156
667
  );
157
- const s = h(n, "style-src");
158
- if (/\sstyle\s*=/i.test(e) && !s.includes("'unsafe-inline'"))
668
+ if (a && /\sstyle\s*=/i.test(e) && !a.includes("'unsafe-inline'"))
159
669
  throw new Error(
160
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.`
161
671
  );
162
672
  }
163
- function z(t) {
673
+ function Qt(t) {
164
674
  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);
675
+ for (const r of t.split(";")) {
676
+ const [n, ...i] = r.trim().split(/\s+/);
677
+ n && e.set(n.toLowerCase(), i);
168
678
  }
169
679
  return e;
170
680
  }
171
- function h(t, e) {
172
- 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
+ }
173
687
  }
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)
688
+ async function M(t, e, r, n) {
689
+ if (!(!n || n.includes("'unsafe-inline'")))
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)
178
702
  continue;
179
- const s = await W(n.content);
180
- if (!r.includes(s))
703
+ const a = await D(i.content);
704
+ if (!n.includes(a))
181
705
  throw new Error(
182
- `Static output for ${JSON.stringify(t)} contains an inline ${i} without the required CSP hash ${s}.`
706
+ `Static output for ${JSON.stringify(t)} contains an inline ${r} without the required CSP hash ${a}.`
183
707
  );
184
708
  }
185
709
  }
186
- function D(t, e) {
187
- const i = t.toLowerCase(), r = [], n = `<${e}`, s = `</${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}`;
188
745
  let c = 0;
189
746
  for (; c < t.length; ) {
190
- const o = i.indexOf(n, c);
747
+ const o = r.indexOf(i, c);
191
748
  if (o === -1)
192
749
  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)
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)
195
752
  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;
753
+ n.push({
754
+ attributes: t.slice(o + i.length, s),
755
+ content: t.slice(s + 1, f)
756
+ }), c = l + 1;
200
757
  }
201
- return r;
758
+ return n;
202
759
  }
203
- function G(t) {
760
+ function Z(t) {
204
761
  return Object.fromEntries(
205
- [...t.entries()].sort(([e], [i]) => e.localeCompare(i))
762
+ [...t.entries()].sort(([e], [r]) => e.localeCompare(r))
206
763
  );
207
764
  }
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-"));
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-"));
212
769
  try {
213
770
  for (const o of e) {
214
- const a = v(n, o.file);
215
- await d(g(a), { recursive: !0 }), await m(a, o.html);
771
+ const s = I(i, o.file);
772
+ await E(N(s), { recursive: !0 }), await A(s, o.body);
216
773
  }
217
- await m(
218
- S(n, N),
219
- `${JSON.stringify(i, null, 2)}
774
+ await A(
775
+ m(i, G),
776
+ `${JSON.stringify(r, null, 2)}
220
777
  `
221
778
  );
222
- const s = await Q(t);
223
- await d(t, { recursive: !0 }), await C(n, t, { recursive: !0, force: !0 });
779
+ const a = await ee(t);
780
+ await E(t, { recursive: !0 }), await k(i, t, { recursive: !0, force: !0 });
224
781
  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 });
782
+ for (const o of a)
783
+ c.has(o) || await $(I(t, o), { force: !0 });
227
784
  } finally {
228
- await y(n, { force: !0, recursive: !0 });
785
+ await $(i, { force: !0, recursive: !0 });
229
786
  }
230
787
  }
231
- async function Q(t) {
788
+ async function ee(t) {
232
789
  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] : []
790
+ const e = await v(m(t, G), "utf8"), r = JSON.parse(e);
791
+ return r.adapter !== "static" || r.version !== 1 || !Array.isArray(r.entries) ? [] : r.entries.flatMap(
792
+ (n) => typeof n.file == "string" && Q(n.file) ? [n.file] : []
236
793
  );
237
794
  } catch {
238
795
  return [];
239
796
  }
240
797
  }
241
- function v(t, e) {
242
- if (!J(e))
798
+ function I(t, e) {
799
+ if (!Q(e))
243
800
  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(".."))
801
+ const r = h(t), n = h(r, e);
802
+ if (w(r, n).split(g).includes(".."))
246
803
  throw new Error(`Static output file escaped the output directory: ${JSON.stringify(e)}.`);
247
- return r;
804
+ return n;
248
805
  }
249
- function J(t) {
806
+ function Q(t) {
250
807
  return !!t && !t.startsWith("/") && !t.startsWith("\\") && !t.split(/[\\/]/).includes("..");
251
808
  }
252
809
  export {
253
- nt as generateStaticOutput,
254
- it 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
255
816
  };
256
817
  //# sourceMappingURL=index.js.map