@demiurgejs/core 0.2.0-beta.4 → 0.2.0-beta.6

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 (161) hide show
  1. package/README.md +37 -0
  2. package/bin/demiurge.mjs +23 -1
  3. package/dist/adapter/index.d.ts +1 -1
  4. package/dist/adapter/index.d.ts.map +1 -1
  5. package/dist/browser/file-router.d.ts +1 -1
  6. package/dist/chunks/{document-shell-CpJnFtSC.js → document-shell-C0aPrkhd.js} +2 -2
  7. package/dist/chunks/{document-shell-CpJnFtSC.js.map → document-shell-C0aPrkhd.js.map} +1 -1
  8. package/dist/chunks/image-CRerJ5BY.js +145 -0
  9. package/dist/chunks/image-CRerJ5BY.js.map +1 -0
  10. package/dist/chunks/{image-codec-BmzWnH6W.js → image-codec-CQ8Cwxwb.js} +2 -2
  11. package/dist/chunks/{image-codec-BmzWnH6W.js.map → image-codec-CQ8Cwxwb.js.map} +1 -1
  12. package/dist/chunks/{images-BQ80950B.js → images-QgdmLyQ3.js} +11 -11
  13. package/dist/chunks/{images-BQ80950B.js.map → images-QgdmLyQ3.js.map} +1 -1
  14. package/dist/chunks/{index-BVk9zWbe.js → index-LYve1rQp.js} +287 -351
  15. package/dist/chunks/index-LYve1rQp.js.map +1 -0
  16. package/dist/chunks/links-iU22QkCE.js +68 -0
  17. package/dist/chunks/links-iU22QkCE.js.map +1 -0
  18. package/dist/chunks/plugin-bkP6WwrS.js +2311 -0
  19. package/dist/chunks/plugin-bkP6WwrS.js.map +1 -0
  20. package/dist/chunks/runtime-BH519j2t.js +294 -0
  21. package/dist/chunks/runtime-BH519j2t.js.map +1 -0
  22. package/dist/chunks/streaming-BlKlC3nw.js +427 -0
  23. package/dist/chunks/streaming-BlKlC3nw.js.map +1 -0
  24. package/dist/chunks/{testing-DueXbMo4.js → testing-BEW1nchS.js} +2161 -1562
  25. package/dist/chunks/testing-BEW1nchS.js.map +1 -0
  26. package/dist/chunks/{vite-DO70kZA6.js → vite-BADZA8Fl.js} +90 -87
  27. package/dist/chunks/vite-BADZA8Fl.js.map +1 -0
  28. package/dist/cli.d.ts +10 -2
  29. package/dist/cli.d.ts.map +1 -1
  30. package/dist/cli.js +277 -87
  31. package/dist/cli.js.map +1 -1
  32. package/dist/config/index.js +2 -2
  33. package/dist/config/types.d.ts +14 -2
  34. package/dist/config/types.d.ts.map +1 -1
  35. package/dist/config/validate.d.ts.map +1 -1
  36. package/dist/data/cache.d.ts +5 -0
  37. package/dist/data/cache.d.ts.map +1 -1
  38. package/dist/data/index.d.ts +1 -1
  39. package/dist/data/index.d.ts.map +1 -1
  40. package/dist/data/testing.d.ts.map +1 -1
  41. package/dist/data/testing.js +101 -67
  42. package/dist/data/testing.js.map +1 -1
  43. package/dist/data/tiered.d.ts.map +1 -1
  44. package/dist/edge/index.js +27 -26
  45. package/dist/edge/index.js.map +1 -1
  46. package/dist/edge/stores.d.ts.map +1 -1
  47. package/dist/index.d.ts +4 -4
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +158 -135
  50. package/dist/index.js.map +1 -1
  51. package/dist/inspect/command.d.ts +28 -0
  52. package/dist/inspect/command.d.ts.map +1 -0
  53. package/dist/inspect/index.d.ts +9 -0
  54. package/dist/inspect/index.d.ts.map +1 -0
  55. package/dist/inspect/redact.d.ts +35 -0
  56. package/dist/inspect/redact.d.ts.map +1 -0
  57. package/dist/inspect/report.d.ts +24 -0
  58. package/dist/inspect/report.d.ts.map +1 -0
  59. package/dist/inspect/types.d.ts +102 -0
  60. package/dist/inspect/types.d.ts.map +1 -0
  61. package/dist/internal/testing.js +12 -12
  62. package/dist/kv/index.js +7 -6
  63. package/dist/kv/index.js.map +1 -1
  64. package/dist/kv/store.d.ts.map +1 -1
  65. package/dist/node/http.d.ts +7 -0
  66. package/dist/node/http.d.ts.map +1 -1
  67. package/dist/node/index.d.ts +2 -2
  68. package/dist/node/index.d.ts.map +1 -1
  69. package/dist/node/index.js +31 -28
  70. package/dist/node/index.js.map +1 -1
  71. package/dist/node/serve.d.ts +4 -0
  72. package/dist/node/serve.d.ts.map +1 -1
  73. package/dist/redis/index.js +29 -28
  74. package/dist/redis/index.js.map +1 -1
  75. package/dist/redis/store.d.ts.map +1 -1
  76. package/dist/route/index.d.ts +1 -0
  77. package/dist/route/index.d.ts.map +1 -1
  78. package/dist/route/mutation.d.ts.map +1 -1
  79. package/dist/route/serialization.d.ts +24 -0
  80. package/dist/route/serialization.d.ts.map +1 -0
  81. package/dist/route/webhook.d.ts +6 -1
  82. package/dist/route/webhook.d.ts.map +1 -1
  83. package/dist/router/manifest.d.ts.map +1 -1
  84. package/dist/security/audit.d.ts +2 -1
  85. package/dist/security/audit.d.ts.map +1 -1
  86. package/dist/security/authorization.d.ts +36 -0
  87. package/dist/security/authorization.d.ts.map +1 -0
  88. package/dist/security/csrf.d.ts.map +1 -1
  89. package/dist/security/env-startup.d.ts +0 -2
  90. package/dist/security/env-startup.d.ts.map +1 -1
  91. package/dist/security/env.d.ts +27 -8
  92. package/dist/security/env.d.ts.map +1 -1
  93. package/dist/security/exceptions.d.ts +29 -0
  94. package/dist/security/exceptions.d.ts.map +1 -0
  95. package/dist/security/finding-codes.d.ts +56 -0
  96. package/dist/security/finding-codes.d.ts.map +1 -0
  97. package/dist/security/index.d.ts +5 -2
  98. package/dist/security/index.d.ts.map +1 -1
  99. package/dist/security/policy.d.ts +2 -5
  100. package/dist/security/policy.d.ts.map +1 -1
  101. package/dist/security/report.d.ts +2 -1
  102. package/dist/security/report.d.ts.map +1 -1
  103. package/dist/security/request.d.ts +1 -0
  104. package/dist/security/request.d.ts.map +1 -1
  105. package/dist/security/types.d.ts +138 -5
  106. package/dist/security/types.d.ts.map +1 -1
  107. package/dist/security/upload.d.ts +3 -3
  108. package/dist/security/upload.d.ts.map +1 -1
  109. package/dist/security/verification.d.ts.map +1 -1
  110. package/dist/server/request-handler.d.ts +3 -2
  111. package/dist/server/request-handler.d.ts.map +1 -1
  112. package/dist/server-only/browser.d.ts +2 -0
  113. package/dist/server-only/browser.d.ts.map +1 -0
  114. package/dist/server-only/browser.js +4 -0
  115. package/dist/server-only/browser.js.map +1 -0
  116. package/dist/server-only/index.d.ts +2 -0
  117. package/dist/server-only/index.d.ts.map +1 -0
  118. package/dist/server-only/index.js +2 -0
  119. package/dist/server-only/index.js.map +1 -0
  120. package/dist/static/index.d.ts.map +1 -1
  121. package/dist/static/index.js +255 -255
  122. package/dist/static/index.js.map +1 -1
  123. package/dist/static/testing.d.ts +26 -0
  124. package/dist/static/testing.d.ts.map +1 -0
  125. package/dist/static/testing.js +76 -0
  126. package/dist/static/testing.js.map +1 -0
  127. package/dist/testing/index.d.ts +47 -0
  128. package/dist/testing/index.d.ts.map +1 -0
  129. package/dist/testing/index.js +99 -0
  130. package/dist/testing/index.js.map +1 -0
  131. package/dist/vercel/build.d.ts +31 -0
  132. package/dist/vercel/build.d.ts.map +1 -0
  133. package/dist/vercel/config.d.ts +15 -0
  134. package/dist/vercel/config.d.ts.map +1 -0
  135. package/dist/vercel/index.d.ts +7 -0
  136. package/dist/vercel/index.d.ts.map +1 -0
  137. package/dist/vercel/index.js +11 -0
  138. package/dist/vercel/index.js.map +1 -0
  139. package/dist/vercel/runtime.d.ts +29 -0
  140. package/dist/vercel/runtime.d.ts.map +1 -0
  141. package/dist/vite/index.d.ts +9 -4
  142. package/dist/vite/index.d.ts.map +1 -1
  143. package/dist/vite/index.js +28 -21
  144. package/dist/vite/plugin.d.ts +18 -2
  145. package/dist/vite/plugin.d.ts.map +1 -1
  146. package/dist/vite/policy-verification.d.ts +33 -2
  147. package/dist/vite/policy-verification.d.ts.map +1 -1
  148. package/dist/vite/route-audit.d.ts +14 -2
  149. package/dist/vite/route-audit.d.ts.map +1 -1
  150. package/dist/vite/server-only-boundary.d.ts +8 -0
  151. package/dist/vite/server-only-boundary.d.ts.map +1 -0
  152. package/package.json +18 -1
  153. package/dist/chunks/env-startup-DOBYWlZD.js +0 -257
  154. package/dist/chunks/env-startup-DOBYWlZD.js.map +0 -1
  155. package/dist/chunks/index-BVk9zWbe.js.map +0 -1
  156. package/dist/chunks/plugin-BQgMiHxa.js +0 -1827
  157. package/dist/chunks/plugin-BQgMiHxa.js.map +0 -1
  158. package/dist/chunks/streaming-BEbPN7Uk.js +0 -469
  159. package/dist/chunks/streaming-BEbPN7Uk.js.map +0 -1
  160. package/dist/chunks/testing-DueXbMo4.js.map +0 -1
  161. package/dist/chunks/vite-DO70kZA6.js.map +0 -1
@@ -1,14 +1,15 @@
1
1
  import { createServer as H } from "node:http";
2
- import { d as I } from "../chunks/index-BVk9zWbe.js";
3
- import { r as C, v as L, t as x, U as A, w as F, a as M, b as k } from "../chunks/streaming-BEbPN7Uk.js";
4
- import { c as _e, d as je, e as Be, f as ze } from "../chunks/streaming-BEbPN7Uk.js";
2
+ import { d as C } from "../chunks/index-LYve1rQp.js";
3
+ import { r as I, v as x, t as L, U as A, w as F, a as M, b as k } from "../chunks/streaming-BlKlC3nw.js";
4
+ import { C as _e, c as je, d as Be } from "../chunks/streaming-BlKlC3nw.js";
5
5
  import { constants as S } from "node:fs";
6
6
  import { realpath as T, open as W, lstat as D, readFile as $ } from "node:fs/promises";
7
7
  import { resolve as P, sep as y, extname as U, relative as _, join as O } from "node:path";
8
- import { Readable as N } from "node:stream";
9
- import { I as j, R as B, i as z, c as G } from "../chunks/static-files-ehaD1kE7.js";
10
- import { fileURLToPath as V } from "node:url";
11
- import { p as q } from "../chunks/manifest-vO6c0G0W.js";
8
+ import { Readable as E } from "node:stream";
9
+ import { I as j, R as B, i as z, c as q } from "../chunks/static-files-ehaD1kE7.js";
10
+ import { c as qe, a as Ge } from "../chunks/image-CRerJ5BY.js";
11
+ import { fileURLToPath as G } from "node:url";
12
+ import { p as V } from "../chunks/manifest-vO6c0G0W.js";
12
13
  const Y = /* @__PURE__ */ new Set(["demiurge-manifest.json", "index.html"]);
13
14
  function J(e) {
14
15
  const t = P(e.root), n = T(t), r = ae(e.prefix), o = e.exclude ?? se, a = e.immutable ?? ie;
@@ -43,14 +44,14 @@ function J(e) {
43
44
  if (u) {
44
45
  const w = u.end - u.start + 1;
45
46
  return l.set("content-length", String(w)), l.set("content-range", `bytes ${u.start}-${u.end}/${i.size}`), c.method === "HEAD" ? (await h.close(), new Response(null, { headers: l, status: 206 })) : new Response(
46
- N.toWeb(
47
+ E.toWeb(
47
48
  h.createReadStream({ end: u.end, start: u.start })
48
49
  ),
49
50
  { headers: l, status: 206 }
50
51
  );
51
52
  }
52
53
  return c.method === "HEAD" ? (await h.close(), new Response(null, { headers: l })) : new Response(
53
- N.toWeb(h.createReadStream()),
54
+ E.toWeb(h.createReadStream()),
54
55
  { headers: l }
55
56
  );
56
57
  };
@@ -62,7 +63,7 @@ function Q(e, t, n) {
62
63
  const r = e.headers.get("if-none-match");
63
64
  if (r !== null)
64
65
  return r.trim() === "*" || r.split(",").some(
65
- (d) => E(d) === E(t)
66
+ (d) => N(d) === N(t)
66
67
  );
67
68
  const o = e.headers.get("if-modified-since");
68
69
  if (o === null)
@@ -70,7 +71,7 @@ function Q(e, t, n) {
70
71
  const a = Date.parse(o);
71
72
  return Number.isFinite(a) && Math.floor(n / 1e3) * 1e3 <= a;
72
73
  }
73
- function E(e) {
74
+ function N(e) {
74
75
  return e.trim().replace(/^W\//i, "");
75
76
  }
76
77
  function X(e, t) {
@@ -179,13 +180,13 @@ function le(e) {
179
180
  return e.slice(e.lastIndexOf(y) + 1);
180
181
  }
181
182
  function ue(e) {
182
- return G(U(e));
183
+ return q(U(e));
183
184
  }
184
185
  const de = "dist/client", fe = "/.well-known/ready";
185
186
  async function We(e) {
186
- const t = e.env ?? process.env, n = V(
187
+ const t = e.env ?? process.env, n = G(
187
188
  new URL(e.clientDir ?? de, e.base)
188
- ), r = q(
189
+ ), r = V(
189
190
  await $(O(n, "demiurge-manifest.json"), "utf8")
190
191
  ), o = e.host ?? t.HOST ?? "127.0.0.1", a = me(t.PORT, e.port), d = he(
191
192
  e.allowedHosts,
@@ -194,7 +195,7 @@ async function We(e) {
194
195
  ), c = e.name ?? "Demiurge Node server", m = e.readyPath === !1 ? void 0 : e.readyPath ?? fe, g = [], h = {
195
196
  page: {
196
197
  clientEntry: r.clientEntry,
197
- renderPage: C,
198
+ renderPage: I,
198
199
  styles: r.styles
199
200
  },
200
201
  root: n,
@@ -245,12 +246,13 @@ function ge(e, t) {
245
246
  );
246
247
  return n;
247
248
  }
248
- const De = I({
249
+ const De = C({
249
250
  name: "node",
250
251
  capabilities: {
251
252
  backgroundLifetime: !0,
252
253
  crossOriginIsolationHeaders: !0,
253
254
  nonceInjection: !0,
255
+ requestTimeoutEnforcement: !0,
254
256
  streaming: !0
255
257
  }
256
258
  }), we = {
@@ -259,7 +261,7 @@ const De = I({
259
261
  requestTimeout: 3e5
260
262
  }, ye = 3e4;
261
263
  function pe(e) {
262
- L(e);
264
+ x(e);
263
265
  const t = Pe(e.static), n = e.onError ?? p;
264
266
  return function(a, d) {
265
267
  const c = be(a, d);
@@ -270,7 +272,7 @@ function pe(e) {
270
272
  async function r(o, a, d) {
271
273
  let c;
272
274
  try {
273
- c = x(o, {
275
+ c = L(o, {
274
276
  allowedHosts: e.allowedHosts,
275
277
  signal: d,
276
278
  trustProxy: e.trustProxy
@@ -310,7 +312,7 @@ function Re(e) {
310
312
  e.statusCode = 421, e.setHeader("content-type", "text/plain; charset=utf-8"), e.end("Misdirected Request");
311
313
  }
312
314
  function Se(e) {
313
- const t = Ee(e.timeouts), n = Ne(e.readyPath), r = n ? async (a) => {
315
+ const t = Ne(e.timeouts), n = Ee(e.readyPath), r = n ? async (a) => {
314
316
  if (new URL(a.url).pathname !== n)
315
317
  return e.handler(a);
316
318
  const d = o.isReady();
@@ -326,7 +328,7 @@ function Se(e) {
326
328
  );
327
329
  return o.keepAliveTimeout = t.keepAliveTimeout, o.headersTimeout = t.headersTimeout, o.requestTimeout = t.requestTimeout, Te(o, e.shutdown);
328
330
  }
329
- function Ne(e) {
331
+ function Ee(e) {
330
332
  if (e !== void 0) {
331
333
  if (!e.startsWith("/") || e.includes("?"))
332
334
  throw new Error(
@@ -335,7 +337,7 @@ function Ne(e) {
335
337
  return e;
336
338
  }
337
339
  }
338
- function Ee(e) {
340
+ function Ne(e) {
339
341
  const t = {
340
342
  ...we,
341
343
  ...e
@@ -439,10 +441,11 @@ function Oe(e) {
439
441
  e.statusCode = 500, e.setHeader("content-type", "text/plain; charset=utf-8"), e.end("Internal Server Error");
440
442
  }
441
443
  export {
444
+ _e as ConsumedRequestBodyError,
442
445
  A as UnsupportedMethodError,
443
446
  M as UntrustedHostError,
444
- _e as createFontAssetHandler,
445
- je as createImageOptimizer,
447
+ qe as createFontAssetHandler,
448
+ Ge as createImageOptimizer,
446
449
  pe as createNodeRequestListener,
447
450
  Se as createNodeServer,
448
451
  J as createStaticFileHandler,
@@ -450,12 +453,12 @@ export {
450
453
  fe as defaultNodeBuildReadyPath,
451
454
  we as defaultNodeServerTimeouts,
452
455
  De as nodeAdapter,
453
- C as renderNodePageResponse,
454
- Be as renderStreamingPageResponse,
456
+ I as renderNodePageResponse,
457
+ je as renderStreamingPageResponse,
455
458
  We as serveNodeBuild,
456
- ze as toHeaders,
457
- x as toWebRequest,
458
- L as validateNodeOriginPolicy,
459
+ Be as toHeaders,
460
+ L as toWebRequest,
461
+ x as validateNodeOriginPolicy,
459
462
  k as writeWebResponse
460
463
  };
461
464
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/node/static.ts","../../src/node/serve.ts","../../src/node/index.ts"],"sourcesContent":["import { constants } from \"node:fs\";\nimport { lstat, open, realpath } from \"node:fs/promises\";\nimport { extname, join, relative, resolve, sep } from \"node:path\";\nimport { Readable } from \"node:stream\";\nimport {\n contentTypeForExtension,\n IMMUTABLE_FILE_CACHE_CONTROL,\n isContentHashedFileName,\n REVALIDATED_FILE_CACHE_CONTROL,\n} from \"../static-files\";\n\nexport type StaticFileHandler = (request: Request) => Promise<Response | null>;\n\nexport type StaticFileHandlerOptions = {\n // Receives the file's path relative to `root`, always \"/\"-separated, so a\n // predicate can distinguish `index.html` from `docs/index.html`.\n exclude?: (path: string) => boolean;\n immutable?: (fileName: string) => boolean;\n prefix?: string;\n root: string;\n};\n\n// A null result keeps the handler composable. It means that the request does not\n// identify an owned file. The route pipeline owns all other responses, including\n// the 404 body and security headers. A traversal attempt gives the same result.\n// Plain static requests must not access the framework build output. The output\n// includes the SPA shell and the Node configuration manifest. The route pipeline\n// serves the shell and applies the `@policy.ts` headers. The server never serves\n// `demiurge-manifest.json` publicly. This exclusion applies only to the two root\n// files. An application can serve a nested file such as `docs/index.html`.\nconst defaultExcludedPaths = new Set([\"demiurge-manifest.json\", \"index.html\"]);\n\nexport function createStaticFileHandler(\n options: StaticFileHandlerOptions,\n): StaticFileHandler {\n const root = resolve(options.root);\n const realRoot = realpath(root);\n const prefix = normalizePrefix(options.prefix);\n const isExcluded = options.exclude ?? defaultExcluded;\n const isImmutable = options.immutable ?? defaultImmutable;\n\n return async function handleStaticFile(request) {\n if (request.method !== \"GET\" && request.method !== \"HEAD\") {\n return null;\n }\n\n const filePath = resolveFilePath(\n root,\n prefix,\n new URL(request.url).pathname,\n );\n\n if (!filePath || isExcluded(toRelativePath(root, filePath))) {\n return null;\n }\n\n const opened = await openStaticFile(root, await safeRealRoot(realRoot), filePath);\n\n if (!opened) {\n return null;\n }\n\n const { file, stats } = opened;\n\n const etag = createWeakEtag(stats.size, stats.mtimeMs);\n const lastModified = stats.mtime.toUTCString();\n const headers = new Headers({\n \"accept-ranges\": \"bytes\",\n \"cache-control\": isImmutable(fileNameOf(filePath))\n ? IMMUTABLE_FILE_CACHE_CONTROL\n : REVALIDATED_FILE_CACHE_CONTROL,\n \"content-length\": String(stats.size),\n \"content-type\": contentTypeOf(filePath),\n \"cross-origin-resource-policy\": \"same-origin\",\n etag,\n \"last-modified\": lastModified,\n \"x-content-type-options\": \"nosniff\",\n });\n\n if (isNotModified(request, etag, stats.mtimeMs)) {\n await file.close();\n headers.delete(\"content-length\");\n headers.delete(\"content-type\");\n\n return new Response(null, { headers, status: 304 });\n }\n\n const range = canApplyRange(request, stats.mtimeMs)\n ? parseRange(request.headers.get(\"range\"), stats.size)\n : null;\n\n if (range === \"unsatisfiable\") {\n await file.close();\n headers.delete(\"content-length\");\n headers.delete(\"content-type\");\n headers.set(\"content-range\", `bytes */${stats.size}`);\n\n return new Response(null, { headers, status: 416 });\n }\n\n if (range) {\n const contentLength = range.end - range.start + 1;\n headers.set(\"content-length\", String(contentLength));\n headers.set(\"content-range\", `bytes ${range.start}-${range.end}/${stats.size}`);\n\n if (request.method === \"HEAD\") {\n await file.close();\n return new Response(null, { headers, status: 206 });\n }\n\n // TYPE-EVIDENCE: Readable.toWeb returns a web stream that matches the DOM ReadableStream body type.\n return new Response(\n Readable.toWeb(\n file.createReadStream({ end: range.end, start: range.start }),\n ) as ReadableStream,\n { headers, status: 206 },\n );\n }\n\n if (request.method === \"HEAD\") {\n await file.close();\n return new Response(null, { headers });\n }\n\n // TYPE-EVIDENCE: Readable.toWeb returns a web stream that matches the DOM ReadableStream body type.\n return new Response(\n Readable.toWeb(file.createReadStream()) as ReadableStream,\n { headers },\n );\n };\n}\n\nfunction createWeakEtag(size: number, mtimeMs: number) {\n return `W/\"${size.toString(16)}-${Math.trunc(mtimeMs).toString(16)}\"`;\n}\n\nfunction isNotModified(request: Request, etag: string, mtimeMs: number) {\n const ifNoneMatch = request.headers.get(\"if-none-match\");\n\n // If-None-Match takes precedence over If-Modified-Since. Weak comparison is\n // correct for GET/HEAD cache validation, so W/ is removed from both sides.\n if (ifNoneMatch !== null) {\n return ifNoneMatch.trim() === \"*\" || ifNoneMatch.split(\",\").some(\n (candidate) => weakEtagValue(candidate) === weakEtagValue(etag),\n );\n }\n\n const ifModifiedSince = request.headers.get(\"if-modified-since\");\n\n if (ifModifiedSince === null) {\n return false;\n }\n\n const since = Date.parse(ifModifiedSince);\n\n // HTTP dates have one-second precision. Compare the file timestamp at the\n // same precision rather than making a freshly-written file look newer.\n return Number.isFinite(since) && Math.floor(mtimeMs / 1000) * 1000 <= since;\n}\n\nfunction weakEtagValue(value: string) {\n return value.trim().replace(/^W\\//i, \"\");\n}\n\ntype ByteRange = { end: number; start: number };\n\nfunction parseRange(\n header: string | null,\n size: number,\n): ByteRange | \"unsatisfiable\" | null {\n if (header === null) {\n return null;\n }\n\n const match = /^bytes=(\\d*)-(\\d*)$/.exec(header.trim());\n\n // A server that does not support the requested unit, syntax, or multiple\n // ranges ignores Range and returns the complete representation. A 416 is\n // reserved for a valid byte-range set that cannot select this resource.\n if (!match || (!match[1] && !match[2])) {\n return null;\n }\n\n if (size === 0) {\n return \"unsatisfiable\";\n }\n\n if (!match[1]) {\n const suffixLength = Number(match[2]);\n\n if (!Number.isSafeInteger(suffixLength) || suffixLength <= 0) {\n return null;\n }\n\n return { start: Math.max(0, size - suffixLength), end: size - 1 };\n }\n\n const start = Number(match[1]);\n const requestedEnd = match[2] ? Number(match[2]) : size - 1;\n\n if (!Number.isSafeInteger(start) || !Number.isSafeInteger(requestedEnd)) {\n return null;\n }\n\n if (start >= size) {\n return \"unsatisfiable\";\n }\n\n if (match[2] && requestedEnd < start) {\n return null;\n }\n\n return { start, end: Math.min(requestedEnd, size - 1) };\n}\n\nfunction canApplyRange(request: Request, mtimeMs: number) {\n const ifRange = request.headers.get(\"if-range\");\n\n if (ifRange === null) {\n return true;\n }\n\n // If-Range requires strong comparison for an entity-tag. This handler's\n // stat-derived validator is intentionally weak, so only an HTTP date can\n // authorize a partial response.\n if (ifRange.trim().startsWith('\"') || /^W\\//i.test(ifRange.trim())) {\n return false;\n }\n\n const date = Date.parse(ifRange);\n return Number.isFinite(date) && Math.floor(mtimeMs / 1000) * 1000 <= date;\n}\n\nfunction resolveFilePath(root: string, prefix: string, pathname: string) {\n let decoded: string;\n\n try {\n decoded = decodeURIComponent(pathname);\n } catch {\n return null;\n }\n\n // A null byte truncates the path for some system calls. A name such as\n // \"app.js\\0.txt\" could read a file that differs from the checked file.\n if (decoded.includes(\"\\0\")) {\n return null;\n }\n\n if (prefix) {\n if (!decoded.startsWith(prefix)) {\n return null;\n }\n\n decoded = decoded.slice(prefix.length - 1);\n }\n\n if (decoded.endsWith(\"/\")) {\n return null;\n }\n\n const candidate = resolve(root, `.${decoded}`);\n\n return candidate.startsWith(`${root}${sep}`) ? candidate : null;\n}\n\nasync function safeRealRoot(root: Promise<string>) {\n try {\n return await root;\n } catch {\n return null;\n }\n}\n\nasync function openStaticFile(\n root: string,\n realRoot: string | null,\n filePath: string,\n) {\n if (!realRoot || !(await hasNoSymlinkComponents(root, filePath))) {\n return null;\n }\n\n let resolvedTarget: string;\n\n try {\n resolvedTarget = await realpath(filePath);\n } catch {\n return null;\n }\n\n if (!isPathInside(realRoot, resolvedTarget)) {\n return null;\n }\n\n const noFollow =\n typeof constants.O_NOFOLLOW === \"number\" ? constants.O_NOFOLLOW : 0;\n let file: Awaited<ReturnType<typeof open>>;\n\n try {\n // O_NOFOLLOW closes the final-component race on platforms that expose it.\n // The component walk and realpath containment check cover directory links.\n file = await open(filePath, constants.O_RDONLY | noFollow);\n } catch {\n return null;\n }\n\n try {\n const stats = await file.stat();\n\n if (!stats.isFile()) {\n await file.close();\n return null;\n }\n\n return { file, stats };\n } catch {\n await file.close();\n return null;\n }\n}\n\nasync function hasNoSymlinkComponents(root: string, filePath: string) {\n const parts = relative(root, filePath).split(sep);\n let current = root;\n\n try {\n for (const part of parts) {\n current = join(current, part);\n\n if ((await lstat(current)).isSymbolicLink()) {\n return false;\n }\n }\n } catch {\n return false;\n }\n\n return true;\n}\n\nfunction isPathInside(root: string, candidate: string) {\n return candidate.startsWith(`${root}${sep}`);\n}\n\nfunction normalizePrefix(prefix: string | undefined) {\n if (!prefix || prefix === \"/\") {\n return \"\";\n }\n\n return `/${prefix.replace(/^\\/|\\/$/g, \"\")}/`;\n}\n\nfunction defaultImmutable(fileName: string) {\n return isContentHashedFileName(fileName);\n}\n\nfunction defaultExcluded(path: string) {\n return defaultExcludedPaths.has(path);\n}\n\nfunction toRelativePath(root: string, filePath: string) {\n return filePath.slice(root.length + 1).split(sep).join(\"/\");\n}\n\nfunction fileNameOf(filePath: string) {\n return filePath.slice(filePath.lastIndexOf(sep) + 1);\n}\n\nfunction contentTypeOf(filePath: string) {\n return contentTypeForExtension(extname(filePath));\n}\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { parseClientManifest } from \"../manifest\";\nimport type { PageRenderer, RequestHandler } from \"../server\";\nimport {\n createNodeServer,\n type NodeGracefulShutdownOptions,\n type NodeRequestListenerOptions,\n type NodeServer,\n type NodeServerTimeouts,\n} from \"./index\";\nimport type { TrustProxy } from \"./http\";\nimport { renderNodePageResponse } from \"./streaming\";\nimport type { StaticFileHandler, StaticFileHandlerOptions } from \"./static\";\n\nexport type NodeBuildPageOptions = {\n clientEntry: string;\n renderPage: PageRenderer;\n styles: string[];\n};\n\nexport type NodeBuildContext = {\n page: NodeBuildPageOptions;\n root: string;\n waitUntil: (promise: Promise<unknown>) => void;\n};\n\nexport type ServeNodeBuildEnvironment = Record<string, string | undefined>;\n\nexport type ServeNodeBuildOptions = {\n allowedHosts?: readonly string[];\n base: string | URL;\n clientDir?: string;\n createHandler: (\n context: NodeBuildContext,\n ) => RequestHandler | Promise<RequestHandler>;\n env?: ServeNodeBuildEnvironment;\n host?: string;\n name?: string;\n onError?: NodeRequestListenerOptions[\"onError\"];\n // When set, this replaces the default listen log entirely, so `name` is\n // not used.\n onListen?: (address: { host: string; port: number; server: NodeServer }) => void;\n port?: number;\n readyPath?: string | false;\n shutdown?: NodeGracefulShutdownOptions;\n // A caller that needs a font handler or an image optimizer in front of the\n // plain file handler returns the composed handler from this factory.\n static?:\n | StaticFileHandlerOptions\n | ((context: NodeBuildContext) => StaticFileHandler | StaticFileHandlerOptions);\n timeouts?: Partial<NodeServerTimeouts>;\n trustProxy?: TrustProxy;\n};\n\nexport const defaultNodeBuildClientDir = \"dist/client\";\nexport const defaultNodeBuildReadyPath = \"/.well-known/ready\";\n\n/**\n * Boot a built Demiurge app as one production Node process.\n *\n * The helper reads the browser manifest, resolves the host allowlist and the\n * bind address from the environment, serves hashed assets from the client\n * build, answers the readiness path, and listens.\n */\nexport async function serveNodeBuild(\n options: ServeNodeBuildOptions,\n): Promise<NodeServer> {\n const environment = options.env ?? process.env;\n const root = fileURLToPath(\n new URL(options.clientDir ?? defaultNodeBuildClientDir, options.base),\n );\n const manifest = parseClientManifest(\n await readFile(join(root, \"demiurge-manifest.json\"), \"utf8\"),\n );\n const host = options.host ?? environment.HOST ?? \"127.0.0.1\";\n const port = resolvePort(environment.PORT, options.port);\n const allowedHosts = resolveAllowedHosts(\n options.allowedHosts,\n environment.ALLOWED_HOSTS,\n host,\n );\n const name = options.name ?? \"Demiurge Node server\";\n const readyPath = options.readyPath === false\n ? undefined\n : options.readyPath ?? defaultNodeBuildReadyPath;\n\n // A caller's createHandler may call waitUntil synchronously (for example to\n // warm a cache at startup), before the server exists. Buffer those promises\n // here and flush them into the real server once it is constructed, so an\n // early call just works instead of throwing.\n const pendingWaitUntil: Promise<unknown>[] = [];\n const context: NodeBuildContext = {\n page: {\n clientEntry: manifest.clientEntry,\n renderPage: renderNodePageResponse,\n styles: manifest.styles,\n },\n root,\n waitUntil(promise) {\n pendingWaitUntil.push(promise);\n },\n };\n const handler = await options.createHandler(context);\n\n const server = createNodeServer({\n allowedHosts,\n handler,\n onError: options.onError,\n readyPath,\n shutdown: options.shutdown,\n static: resolveStatic(options.static, context),\n timeouts: options.timeouts,\n trustProxy: options.trustProxy,\n });\n\n context.waitUntil = (promise) => {\n server.waitUntil(promise);\n };\n for (const promise of pendingWaitUntil) {\n server.waitUntil(promise);\n }\n\n await new Promise<void>((resolveListen, rejectListen) => {\n server.once(\"error\", rejectListen);\n server.listen(port, host, () => {\n server.off(\"error\", rejectListen);\n resolveListen();\n });\n });\n\n const address = server.address();\n // Port 0 asks the operating system for a free port. Report the bound port so\n // a caller can reach the server.\n const boundPort = typeof address === \"object\" && address\n ? address.port\n : port;\n\n if (options.onListen) {\n options.onListen({ host, port: boundPort, server });\n } else {\n console.log(`${name} listening on http://${host}:${boundPort}`);\n }\n\n return server;\n}\n\nfunction resolvePort(configured: string | undefined, fallback: number | undefined) {\n const value = configured ?? String(fallback ?? 4173);\n const port = Number(value);\n\n if (!Number.isSafeInteger(port) || port < 0 || port > 65_535) {\n throw new Error(\"Demiurge Node PORT must be an integer from 0 through 65535.\");\n }\n\n return port;\n}\n\nfunction resolveAllowedHosts(\n configured: readonly string[] | undefined,\n fromEnvironment: string | undefined,\n host: string,\n) {\n if (configured) {\n return configured;\n }\n\n if (fromEnvironment) {\n return fromEnvironment\n .split(\",\")\n .map((value) => value.trim())\n .filter(Boolean);\n }\n\n return host === \"localhost\" ? [host] : [host, \"localhost\"];\n}\n\nfunction resolveStatic(\n configured: ServeNodeBuildOptions[\"static\"],\n context: NodeBuildContext,\n) {\n if (!configured) {\n return { root: context.root };\n }\n\n if (typeof configured !== \"function\") {\n return configured;\n }\n\n const resolved = configured(context);\n\n // A factory returns a StaticFileHandler or a StaticFileHandlerOptions\n // object, both synchronously. A StaticFileHandler passed directly instead\n // (the shape createNodeServer's own `static` option accepts) is an async\n // function. Calling it here as a factory always returns a Promise. That\n // catches the mistake early, with a clear message, instead of a failure\n // deep inside the static file handler.\n if (resolved instanceof Promise) {\n throw new TypeError(\n \"The `static` option must be a StaticFileHandlerOptions object or a \" +\n \"factory `(context) => StaticFileHandler | StaticFileHandlerOptions`. \" +\n \"It looks like a StaticFileHandler was passed directly. Wrap it: \" +\n \"`static: () => yourHandler`.\",\n );\n }\n\n return resolved;\n}\n","import { createServer } from \"node:http\";\nimport type { IncomingMessage, Server, ServerResponse } from \"node:http\";\nimport type { Socket } from \"node:net\";\nimport { defineAdapter } from \"../adapter\";\nimport type { RequestHandler } from \"../server\";\nimport {\n UntrustedHostError,\n UnsupportedMethodError,\n toWebRequest,\n validateNodeOriginPolicy,\n writeNotImplemented,\n writeWebResponse,\n} from \"./http\";\nimport { createStaticFileHandler } from \"./static\";\nimport type { StaticFileHandler, StaticFileHandlerOptions } from \"./static\";\n\nexport {\n UntrustedHostError,\n UnsupportedMethodError,\n toHeaders,\n toWebRequest,\n validateNodeOriginPolicy,\n writeWebResponse,\n} from \"./http\";\nexport { createFontAssetHandler } from \"./font\";\nexport type { FontAssetHandlerOptions } from \"./font\";\nexport { createImageOptimizer } from \"./image\";\nexport type {\n ImageOptimizerFetch,\n ImageOptimizerOptions,\n} from \"./image\";\nexport { createStaticFileHandler } from \"./static\";\nexport {\n defaultNodeBuildClientDir,\n defaultNodeBuildReadyPath,\n serveNodeBuild,\n} from \"./serve\";\nexport type {\n NodeBuildContext,\n NodeBuildPageOptions,\n ServeNodeBuildEnvironment,\n ServeNodeBuildOptions,\n} from \"./serve\";\nexport {\n renderNodePageResponse,\n renderStreamingPageResponse,\n} from \"./streaming\";\nexport type {\n HttpScheme,\n NodeOriginPolicy,\n ToWebRequestOptions,\n TrustProxy,\n} from \"./http\";\nexport type { StaticFileHandler, StaticFileHandlerOptions } from \"./static\";\n\nexport const nodeAdapter = defineAdapter({\n name: \"node\",\n capabilities: {\n backgroundLifetime: true,\n crossOriginIsolationHeaders: true,\n nonceInjection: true,\n streaming: true,\n },\n});\n\nexport type NodeRequestListener = (\n request: IncomingMessage,\n response: ServerResponse,\n) => void;\n\nexport type NodeRequestListenerOptions = import(\"./http\").NodeOriginPolicy & {\n handler: RequestHandler;\n onError?: (error: unknown, request: IncomingMessage) => void;\n static?: StaticFileHandler | StaticFileHandlerOptions;\n};\n\nexport type NodeServerTimeouts = {\n headersTimeout: number;\n keepAliveTimeout: number;\n requestTimeout: number;\n};\n\nexport type NodeShutdownSignal = \"SIGINT\" | \"SIGTERM\";\nexport type NodeServerState = \"draining\" | \"ready\" | \"stopped\";\n\nexport type NodeGracefulShutdownOptions = {\n gracePeriod?: number;\n onBackgroundError?: (error: unknown) => void;\n onStateChange?: (state: NodeServerState) => void;\n signals?: readonly NodeShutdownSignal[];\n};\n\nexport type NodeServerOptions = NodeRequestListenerOptions & {\n readyPath?: string;\n shutdown?: NodeGracefulShutdownOptions;\n timeouts?: Partial<NodeServerTimeouts>;\n};\n\nexport type NodeServer = Server & {\n isReady: () => boolean;\n shutdown: () => Promise<void>;\n waitUntil: (promise: Promise<unknown>) => void;\n};\n\nexport const defaultNodeServerTimeouts = {\n headersTimeout: 66_000,\n keepAliveTimeout: 65_000,\n requestTimeout: 300_000,\n} as const satisfies NodeServerTimeouts;\n\nconst defaultShutdownGracePeriod = 30_000;\n\nexport function createNodeRequestListener(\n options: NodeRequestListenerOptions,\n): NodeRequestListener {\n validateNodeOriginPolicy(options);\n const serveStaticFile = toStaticFileHandler(options.static);\n const onError = options.onError ?? defaultOnError;\n\n return function handleNodeRequest(request, response) {\n const connection = createRequestAbort(request, response);\n\n void respond(request, response, connection.signal)\n .catch((error: unknown) => {\n if (connection.signal.aborted) {\n return;\n }\n\n onError(error, request);\n writeServerError(response);\n })\n .finally(connection.cleanup);\n };\n\n async function respond(\n request: IncomingMessage,\n response: ServerResponse,\n signal: AbortSignal,\n ) {\n let webRequest: Request;\n\n try {\n webRequest = toWebRequest(request, {\n allowedHosts: options.allowedHosts,\n signal,\n trustProxy: options.trustProxy,\n });\n } catch (error) {\n if (error instanceof UnsupportedMethodError) {\n writeNotImplemented(response);\n return;\n }\n\n if (error instanceof UntrustedHostError) {\n writeMisdirectedRequest(response);\n return;\n }\n\n throw error;\n }\n\n const staticResponse = await serveStaticFile?.(webRequest);\n\n await writeWebResponse(\n response,\n staticResponse ?? (await options.handler(webRequest)),\n );\n }\n}\n\nfunction createRequestAbort(\n request: IncomingMessage,\n response: ServerResponse,\n) {\n const controller = new AbortController();\n const abort = () => {\n if (!controller.signal.aborted) {\n controller.abort(new DOMException(\"Client disconnected.\", \"AbortError\"));\n }\n };\n const abortPrematureResponse = () => {\n if (!response.writableFinished) {\n abort();\n }\n };\n\n request.once(\"aborted\", abort);\n response.once(\"close\", abortPrematureResponse);\n\n return {\n cleanup() {\n request.off(\"aborted\", abort);\n response.off(\"close\", abortPrematureResponse);\n },\n signal: controller.signal,\n };\n}\n\nfunction writeMisdirectedRequest(response: ServerResponse) {\n response.statusCode = 421;\n response.setHeader(\"content-type\", \"text/plain; charset=utf-8\");\n response.end(\"Misdirected Request\");\n}\n\nexport function createNodeServer(\n options: NodeServerOptions,\n): NodeServer {\n const timeouts = normalizeNodeServerTimeouts(options.timeouts);\n const readyPath = normalizeReadyPath(options.readyPath);\n // The readiness answer needs the server the framework has not created yet.\n // The closure reads it after listen, so the later binding is always set.\n const handler: RequestHandler = readyPath\n ? async (request) => {\n if (new URL(request.url).pathname !== readyPath) {\n return options.handler(request);\n }\n\n const ready = server.isReady();\n\n return new Response(ready ? \"ready\" : \"draining\", {\n headers: {\n \"cache-control\": \"no-store\",\n \"content-type\": \"text/plain; charset=utf-8\",\n },\n status: ready ? 200 : 503,\n });\n }\n : options.handler;\n // TYPE-EVIDENCE: createServer returns an http.Server that the framework manages as a node server. The cast adds the framework lifecycle type.\n const server = createServer(\n createNodeRequestListener({ ...options, handler }),\n ) as NodeServer;\n server.keepAliveTimeout = timeouts.keepAliveTimeout;\n server.headersTimeout = timeouts.headersTimeout;\n server.requestTimeout = timeouts.requestTimeout;\n\n return attachNodeServerLifecycle(server, options.shutdown);\n}\n\nfunction normalizeReadyPath(configured: string | undefined) {\n if (configured === undefined) {\n return undefined;\n }\n\n if (!configured.startsWith(\"/\") || configured.includes(\"?\")) {\n throw new Error(\n \"Demiurge Node readyPath must be an absolute path without a query string.\",\n );\n }\n\n return configured;\n}\n\nfunction normalizeNodeServerTimeouts(\n configured: Partial<NodeServerTimeouts> | undefined,\n) {\n const timeouts = {\n ...defaultNodeServerTimeouts,\n ...configured,\n } satisfies NodeServerTimeouts;\n\n for (const [name, value] of Object.entries(timeouts)) {\n if (!Number.isSafeInteger(value) || value <= 0) {\n throw new Error(\n `Demiurge Node ${name} must be a positive integer in milliseconds.`,\n );\n }\n }\n\n if (timeouts.headersTimeout <= timeouts.keepAliveTimeout) {\n throw new Error(\n \"Demiurge Node headersTimeout must be greater than keepAliveTimeout.\",\n );\n }\n\n return timeouts;\n}\n\nfunction attachNodeServerLifecycle(\n server: NodeServer,\n options: NodeGracefulShutdownOptions | undefined,\n) {\n const gracePeriod = options?.gracePeriod ?? defaultShutdownGracePeriod;\n\n if (!Number.isSafeInteger(gracePeriod) || gracePeriod < 0) {\n throw new Error(\n \"Demiurge Node shutdown gracePeriod must be a non-negative integer in milliseconds.\",\n );\n }\n\n let draining = false;\n let shutdownPromise: Promise<void> | undefined;\n let checkShutdownCompletion: (() => void) | undefined;\n const signalHandlers = new Map<NodeShutdownSignal, () => void>();\n const activeResponses = new Map<Socket, number>();\n const backgroundTasks = new Set<Promise<void>>();\n\n server.on(\"connection\", (socket) => {\n activeResponses.set(socket, 0);\n socket.once(\"close\", () => activeResponses.delete(socket));\n });\n server.on(\"request\", (_request, response) => {\n const socket = response.socket;\n\n if (!socket) {\n return;\n }\n\n activeResponses.set(socket, (activeResponses.get(socket) ?? 0) + 1);\n let settled = false;\n const settle = () => {\n if (settled) {\n return;\n }\n\n settled = true;\n const remaining = Math.max(0, (activeResponses.get(socket) ?? 1) - 1);\n activeResponses.set(socket, remaining);\n\n if (draining && remaining === 0) {\n socket.destroy();\n }\n };\n response.once(\"finish\", settle);\n response.once(\"close\", settle);\n });\n\n server.isReady = () => server.listening && !draining;\n server.waitUntil = (promise) => {\n const tracked = Promise.resolve(promise)\n .catch((error: unknown) => {\n try {\n (options?.onBackgroundError ?? defaultOnError)(error);\n } catch (reportingError) {\n defaultOnError(reportingError);\n }\n })\n .then(() => undefined)\n .finally(() => {\n backgroundTasks.delete(tracked);\n checkShutdownCompletion?.();\n });\n backgroundTasks.add(tracked);\n };\n server.shutdown = () => {\n if (shutdownPromise) {\n return shutdownPromise;\n }\n\n draining = true;\n options?.onStateChange?.(\"draining\");\n shutdownPromise = new Promise<void>((resolveShutdown, rejectShutdown) => {\n let closeError: Error | undefined;\n let deadlineReached = false;\n let serverClosed = false;\n let settled = false;\n const forceTimer = setTimeout(() => {\n deadlineReached = true;\n server.closeAllConnections();\n completeShutdown();\n }, gracePeriod);\n\n server.close((error) => {\n // TYPE-EVIDENCE: Node close callbacks pass an error with an optional code. The cast reads that code to detect an ordinary shutdown condition.\n if (error && (error as NodeJS.ErrnoException).code !== \"ERR_SERVER_NOT_RUNNING\") {\n closeError = error;\n }\n\n serverClosed = true;\n completeShutdown();\n });\n server.closeIdleConnections();\n closeTrackedIdleConnections();\n // A response can finish in the same turn shutdown begins and transition\n // from active to idle just after the first sweep.\n setImmediate(() => {\n server.closeIdleConnections();\n closeTrackedIdleConnections();\n });\n\n checkShutdownCompletion = completeShutdown;\n\n function completeShutdown() {\n if (\n settled ||\n !serverClosed ||\n (!deadlineReached && backgroundTasks.size > 0)\n ) {\n return;\n }\n\n settled = true;\n checkShutdownCompletion = undefined;\n clearTimeout(forceTimer);\n removeSignalHandlers();\n options?.onStateChange?.(\"stopped\");\n\n if (closeError) {\n rejectShutdown(closeError);\n return;\n }\n\n resolveShutdown();\n }\n });\n\n return shutdownPromise;\n };\n\n server.on(\"listening\", () => options?.onStateChange?.(\"ready\"));\n\n for (const signal of new Set(options?.signals ?? [])) {\n const handler = () => {\n void server.shutdown().catch(defaultOnError);\n };\n signalHandlers.set(signal, handler);\n process.once(signal, handler);\n }\n\n server.once(\"close\", removeSignalHandlers);\n\n return server;\n\n function removeSignalHandlers() {\n for (const [signal, handler] of signalHandlers) {\n process.off(signal, handler);\n }\n\n signalHandlers.clear();\n }\n\n function closeTrackedIdleConnections() {\n for (const [socket, count] of activeResponses) {\n if (count === 0) {\n socket.destroy();\n }\n }\n }\n}\n\nfunction toStaticFileHandler(\n value: StaticFileHandler | StaticFileHandlerOptions | undefined,\n) {\n if (!value) {\n return undefined;\n }\n\n return typeof value === \"function\" ? value : createStaticFileHandler(value);\n}\n\nfunction defaultOnError(error: unknown) {\n console.error(error);\n}\n\n// The body stays generic on purpose. A stack trace here would hand an attacker\n// file paths and framework internals for free.\nfunction writeServerError(response: ServerResponse) {\n if (response.headersSent) {\n response.destroy();\n return;\n }\n\n response.statusCode = 500;\n response.setHeader(\"content-type\", \"text/plain; charset=utf-8\");\n response.end(\"Internal Server Error\");\n}\n"],"names":["defaultExcludedPaths","createStaticFileHandler","options","root","resolve","realRoot","realpath","prefix","normalizePrefix","isExcluded","defaultExcluded","isImmutable","defaultImmutable","request","filePath","resolveFilePath","toRelativePath","opened","openStaticFile","safeRealRoot","file","stats","etag","createWeakEtag","lastModified","headers","fileNameOf","IMMUTABLE_FILE_CACHE_CONTROL","REVALIDATED_FILE_CACHE_CONTROL","contentTypeOf","isNotModified","range","canApplyRange","parseRange","contentLength","Readable","size","mtimeMs","ifNoneMatch","candidate","weakEtagValue","ifModifiedSince","since","value","header","match","suffixLength","start","requestedEnd","ifRange","date","pathname","decoded","sep","hasNoSymlinkComponents","resolvedTarget","isPathInside","noFollow","constants","open","parts","relative","current","part","join","lstat","fileName","isContentHashedFileName","path","contentTypeForExtension","extname","defaultNodeBuildClientDir","defaultNodeBuildReadyPath","serveNodeBuild","environment","fileURLToPath","manifest","parseClientManifest","readFile","host","port","resolvePort","allowedHosts","resolveAllowedHosts","name","readyPath","pendingWaitUntil","context","renderNodePageResponse","promise","handler","server","createNodeServer","resolveStatic","resolveListen","rejectListen","address","boundPort","configured","fallback","fromEnvironment","resolved","nodeAdapter","defineAdapter","defaultNodeServerTimeouts","defaultShutdownGracePeriod","createNodeRequestListener","validateNodeOriginPolicy","serveStaticFile","toStaticFileHandler","onError","defaultOnError","response","connection","createRequestAbort","respond","error","writeServerError","signal","webRequest","toWebRequest","UnsupportedMethodError","writeNotImplemented","UntrustedHostError","writeMisdirectedRequest","staticResponse","writeWebResponse","controller","abort","abortPrematureResponse","timeouts","normalizeNodeServerTimeouts","normalizeReadyPath","ready","createServer","attachNodeServerLifecycle","gracePeriod","draining","shutdownPromise","checkShutdownCompletion","signalHandlers","activeResponses","backgroundTasks","socket","_request","settled","settle","remaining","tracked","reportingError","resolveShutdown","rejectShutdown","closeError","deadlineReached","serverClosed","forceTimer","completeShutdown","closeTrackedIdleConnections","removeSignalHandlers","count"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/node/static.ts","../../src/node/serve.ts","../../src/node/index.ts"],"sourcesContent":["import { constants } from \"node:fs\";\nimport { lstat, open, realpath } from \"node:fs/promises\";\nimport { extname, join, relative, resolve, sep } from \"node:path\";\nimport { Readable } from \"node:stream\";\nimport {\n contentTypeForExtension,\n IMMUTABLE_FILE_CACHE_CONTROL,\n isContentHashedFileName,\n REVALIDATED_FILE_CACHE_CONTROL,\n} from \"../static-files\";\n\nexport type StaticFileHandler = (request: Request) => Promise<Response | null>;\n\nexport type StaticFileHandlerOptions = {\n // Receives the file's path relative to `root`, always \"/\"-separated, so a\n // predicate can distinguish `index.html` from `docs/index.html`.\n exclude?: (path: string) => boolean;\n immutable?: (fileName: string) => boolean;\n prefix?: string;\n root: string;\n};\n\n// A null result keeps the handler composable. It means that the request does not\n// identify an owned file. The route pipeline owns all other responses, including\n// the 404 body and security headers. A traversal attempt gives the same result.\n// Plain static requests must not access the framework build output. The output\n// includes the SPA shell and the Node configuration manifest. The route pipeline\n// serves the shell and applies the `@policy.ts` headers. The server never serves\n// `demiurge-manifest.json` publicly. This exclusion applies only to the two root\n// files. An application can serve a nested file such as `docs/index.html`.\nconst defaultExcludedPaths = new Set([\"demiurge-manifest.json\", \"index.html\"]);\n\nexport function createStaticFileHandler(\n options: StaticFileHandlerOptions,\n): StaticFileHandler {\n const root = resolve(options.root);\n const realRoot = realpath(root);\n const prefix = normalizePrefix(options.prefix);\n const isExcluded = options.exclude ?? defaultExcluded;\n const isImmutable = options.immutable ?? defaultImmutable;\n\n return async function handleStaticFile(request) {\n if (request.method !== \"GET\" && request.method !== \"HEAD\") {\n return null;\n }\n\n const filePath = resolveFilePath(\n root,\n prefix,\n new URL(request.url).pathname,\n );\n\n if (!filePath || isExcluded(toRelativePath(root, filePath))) {\n return null;\n }\n\n const opened = await openStaticFile(root, await safeRealRoot(realRoot), filePath);\n\n if (!opened) {\n return null;\n }\n\n const { file, stats } = opened;\n\n const etag = createWeakEtag(stats.size, stats.mtimeMs);\n const lastModified = stats.mtime.toUTCString();\n const headers = new Headers({\n \"accept-ranges\": \"bytes\",\n \"cache-control\": isImmutable(fileNameOf(filePath))\n ? IMMUTABLE_FILE_CACHE_CONTROL\n : REVALIDATED_FILE_CACHE_CONTROL,\n \"content-length\": String(stats.size),\n \"content-type\": contentTypeOf(filePath),\n \"cross-origin-resource-policy\": \"same-origin\",\n etag,\n \"last-modified\": lastModified,\n \"x-content-type-options\": \"nosniff\",\n });\n\n if (isNotModified(request, etag, stats.mtimeMs)) {\n await file.close();\n headers.delete(\"content-length\");\n headers.delete(\"content-type\");\n\n return new Response(null, { headers, status: 304 });\n }\n\n const range = canApplyRange(request, stats.mtimeMs)\n ? parseRange(request.headers.get(\"range\"), stats.size)\n : null;\n\n if (range === \"unsatisfiable\") {\n await file.close();\n headers.delete(\"content-length\");\n headers.delete(\"content-type\");\n headers.set(\"content-range\", `bytes */${stats.size}`);\n\n return new Response(null, { headers, status: 416 });\n }\n\n if (range) {\n const contentLength = range.end - range.start + 1;\n headers.set(\"content-length\", String(contentLength));\n headers.set(\"content-range\", `bytes ${range.start}-${range.end}/${stats.size}`);\n\n if (request.method === \"HEAD\") {\n await file.close();\n return new Response(null, { headers, status: 206 });\n }\n\n // TYPE-EVIDENCE: Readable.toWeb returns a web stream that matches the DOM ReadableStream body type.\n return new Response(\n Readable.toWeb(\n file.createReadStream({ end: range.end, start: range.start }),\n ) as ReadableStream,\n { headers, status: 206 },\n );\n }\n\n if (request.method === \"HEAD\") {\n await file.close();\n return new Response(null, { headers });\n }\n\n // TYPE-EVIDENCE: Readable.toWeb returns a web stream that matches the DOM ReadableStream body type.\n return new Response(\n Readable.toWeb(file.createReadStream()) as ReadableStream,\n { headers },\n );\n };\n}\n\nfunction createWeakEtag(size: number, mtimeMs: number) {\n return `W/\"${size.toString(16)}-${Math.trunc(mtimeMs).toString(16)}\"`;\n}\n\nfunction isNotModified(request: Request, etag: string, mtimeMs: number) {\n const ifNoneMatch = request.headers.get(\"if-none-match\");\n\n // If-None-Match takes precedence over If-Modified-Since. Weak comparison is\n // correct for GET/HEAD cache validation, so W/ is removed from both sides.\n if (ifNoneMatch !== null) {\n return ifNoneMatch.trim() === \"*\" || ifNoneMatch.split(\",\").some(\n (candidate) => weakEtagValue(candidate) === weakEtagValue(etag),\n );\n }\n\n const ifModifiedSince = request.headers.get(\"if-modified-since\");\n\n if (ifModifiedSince === null) {\n return false;\n }\n\n const since = Date.parse(ifModifiedSince);\n\n // HTTP dates have one-second precision. Compare the file timestamp at the\n // same precision rather than making a freshly-written file look newer.\n return Number.isFinite(since) && Math.floor(mtimeMs / 1000) * 1000 <= since;\n}\n\nfunction weakEtagValue(value: string) {\n return value.trim().replace(/^W\\//i, \"\");\n}\n\ntype ByteRange = { end: number; start: number };\n\nfunction parseRange(\n header: string | null,\n size: number,\n): ByteRange | \"unsatisfiable\" | null {\n if (header === null) {\n return null;\n }\n\n const match = /^bytes=(\\d*)-(\\d*)$/.exec(header.trim());\n\n // A server that does not support the requested unit, syntax, or multiple\n // ranges ignores Range and returns the complete representation. A 416 is\n // reserved for a valid byte-range set that cannot select this resource.\n if (!match || (!match[1] && !match[2])) {\n return null;\n }\n\n if (size === 0) {\n return \"unsatisfiable\";\n }\n\n if (!match[1]) {\n const suffixLength = Number(match[2]);\n\n if (!Number.isSafeInteger(suffixLength) || suffixLength <= 0) {\n return null;\n }\n\n return { start: Math.max(0, size - suffixLength), end: size - 1 };\n }\n\n const start = Number(match[1]);\n const requestedEnd = match[2] ? Number(match[2]) : size - 1;\n\n if (!Number.isSafeInteger(start) || !Number.isSafeInteger(requestedEnd)) {\n return null;\n }\n\n if (start >= size) {\n return \"unsatisfiable\";\n }\n\n if (match[2] && requestedEnd < start) {\n return null;\n }\n\n return { start, end: Math.min(requestedEnd, size - 1) };\n}\n\nfunction canApplyRange(request: Request, mtimeMs: number) {\n const ifRange = request.headers.get(\"if-range\");\n\n if (ifRange === null) {\n return true;\n }\n\n // If-Range requires strong comparison for an entity-tag. This handler's\n // stat-derived validator is intentionally weak, so only an HTTP date can\n // authorize a partial response.\n if (ifRange.trim().startsWith('\"') || /^W\\//i.test(ifRange.trim())) {\n return false;\n }\n\n const date = Date.parse(ifRange);\n return Number.isFinite(date) && Math.floor(mtimeMs / 1000) * 1000 <= date;\n}\n\nfunction resolveFilePath(root: string, prefix: string, pathname: string) {\n let decoded: string;\n\n try {\n decoded = decodeURIComponent(pathname);\n } catch {\n return null;\n }\n\n // A null byte truncates the path for some system calls. A name such as\n // \"app.js\\0.txt\" could read a file that differs from the checked file.\n if (decoded.includes(\"\\0\")) {\n return null;\n }\n\n if (prefix) {\n if (!decoded.startsWith(prefix)) {\n return null;\n }\n\n decoded = decoded.slice(prefix.length - 1);\n }\n\n if (decoded.endsWith(\"/\")) {\n return null;\n }\n\n const candidate = resolve(root, `.${decoded}`);\n\n return candidate.startsWith(`${root}${sep}`) ? candidate : null;\n}\n\nasync function safeRealRoot(root: Promise<string>) {\n try {\n return await root;\n } catch {\n return null;\n }\n}\n\nasync function openStaticFile(\n root: string,\n realRoot: string | null,\n filePath: string,\n) {\n if (!realRoot || !(await hasNoSymlinkComponents(root, filePath))) {\n return null;\n }\n\n let resolvedTarget: string;\n\n try {\n resolvedTarget = await realpath(filePath);\n } catch {\n return null;\n }\n\n if (!isPathInside(realRoot, resolvedTarget)) {\n return null;\n }\n\n const noFollow =\n typeof constants.O_NOFOLLOW === \"number\" ? constants.O_NOFOLLOW : 0;\n let file: Awaited<ReturnType<typeof open>>;\n\n try {\n // O_NOFOLLOW closes the final-component race on platforms that expose it.\n // The component walk and realpath containment check cover directory links.\n file = await open(filePath, constants.O_RDONLY | noFollow);\n } catch {\n return null;\n }\n\n try {\n const stats = await file.stat();\n\n if (!stats.isFile()) {\n await file.close();\n return null;\n }\n\n return { file, stats };\n } catch {\n await file.close();\n return null;\n }\n}\n\nasync function hasNoSymlinkComponents(root: string, filePath: string) {\n const parts = relative(root, filePath).split(sep);\n let current = root;\n\n try {\n for (const part of parts) {\n current = join(current, part);\n\n if ((await lstat(current)).isSymbolicLink()) {\n return false;\n }\n }\n } catch {\n return false;\n }\n\n return true;\n}\n\nfunction isPathInside(root: string, candidate: string) {\n return candidate.startsWith(`${root}${sep}`);\n}\n\nfunction normalizePrefix(prefix: string | undefined) {\n if (!prefix || prefix === \"/\") {\n return \"\";\n }\n\n return `/${prefix.replace(/^\\/|\\/$/g, \"\")}/`;\n}\n\nfunction defaultImmutable(fileName: string) {\n return isContentHashedFileName(fileName);\n}\n\nfunction defaultExcluded(path: string) {\n return defaultExcludedPaths.has(path);\n}\n\nfunction toRelativePath(root: string, filePath: string) {\n return filePath.slice(root.length + 1).split(sep).join(\"/\");\n}\n\nfunction fileNameOf(filePath: string) {\n return filePath.slice(filePath.lastIndexOf(sep) + 1);\n}\n\nfunction contentTypeOf(filePath: string) {\n return contentTypeForExtension(extname(filePath));\n}\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { parseClientManifest } from \"../manifest\";\nimport type { PageRenderer, RequestHandler } from \"../server\";\nimport {\n createNodeServer,\n type NodeGracefulShutdownOptions,\n type NodeRequestListenerOptions,\n type NodeServer,\n type NodeServerTimeouts,\n} from \"./index\";\nimport type { TrustProxy } from \"./http\";\nimport { renderNodePageResponse } from \"./streaming\";\nimport type { StaticFileHandler, StaticFileHandlerOptions } from \"./static\";\n\nexport type NodeBuildPageOptions = {\n clientEntry: string;\n renderPage: PageRenderer;\n styles: string[];\n};\n\nexport type NodeBuildContext = {\n page: NodeBuildPageOptions;\n root: string;\n waitUntil: (promise: Promise<unknown>) => void;\n};\n\nexport type NodeBuildRuntime = {\n createHandler: (\n context: NodeBuildContext,\n ) => RequestHandler | Promise<RequestHandler>;\n createStatic?: (\n context: NodeBuildContext,\n ) => StaticFileHandler | StaticFileHandlerOptions;\n};\n\nexport type ServeNodeBuildEnvironment = Record<string, string | undefined>;\n\nexport type ServeNodeBuildOptions = {\n allowedHosts?: readonly string[];\n base: string | URL;\n clientDir?: string;\n createHandler: (\n context: NodeBuildContext,\n ) => RequestHandler | Promise<RequestHandler>;\n env?: ServeNodeBuildEnvironment;\n host?: string;\n name?: string;\n onError?: NodeRequestListenerOptions[\"onError\"];\n // When set, this replaces the default listen log entirely, so `name` is\n // not used.\n onListen?: (address: { host: string; port: number; server: NodeServer }) => void;\n port?: number;\n readyPath?: string | false;\n shutdown?: NodeGracefulShutdownOptions;\n // A caller that needs a font handler or an image optimizer in front of the\n // plain file handler returns the composed handler from this factory.\n static?:\n | StaticFileHandlerOptions\n | ((context: NodeBuildContext) => StaticFileHandler | StaticFileHandlerOptions);\n timeouts?: Partial<NodeServerTimeouts>;\n trustProxy?: TrustProxy;\n};\n\nexport const defaultNodeBuildClientDir = \"dist/client\";\nexport const defaultNodeBuildReadyPath = \"/.well-known/ready\";\n\n/**\n * Boot a built Demiurge app as one production Node process.\n *\n * The helper reads the browser manifest, resolves the host allowlist and the\n * bind address from the environment, serves hashed assets from the client\n * build, answers the readiness path, and listens.\n */\nexport async function serveNodeBuild(\n options: ServeNodeBuildOptions,\n): Promise<NodeServer> {\n const environment = options.env ?? process.env;\n const root = fileURLToPath(\n new URL(options.clientDir ?? defaultNodeBuildClientDir, options.base),\n );\n const manifest = parseClientManifest(\n await readFile(join(root, \"demiurge-manifest.json\"), \"utf8\"),\n );\n const host = options.host ?? environment.HOST ?? \"127.0.0.1\";\n const port = resolvePort(environment.PORT, options.port);\n const allowedHosts = resolveAllowedHosts(\n options.allowedHosts,\n environment.ALLOWED_HOSTS,\n host,\n );\n const name = options.name ?? \"Demiurge Node server\";\n const readyPath = options.readyPath === false\n ? undefined\n : options.readyPath ?? defaultNodeBuildReadyPath;\n\n // A caller's createHandler may call waitUntil synchronously (for example to\n // warm a cache at startup), before the server exists. Buffer those promises\n // here and flush them into the real server once it is constructed, so an\n // early call just works instead of throwing.\n const pendingWaitUntil: Promise<unknown>[] = [];\n const context: NodeBuildContext = {\n page: {\n clientEntry: manifest.clientEntry,\n renderPage: renderNodePageResponse,\n styles: manifest.styles,\n },\n root,\n waitUntil(promise) {\n pendingWaitUntil.push(promise);\n },\n };\n const handler = await options.createHandler(context);\n\n const server = createNodeServer({\n allowedHosts,\n handler,\n onError: options.onError,\n readyPath,\n shutdown: options.shutdown,\n static: resolveStatic(options.static, context),\n timeouts: options.timeouts,\n trustProxy: options.trustProxy,\n });\n\n context.waitUntil = (promise) => {\n server.waitUntil(promise);\n };\n for (const promise of pendingWaitUntil) {\n server.waitUntil(promise);\n }\n\n await new Promise<void>((resolveListen, rejectListen) => {\n server.once(\"error\", rejectListen);\n server.listen(port, host, () => {\n server.off(\"error\", rejectListen);\n resolveListen();\n });\n });\n\n const address = server.address();\n // Port 0 asks the operating system for a free port. Report the bound port so\n // a caller can reach the server.\n const boundPort = typeof address === \"object\" && address\n ? address.port\n : port;\n\n if (options.onListen) {\n options.onListen({ host, port: boundPort, server });\n } else {\n console.log(`${name} listening on http://${host}:${boundPort}`);\n }\n\n return server;\n}\n\nfunction resolvePort(configured: string | undefined, fallback: number | undefined) {\n const value = configured ?? String(fallback ?? 4173);\n const port = Number(value);\n\n if (!Number.isSafeInteger(port) || port < 0 || port > 65_535) {\n throw new Error(\"Demiurge Node PORT must be an integer from 0 through 65535.\");\n }\n\n return port;\n}\n\nfunction resolveAllowedHosts(\n configured: readonly string[] | undefined,\n fromEnvironment: string | undefined,\n host: string,\n) {\n if (configured) {\n return configured;\n }\n\n if (fromEnvironment) {\n return fromEnvironment\n .split(\",\")\n .map((value) => value.trim())\n .filter(Boolean);\n }\n\n return host === \"localhost\" ? [host] : [host, \"localhost\"];\n}\n\nfunction resolveStatic(\n configured: ServeNodeBuildOptions[\"static\"],\n context: NodeBuildContext,\n) {\n if (!configured) {\n return { root: context.root };\n }\n\n if (typeof configured !== \"function\") {\n return configured;\n }\n\n const resolved = configured(context);\n\n // A factory returns a StaticFileHandler or a StaticFileHandlerOptions\n // object, both synchronously. A StaticFileHandler passed directly instead\n // (the shape createNodeServer's own `static` option accepts) is an async\n // function. Calling it here as a factory always returns a Promise. That\n // catches the mistake early, with a clear message, instead of a failure\n // deep inside the static file handler.\n if (resolved instanceof Promise) {\n throw new TypeError(\n \"The `static` option must be a StaticFileHandlerOptions object or a \" +\n \"factory `(context) => StaticFileHandler | StaticFileHandlerOptions`. \" +\n \"It looks like a StaticFileHandler was passed directly. Wrap it: \" +\n \"`static: () => yourHandler`.\",\n );\n }\n\n return resolved;\n}\n","import { createServer } from \"node:http\";\nimport type { IncomingMessage, Server, ServerResponse } from \"node:http\";\nimport type { Socket } from \"node:net\";\nimport { defineAdapter } from \"../adapter\";\nimport type { RequestHandler } from \"../server\";\nimport {\n UntrustedHostError,\n UnsupportedMethodError,\n toWebRequest,\n validateNodeOriginPolicy,\n writeNotImplemented,\n writeWebResponse,\n} from \"./http\";\nimport { createStaticFileHandler } from \"./static\";\nimport type { StaticFileHandler, StaticFileHandlerOptions } from \"./static\";\n\nexport {\n ConsumedRequestBodyError,\n UntrustedHostError,\n UnsupportedMethodError,\n toHeaders,\n toWebRequest,\n validateNodeOriginPolicy,\n writeWebResponse,\n} from \"./http\";\nexport { createFontAssetHandler } from \"./font\";\nexport type { FontAssetHandlerOptions } from \"./font\";\nexport { createImageOptimizer } from \"./image\";\nexport type {\n ImageOptimizerFetch,\n ImageOptimizerOptions,\n} from \"./image\";\nexport { createStaticFileHandler } from \"./static\";\nexport {\n defaultNodeBuildClientDir,\n defaultNodeBuildReadyPath,\n serveNodeBuild,\n} from \"./serve\";\nexport type {\n NodeBuildContext,\n NodeBuildPageOptions,\n NodeBuildRuntime,\n ServeNodeBuildEnvironment,\n ServeNodeBuildOptions,\n} from \"./serve\";\nexport {\n renderNodePageResponse,\n renderStreamingPageResponse,\n} from \"./streaming\";\nexport type {\n HttpScheme,\n NodeOriginPolicy,\n ToWebRequestOptions,\n TrustProxy,\n} from \"./http\";\nexport type { StaticFileHandler, StaticFileHandlerOptions } from \"./static\";\n\n// `requestTimeoutEnforcement` is true because `createNodeServer` sets a real\n// `headersTimeout`, `keepAliveTimeout`, and `requestTimeout` on the\n// `http.Server`. Those bound how long a connection can stay open while the\n// shared pipeline reads a body without a `Content-Length`. The shared\n// pipeline itself does not own that bound.\nexport const nodeAdapter = defineAdapter({\n name: \"node\",\n capabilities: {\n backgroundLifetime: true,\n crossOriginIsolationHeaders: true,\n nonceInjection: true,\n requestTimeoutEnforcement: true,\n streaming: true,\n },\n});\n\nexport type NodeRequestListener = (\n request: IncomingMessage,\n response: ServerResponse,\n) => void;\n\nexport type NodeRequestListenerOptions = import(\"./http\").NodeOriginPolicy & {\n handler: RequestHandler;\n onError?: (error: unknown, request: IncomingMessage) => void;\n static?: StaticFileHandler | StaticFileHandlerOptions;\n};\n\nexport type NodeServerTimeouts = {\n headersTimeout: number;\n keepAliveTimeout: number;\n requestTimeout: number;\n};\n\nexport type NodeShutdownSignal = \"SIGINT\" | \"SIGTERM\";\nexport type NodeServerState = \"draining\" | \"ready\" | \"stopped\";\n\nexport type NodeGracefulShutdownOptions = {\n gracePeriod?: number;\n onBackgroundError?: (error: unknown) => void;\n onStateChange?: (state: NodeServerState) => void;\n signals?: readonly NodeShutdownSignal[];\n};\n\nexport type NodeServerOptions = NodeRequestListenerOptions & {\n readyPath?: string;\n shutdown?: NodeGracefulShutdownOptions;\n timeouts?: Partial<NodeServerTimeouts>;\n};\n\nexport type NodeServer = Server & {\n isReady: () => boolean;\n shutdown: () => Promise<void>;\n waitUntil: (promise: Promise<unknown>) => void;\n};\n\nexport const defaultNodeServerTimeouts = {\n headersTimeout: 66_000,\n keepAliveTimeout: 65_000,\n requestTimeout: 300_000,\n} as const satisfies NodeServerTimeouts;\n\nconst defaultShutdownGracePeriod = 30_000;\n\nexport function createNodeRequestListener(\n options: NodeRequestListenerOptions,\n): NodeRequestListener {\n validateNodeOriginPolicy(options);\n const serveStaticFile = toStaticFileHandler(options.static);\n const onError = options.onError ?? defaultOnError;\n\n return function handleNodeRequest(request, response) {\n const connection = createRequestAbort(request, response);\n\n void respond(request, response, connection.signal)\n .catch((error: unknown) => {\n if (connection.signal.aborted) {\n return;\n }\n\n onError(error, request);\n writeServerError(response);\n })\n .finally(connection.cleanup);\n };\n\n async function respond(\n request: IncomingMessage,\n response: ServerResponse,\n signal: AbortSignal,\n ) {\n let webRequest: Request;\n\n try {\n webRequest = toWebRequest(request, {\n allowedHosts: options.allowedHosts,\n signal,\n trustProxy: options.trustProxy,\n });\n } catch (error) {\n if (error instanceof UnsupportedMethodError) {\n writeNotImplemented(response);\n return;\n }\n\n if (error instanceof UntrustedHostError) {\n writeMisdirectedRequest(response);\n return;\n }\n\n throw error;\n }\n\n const staticResponse = await serveStaticFile?.(webRequest);\n\n await writeWebResponse(\n response,\n staticResponse ?? (await options.handler(webRequest)),\n );\n }\n}\n\nfunction createRequestAbort(\n request: IncomingMessage,\n response: ServerResponse,\n) {\n const controller = new AbortController();\n const abort = () => {\n if (!controller.signal.aborted) {\n controller.abort(new DOMException(\"Client disconnected.\", \"AbortError\"));\n }\n };\n const abortPrematureResponse = () => {\n if (!response.writableFinished) {\n abort();\n }\n };\n\n request.once(\"aborted\", abort);\n response.once(\"close\", abortPrematureResponse);\n\n return {\n cleanup() {\n request.off(\"aborted\", abort);\n response.off(\"close\", abortPrematureResponse);\n },\n signal: controller.signal,\n };\n}\n\nfunction writeMisdirectedRequest(response: ServerResponse) {\n response.statusCode = 421;\n response.setHeader(\"content-type\", \"text/plain; charset=utf-8\");\n response.end(\"Misdirected Request\");\n}\n\nexport function createNodeServer(\n options: NodeServerOptions,\n): NodeServer {\n const timeouts = normalizeNodeServerTimeouts(options.timeouts);\n const readyPath = normalizeReadyPath(options.readyPath);\n // The readiness answer needs the server the framework has not created yet.\n // The closure reads it after listen, so the later binding is always set.\n const handler: RequestHandler = readyPath\n ? async (request) => {\n if (new URL(request.url).pathname !== readyPath) {\n return options.handler(request);\n }\n\n const ready = server.isReady();\n\n return new Response(ready ? \"ready\" : \"draining\", {\n headers: {\n \"cache-control\": \"no-store\",\n \"content-type\": \"text/plain; charset=utf-8\",\n },\n status: ready ? 200 : 503,\n });\n }\n : options.handler;\n // TYPE-EVIDENCE: createServer returns an http.Server that the framework manages as a node server. The cast adds the framework lifecycle type.\n const server = createServer(\n createNodeRequestListener({ ...options, handler }),\n ) as NodeServer;\n server.keepAliveTimeout = timeouts.keepAliveTimeout;\n server.headersTimeout = timeouts.headersTimeout;\n server.requestTimeout = timeouts.requestTimeout;\n\n return attachNodeServerLifecycle(server, options.shutdown);\n}\n\nfunction normalizeReadyPath(configured: string | undefined) {\n if (configured === undefined) {\n return undefined;\n }\n\n if (!configured.startsWith(\"/\") || configured.includes(\"?\")) {\n throw new Error(\n \"Demiurge Node readyPath must be an absolute path without a query string.\",\n );\n }\n\n return configured;\n}\n\nfunction normalizeNodeServerTimeouts(\n configured: Partial<NodeServerTimeouts> | undefined,\n) {\n const timeouts = {\n ...defaultNodeServerTimeouts,\n ...configured,\n } satisfies NodeServerTimeouts;\n\n for (const [name, value] of Object.entries(timeouts)) {\n if (!Number.isSafeInteger(value) || value <= 0) {\n throw new Error(\n `Demiurge Node ${name} must be a positive integer in milliseconds.`,\n );\n }\n }\n\n if (timeouts.headersTimeout <= timeouts.keepAliveTimeout) {\n throw new Error(\n \"Demiurge Node headersTimeout must be greater than keepAliveTimeout.\",\n );\n }\n\n return timeouts;\n}\n\nfunction attachNodeServerLifecycle(\n server: NodeServer,\n options: NodeGracefulShutdownOptions | undefined,\n) {\n const gracePeriod = options?.gracePeriod ?? defaultShutdownGracePeriod;\n\n if (!Number.isSafeInteger(gracePeriod) || gracePeriod < 0) {\n throw new Error(\n \"Demiurge Node shutdown gracePeriod must be a non-negative integer in milliseconds.\",\n );\n }\n\n let draining = false;\n let shutdownPromise: Promise<void> | undefined;\n let checkShutdownCompletion: (() => void) | undefined;\n const signalHandlers = new Map<NodeShutdownSignal, () => void>();\n const activeResponses = new Map<Socket, number>();\n const backgroundTasks = new Set<Promise<void>>();\n\n server.on(\"connection\", (socket) => {\n activeResponses.set(socket, 0);\n socket.once(\"close\", () => activeResponses.delete(socket));\n });\n server.on(\"request\", (_request, response) => {\n const socket = response.socket;\n\n if (!socket) {\n return;\n }\n\n activeResponses.set(socket, (activeResponses.get(socket) ?? 0) + 1);\n let settled = false;\n const settle = () => {\n if (settled) {\n return;\n }\n\n settled = true;\n const remaining = Math.max(0, (activeResponses.get(socket) ?? 1) - 1);\n activeResponses.set(socket, remaining);\n\n if (draining && remaining === 0) {\n socket.destroy();\n }\n };\n response.once(\"finish\", settle);\n response.once(\"close\", settle);\n });\n\n server.isReady = () => server.listening && !draining;\n server.waitUntil = (promise) => {\n const tracked = Promise.resolve(promise)\n .catch((error: unknown) => {\n try {\n (options?.onBackgroundError ?? defaultOnError)(error);\n } catch (reportingError) {\n defaultOnError(reportingError);\n }\n })\n .then(() => undefined)\n .finally(() => {\n backgroundTasks.delete(tracked);\n checkShutdownCompletion?.();\n });\n backgroundTasks.add(tracked);\n };\n server.shutdown = () => {\n if (shutdownPromise) {\n return shutdownPromise;\n }\n\n draining = true;\n options?.onStateChange?.(\"draining\");\n shutdownPromise = new Promise<void>((resolveShutdown, rejectShutdown) => {\n let closeError: Error | undefined;\n let deadlineReached = false;\n let serverClosed = false;\n let settled = false;\n const forceTimer = setTimeout(() => {\n deadlineReached = true;\n server.closeAllConnections();\n completeShutdown();\n }, gracePeriod);\n\n server.close((error) => {\n // TYPE-EVIDENCE: Node close callbacks pass an error with an optional code. The cast reads that code to detect an ordinary shutdown condition.\n if (error && (error as NodeJS.ErrnoException).code !== \"ERR_SERVER_NOT_RUNNING\") {\n closeError = error;\n }\n\n serverClosed = true;\n completeShutdown();\n });\n server.closeIdleConnections();\n closeTrackedIdleConnections();\n // A response can finish in the same turn shutdown begins and transition\n // from active to idle just after the first sweep.\n setImmediate(() => {\n server.closeIdleConnections();\n closeTrackedIdleConnections();\n });\n\n checkShutdownCompletion = completeShutdown;\n\n function completeShutdown() {\n if (\n settled ||\n !serverClosed ||\n (!deadlineReached && backgroundTasks.size > 0)\n ) {\n return;\n }\n\n settled = true;\n checkShutdownCompletion = undefined;\n clearTimeout(forceTimer);\n removeSignalHandlers();\n options?.onStateChange?.(\"stopped\");\n\n if (closeError) {\n rejectShutdown(closeError);\n return;\n }\n\n resolveShutdown();\n }\n });\n\n return shutdownPromise;\n };\n\n server.on(\"listening\", () => options?.onStateChange?.(\"ready\"));\n\n for (const signal of new Set(options?.signals ?? [])) {\n const handler = () => {\n void server.shutdown().catch(defaultOnError);\n };\n signalHandlers.set(signal, handler);\n process.once(signal, handler);\n }\n\n server.once(\"close\", removeSignalHandlers);\n\n return server;\n\n function removeSignalHandlers() {\n for (const [signal, handler] of signalHandlers) {\n process.off(signal, handler);\n }\n\n signalHandlers.clear();\n }\n\n function closeTrackedIdleConnections() {\n for (const [socket, count] of activeResponses) {\n if (count === 0) {\n socket.destroy();\n }\n }\n }\n}\n\nfunction toStaticFileHandler(\n value: StaticFileHandler | StaticFileHandlerOptions | undefined,\n) {\n if (!value) {\n return undefined;\n }\n\n return typeof value === \"function\" ? value : createStaticFileHandler(value);\n}\n\nfunction defaultOnError(error: unknown) {\n console.error(error);\n}\n\n// The body stays generic on purpose. A stack trace here would hand an attacker\n// file paths and framework internals for free.\nfunction writeServerError(response: ServerResponse) {\n if (response.headersSent) {\n response.destroy();\n return;\n }\n\n response.statusCode = 500;\n response.setHeader(\"content-type\", \"text/plain; charset=utf-8\");\n response.end(\"Internal Server Error\");\n}\n"],"names":["defaultExcludedPaths","createStaticFileHandler","options","root","resolve","realRoot","realpath","prefix","normalizePrefix","isExcluded","defaultExcluded","isImmutable","defaultImmutable","request","filePath","resolveFilePath","toRelativePath","opened","openStaticFile","safeRealRoot","file","stats","etag","createWeakEtag","lastModified","headers","fileNameOf","IMMUTABLE_FILE_CACHE_CONTROL","REVALIDATED_FILE_CACHE_CONTROL","contentTypeOf","isNotModified","range","canApplyRange","parseRange","contentLength","Readable","size","mtimeMs","ifNoneMatch","candidate","weakEtagValue","ifModifiedSince","since","value","header","match","suffixLength","start","requestedEnd","ifRange","date","pathname","decoded","sep","hasNoSymlinkComponents","resolvedTarget","isPathInside","noFollow","constants","open","parts","relative","current","part","join","lstat","fileName","isContentHashedFileName","path","contentTypeForExtension","extname","defaultNodeBuildClientDir","defaultNodeBuildReadyPath","serveNodeBuild","environment","fileURLToPath","manifest","parseClientManifest","readFile","host","port","resolvePort","allowedHosts","resolveAllowedHosts","name","readyPath","pendingWaitUntil","context","renderNodePageResponse","promise","handler","server","createNodeServer","resolveStatic","resolveListen","rejectListen","address","boundPort","configured","fallback","fromEnvironment","resolved","nodeAdapter","defineAdapter","defaultNodeServerTimeouts","defaultShutdownGracePeriod","createNodeRequestListener","validateNodeOriginPolicy","serveStaticFile","toStaticFileHandler","onError","defaultOnError","response","connection","createRequestAbort","respond","error","writeServerError","signal","webRequest","toWebRequest","UnsupportedMethodError","writeNotImplemented","UntrustedHostError","writeMisdirectedRequest","staticResponse","writeWebResponse","controller","abort","abortPrematureResponse","timeouts","normalizeNodeServerTimeouts","normalizeReadyPath","ready","createServer","attachNodeServerLifecycle","gracePeriod","draining","shutdownPromise","checkShutdownCompletion","signalHandlers","activeResponses","backgroundTasks","socket","_request","settled","settle","remaining","tracked","reportingError","resolveShutdown","rejectShutdown","closeError","deadlineReached","serverClosed","forceTimer","completeShutdown","closeTrackedIdleConnections","removeSignalHandlers","count"],"mappings":"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"}
@@ -12,6 +12,10 @@ export type NodeBuildContext = {
12
12
  root: string;
13
13
  waitUntil: (promise: Promise<unknown>) => void;
14
14
  };
15
+ export type NodeBuildRuntime = {
16
+ createHandler: (context: NodeBuildContext) => RequestHandler | Promise<RequestHandler>;
17
+ createStatic?: (context: NodeBuildContext) => StaticFileHandler | StaticFileHandlerOptions;
18
+ };
15
19
  export type ServeNodeBuildEnvironment = Record<string, string | undefined>;
16
20
  export type ServeNodeBuildOptions = {
17
21
  allowedHosts?: readonly string[];
@@ -1 +1 @@
1
- {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/node/serve.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC9D,OAAO,EAEL,KAAK,2BAA2B,EAChC,KAAK,0BAA0B,EAC/B,KAAK,UAAU,EACf,KAAK,kBAAkB,EACxB,MAAM,SAAS,CAAC;AACjB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEzC,OAAO,KAAK,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAE5E,MAAM,MAAM,oBAAoB,GAAG;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,YAAY,CAAC;IACzB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,oBAAoB,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAE3E,MAAM,MAAM,qBAAqB,GAAG;IAClC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,CACb,OAAO,EAAE,gBAAgB,KACtB,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAC9C,GAAG,CAAC,EAAE,yBAAyB,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,0BAA0B,CAAC,SAAS,CAAC,CAAC;IAGhD,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,UAAU,CAAA;KAAE,KAAK,IAAI,CAAC;IACjF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC3B,QAAQ,CAAC,EAAE,2BAA2B,CAAC;IAGvC,MAAM,CAAC,EACH,wBAAwB,GACxB,CAAC,CAAC,OAAO,EAAE,gBAAgB,KAAK,iBAAiB,GAAG,wBAAwB,CAAC,CAAC;IAClF,QAAQ,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACvC,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB,CAAC;AAEF,eAAO,MAAM,yBAAyB,gBAAgB,CAAC;AACvD,eAAO,MAAM,yBAAyB,uBAAuB,CAAC;AAE9D;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,UAAU,CAAC,CA8ErB"}
1
+ {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/node/serve.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC9D,OAAO,EAEL,KAAK,2BAA2B,EAChC,KAAK,0BAA0B,EAC/B,KAAK,UAAU,EACf,KAAK,kBAAkB,EACxB,MAAM,SAAS,CAAC;AACjB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEzC,OAAO,KAAK,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAE5E,MAAM,MAAM,oBAAoB,GAAG;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,YAAY,CAAC;IACzB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,oBAAoB,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,aAAa,EAAE,CACb,OAAO,EAAE,gBAAgB,KACtB,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAC9C,YAAY,CAAC,EAAE,CACb,OAAO,EAAE,gBAAgB,KACtB,iBAAiB,GAAG,wBAAwB,CAAC;CACnD,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAE3E,MAAM,MAAM,qBAAqB,GAAG;IAClC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,CACb,OAAO,EAAE,gBAAgB,KACtB,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAC9C,GAAG,CAAC,EAAE,yBAAyB,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,0BAA0B,CAAC,SAAS,CAAC,CAAC;IAGhD,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,UAAU,CAAA;KAAE,KAAK,IAAI,CAAC;IACjF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC3B,QAAQ,CAAC,EAAE,2BAA2B,CAAC;IAGvC,MAAM,CAAC,EACH,wBAAwB,GACxB,CAAC,CAAC,OAAO,EAAE,gBAAgB,KAAK,iBAAiB,GAAG,wBAAwB,CAAC,CAAC;IAClF,QAAQ,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACvC,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB,CAAC;AAEF,eAAO,MAAM,yBAAyB,gBAAgB,CAAC;AACvD,eAAO,MAAM,yBAAyB,uBAAuB,CAAC;AAE9D;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,UAAU,CAAC,CA8ErB"}
@@ -108,23 +108,24 @@ function L(e) {
108
108
  throw new Error(
109
109
  "Demiurge Redis cache store requires an ioredis client. Pass a connected ioredis Redis instance as `client`."
110
110
  );
111
- const t = y(e.client), l = e.keyPrefix ?? S, d = `${l}entry:`, i = `${l}tag:`, a = `${l}lease:`;
111
+ const t = y(e.client), l = e.keyPrefix ?? S, d = `${l}entry:`, s = `${l}tag:`, a = `${l}lease:`;
112
112
  return {
113
- async acquireRefreshLease(r, n, s) {
113
+ capabilities: { atomicity: "strong" },
114
+ async acquireRefreshLease(r, n, i) {
114
115
  return await t.call(
115
116
  "SET",
116
117
  a + r,
117
118
  n,
118
119
  "NX",
119
120
  "PXAT",
120
- String(s)
121
+ String(i)
121
122
  ) === "OK";
122
123
  },
123
124
  async delete(r) {
124
125
  return await t.demiurgeCacheDelete(
125
126
  d + r,
126
127
  a + r,
127
- i,
128
+ s,
128
129
  r
129
130
  ) === 1;
130
131
  },
@@ -135,19 +136,19 @@ function L(e) {
135
136
  async invalidateTags(r) {
136
137
  return r.length === 0 ? 0 : await t.demiurgeCacheInvalidateTags(
137
138
  JSON.stringify(r),
138
- i,
139
+ s,
139
140
  d,
140
141
  a
141
142
  );
142
143
  },
143
- async publishRefresh(r, n, s) {
144
+ async publishRefresh(r, n, i) {
144
145
  return await t.demiurgeCachePublishRefresh(
145
146
  d + r,
146
147
  a + r,
147
148
  n,
148
- JSON.stringify(s),
149
- s.staleUntil === null ? "" : String(s.staleUntil),
150
- i,
149
+ JSON.stringify(i),
150
+ i.staleUntil === null ? "" : String(i.staleUntil),
151
+ s,
151
152
  r
152
153
  ) === 1;
153
154
  },
@@ -160,7 +161,7 @@ function L(e) {
160
161
  a + r,
161
162
  JSON.stringify(n),
162
163
  n.staleUntil === null ? "" : String(n.staleUntil),
163
- i,
164
+ s,
164
165
  r
165
166
  );
166
167
  }
@@ -194,10 +195,10 @@ function D(e) {
194
195
  );
195
196
  const t = w(e.client), l = e.keyPrefix ?? A;
196
197
  return {
197
- async increment(d, i) {
198
+ async increment(d, s) {
198
199
  const [a, r] = await t.demiurgeRateLimitIncrement(
199
200
  l + d,
200
- String(i)
201
+ String(s)
201
202
  );
202
203
  return { count: a, resetAt: r };
203
204
  }
@@ -246,13 +247,13 @@ function O(e) {
246
247
  throw new Error(
247
248
  "Demiurge Redis session store requires an ioredis client. Pass a connected ioredis Redis instance as `client`."
248
249
  );
249
- const t = Y(e.client), l = f(e.namespace), d = `${e.keyPrefix ?? G}${l}:`, i = (a) => d + a;
250
+ const t = Y(e.client), l = f(e.namespace), d = `${e.keyPrefix ?? G}${l}:`, s = (a) => d + a;
250
251
  return {
251
252
  async create(a) {
252
253
  const r = o(a, 0);
253
254
  try {
254
255
  return await t.demiurgeSessionCreate(
255
- i(r.id),
256
+ s(r.id),
256
257
  JSON.stringify(r),
257
258
  String(c(r))
258
259
  ) === 1 ? { record: r, status: "stored" } : { status: "conflict" };
@@ -261,31 +262,31 @@ function O(e) {
261
262
  }
262
263
  },
263
264
  async destroy(a) {
264
- return await t.del(i(a)) === 1;
265
+ return await t.del(s(a)) === 1;
265
266
  },
266
267
  async read(a, r) {
267
- const n = await t.get(i(a));
268
+ const n = await t.get(s(a));
268
269
  if (!n)
269
270
  return;
270
- const s = b(n);
271
- if (s) {
272
- if (c(s) <= r) {
273
- await t.del(i(a));
271
+ const i = b(n);
272
+ if (i) {
273
+ if (c(i) <= r) {
274
+ await t.del(s(a));
274
275
  return;
275
276
  }
276
- return s;
277
+ return i;
277
278
  }
278
279
  },
279
280
  async rotate(a, r, n) {
280
- const s = o(r, n + 1);
281
+ const i = o(r, n + 1);
281
282
  try {
282
283
  return await t.demiurgeSessionRotate(
283
- i(a),
284
- i(s.id),
284
+ s(a),
285
+ s(i.id),
285
286
  String(n),
286
- JSON.stringify(s),
287
- String(c(s))
288
- ) === 1 ? { record: s, status: "stored" } : { status: "conflict" };
287
+ JSON.stringify(i),
288
+ String(c(i))
289
+ ) === 1 ? { record: i, status: "stored" } : { status: "conflict" };
289
290
  } catch {
290
291
  return { status: "unavailable" };
291
292
  }
@@ -294,7 +295,7 @@ function O(e) {
294
295
  const n = o(a, r + 1);
295
296
  try {
296
297
  return await t.demiurgeSessionUpdate(
297
- i(n.id),
298
+ s(n.id),
298
299
  String(r),
299
300
  JSON.stringify(n),
300
301
  String(c(n))