@demiurgejs/core 0.2.0-beta.1 → 0.2.0-beta.3

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 (156) hide show
  1. package/README.md +2 -0
  2. package/dist/adapter/testing.d.ts +33 -0
  3. package/dist/adapter/testing.d.ts.map +1 -0
  4. package/dist/adapter/testing.js +251 -0
  5. package/dist/adapter/testing.js.map +1 -0
  6. package/dist/browser/file-router.d.ts.map +1 -1
  7. package/dist/chunks/document-shell-WoM8yZlR.js +35 -0
  8. package/dist/chunks/document-shell-WoM8yZlR.js.map +1 -0
  9. package/dist/chunks/image-codec-Di53WpcH.js +141 -0
  10. package/dist/chunks/image-codec-Di53WpcH.js.map +1 -0
  11. package/dist/chunks/images-Edar3eU1.js +339 -0
  12. package/dist/chunks/images-Edar3eU1.js.map +1 -0
  13. package/dist/chunks/request-metadata-DaIYq4Ea.js +677 -0
  14. package/dist/chunks/request-metadata-DaIYq4Ea.js.map +1 -0
  15. package/dist/chunks/streaming-D0fGAuiO.js +469 -0
  16. package/dist/chunks/streaming-D0fGAuiO.js.map +1 -0
  17. package/dist/chunks/{testing-DBjVCN5v.js → testing-CRflAw4X.js} +1300 -1139
  18. package/dist/chunks/testing-CRflAw4X.js.map +1 -0
  19. package/dist/cli.d.ts.map +1 -1
  20. package/dist/cli.js +63 -54
  21. package/dist/cli.js.map +1 -1
  22. package/dist/data/cache.d.ts +8 -0
  23. package/dist/data/cache.d.ts.map +1 -1
  24. package/dist/data/idempotency.d.ts.map +1 -1
  25. package/dist/data/index.d.ts +3 -1
  26. package/dist/data/index.d.ts.map +1 -1
  27. package/dist/data/testing.d.ts.map +1 -1
  28. package/dist/data/testing.js +94 -72
  29. package/dist/data/testing.js.map +1 -1
  30. package/dist/data/tiered.d.ts +7 -0
  31. package/dist/data/tiered.d.ts.map +1 -0
  32. package/dist/document/deferred-scripts.d.ts +11 -0
  33. package/dist/document/deferred-scripts.d.ts.map +1 -0
  34. package/dist/document/hydration.d.ts.map +1 -1
  35. package/dist/document/index.d.ts +4 -1
  36. package/dist/document/index.d.ts.map +1 -1
  37. package/dist/document/render.d.ts.map +1 -1
  38. package/dist/document/scripts.d.ts +12 -1
  39. package/dist/document/scripts.d.ts.map +1 -1
  40. package/dist/document/trusted-types.d.ts +10 -0
  41. package/dist/document/trusted-types.d.ts.map +1 -0
  42. package/dist/edge/assets.d.ts +14 -0
  43. package/dist/edge/assets.d.ts.map +1 -0
  44. package/dist/edge/index.d.ts +19 -0
  45. package/dist/edge/index.d.ts.map +1 -0
  46. package/dist/edge/index.js +286 -0
  47. package/dist/edge/index.js.map +1 -0
  48. package/dist/edge/stores.d.ts +8 -0
  49. package/dist/edge/stores.d.ts.map +1 -0
  50. package/dist/edge/streaming.d.ts +7 -0
  51. package/dist/edge/streaming.d.ts.map +1 -0
  52. package/dist/index.d.ts +7 -7
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +895 -556
  55. package/dist/index.js.map +1 -1
  56. package/dist/internal/testing.js +6 -6
  57. package/dist/kv/index.d.ts +5 -0
  58. package/dist/kv/index.d.ts.map +1 -0
  59. package/dist/kv/index.js +126 -0
  60. package/dist/kv/index.js.map +1 -0
  61. package/dist/kv/rate-limit-store.d.ts +8 -0
  62. package/dist/kv/rate-limit-store.d.ts.map +1 -0
  63. package/dist/kv/store.d.ts +28 -0
  64. package/dist/kv/store.d.ts.map +1 -0
  65. package/dist/node/font.d.ts +5 -0
  66. package/dist/node/font.d.ts.map +1 -0
  67. package/dist/node/http.d.ts.map +1 -1
  68. package/dist/node/image.d.ts +15 -0
  69. package/dist/node/image.d.ts.map +1 -0
  70. package/dist/node/index.d.ts +4 -0
  71. package/dist/node/index.d.ts.map +1 -1
  72. package/dist/node/index.js +25 -23
  73. package/dist/node/index.js.map +1 -1
  74. package/dist/node/static.d.ts.map +1 -1
  75. package/dist/node/streaming.d.ts.map +1 -1
  76. package/dist/platform/analytics.d.ts +58 -5
  77. package/dist/platform/analytics.d.ts.map +1 -1
  78. package/dist/platform/font-assets.d.ts +19 -0
  79. package/dist/platform/font-assets.d.ts.map +1 -0
  80. package/dist/platform/fonts.d.ts +14 -4
  81. package/dist/platform/fonts.d.ts.map +1 -1
  82. package/dist/platform/image-codec.d.ts +15 -0
  83. package/dist/platform/image-codec.d.ts.map +1 -0
  84. package/dist/platform/image-url.d.ts +17 -0
  85. package/dist/platform/image-url.d.ts.map +1 -0
  86. package/dist/platform/image.d.ts +8 -0
  87. package/dist/platform/image.d.ts.map +1 -0
  88. package/dist/platform/images.d.ts +15 -0
  89. package/dist/platform/images.d.ts.map +1 -1
  90. package/dist/platform/index.d.ts +13 -6
  91. package/dist/platform/index.d.ts.map +1 -1
  92. package/dist/platform/observability.d.ts +2 -1
  93. package/dist/platform/observability.d.ts.map +1 -1
  94. package/dist/platform/web-vitals-client.d.ts +32 -0
  95. package/dist/platform/web-vitals-client.d.ts.map +1 -0
  96. package/dist/platform/web-vitals.d.ts +78 -0
  97. package/dist/platform/web-vitals.d.ts.map +1 -0
  98. package/dist/redis/index.d.ts +5 -0
  99. package/dist/redis/index.d.ts.map +1 -0
  100. package/dist/redis/index.js +209 -0
  101. package/dist/redis/index.js.map +1 -0
  102. package/dist/redis/rate-limit-store.d.ts +8 -0
  103. package/dist/redis/rate-limit-store.d.ts.map +1 -0
  104. package/dist/redis/store.d.ts +8 -0
  105. package/dist/redis/store.d.ts.map +1 -0
  106. package/dist/route/action.d.ts.map +1 -1
  107. package/dist/route/middleware.d.ts.map +1 -1
  108. package/dist/route/response.d.ts.map +1 -1
  109. package/dist/router/index.d.ts +1 -1
  110. package/dist/router/index.d.ts.map +1 -1
  111. package/dist/router/manifest.d.ts +1 -0
  112. package/dist/router/manifest.d.ts.map +1 -1
  113. package/dist/security/cookies.d.ts +26 -0
  114. package/dist/security/cookies.d.ts.map +1 -0
  115. package/dist/security/env.d.ts.map +1 -1
  116. package/dist/security/fetch-metadata.d.ts +29 -0
  117. package/dist/security/fetch-metadata.d.ts.map +1 -0
  118. package/dist/security/index.d.ts +5 -1
  119. package/dist/security/index.d.ts.map +1 -1
  120. package/dist/security/policy.d.ts +2 -27
  121. package/dist/security/policy.d.ts.map +1 -1
  122. package/dist/security/rate-limit.d.ts +6 -3
  123. package/dist/security/rate-limit.d.ts.map +1 -1
  124. package/dist/security/request.d.ts.map +1 -1
  125. package/dist/security/types.d.ts +82 -6
  126. package/dist/security/types.d.ts.map +1 -1
  127. package/dist/security/verification.d.ts.map +1 -1
  128. package/dist/server/document-shell.d.ts +12 -0
  129. package/dist/server/document-shell.d.ts.map +1 -0
  130. package/dist/server/index.d.ts +1 -1
  131. package/dist/server/index.d.ts.map +1 -1
  132. package/dist/server/request-handler.d.ts +6 -2
  133. package/dist/server/request-handler.d.ts.map +1 -1
  134. package/dist/static/images.d.ts +13 -0
  135. package/dist/static/images.d.ts.map +1 -0
  136. package/dist/static/index.d.ts +8 -0
  137. package/dist/static/index.d.ts.map +1 -1
  138. package/dist/static/index.js +421 -313
  139. package/dist/static/index.js.map +1 -1
  140. package/dist/static/vercel.d.ts +3 -0
  141. package/dist/static/vercel.d.ts.map +1 -1
  142. package/dist/vite/index.d.ts +3 -0
  143. package/dist/vite/index.d.ts.map +1 -1
  144. package/dist/vite/index.js +1041 -652
  145. package/dist/vite/index.js.map +1 -1
  146. package/dist/vite/plugin.d.ts +9 -0
  147. package/dist/vite/plugin.d.ts.map +1 -1
  148. package/dist/vite/policy-verification.d.ts.map +1 -1
  149. package/dist/vite/route-audit.d.ts +50 -0
  150. package/dist/vite/route-audit.d.ts.map +1 -0
  151. package/package.json +34 -3
  152. package/dist/chunks/request-metadata-DwEO1EAS.js +0 -477
  153. package/dist/chunks/request-metadata-DwEO1EAS.js.map +0 -1
  154. package/dist/chunks/streaming-Ci6vf3BB.js +0 -353
  155. package/dist/chunks/streaming-Ci6vf3BB.js.map +0 -1
  156. package/dist/chunks/testing-DBjVCN5v.js.map +0 -1
@@ -1,15 +1,15 @@
1
- import { h as u, c as n, j as b, ar as i, i as r, as as _, at as c, x as d, u as h, w as m, au as R, av as g, aw as p, ax as f, ay as F } from "../chunks/testing-DBjVCN5v.js";
1
+ import { h as n, b as u, y as b, ay as i, n as _, j as r, az as c, H as d, G as h, i as m, aA as R, aB as g, aC as p, aD as f, aE as F } from "../chunks/testing-CRflAw4X.js";
2
2
  import "react-dom/server";
3
- import "../chunks/request-metadata-DwEO1EAS.js";
3
+ import "../chunks/request-metadata-DaIYq4Ea.js";
4
4
  import "react";
5
5
  import "react/jsx-runtime";
6
6
  export {
7
- u as handleRequestWithManifest,
8
- n as unstable_collectStaticRoutePaths,
7
+ n as handleRequestWithManifest,
8
+ u as unstable_collectStaticRoutePaths,
9
9
  b as unstable_createRouteManifest,
10
10
  i as unstable_findPageMatch,
11
- r as unstable_findRouteMatch,
12
- _ as unstable_isAttachedFileForRoute,
11
+ _ as unstable_findRouteMatch,
12
+ r as unstable_isAttachedFileForRoute,
13
13
  c as unstable_isLayoutForPage,
14
14
  d as unstable_loadErrorFallback,
15
15
  h as unstable_loadLoadingFallback,
@@ -0,0 +1,5 @@
1
+ export { createKvCacheStore } from "./store";
2
+ export type { EdgeKvListKey, EdgeKvListResult, EdgeKvNamespace, EdgeKvPutOptions, KvCacheStoreOptions, } from "./store";
3
+ export { createKvRateLimitStore } from "./rate-limit-store";
4
+ export type { KvRateLimitStoreOptions } from "./rate-limit-store";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/kv/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAC7C,YAAY,EACV,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,YAAY,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,126 @@
1
+ const $ = "demiurge:cache:";
2
+ function A(n) {
3
+ if (!n.namespace || typeof n.namespace.get != "function")
4
+ throw new Error(
5
+ "Demiurge KV cache store requires an EdgeKvNamespace. Pass a connected KV client matching the get/put/delete/list interface documented on EdgeKvNamespace."
6
+ );
7
+ const a = n.namespace, d = n.keyPrefix ?? $, g = `${d}entry:`, w = `${d}tag:`, m = `${d}lease:`;
8
+ function o(e) {
9
+ return g + e;
10
+ }
11
+ function r(e) {
12
+ return m + e;
13
+ }
14
+ function l(e, t) {
15
+ return `${w}${e}:${t}`;
16
+ }
17
+ async function s(e) {
18
+ const t = await a.get(o(e));
19
+ return t ? JSON.parse(t) : void 0;
20
+ }
21
+ async function u(e, t) {
22
+ await Promise.all(
23
+ t.map((i) => a.delete(l(i, e)))
24
+ );
25
+ }
26
+ async function E(e, t, i) {
27
+ await Promise.all(
28
+ t.map(
29
+ (c) => a.put(l(c, e), "1", { expiration: i })
30
+ )
31
+ );
32
+ }
33
+ async function x(e, t) {
34
+ const i = await s(e);
35
+ i && await u(e, i.tags);
36
+ const c = S(t);
37
+ await a.put(o(e), JSON.stringify(t), { expiration: c }), await E(e, t.tags, c);
38
+ }
39
+ return {
40
+ async acquireRefreshLease(e, t, i) {
41
+ return await a.get(r(e)) ? !1 : (await a.put(r(e), t, {
42
+ expiration: P(i)
43
+ }), !0);
44
+ },
45
+ async delete(e) {
46
+ const t = await s(e);
47
+ return await a.delete(r(e)), t ? (await u(e, t.tags), await a.delete(o(e)), !0) : !1;
48
+ },
49
+ async get(e) {
50
+ return await s(e);
51
+ },
52
+ async invalidateTags(e) {
53
+ if (e.length === 0)
54
+ return 0;
55
+ const t = /* @__PURE__ */ new Set();
56
+ let i = 0;
57
+ for (const c of e) {
58
+ const y = l(c, "");
59
+ let p;
60
+ do {
61
+ const h = await a.list({
62
+ cursor: p,
63
+ limit: 1e3,
64
+ prefix: y
65
+ });
66
+ for (const K of h.keys) {
67
+ const f = K.name.slice(y.length);
68
+ if (t.has(f))
69
+ continue;
70
+ t.add(f);
71
+ const v = await s(f);
72
+ if (!v) {
73
+ await a.delete(K.name);
74
+ continue;
75
+ }
76
+ await u(f, v.tags), await a.delete(o(f)), await a.delete(r(f)), i += 1;
77
+ }
78
+ p = h.list_complete ? void 0 : h.cursor;
79
+ } while (p);
80
+ }
81
+ return i;
82
+ },
83
+ async publishRefresh(e, t, i) {
84
+ return await a.get(r(e)) !== t ? !1 : (await x(e, i), await a.delete(r(e)), !0);
85
+ },
86
+ async releaseRefreshLease(e, t) {
87
+ await a.get(r(e)) === t && await a.delete(r(e));
88
+ },
89
+ async set(e, t) {
90
+ await x(e, t), await a.delete(r(e));
91
+ }
92
+ };
93
+ }
94
+ function S(n) {
95
+ return n.staleUntil === null ? void 0 : P(n.staleUntil);
96
+ }
97
+ function P(n) {
98
+ return Math.ceil(n / 1e3);
99
+ }
100
+ const N = "demiurge:rate-limit:";
101
+ function L(n) {
102
+ if (!n.namespace || typeof n.namespace.get != "function")
103
+ throw new Error(
104
+ "Demiurge KV rate limit store requires an EdgeKvNamespace. Pass a connected KV client matching the get/put/delete/list interface documented on EdgeKvNamespace."
105
+ );
106
+ const a = n.namespace, d = n.keyPrefix ?? N;
107
+ function g(w) {
108
+ return `${d}${w}`;
109
+ }
110
+ return {
111
+ async increment(w, m, o) {
112
+ const r = g(w), l = await a.get(r), s = l ? JSON.parse(l) : void 0, u = !s || s.resetAt <= o ? { count: 1, resetAt: o + m } : { count: s.count + 1, resetAt: s.resetAt };
113
+ return await a.put(r, JSON.stringify(u), {
114
+ expiration: b(u.resetAt)
115
+ }), u;
116
+ }
117
+ };
118
+ }
119
+ function b(n) {
120
+ return Math.ceil(n / 1e3);
121
+ }
122
+ export {
123
+ A as createKvCacheStore,
124
+ L as createKvRateLimitStore
125
+ };
126
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../../src/kv/store.ts","../../src/kv/rate-limit-store.ts"],"sourcesContent":["import type { CacheStore, CacheStoreEntry } from \"../data/cache\";\n\n// This type documents the interface an adapter FOR a KV store needs, not a\n// dependency on any vendor SDK. It is modeled closely on the binding API\n// Cloudflare Workers KV exposes, because that shape is the one most other\n// edge KV providers already copy. The application supplies its own\n// connected client matching this interface, the same way\n// `createRedisCacheStore` takes a connected `ioredis` client rather than\n// owning the connection. A Deno KV or Vercel Edge Config client can satisfy\n// this interface with a small wrapper even when its native method names\n// differ.\nexport type EdgeKvListKey = {\n name: string;\n};\n\nexport type EdgeKvListResult = {\n cursor?: string;\n keys: readonly EdgeKvListKey[];\n list_complete: boolean;\n};\n\nexport type EdgeKvPutOptions = {\n // Absolute expiration, in seconds since the Unix epoch. This store always\n // uses `expiration` rather than `expirationTtl` so an entry's lifetime\n // tracks its `staleUntil` timestamp exactly. Redis gets the same result\n // with `PEXPIREAT` instead of a relative `PEXPIRE`.\n expiration?: number;\n};\n\nexport type EdgeKvNamespace = {\n delete: (key: string) => Promise<void>;\n get: (key: string) => Promise<string | null>;\n list: (options?: {\n cursor?: string;\n limit?: number;\n prefix?: string;\n }) => Promise<EdgeKvListResult>;\n put: (key: string, value: string, options?: EdgeKvPutOptions) => Promise<void>;\n};\n\nexport type KvCacheStoreOptions = {\n // Every consumer of one KV namespace shares one keyspace. This prefix\n // scopes the store's entry, tag, and lease keys away from an\n // application's other use of the same namespace. Two Demiurge\n // deployments that share a namespace still need distinct prefixes, the\n // same way they need distinct cache namespaces.\n keyPrefix?: string;\n // The store issues operations on a client the application already\n // constructed and bound. Which provider, region, and namespace ID back\n // it is the application's decision, not this store's.\n namespace: EdgeKvNamespace;\n};\n\nconst defaultKeyPrefix = \"demiurge:cache:\";\nconst listPageLimit = 1000;\n\n// KV stores give up two things Redis's Lua scripts provided: cross-key\n// atomicity and a compare-and-swap primitive. Every write below is\n// therefore several sequential operations rather than one atomic script.\n//\n// Concretely, `set()`, `delete()`, and `publishRefresh()` each read the\n// previous entry, then write tag membership changes and the entry itself as\n// separate operations. A reader racing with one of these calls can briefly\n// see an entry whose tag memberships have not finished updating. It can\n// also see a tag membership entry whose backing cache entry is already\n// gone. `invalidateTags()` tolerates the latter case. It treats a\n// membership entry with no backing cache entry as already invalid and\n// simply removes it.\n//\n// `acquireRefreshLease()` and `publishRefresh()` implement single-writer\n// coordination with a get-then-write pattern, not a real compare-and-swap.\n// Two isolates that call `acquireRefreshLease()` within the same\n// observation window can both see no lease and both write one. The worst\n// case is redundant refresh work, the same failure mode\n// `staleWhileRevalidate` already tolerates when no coordination exists at\n// all. Do not rely on this store for exclusive-execution correctness\n// beyond that. The Redis store's atomic Lua scripts give a stronger\n// guarantee where that matters.\n//\n// Tag invalidation lists membership keys by prefix and deletes each\n// matching entry. `list()` on a real KV store is typically eventually\n// consistent. A membership entry written just before a matching `list()`\n// call may not appear on that call. A store that needs read-your-writes\n// tag invalidation should use the Redis store instead.\nexport function createKvCacheStore(options: KvCacheStoreOptions): CacheStore {\n if (!options.namespace || typeof options.namespace.get !== \"function\") {\n throw new Error(\n \"Demiurge KV cache store requires an EdgeKvNamespace. Pass a connected KV client matching the get/put/delete/list interface documented on EdgeKvNamespace.\",\n );\n }\n\n const kv = options.namespace;\n const prefix = options.keyPrefix ?? defaultKeyPrefix;\n const entryPrefix = `${prefix}entry:`;\n const tagPrefix = `${prefix}tag:`;\n const leasePrefix = `${prefix}lease:`;\n\n function entryKey(key: string) {\n return entryPrefix + key;\n }\n\n function leaseKey(key: string) {\n return leasePrefix + key;\n }\n\n function tagMemberKey(tagId: string, key: string) {\n return `${tagPrefix}${tagId}:${key}`;\n }\n\n async function readEntry(key: string): Promise<CacheStoreEntry | undefined> {\n const raw = await kv.get(entryKey(key));\n // TYPE-EVIDENCE: the stored raw value is JSON that the store serialized from a cache entry. The cast restores that shape.\n return raw ? (JSON.parse(raw) as CacheStoreEntry) : undefined;\n }\n\n async function removeTagMemberships(key: string, tags: readonly string[]) {\n await Promise.all(\n tags.map((tagId) => kv.delete(tagMemberKey(tagId, key))),\n );\n }\n\n async function addTagMemberships(\n key: string,\n tags: readonly string[],\n expiration: number | undefined,\n ) {\n await Promise.all(\n tags.map((tagId) =>\n kv.put(tagMemberKey(tagId, key), \"1\", { expiration })\n ),\n );\n }\n\n async function writeEntry(key: string, entry: CacheStoreEntry) {\n const previous = await readEntry(key);\n\n if (previous) {\n await removeTagMemberships(key, previous.tags);\n }\n\n const expiration = entryExpiration(entry);\n await kv.put(entryKey(key), JSON.stringify(entry), { expiration });\n await addTagMemberships(key, entry.tags, expiration);\n }\n\n return {\n async acquireRefreshLease(key, token, expiresAt) {\n const existing = await kv.get(leaseKey(key));\n\n if (existing) {\n return false;\n }\n\n await kv.put(leaseKey(key), token, {\n expiration: toExpirationSeconds(expiresAt),\n });\n\n return true;\n },\n async delete(key) {\n const previous = await readEntry(key);\n await kv.delete(leaseKey(key));\n\n if (!previous) {\n return false;\n }\n\n await removeTagMemberships(key, previous.tags);\n await kv.delete(entryKey(key));\n\n return true;\n },\n async get(key) {\n return await readEntry(key);\n },\n async invalidateTags(tags) {\n if (tags.length === 0) {\n return 0;\n }\n\n const seen = new Set<string>();\n let deleted = 0;\n\n for (const tagId of tags) {\n const membershipPrefix = tagMemberKey(tagId, \"\");\n let cursor: string | undefined;\n\n do {\n const page = await kv.list({\n cursor,\n limit: listPageLimit,\n prefix: membershipPrefix,\n });\n\n for (const listedKey of page.keys) {\n const rawKey = listedKey.name.slice(membershipPrefix.length);\n\n if (seen.has(rawKey)) {\n continue;\n }\n\n seen.add(rawKey);\n\n const entry = await readEntry(rawKey);\n\n if (!entry) {\n await kv.delete(listedKey.name);\n continue;\n }\n\n await removeTagMemberships(rawKey, entry.tags);\n await kv.delete(entryKey(rawKey));\n await kv.delete(leaseKey(rawKey));\n deleted += 1;\n }\n\n cursor = page.list_complete ? undefined : page.cursor;\n } while (cursor);\n }\n\n return deleted;\n },\n async publishRefresh(key, token, entry) {\n const owner = await kv.get(leaseKey(key));\n\n if (owner !== token) {\n return false;\n }\n\n await writeEntry(key, entry);\n await kv.delete(leaseKey(key));\n\n return true;\n },\n async releaseRefreshLease(key, token) {\n const owner = await kv.get(leaseKey(key));\n\n if (owner === token) {\n await kv.delete(leaseKey(key));\n }\n },\n async set(key, entry) {\n await writeEntry(key, entry);\n await kv.delete(leaseKey(key));\n },\n };\n}\n\nfunction entryExpiration(entry: CacheStoreEntry) {\n return entry.staleUntil === null\n ? undefined\n : toExpirationSeconds(entry.staleUntil);\n}\n\nfunction toExpirationSeconds(epochMilliseconds: number) {\n return Math.ceil(epochMilliseconds / 1000);\n}\n","import type { RateLimitStore } from \"../security/types\";\nimport type { EdgeKvNamespace } from \"./store\";\n\nexport type KvRateLimitStoreOptions = {\n // Every consumer of one KV namespace shares one keyspace. This prefix\n // scopes the store's counter keys away from an application's other use of\n // the same namespace, the same way `KvCacheStoreOptions.keyPrefix` scopes\n // `createKvCacheStore`'s keys.\n keyPrefix?: string;\n // The store issues operations on a client the application already\n // constructed and bound. Which provider, region, and namespace ID back\n // it is the application's decision, not this store's.\n namespace: EdgeKvNamespace;\n};\n\ntype KvRateLimitEntry = {\n count: number;\n resetAt: number;\n};\n\nconst defaultKeyPrefix = \"demiurge:rate-limit:\";\n\n// KV gives up the same thing here that `createKvCacheStore` gives up:\n// cross-operation atomicity. Plain KV has no compare-and-swap, so\n// `increment()` is necessarily a get-then-write, not a single atomic\n// operation. Two requests that call `increment()` within the same\n// observation window can both read the same prior count. Both then write\n// `count + 1`, so one increment is lost. The store can therefore undercount\n// under concurrent requests in that narrow window. It cannot overcount, and\n// it never blocks a request that should have been limited by more than one\n// request's worth of slack. Treat this as a soft limiter suitable for\n// coarse abuse protection, not an exact one. The Redis store's atomic Lua\n// script gives a stronger guarantee where that matters.\nexport function createKvRateLimitStore(\n options: KvRateLimitStoreOptions,\n): RateLimitStore {\n if (!options.namespace || typeof options.namespace.get !== \"function\") {\n throw new Error(\n \"Demiurge KV rate limit store requires an EdgeKvNamespace. Pass a connected KV client matching the get/put/delete/list interface documented on EdgeKvNamespace.\",\n );\n }\n\n const kv = options.namespace;\n const prefix = options.keyPrefix ?? defaultKeyPrefix;\n\n function counterKey(key: string) {\n return `${prefix}${key}`;\n }\n\n return {\n async increment(key, windowMs, now) {\n const storeKey = counterKey(key);\n const raw = await kv.get(storeKey);\n // TYPE-EVIDENCE: the stored raw value is JSON that the store serialized as a rate limit entry. The cast restores that shape.\n const existing = raw ? (JSON.parse(raw) as KvRateLimitEntry) : undefined;\n\n const next: KvRateLimitEntry = !existing || existing.resetAt <= now\n ? { count: 1, resetAt: now + windowMs }\n : { count: existing.count + 1, resetAt: existing.resetAt };\n\n await kv.put(storeKey, JSON.stringify(next), {\n expiration: toExpirationSeconds(next.resetAt),\n });\n\n return next;\n },\n };\n}\n\nfunction toExpirationSeconds(epochMilliseconds: number) {\n return Math.ceil(epochMilliseconds / 1000);\n}\n"],"names":["defaultKeyPrefix","createKvCacheStore","options","kv","prefix","entryPrefix","tagPrefix","leasePrefix","entryKey","key","leaseKey","tagMemberKey","tagId","readEntry","raw","removeTagMemberships","tags","addTagMemberships","expiration","writeEntry","entry","previous","entryExpiration","token","expiresAt","toExpirationSeconds","seen","deleted","membershipPrefix","cursor","page","listedKey","rawKey","epochMilliseconds","createKvRateLimitStore","counterKey","windowMs","now","storeKey","existing","next"],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { RateLimitStore } from "../security/types";
2
+ import type { EdgeKvNamespace } from "./store";
3
+ export type KvRateLimitStoreOptions = {
4
+ keyPrefix?: string;
5
+ namespace: EdgeKvNamespace;
6
+ };
7
+ export declare function createKvRateLimitStore(options: KvRateLimitStoreOptions): RateLimitStore;
8
+ //# sourceMappingURL=rate-limit-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit-store.d.ts","sourceRoot":"","sources":["../../src/kv/rate-limit-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,MAAM,MAAM,uBAAuB,GAAG;IAKpC,SAAS,CAAC,EAAE,MAAM,CAAC;IAInB,SAAS,EAAE,eAAe,CAAC;CAC5B,CAAC;AAoBF,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,uBAAuB,GAC/B,cAAc,CAgChB"}
@@ -0,0 +1,28 @@
1
+ import type { CacheStore } from "../data/cache";
2
+ export type EdgeKvListKey = {
3
+ name: string;
4
+ };
5
+ export type EdgeKvListResult = {
6
+ cursor?: string;
7
+ keys: readonly EdgeKvListKey[];
8
+ list_complete: boolean;
9
+ };
10
+ export type EdgeKvPutOptions = {
11
+ expiration?: number;
12
+ };
13
+ export type EdgeKvNamespace = {
14
+ delete: (key: string) => Promise<void>;
15
+ get: (key: string) => Promise<string | null>;
16
+ list: (options?: {
17
+ cursor?: string;
18
+ limit?: number;
19
+ prefix?: string;
20
+ }) => Promise<EdgeKvListResult>;
21
+ put: (key: string, value: string, options?: EdgeKvPutOptions) => Promise<void>;
22
+ };
23
+ export type KvCacheStoreOptions = {
24
+ keyPrefix?: string;
25
+ namespace: EdgeKvNamespace;
26
+ };
27
+ export declare function createKvCacheStore(options: KvCacheStoreOptions): CacheStore;
28
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/kv/store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAmB,MAAM,eAAe,CAAC;AAWjE,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,SAAS,aAAa,EAAE,CAAC;IAC/B,aAAa,EAAE,OAAO,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAK7B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC7C,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAChC,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAChF,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAMhC,SAAS,CAAC,EAAE,MAAM,CAAC;IAInB,SAAS,EAAE,eAAe,CAAC;CAC5B,CAAC;AAiCF,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,UAAU,CAkK3E"}
@@ -0,0 +1,5 @@
1
+ import { type FontAssetOptions } from "../platform/font-assets";
2
+ import type { StaticFileHandler } from "./static";
3
+ export type FontAssetHandlerOptions = FontAssetOptions;
4
+ export declare function createFontAssetHandler(options: FontAssetHandlerOptions): StaticFileHandler;
5
+ //# sourceMappingURL=font.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"font.d.ts","sourceRoot":"","sources":["../../src/node/font.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAElD,MAAM,MAAM,uBAAuB,GAAG,gBAAgB,CAAC;AAKvD,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,uBAAuB,GAC/B,iBAAiB,CA0CnB"}
@@ -1 +1 @@
1
- {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/node/http.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,mBAAmB,EACnB,eAAe,EACf,cAAc,EACf,MAAM,WAAW,CAAC;AAGnB,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,OAAO,CAAC;AAE1C,MAAM,MAAM,gBAAgB,GAAG;IAC7B,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,gBAAgB,GAAG;IACnD,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,UAAU,GAClB,KAAK,GACL;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAclC,qBAAa,sBAAuB,SAAQ,KAAK;IAC/C,MAAM,EAAE,MAAM,CAAC;gBAEH,MAAM,EAAE,MAAM;CAK3B;AAED,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,IAAI,EAAE,MAAM,CAAC;gBAED,IAAI,EAAE,MAAM;CAKzB;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,gBAAgB,QA+BhE;AAED,wBAAgB,YAAY,CAC1B,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,WA0C7B;AAgOD,wBAAgB,mBAAmB,CAAC,cAAc,EAAE,cAAc,QAIjE;AAED,wBAAsB,gBAAgB,CACpC,cAAc,EAAE,cAAc,EAC9B,WAAW,EAAE,QAAQ,iBAgDtB;AAsBD,wBAAgB,SAAS,CAAC,OAAO,EAAE,mBAAmB,WAiBrD"}
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/node/http.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,mBAAmB,EACnB,eAAe,EACf,cAAc,EACf,MAAM,WAAW,CAAC;AAGnB,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,OAAO,CAAC;AAE1C,MAAM,MAAM,gBAAgB,GAAG;IAC7B,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,gBAAgB,GAAG;IACnD,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,UAAU,GAClB,KAAK,GACL;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAclC,qBAAa,sBAAuB,SAAQ,KAAK;IAC/C,MAAM,EAAE,MAAM,CAAC;gBAEH,MAAM,EAAE,MAAM;CAK3B;AAED,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,IAAI,EAAE,MAAM,CAAC;gBAED,IAAI,EAAE,MAAM;CAKzB;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,gBAAgB,QA+BhE;AAED,wBAAgB,YAAY,CAC1B,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,WA2C7B;AAiOD,wBAAgB,mBAAmB,CAAC,cAAc,EAAE,cAAc,QAIjE;AAED,wBAAsB,gBAAgB,CACpC,cAAc,EAAE,cAAc,EAC9B,WAAW,EAAE,QAAQ,iBAiDtB;AAsBD,wBAAgB,SAAS,CAAC,OAAO,EAAE,mBAAmB,WAiBrD"}
@@ -0,0 +1,15 @@
1
+ import type { ImageVariantDescriptor } from "../platform/image-url";
2
+ import type { ImagePolicy } from "../platform/images";
3
+ import type { StaticFileHandler } from "./static";
4
+ export type ImageOptimizerFetch = (input: string, init?: {
5
+ signal?: AbortSignal;
6
+ }) => Promise<Response>;
7
+ export type ImageOptimizerOptions = {
8
+ cacheSize?: number;
9
+ fetch?: ImageOptimizerFetch;
10
+ policy?: ImagePolicy;
11
+ resolveVariant?: (pathname: string) => ImageVariantDescriptor | undefined;
12
+ root: string;
13
+ };
14
+ export declare function createImageOptimizer(options: ImageOptimizerOptions): StaticFileHandler;
15
+ //# sourceMappingURL=image.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../src/node/image.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAKpE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAGlD,MAAM,MAAM,mBAAmB,GAAG,CAChC,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,KAC5B,OAAO,CAAC,QAAQ,CAAC,CAAC;AAEvB,MAAM,MAAM,qBAAqB,GAAG;IAGlC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,mBAAmB,CAAC;IAC5B,MAAM,CAAC,EAAE,WAAW,CAAC;IAIrB,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,sBAAsB,GAAG,SAAS,CAAC;IAG1E,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAQF,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,qBAAqB,GAC7B,iBAAiB,CAkGnB"}
@@ -2,6 +2,10 @@ import type { IncomingMessage, Server, ServerResponse } from "node:http";
2
2
  import type { RequestHandler } from "../server";
3
3
  import type { StaticFileHandler, StaticFileHandlerOptions } from "./static";
4
4
  export { UntrustedHostError, UnsupportedMethodError, toHeaders, toWebRequest, validateNodeOriginPolicy, writeWebResponse, } from "./http";
5
+ export { createFontAssetHandler } from "./font";
6
+ export type { FontAssetHandlerOptions } from "./font";
7
+ export { createImageOptimizer } from "./image";
8
+ export type { ImageOptimizerFetch, ImageOptimizerOptions, } from "./image";
5
9
  export { createStaticFileHandler } from "./static";
6
10
  export { renderNodePageResponse, renderStreamingPageResponse, } from "./streaming";
7
11
  export type { HttpScheme, NodeOriginPolicy, ToWebRequestOptions, TrustProxy, } from "./http";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAUhD,OAAO,KAAK,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAE5E,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,SAAS,EACT,YAAY,EACZ,wBAAwB,EACxB,gBAAgB,GACjB,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AACnD,OAAO,EACL,sBAAsB,EACtB,2BAA2B,GAC5B,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,UAAU,EACV,gBAAgB,EAChB,mBAAmB,EACnB,UAAU,GACX,MAAM,QAAQ,CAAC;AAChB,YAAY,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAE5E,eAAO,MAAM,WAAW,sBAQtB,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAChC,OAAO,EAAE,eAAe,EACxB,QAAQ,EAAE,cAAc,KACrB,IAAI,CAAC;AAEV,MAAM,MAAM,0BAA0B,GAAG,OAAO,QAAQ,EAAE,gBAAgB,GAAG;IAC3E,OAAO,EAAE,cAAc,CAAC;IACxB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IAC7D,MAAM,CAAC,EAAE,iBAAiB,GAAG,wBAAwB,CAAC;CACvD,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,SAAS,CAAC;AACtD,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,OAAO,GAAG,SAAS,CAAC;AAE/D,MAAM,MAAM,2BAA2B,GAAG;IACxC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;IACjD,OAAO,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAC;CACzC,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,0BAA0B,GAAG;IAC3D,QAAQ,CAAC,EAAE,2BAA2B,CAAC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG;IAChC,OAAO,EAAE,MAAM,OAAO,CAAC;IACvB,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;CAChD,CAAC;AAEF,eAAO,MAAM,yBAAyB;;;;CAIC,CAAC;AAIxC,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,0BAA0B,GAClC,mBAAmB,CAsDrB;AAoCD,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,iBAAiB,GACzB,UAAU,CAQZ"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAUhD,OAAO,KAAK,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAE5E,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,SAAS,EACT,YAAY,EACZ,wBAAwB,EACxB,gBAAgB,GACjB,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,sBAAsB,EAAE,MAAM,QAAQ,CAAC;AAChD,YAAY,EAAE,uBAAuB,EAAE,MAAM,QAAQ,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAC/C,YAAY,EACV,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AACnD,OAAO,EACL,sBAAsB,EACtB,2BAA2B,GAC5B,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,UAAU,EACV,gBAAgB,EAChB,mBAAmB,EACnB,UAAU,GACX,MAAM,QAAQ,CAAC;AAChB,YAAY,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAE5E,eAAO,MAAM,WAAW,sBAQtB,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAChC,OAAO,EAAE,eAAe,EACxB,QAAQ,EAAE,cAAc,KACrB,IAAI,CAAC;AAEV,MAAM,MAAM,0BAA0B,GAAG,OAAO,QAAQ,EAAE,gBAAgB,GAAG;IAC3E,OAAO,EAAE,cAAc,CAAC;IACxB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IAC7D,MAAM,CAAC,EAAE,iBAAiB,GAAG,wBAAwB,CAAC;CACvD,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,SAAS,CAAC;AACtD,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,OAAO,GAAG,SAAS,CAAC;AAE/D,MAAM,MAAM,2BAA2B,GAAG;IACxC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;IACjD,OAAO,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAC;CACzC,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,0BAA0B,GAAG;IAC3D,QAAQ,CAAC,EAAE,2BAA2B,CAAC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG;IAChC,OAAO,EAAE,MAAM,OAAO,CAAC;IACvB,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;CAChD,CAAC;AAEF,eAAO,MAAM,yBAAyB;;;;CAIC,CAAC;AAIxC,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,0BAA0B,GAClC,mBAAmB,CAsDrB;AAoCD,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,iBAAiB,GACzB,UAAU,CASZ"}
@@ -1,9 +1,9 @@
1
- import { createServer as I } from "node:http";
2
- import { d as v } from "../chunks/request-metadata-DwEO1EAS.js";
3
- import { v as O, t as M, U as A, w as L, a as H, b as k } from "../chunks/streaming-Ci6vf3BB.js";
4
- import { r as ve, c as Oe, d as Me } from "../chunks/streaming-Ci6vf3BB.js";
1
+ import { createServer as C } from "node:http";
2
+ import { d as O } from "../chunks/request-metadata-DaIYq4Ea.js";
3
+ import { v, t as A, U as M, w as H, a as L, b as k } from "../chunks/streaming-D0fGAuiO.js";
4
+ import { c as Oe, d as ve, r as Ae, e as Me, f as He } from "../chunks/streaming-D0fGAuiO.js";
5
5
  import { constants as S } from "node:fs";
6
- import { realpath as T, open as j, lstat as F } from "node:fs/promises";
6
+ import { realpath as T, open as F, lstat as j } from "node:fs/promises";
7
7
  import { resolve as x, sep as w, extname as P, relative as W, join as $ } from "node:path";
8
8
  import { Readable as N } from "node:stream";
9
9
  import { I as _, R as D, i as U } from "../chunks/static-files-DUjHw-4H.js";
@@ -153,7 +153,7 @@ async function X(e, t, n) {
153
153
  const o = typeof S.O_NOFOLLOW == "number" ? S.O_NOFOLLOW : 0;
154
154
  let i;
155
155
  try {
156
- i = await j(n, S.O_RDONLY | o);
156
+ i = await F(n, S.O_RDONLY | o);
157
157
  } catch {
158
158
  return null;
159
159
  }
@@ -169,7 +169,7 @@ async function Z(e, t) {
169
169
  let r = e;
170
170
  try {
171
171
  for (const o of n)
172
- if (r = $(r, o), (await F(r)).isSymbolicLink())
172
+ if (r = $(r, o), (await j(r)).isSymbolicLink())
173
173
  return !1;
174
174
  } catch {
175
175
  return !1;
@@ -197,7 +197,7 @@ function ie(e) {
197
197
  function ae(e) {
198
198
  return z[P(e).toLowerCase()] ?? "application/octet-stream";
199
199
  }
200
- const Te = v({
200
+ const Te = O({
201
201
  name: "node",
202
202
  capabilities: {
203
203
  backgroundLifetime: !0,
@@ -211,7 +211,7 @@ const Te = v({
211
211
  requestTimeout: 3e5
212
212
  }, ce = 3e4;
213
213
  function le(e) {
214
- O(e);
214
+ v(e);
215
215
  const t = ge(e.static), n = e.onError ?? b;
216
216
  return function(i, u) {
217
217
  const s = ue(i, u);
@@ -222,17 +222,17 @@ function le(e) {
222
222
  async function r(o, i, u) {
223
223
  let s;
224
224
  try {
225
- s = M(o, {
225
+ s = A(o, {
226
226
  allowedHosts: e.allowedHosts,
227
227
  signal: u,
228
228
  trustProxy: e.trustProxy
229
229
  });
230
230
  } catch (g) {
231
- if (g instanceof A) {
232
- L(i);
231
+ if (g instanceof M) {
232
+ H(i);
233
233
  return;
234
234
  }
235
- if (g instanceof H) {
235
+ if (g instanceof L) {
236
236
  fe(i);
237
237
  return;
238
238
  }
@@ -262,7 +262,7 @@ function fe(e) {
262
262
  e.statusCode = 421, e.setHeader("content-type", "text/plain; charset=utf-8"), e.end("Misdirected Request");
263
263
  }
264
264
  function xe(e) {
265
- const t = de(e.timeouts), n = I(le(e));
265
+ const t = de(e.timeouts), n = C(le(e));
266
266
  return n.keepAliveTimeout = t.keepAliveTimeout, n.headersTimeout = t.headersTimeout, n.requestTimeout = t.requestTimeout, me(n, e.shutdown);
267
267
  }
268
268
  function de(e) {
@@ -319,7 +319,7 @@ function me(e, t) {
319
319
  m.add(l);
320
320
  }, e.shutdown = () => o || (r = !0, t?.onStateChange?.("draining"), o = new Promise((a, l) => {
321
321
  let f, c = !1, d = !1, p = !1;
322
- const C = setTimeout(() => {
322
+ const I = setTimeout(() => {
323
323
  c = !0, e.closeAllConnections(), y();
324
324
  }, n);
325
325
  e.close((R) => {
@@ -329,7 +329,7 @@ function me(e, t) {
329
329
  }), i = y;
330
330
  function y() {
331
331
  if (!(p || !d || !c && m.size > 0)) {
332
- if (p = !0, i = void 0, clearTimeout(C), g(), t?.onStateChange?.("stopped"), f) {
332
+ if (p = !0, i = void 0, clearTimeout(I), g(), t?.onStateChange?.("stopped"), f) {
333
333
  l(f);
334
334
  return;
335
335
  }
@@ -369,18 +369,20 @@ function he(e) {
369
369
  e.statusCode = 500, e.setHeader("content-type", "text/plain; charset=utf-8"), e.end("Internal Server Error");
370
370
  }
371
371
  export {
372
- A as UnsupportedMethodError,
373
- H as UntrustedHostError,
372
+ M as UnsupportedMethodError,
373
+ L as UntrustedHostError,
374
+ Oe as createFontAssetHandler,
375
+ ve as createImageOptimizer,
374
376
  le as createNodeRequestListener,
375
377
  xe as createNodeServer,
376
378
  V as createStaticFileHandler,
377
379
  se as defaultNodeServerTimeouts,
378
380
  Te as nodeAdapter,
379
- ve as renderNodePageResponse,
380
- Oe as renderStreamingPageResponse,
381
- Me as toHeaders,
382
- M as toWebRequest,
383
- O as validateNodeOriginPolicy,
381
+ Ae as renderNodePageResponse,
382
+ Me as renderStreamingPageResponse,
383
+ He as toHeaders,
384
+ A as toWebRequest,
385
+ v as validateNodeOriginPolicy,
384
386
  k as writeWebResponse
385
387
  };
386
388
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/node/static.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 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.\nconst contentTypes: Record<string, string> = {\n \".avif\": \"image/avif\",\n \".css\": \"text/css; charset=utf-8\",\n \".gif\": \"image/gif\",\n \".html\": \"text/html; charset=utf-8\",\n \".ico\": \"image/x-icon\",\n \".jpeg\": \"image/jpeg\",\n \".jpg\": \"image/jpeg\",\n \".js\": \"text/javascript; charset=utf-8\",\n \".json\": \"application/json; charset=utf-8\",\n \".mjs\": \"text/javascript; charset=utf-8\",\n \".png\": \"image/png\",\n \".svg\": \"image/svg+xml\",\n \".txt\": \"text/plain; charset=utf-8\",\n \".webmanifest\": \"application/manifest+json\",\n \".webp\": \"image/webp\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n};\n\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 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 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 (\n contentTypes[extname(filePath).toLowerCase()] ?? \"application/octet-stream\"\n );\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 { createStaticFileHandler } from \"./static\";\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 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 server = createServer(createNodeRequestListener(options)) 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 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 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":["contentTypes","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","extname","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","createNodeServer","timeouts","normalizeNodeServerTimeouts","server","createServer","attachNodeServerLifecycle","configured","name","gracePeriod","draining","shutdownPromise","checkShutdownCompletion","signalHandlers","activeResponses","backgroundTasks","socket","_request","settled","settle","remaining","promise","tracked","reportingError","resolveShutdown","rejectShutdown","closeError","deadlineReached","serverClosed","forceTimer","completeShutdown","closeTrackedIdleConnections","removeSignalHandlers","handler","count"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/node/static.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 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.\nconst contentTypes: Record<string, string> = {\n \".avif\": \"image/avif\",\n \".css\": \"text/css; charset=utf-8\",\n \".gif\": \"image/gif\",\n \".html\": \"text/html; charset=utf-8\",\n \".ico\": \"image/x-icon\",\n \".jpeg\": \"image/jpeg\",\n \".jpg\": \"image/jpeg\",\n \".js\": \"text/javascript; charset=utf-8\",\n \".json\": \"application/json; charset=utf-8\",\n \".mjs\": \"text/javascript; charset=utf-8\",\n \".png\": \"image/png\",\n \".svg\": \"image/svg+xml\",\n \".txt\": \"text/plain; charset=utf-8\",\n \".webmanifest\": \"application/manifest+json\",\n \".webp\": \"image/webp\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n};\n\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 (\n contentTypes[extname(filePath).toLowerCase()] ?? \"application/octet-stream\"\n );\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 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 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 // 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(createNodeRequestListener(options)) 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 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":["contentTypes","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","extname","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","createNodeServer","timeouts","normalizeNodeServerTimeouts","server","createServer","attachNodeServerLifecycle","configured","name","gracePeriod","draining","shutdownPromise","checkShutdownCompletion","signalHandlers","activeResponses","backgroundTasks","socket","_request","settled","settle","remaining","promise","tracked","reportingError","resolveShutdown","rejectShutdown","closeError","deadlineReached","serverClosed","forceTimer","completeShutdown","closeTrackedIdleConnections","removeSignalHandlers","handler","count"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"static.d.ts","sourceRoot":"","sources":["../../src/node/static.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;AAE/E,MAAM,MAAM,wBAAwB,GAAG;IAGrC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACpC,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAgCF,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,wBAAwB,GAChC,iBAAiB,CA8FnB"}
1
+ {"version":3,"file":"static.d.ts","sourceRoot":"","sources":["../../src/node/static.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;AAE/E,MAAM,MAAM,wBAAwB,GAAG;IAGrC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACpC,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAgCF,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,wBAAwB,GAChC,iBAAiB,CAgGnB"}