reroute-js 0.9.0 → 0.9.2

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 (124) hide show
  1. package/_/basic/package.json +1 -0
  2. package/_/basic/src/client/index.html +0 -1
  3. package/_/blog/package.json +1 -0
  4. package/_/store/package.json +1 -0
  5. package/cli/bin.d.ts +1 -1
  6. package/cli/bin.js +558 -674
  7. package/cli/bin.js.map +19 -24
  8. package/cli/index.d.ts +1 -1
  9. package/cli/index.js +47 -24
  10. package/cli/index.js.map +5 -5
  11. package/cli/src/cli.d.ts +1 -1
  12. package/cli/src/commands/analyze.d.ts +1 -1
  13. package/cli/src/commands/build.d.ts +3 -4
  14. package/cli/src/commands/build.d.ts.map +1 -1
  15. package/cli/src/commands/dev.d.ts +2 -3
  16. package/cli/src/commands/dev.d.ts.map +1 -1
  17. package/cli/src/commands/gen.d.ts +1 -1
  18. package/cli/src/commands/gen.d.ts.map +1 -1
  19. package/cli/src/commands/init.d.ts +1 -1
  20. package/cli/src/commands/start.d.ts +3 -4
  21. package/cli/src/commands/start.d.ts.map +1 -1
  22. package/cli/src/libs/command.d.ts +1 -1
  23. package/cli/src/libs/index.d.ts +1 -1
  24. package/cli/src/libs/log.d.ts +1 -1
  25. package/cli/src/libs/log.d.ts.map +1 -1
  26. package/cli/src/libs/markdown-processor.d.ts +2 -1
  27. package/cli/src/libs/markdown-processor.d.ts.map +1 -1
  28. package/cli/src/libs/markdown.d.ts +1 -1
  29. package/cli/src/libs/production.d.ts +1 -1
  30. package/cli/src/libs/server.d.ts +18 -0
  31. package/cli/src/libs/server.d.ts.map +1 -0
  32. package/cli/src/libs/tailwind.d.ts +2 -2
  33. package/cli/src/libs/tailwind.d.ts.map +1 -1
  34. package/cli/src/libs/version.d.ts +1 -1
  35. package/core/index.d.ts +1 -1
  36. package/core/index.js +99 -410
  37. package/core/index.js.map +7 -10
  38. package/core/src/bundler/hash.d.ts +1 -1
  39. package/core/src/bundler/index.d.ts +1 -2
  40. package/core/src/bundler/index.d.ts.map +1 -1
  41. package/core/src/content/discovery.d.ts +1 -3
  42. package/core/src/content/discovery.d.ts.map +1 -1
  43. package/core/src/content/index.d.ts +1 -2
  44. package/core/src/content/index.d.ts.map +1 -1
  45. package/core/src/content/metadata.d.ts +1 -1
  46. package/core/src/index.d.ts +1 -1
  47. package/core/src/ssr/data.d.ts +1 -1
  48. package/core/src/ssr/index.d.ts +1 -1
  49. package/core/src/ssr/modules.d.ts +1 -1
  50. package/core/src/ssr/render.d.ts +1 -1
  51. package/core/src/ssr/render.d.ts.map +1 -1
  52. package/core/src/ssr/seed.d.ts +1 -1
  53. package/core/src/template/html.d.ts +1 -1
  54. package/core/src/template/index.d.ts +1 -1
  55. package/core/src/types.d.ts +2 -22
  56. package/core/src/types.d.ts.map +1 -1
  57. package/core/src/utils/cache.d.ts +1 -1
  58. package/core/src/utils/compression.d.ts +1 -1
  59. package/core/src/utils/compression.d.ts.map +1 -1
  60. package/core/src/utils/index.d.ts +1 -1
  61. package/core/src/utils/mime.d.ts +1 -1
  62. package/core/src/utils/path.d.ts +1 -1
  63. package/elysia/index.d.ts +1 -1
  64. package/elysia/index.js +300 -773
  65. package/elysia/index.js.map +14 -17
  66. package/elysia/src/index.d.ts +1 -1
  67. package/elysia/src/libs/cache.d.ts +14 -0
  68. package/elysia/src/libs/cache.d.ts.map +1 -0
  69. package/elysia/src/libs/http.d.ts +1 -1
  70. package/elysia/src/libs/image.d.ts +1 -1
  71. package/elysia/src/libs/image.d.ts.map +1 -1
  72. package/elysia/src/plugin.d.ts +1 -1
  73. package/elysia/src/plugin.d.ts.map +1 -1
  74. package/elysia/src/routes/artifacts.d.ts +9 -2
  75. package/elysia/src/routes/artifacts.d.ts.map +1 -1
  76. package/elysia/src/routes/content.d.ts +3 -2
  77. package/elysia/src/routes/content.d.ts.map +1 -1
  78. package/elysia/src/routes/dev.d.ts +1 -1
  79. package/elysia/src/routes/dev.d.ts.map +1 -1
  80. package/elysia/src/routes/image.d.ts +1 -1
  81. package/elysia/src/routes/ssr.d.ts +1 -1
  82. package/elysia/src/routes/ssr.d.ts.map +1 -1
  83. package/elysia/src/routes/static.d.ts +2 -5
  84. package/elysia/src/routes/static.d.ts.map +1 -1
  85. package/elysia/src/types.d.ts +10 -3
  86. package/elysia/src/types.d.ts.map +1 -1
  87. package/package.json +4 -4
  88. package/react/index.d.ts +1 -1
  89. package/react/index.js +17 -2
  90. package/react/index.js.map +5 -4
  91. package/react/src/components/ClientOnly.d.ts +1 -1
  92. package/react/src/components/ContentRoute.d.ts +1 -1
  93. package/react/src/components/Image.d.ts +1 -1
  94. package/react/src/components/Link.d.ts +1 -1
  95. package/react/src/components/Markdown.d.ts +1 -1
  96. package/react/src/components/Outlet.d.ts +1 -1
  97. package/react/src/components/index.d.ts +1 -1
  98. package/react/src/hooks/index.d.ts +1 -1
  99. package/react/src/hooks/useContent.d.ts +1 -1
  100. package/react/src/hooks/useData.d.ts +1 -1
  101. package/react/src/hooks/useNavigate.d.ts +1 -1
  102. package/react/src/hooks/useParams.d.ts +1 -1
  103. package/react/src/hooks/useRouter.d.ts +1 -1
  104. package/react/src/hooks/useSearchParams.d.ts +1 -1
  105. package/react/src/index.d.ts +1 -1
  106. package/react/src/providers/ContentProvider.d.ts +1 -1
  107. package/react/src/providers/RerouteProvider.d.ts +1 -1
  108. package/react/src/providers/RouterProvider.d.ts +1 -1
  109. package/react/src/providers/index.d.ts +1 -1
  110. package/react/src/types/any.d.ts +1 -1
  111. package/react/src/types/index.d.ts +1 -1
  112. package/react/src/types/router.d.ts +1 -1
  113. package/react/src/utils/content.d.ts +1 -1
  114. package/react/src/utils/head.d.ts +1 -1
  115. package/react/src/utils/index.d.ts +2 -1
  116. package/react/src/utils/index.d.ts.map +1 -1
  117. package/react/src/utils/lazy-route.d.ts +41 -0
  118. package/react/src/utils/lazy-route.d.ts.map +1 -0
  119. package/cli/src/commands/boot.d.ts +0 -18
  120. package/cli/src/commands/boot.d.ts.map +0 -1
  121. package/core/src/bundler/transpile.d.ts +0 -14
  122. package/core/src/bundler/transpile.d.ts.map +0 -1
  123. package/core/src/content/registry.d.ts +0 -11
  124. package/core/src/content/registry.d.ts.map +0 -1
package/elysia/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * reroute-js v0.9.0
2
+ * reroute-js v0.9.2
3
3
  *
4
4
  * @license MIT
5
5
  * @copyright 2025 stewones <hi@stewan.io>
@@ -7,338 +7,33 @@
7
7
  *
8
8
  * Built with Bun <3
9
9
  */
10
- import { createRequire } from "node:module";
11
- var __create = Object.create;
12
- var __getProtoOf = Object.getPrototypeOf;
13
- var __defProp = Object.defineProperty;
14
- var __getOwnPropNames = Object.getOwnPropertyNames;
15
- var __hasOwnProp = Object.prototype.hasOwnProperty;
16
- var __toESM = (mod, isNodeMode, target) => {
17
- target = mod != null ? __create(__getProtoOf(mod)) : {};
18
- const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
19
- for (let key of __getOwnPropNames(mod))
20
- if (!__hasOwnProp.call(to, key))
21
- __defProp(to, key, {
22
- get: () => mod[key],
23
- enumerable: true
24
- });
25
- return to;
26
- };
27
- var __export = (target, all) => {
28
- for (var name in all)
29
- __defProp(target, name, {
30
- get: all[name],
31
- enumerable: true,
32
- configurable: true,
33
- set: (newValue) => all[name] = () => newValue
34
- });
35
- };
36
- var __require = /* @__PURE__ */ createRequire(import.meta.url);
10
+ // packages/core/src/content/discovery.ts
11
+ import { readdir, stat } from "node:fs/promises";
37
12
 
38
13
  // packages/core/src/utils/path.ts
39
- var exports_path = {};
40
- __export(exports_path, {
41
- stripStart: () => stripStart,
42
- stripEnd: () => stripEnd,
43
- join: () => join2,
44
- extname: () => extname,
45
- basename: () => basename
46
- });
47
- function join2(...parts) {
14
+ function join(...parts) {
48
15
  return parts.join("/").replace(/\/+/g, "/");
49
16
  }
50
- function extname(p) {
51
- const i = p.lastIndexOf(".");
52
- return i >= 0 ? p.slice(i) : "";
53
- }
54
- function basename(p, ext) {
55
- const name = p.replace(/\\/g, "/").split("/").pop() || p;
56
- return ext && name.endsWith(ext) ? name.slice(0, -ext.length) : name;
57
- }
58
- function stripStart(p, ch) {
59
- return p.startsWith(ch) ? p.slice(ch.length) : p;
60
- }
61
- function stripEnd(p, ch) {
62
- return p.endsWith(ch) ? p.slice(0, -ch.length) : p;
63
- }
64
17
 
65
- // packages/core/src/bundler/hash.ts
66
- async function generateContentHash(content) {
67
- const data = new TextEncoder().encode(content);
68
- const buf = await crypto.subtle.digest("SHA-256", data);
69
- let hex = "";
70
- for (const b of new Uint8Array(buf))
71
- hex += b.toString(16).padStart(2, "0");
72
- return hex.slice(0, 8);
73
- }
74
- // packages/cli/src/libs/tailwind.ts
75
- import { spawn } from "node:child_process";
76
- import { existsSync, readFileSync } from "node:fs";
77
- import { join } from "node:path";
78
- function isTailwindAvailable(cwd) {
79
- const packageJsonPath = join(cwd, "package.json");
80
- if (!existsSync(packageJsonPath)) {
81
- return false;
82
- }
83
- try {
84
- const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
85
- const deps = {
86
- ...packageJson.dependencies,
87
- ...packageJson.devDependencies
88
- };
89
- return "@tailwindcss/cli" in deps;
90
- } catch {
91
- return false;
92
- }
93
- }
94
- function getTailwindPaths(cwd) {
95
- const input = join(cwd, "src/client/theme.css");
96
- const output = join(cwd, ".reroute/theme.css");
97
- return { input, output };
98
- }
99
- function hasTailwindInput(cwd) {
100
- const { input } = getTailwindPaths(cwd);
101
- if (!existsSync(input)) {
102
- return false;
103
- }
104
- try {
105
- const content = readFileSync(input, "utf-8");
106
- return content.includes("tailwindcss");
107
- } catch {
108
- return false;
109
- }
110
- }
111
- function resolveTailwindBin(cwd) {
112
- const pathsToTry = [
113
- join(cwd, "../node_modules/.bin/tailwindcss"),
114
- join(cwd, "../../node_modules/.bin/tailwindcss"),
115
- join(cwd, "../../../node_modules/.bin/tailwindcss")
116
- ];
117
- for (const binPath of pathsToTry) {
118
- if (existsSync(binPath)) {
119
- return binPath;
120
- }
121
- }
122
- return join(cwd, "node_modules/.bin/tailwindcss");
123
- }
124
- async function buildTailwind(cwd) {
125
- const { input, output } = getTailwindPaths(cwd);
126
- return new Promise((resolve, reject) => {
127
- const tailwindBin = resolveTailwindBin(cwd);
128
- const args = ["-i", input, "-o", output];
129
- console.log(`[reroute/tailwind] build start: -i ${input} -o ${output}`);
130
- const tailwind = spawn(tailwindBin, args, {
131
- cwd,
132
- stdio: "pipe"
133
- });
134
- tailwind.stdout?.on("data", (data) => {
135
- const line = data.toString().trim();
136
- if (line) {
137
- console.log(`[reroute/tailwind] ${line}`);
138
- }
139
- });
140
- tailwind.stderr?.on("data", (data) => {
141
- const line = data.toString().trim();
142
- if (line) {
143
- console.log(`[reroute/tailwind] ${line}`);
144
- }
145
- });
146
- tailwind.on("close", (code) => {
147
- if (code === 0) {
148
- console.log("[reroute/tailwind] build done");
149
- resolve();
150
- } else {
151
- reject(new Error(`Tailwind CSS build failed with code ${code}`));
152
- }
153
- });
154
- tailwind.on("error", (error) => {
155
- reject(error);
156
- });
157
- });
158
- }
159
- async function buildTailwindIfConfigured(cwd) {
160
- try {
161
- if (isTailwindAvailable(cwd) && hasTailwindInput(cwd)) {
162
- await buildTailwind(cwd);
163
- return true;
164
- }
165
- return false;
166
- } catch (e) {
167
- console.warn("[reroute/tailwind] build failed:", e);
168
- return true;
169
- }
170
- }
171
- // packages/core/src/bundler/transpile.ts
172
- var entryUrlToStaticDeps = new Map;
173
- function isWatchMode() {
174
- try {
175
- return Array.isArray(process.execArgv) && process.execArgv.includes("--watch") || Array.isArray(process.argv) && process.argv.includes("--watch");
176
- } catch {
177
- return false;
178
- }
179
- }
180
- async function transpileFile(filePath, originalPath, options, bundleCache) {
181
- const src = await Bun.file(filePath).text();
182
- const cacheKey = `${filePath}-${await generateContentHash(src)}`;
183
- if (bundleCache.has(cacheKey)) {
184
- return bundleCache.get(cacheKey);
185
- }
186
- console.log(`[reroute] Building ${originalPath}${options.minify ? " (minified)" : ""}...`);
187
- try {
188
- if (isWatchMode()) {
189
- const cwd = typeof process !== "undefined" && process.cwd ? process.cwd() : "";
190
- if (cwd) {
191
- await buildTailwindIfConfigured(cwd);
192
- }
193
- }
194
- } catch (e) {
195
- console.warn("[reroute/tailwind] rebuild failed:", e);
196
- }
197
- async function doBuild(sm) {
198
- return await Bun.build({
199
- entrypoints: [filePath],
200
- target: "browser",
201
- format: "esm",
202
- minify: options.minify,
203
- splitting: true,
204
- sourcemap: sm,
205
- jsx: {
206
- runtime: "automatic",
207
- importSource: "react",
208
- development: !options.minify
209
- },
210
- define: {
211
- "process.env.NODE_ENV": options.minify ? '"production"' : '"development"',
212
- __DEV__: options.minify ? "false" : "true",
213
- "import.meta.env.MODE": options.minify ? '"production"' : '"development"'
214
- },
215
- ...options.minify ? { drop: ["console", "debugger"] } : {}
216
- });
217
- }
218
- let result;
18
+ // packages/core/src/content/discovery.ts
19
+ async function discoverCollections(clientDir) {
20
+ const root = join(clientDir, "routes");
21
+ const collections = new Set;
219
22
  try {
220
- result = await doBuild(options.sourcemap ? "external" : "none");
221
- } catch (error) {
222
- console.warn(`[reroute] Build errored for ${originalPath} (sourcemap external). Retrying without sourcemap...`, error);
223
- result = await doBuild("none");
224
- }
225
- if (!result.success) {
226
- console.error(`[reroute] Failed to build ${filePath}`);
227
- for (const log2 of result.logs)
228
- console.error(log2);
229
- throw new Error(`Failed to transpile ${filePath}`);
230
- }
231
- const outputs = await Promise.all(result.outputs.map(async (o) => ({
232
- path: o.path,
233
- text: await o.text()
234
- })));
235
- const entryBase = basename(originalPath, extname(originalPath));
236
- let entry = outputs.find((o) => o.path.endsWith(`${entryBase}.js`));
237
- if (!entry) {
238
- entry = outputs.filter((o) => o.path.endsWith(".js")).sort((a, b) => b.text.length - a.text.length)[0];
239
- }
240
- if (!entry) {
241
- throw new Error(`[reroute] No JS output generated for ${originalPath}`);
242
- }
243
- const code = entry.text;
244
- let sourceMap;
245
- if (options.sourcemap && result.outputs.length > 1) {
246
- const mapOutput = result.outputs.find((o) => o.path.endsWith(".map"));
247
- if (mapOutput) {
248
- sourceMap = await mapOutput.text();
249
- }
250
- }
251
- const contentHash = await generateContentHash(code);
252
- const chunks = outputs.filter((o) => o !== entry && o.path.endsWith(".js")).map((o) => ({
253
- fileName: basename(o.path),
254
- code: o.text,
255
- hash: "",
256
- isEntry: false,
257
- imports: []
258
- }));
259
- for (const c of chunks) {
260
- c.hash = await generateContentHash(c.code);
261
- try {
262
- const bn = c.fileName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
263
- const re = new RegExp(`["'\`]((?:\\./)?${bn})["'\`]`, "g");
264
- const matches = [...code.matchAll(re)];
265
- if (matches.length) {
266
- c.isEntry = false;
23
+ const entries = await readdir(root, { withFileTypes: true });
24
+ for (const entry of entries) {
25
+ if (entry.isDirectory()) {
26
+ const contentDir = join(root, entry.name, "content");
27
+ try {
28
+ await stat(contentDir);
29
+ collections.add(entry.name);
30
+ } catch {}
267
31
  }
268
- } catch {}
269
- }
270
- const staticDepNames = [];
271
- try {
272
- for (const c of chunks) {
273
- const bn = c.fileName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
274
- const re = new RegExp(`["'\`]((?:\\./)?${bn})["'\`]`, "g");
275
- if (re.test(code))
276
- staticDepNames.push(c.fileName);
277
32
  }
278
33
  } catch {}
279
- const bundleInfo = {
280
- hash: contentHash,
281
- code,
282
- sourceMap,
283
- chunks
284
- };
285
- bundleCache.set(cacheKey, bundleInfo);
286
- const sizeKB = (code.length / 1024).toFixed(2);
287
- const gzippedSize = Bun.gzipSync(new TextEncoder().encode(code)).length;
288
- const gzippedKB = (gzippedSize / 1024).toFixed(2);
289
- console.log(`[reroute] Built ${originalPath} -> ${sizeKB} KB (${gzippedKB} KB gzipped)`);
290
- return bundleInfo;
291
- }
292
- async function getBundleUrlsFor(modules, clientDir, prefix, options, bundleCache) {
293
- const mods = Array.isArray(modules) ? modules : [modules];
294
- const urls = [];
295
- const { join: join3 } = await Promise.resolve().then(() => exports_path);
296
- for (const mod of mods) {
297
- const rel = mod.replace(/^\.\//, "");
298
- const fullPath = join3(clientDir, rel);
299
- try {
300
- const bundleInfo = await transpileFile(fullPath, rel, options, bundleCache);
301
- const base = basename(rel, extname(rel));
302
- const entryUrl = `${prefix}/${base}.${bundleInfo.hash}.js`;
303
- urls.push(entryUrl);
304
- try {
305
- const depNames = Array.isArray(bundleInfo.chunks) ? bundleInfo.chunks.map((c) => c.fileName).filter((name) => new RegExp(`["'\`]((?:\\./)?${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})["'\`]`, "g").test(bundleInfo.code)) : [];
306
- const depUrls = depNames.map((n) => `${prefix}/${n}`.replace(/\/+/g, "/"));
307
- entryUrlToStaticDeps.set(entryUrl, depUrls);
308
- } catch {}
309
- } catch (error) {
310
- console.error(`[reroute] Error getting bundle URL for ${rel}:`, error);
311
- urls.push(`${prefix}/${rel}`);
312
- }
313
- }
314
- return urls;
315
- }
316
- function getStaticDepsForUrl(entryUrl) {
317
- return entryUrlToStaticDeps.get(entryUrl) || [];
34
+ return Array.from(collections);
318
35
  }
319
- // packages/core/src/content/discovery.ts
320
- import { readdir, stat as stat2 } from "node:fs/promises";
321
-
322
36
  // packages/core/src/content/metadata.ts
323
- import { stat } from "node:fs/promises";
324
- import { pathToFileURL } from "node:url";
325
- async function getContentMeta(absPath, isWatchMode2) {
326
- try {
327
- const url = pathToFileURL(absPath).href;
328
- const mod = await import(`${url}${isWatchMode2 ? `?t=${Date.now()}` : ""}`);
329
- const meta = mod.meta || mod.frontmatter || {};
330
- if (meta && typeof meta === "object")
331
- return meta;
332
- return {};
333
- } catch {
334
- try {
335
- const s = await stat(absPath);
336
- return { date: new Date(s.mtimeMs).toISOString() };
337
- } catch {
338
- return {};
339
- }
340
- }
341
- }
342
37
  function buildHeadFromMeta(meta) {
343
38
  if (!meta || typeof meta !== "object")
344
39
  return "";
@@ -356,84 +51,13 @@ ${parts.join(`
356
51
  function escapeHtml(input) {
357
52
  return input.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
358
53
  }
359
-
360
- // packages/core/src/content/discovery.ts
361
- async function listContentFiles(dir, baseRel) {
362
- const out = [];
363
- try {
364
- const entries = await readdir(dir, { withFileTypes: true });
365
- for (const entry of entries) {
366
- const full = join2(dir, entry.name);
367
- const rel = join2(baseRel, entry.name);
368
- if (entry.isDirectory()) {
369
- const nested = await listContentFiles(full, rel);
370
- out.push(...nested);
371
- } else if (entry.isFile()) {
372
- if (/\.(tsx|ts)$/.test(entry.name) && !entry.name.startsWith("_")) {
373
- out.push(rel);
374
- }
375
- }
376
- }
377
- } catch {}
378
- return out;
379
- }
380
- async function buildContentDTOs(collectionPath, clientDir, prefix, isWatchMode2) {
381
- const normalized = stripStart(stripEnd(collectionPath, "/"), "/");
382
- const contentRelDir = join2("routes", normalized, "content");
383
- const contentAbsDir = join2(clientDir, contentRelDir);
384
- const files = await listContentFiles(contentAbsDir, "");
385
- const items = [];
386
- for (const rel of files) {
387
- const fullRelPath = join2(contentRelDir, rel);
388
- const absPath = join2(clientDir, fullRelPath);
389
- const noExt = rel.replace(/\.(tsx|ts)$/, "");
390
- const name = basename(noExt);
391
- const moduleUrl = `${prefix}/${fullRelPath}`.replace(/\/+/g, "/");
392
- const meta = await getContentMeta(absPath, isWatchMode2);
393
- const href = `/${normalized}/${name}`.replace(/\\+/g, "/");
394
- items.push({
395
- slug: noExt,
396
- name,
397
- path: fullRelPath,
398
- module: moduleUrl,
399
- meta,
400
- href
401
- });
402
- }
403
- return items;
404
- }
405
- async function discoverCollections(clientDir) {
406
- const root = join2(clientDir, "routes");
407
- const collections = new Set;
408
- try {
409
- const entries = await readdir(root, { withFileTypes: true });
410
- for (const entry of entries) {
411
- if (entry.isDirectory()) {
412
- const contentDir = join2(root, entry.name, "content");
413
- try {
414
- await stat2(contentDir);
415
- collections.add(entry.name);
416
- } catch {}
417
- }
418
- }
419
- } catch {}
420
- return Array.from(collections);
421
- }
422
- // packages/core/src/content/registry.ts
423
- async function generateContentRegistry(cwd) {
424
- try {
425
- const p = join2(cwd, ".reroute", "content.ts");
426
- const exists = await Bun.file(p).exists();
427
- console.log(exists ? "[reroute] Content registry up-to-date" : "[reroute] Warning: .reroute/content.ts not found");
428
- } catch {}
429
- }
430
54
  // packages/core/src/ssr/data.ts
431
- import { pathToFileURL as pathToFileURL3 } from "node:url";
55
+ import { pathToFileURL as pathToFileURL2 } from "node:url";
432
56
 
433
57
  // packages/core/src/ssr/modules.ts
434
- import { readdir as readdir2, stat as stat3 } from "node:fs/promises";
435
- import { pathToFileURL as pathToFileURL2 } from "node:url";
436
- async function importContentModuleForPath(pathname, clientDir, cwd, isWatchMode2) {
58
+ import { readdir as readdir2, stat as stat2 } from "node:fs/promises";
59
+ import { pathToFileURL } from "node:url";
60
+ async function importContentModuleForPath(pathname, clientDir, cwd, isWatchMode) {
437
61
  try {
438
62
  const parts = pathname.split("/").filter(Boolean);
439
63
  if (parts.length < 2)
@@ -441,20 +65,20 @@ async function importContentModuleForPath(pathname, clientDir, cwd, isWatchMode2
441
65
  const collection = parts[0];
442
66
  const name = parts[1];
443
67
  try {
444
- const registryPath = join2(cwd, ".reroute", "content.ts");
445
- const reg = await import(pathToFileURL2(registryPath).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
68
+ const registryPath = join(cwd, ".reroute", "content.ts");
69
+ const reg = await import(pathToFileURL(registryPath).href + (isWatchMode ? `?t=${Date.now()}` : ""));
446
70
  const get = reg?.getContentEntry;
447
71
  const entry = typeof get === "function" ? get(collection, name) : undefined;
448
72
  const moduleUrl = entry?.module;
449
73
  if (moduleUrl?.endsWith(".js")) {
450
- const abs = join2(cwd, moduleUrl.replace(/^\//, ""));
451
- const href = pathToFileURL2(abs).href + (isWatchMode2 ? `?t=${Date.now()}` : "");
74
+ const abs = join(cwd, moduleUrl.replace(/^\//, ""));
75
+ const href = pathToFileURL(abs).href + (isWatchMode ? `?t=${Date.now()}` : "");
452
76
  const mod = await import(href);
453
77
  return mod;
454
78
  }
455
79
  } catch {}
456
80
  try {
457
- const chunkDir = join2(cwd, ".reroute", "chunks", collection);
81
+ const chunkDir = join(cwd, ".reroute", "chunks", collection);
458
82
  const files = await readdir2(chunkDir);
459
83
  const matches = files.filter((n) => n.startsWith(`${name}.`) && n.endsWith(".js"));
460
84
  if (matches.length) {
@@ -462,30 +86,30 @@ async function importContentModuleForPath(pathname, clientDir, cwd, isWatchMode2
462
86
  let latestM = 0;
463
87
  for (const f of matches) {
464
88
  try {
465
- const s = await stat3(join2(chunkDir, f));
89
+ const s = await stat2(join(chunkDir, f));
466
90
  if (s.mtimeMs >= latestM) {
467
91
  latestM = s.mtimeMs;
468
92
  latest = f;
469
93
  }
470
94
  } catch {}
471
95
  }
472
- const absChunk = join2(chunkDir, latest);
473
- const href = pathToFileURL2(absChunk).href + (isWatchMode2 ? `?t=${Date.now()}` : "");
96
+ const absChunk = join(chunkDir, latest);
97
+ const href = pathToFileURL(absChunk).href + (isWatchMode ? `?t=${Date.now()}` : "");
474
98
  const mod = await import(href);
475
99
  return mod;
476
100
  }
477
101
  } catch {}
478
102
  try {
479
- const srcTsx = join2(clientDir, "routes", collection, "content", `${name}.tsx`);
480
- const srcTs = join2(clientDir, "routes", collection, "content", `${name}.ts`);
103
+ const srcTsx = join(clientDir, "routes", collection, "content", `${name}.tsx`);
104
+ const srcTs = join(clientDir, "routes", collection, "content", `${name}.ts`);
481
105
  let absSrc = null;
482
106
  if (await Bun.file(srcTsx).exists())
483
107
  absSrc = srcTsx;
484
108
  else if (await Bun.file(srcTs).exists())
485
109
  absSrc = srcTs;
486
110
  if (absSrc) {
487
- const href = pathToFileURL2(absSrc).href;
488
- const mod = await (isWatchMode2 ? import(`${href}?t=${Date.now()}`) : import(href));
111
+ const href = pathToFileURL(absSrc).href;
112
+ const mod = await (isWatchMode ? import(`${href}?t=${Date.now()}`) : import(href));
489
113
  return mod;
490
114
  }
491
115
  } catch {}
@@ -494,7 +118,7 @@ async function importContentModuleForPath(pathname, clientDir, cwd, isWatchMode2
494
118
  }
495
119
 
496
120
  // packages/core/src/ssr/seed.ts
497
- async function seedSSRModuleForPath(pathname, clientDir, cwd, isWatchMode2) {
121
+ async function seedSSRModuleForPath(pathname, clientDir, cwd, isWatchMode) {
498
122
  try {
499
123
  const parts = pathname.split("/").filter(Boolean);
500
124
  if (parts.length < 2)
@@ -502,7 +126,7 @@ async function seedSSRModuleForPath(pathname, clientDir, cwd, isWatchMode2) {
502
126
  const collection = parts[0];
503
127
  const name = parts[1];
504
128
  const key = `${collection}:${name}`;
505
- const mod = await importContentModuleForPath(pathname, clientDir, cwd, isWatchMode2);
129
+ const mod = await importContentModuleForPath(pathname, clientDir, cwd, isWatchMode);
506
130
  if (!mod)
507
131
  return;
508
132
  const C = mod.default || mod;
@@ -522,9 +146,9 @@ async function seedSSRModuleForPath(pathname, clientDir, cwd, isWatchMode2) {
522
146
 
523
147
  // packages/core/src/ssr/data.ts
524
148
  async function computeSSRDataForPath(params) {
525
- const { pathname, clientDir, cwd, isWatchMode: isWatchMode2 } = params;
149
+ const { pathname, clientDir, cwd, isWatchMode } = params;
526
150
  try {
527
- await seedSSRModuleForPath(pathname, clientDir, cwd, isWatchMode2);
151
+ await seedSSRModuleForPath(pathname, clientDir, cwd, isWatchMode);
528
152
  } catch {}
529
153
  try {
530
154
  const parts = pathname.split("/").filter(Boolean);
@@ -539,15 +163,15 @@ async function computeSSRDataForPath(params) {
539
163
  }
540
164
  } catch {}
541
165
  try {
542
- const routesPath = join2(cwd, ".reroute", "routes.ts");
543
- const m = await import(pathToFileURL3(routesPath).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
166
+ const routesPath = join(cwd, ".reroute", "routes.ts");
167
+ const m = await import(pathToFileURL2(routesPath).href + (isWatchMode ? `?t=${Date.now()}` : ""));
544
168
  const match = typeof m.matchRoute === "function" ? m.matchRoute(pathname) : null;
545
169
  const r = match?.route;
546
170
  const paramsValue = match?.params || {};
547
171
  if (r && typeof r.path === "string") {
548
172
  try {
549
- const abs = join2(clientDir, "routes", String(r.path));
550
- const mod = await import(pathToFileURL3(abs).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
173
+ const abs = join(clientDir, "routes", String(r.path));
174
+ const mod = await import(pathToFileURL2(abs).href + (isWatchMode ? `?t=${Date.now()}` : ""));
551
175
  const ssr = mod?.ssr;
552
176
  const dataFn = ssr?.data;
553
177
  if (typeof dataFn === "function") {
@@ -559,10 +183,10 @@ async function computeSSRDataForPath(params) {
559
183
  return null;
560
184
  }
561
185
  // packages/core/src/ssr/render.ts
562
- import { readdir as readdir3, stat as stat4 } from "node:fs/promises";
563
- import { pathToFileURL as pathToFileURL4 } from "node:url";
186
+ import { readdir as readdir3, stat as stat3 } from "node:fs/promises";
187
+ import { pathToFileURL as pathToFileURL3 } from "node:url";
564
188
 
565
- // node_modules/dedent/dist/dedent.mjs
189
+ // node_modules/.bun/dedent@1.7.0/node_modules/dedent/dist/dedent.mjs
566
190
  function ownKeys(object, enumerableOnly) {
567
191
  var keys = Object.keys(object);
568
192
  if (Object.getOwnPropertySymbols) {
@@ -684,7 +308,7 @@ import { renderToString } from "react-dom/server";
684
308
 
685
309
  // packages/core/src/template/html.ts
686
310
  async function loadIndexHtml(clientDir) {
687
- const templatePath = join2(clientDir, "index.html");
311
+ const templatePath = join(clientDir, "index.html");
688
312
  try {
689
313
  const content = await Bun.file(templatePath).text();
690
314
  return content;
@@ -761,7 +385,7 @@ async function renderSSRDocument(options) {
761
385
  rootComponent,
762
386
  clientDir,
763
387
  cwd,
764
- isWatchMode: isWatchMode2,
388
+ isWatchMode,
765
389
  bundleUrl,
766
390
  head = "",
767
391
  lang = "en",
@@ -777,15 +401,6 @@ async function renderSSRDocument(options) {
777
401
  <link rel="modulepreload" href="${bundleUrl}" />`;
778
402
  }
779
403
  } catch {}
780
- try {
781
- const staticDeps = getStaticDepsForUrl(bundleUrl);
782
- if (Array.isArray(staticDeps) && staticDeps.length) {
783
- for (const dep of staticDeps) {
784
- extraHead += `
785
- <link rel="modulepreload" href="${dep}" />`;
786
- }
787
- }
788
- } catch {}
789
404
  let statusOverride;
790
405
  try {
791
406
  globalThis.__REROUTE_SSR_ACCESSED__ = {};
@@ -798,8 +413,8 @@ async function renderSSRDocument(options) {
798
413
  let modulePath = "";
799
414
  let isContentCollection = false;
800
415
  try {
801
- const maybeDir = join2(clientDir, "routes", collection, "content");
802
- const s = await stat4(maybeDir);
416
+ const maybeDir = join(clientDir, "routes", collection, "content");
417
+ const s = await stat3(maybeDir);
803
418
  isContentCollection = typeof s?.isDirectory === "function" ? s.isDirectory() : true;
804
419
  } catch {
805
420
  isContentCollection = false;
@@ -808,8 +423,8 @@ async function renderSSRDocument(options) {
808
423
  throw new Error("skip-content-preload");
809
424
  }
810
425
  try {
811
- const registryPath = join2(cwd, ".reroute", "content.ts");
812
- const reg = await import(pathToFileURL4(registryPath).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
426
+ const registryPath = join(cwd, ".reroute", "content.ts");
427
+ const reg = await import(pathToFileURL3(registryPath).href + (isWatchMode ? `?t=${Date.now()}` : ""));
813
428
  const get = reg?.getContentEntry;
814
429
  const entry = typeof get === "function" ? get(collection, name) : undefined;
815
430
  const moduleUrl = entry?.module;
@@ -819,7 +434,7 @@ async function renderSSRDocument(options) {
819
434
  } catch {}
820
435
  if (!modulePath) {
821
436
  try {
822
- const chunkDir = join2(cwd, ".reroute", "chunks", collection);
437
+ const chunkDir = join(cwd, ".reroute", "chunks", collection);
823
438
  const files = await readdir3(chunkDir);
824
439
  const candidates = files.filter((n) => n.startsWith(`${name}.`) && n.endsWith(".js"));
825
440
  if (candidates.length) {
@@ -827,25 +442,25 @@ async function renderSSRDocument(options) {
827
442
  let latestM = 0;
828
443
  for (const candidateName of candidates) {
829
444
  try {
830
- const s = await stat4(join2(chunkDir, candidateName));
445
+ const s = await stat3(join(chunkDir, candidateName));
831
446
  if (s.mtimeMs >= latestM) {
832
447
  latestM = s.mtimeMs;
833
448
  latest = candidateName;
834
449
  }
835
450
  } catch {}
836
451
  }
837
- modulePath = `/${join2(".reroute", "chunks", collection, latest).replace(/\\+/g, "/")}`;
452
+ modulePath = `/${join(".reroute", "chunks", collection, latest).replace(/\\+/g, "/")}`;
838
453
  }
839
454
  } catch {}
840
455
  }
841
456
  if (!modulePath) {
842
- const tsx = join2(clientDir, "routes", collection, "content", `${name}.tsx`);
843
- const ts = join2(clientDir, "routes", collection, "content", `${name}.ts`);
457
+ const tsx = join(clientDir, "routes", collection, "content", `${name}.tsx`);
458
+ const ts = join(clientDir, "routes", collection, "content", `${name}.ts`);
844
459
  let srcUrl = "";
845
460
  if (await Bun.file(tsx).exists()) {
846
- srcUrl = `/${join2("routes", collection, "content", `${name}.tsx`).replace(/\\+/g, "/")}`;
461
+ srcUrl = `/${join("routes", collection, "content", `${name}.tsx`).replace(/\\+/g, "/")}`;
847
462
  } else if (await Bun.file(ts).exists()) {
848
- srcUrl = `/${join2("routes", collection, "content", `${name}.ts`).replace(/\\+/g, "/")}`;
463
+ srcUrl = `/${join("routes", collection, "content", `${name}.ts`).replace(/\\+/g, "/")}`;
849
464
  }
850
465
  if (srcUrl) {
851
466
  modulePath = srcUrl;
@@ -863,7 +478,7 @@ async function renderSSRDocument(options) {
863
478
  }
864
479
  }
865
480
  } catch {}
866
- await seedSSRModuleForPath(pathname, clientDir, cwd, isWatchMode2);
481
+ await seedSSRModuleForPath(pathname, clientDir, cwd, isWatchMode);
867
482
  const __SSR_DATA__ = {};
868
483
  try {
869
484
  try {
@@ -883,15 +498,15 @@ async function renderSSRDocument(options) {
883
498
  }
884
499
  } catch {}
885
500
  try {
886
- const routesPath = join2(cwd, ".reroute", "routes.ts");
887
- const m = await import(pathToFileURL4(routesPath).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
501
+ const routesPath = join(cwd, ".reroute", "routes.ts");
502
+ const m = await import(pathToFileURL3(routesPath).href + (isWatchMode ? `?t=${Date.now()}` : ""));
888
503
  const match = typeof m.matchRoute === "function" ? m.matchRoute(pathname) : null;
889
504
  const r = match?.route;
890
505
  const params = match?.params || {};
891
506
  if (r && typeof r.path === "string") {
892
507
  try {
893
- const abs = join2(clientDir, "routes", String(r.path));
894
- const mod = await import(pathToFileURL4(abs).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
508
+ const abs = join(clientDir, "routes", String(r.path));
509
+ const mod = await import(pathToFileURL3(abs).href + (isWatchMode ? `?t=${Date.now()}` : ""));
895
510
  const ssr = mod?.ssr;
896
511
  const dataFn = ssr?.data;
897
512
  if (typeof dataFn === "function") {
@@ -907,8 +522,8 @@ async function renderSSRDocument(options) {
907
522
  } catch {}
908
523
  let __byCollectionForSSR = {};
909
524
  try {
910
- const p = join2(cwd, ".reroute", "content.ts");
911
- const mod = await import(pathToFileURL4(p).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
525
+ const p = join(cwd, ".reroute", "content.ts");
526
+ const mod = await import(pathToFileURL3(p).href + (isWatchMode ? `?t=${Date.now()}` : ""));
912
527
  __byCollectionForSSR = mod?.byCollection || {};
913
528
  try {
914
529
  globalThis.__REROUTE_COLLECTIONS__ = __byCollectionForSSR;
@@ -922,10 +537,10 @@ async function renderSSRDocument(options) {
922
537
  let inlineStyleTag = "";
923
538
  try {
924
539
  const candidates = [
925
- join2(clientDir, "..", ".reroute", "theme.css"),
926
- join2(clientDir, "..", "..", ".reroute", "theme.css"),
927
- join2(clientDir, "..", "..", "..", ".reroute", "theme.css"),
928
- join2(clientDir, "..", "..", "..", "..", ".reroute", "theme.css")
540
+ join(clientDir, "..", ".reroute", "theme.css"),
541
+ join(clientDir, "..", "..", ".reroute", "theme.css"),
542
+ join(clientDir, "..", "..", "..", ".reroute", "theme.css"),
543
+ join(clientDir, "..", "..", "..", "..", ".reroute", "theme.css")
929
544
  ];
930
545
  let cssPath = "";
931
546
  for (const p of candidates) {
@@ -1008,7 +623,7 @@ async function renderSSRDocument(options) {
1008
623
  </script>`;
1009
624
  } catch {}
1010
625
  hydrationScript += scripts.map((src) => `<script type="module" src="${src}"></script>`).join("");
1011
- if (isWatchMode2) {
626
+ if (isWatchMode) {
1012
627
  hydrationScript += `<script type="module" src="/__reroute_watch.js"></script>`;
1013
628
  }
1014
629
  let perPageHead = "";
@@ -1033,8 +648,8 @@ ${ssrHead}`;
1033
648
  }
1034
649
  } catch {}
1035
650
  try {
1036
- const routesPath = join2(cwd, ".reroute", "routes.ts");
1037
- const m = await import(pathToFileURL4(routesPath).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
651
+ const routesPath = join(cwd, ".reroute", "routes.ts");
652
+ const m = await import(pathToFileURL3(routesPath).href + (isWatchMode ? `?t=${Date.now()}` : ""));
1038
653
  const match = typeof m.matchRoute === "function" ? m.matchRoute(pathname) : null;
1039
654
  const r = match?.route;
1040
655
  if (!r) {
@@ -1042,8 +657,8 @@ ${ssrHead}`;
1042
657
  }
1043
658
  if (r && typeof r.path === "string") {
1044
659
  try {
1045
- const abs = join2(clientDir, "routes", String(r.path));
1046
- const mod = await import(pathToFileURL4(abs).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
660
+ const abs = join(clientDir, "routes", String(r.path));
661
+ const mod = await import(pathToFileURL3(abs).href + (isWatchMode ? `?t=${Date.now()}` : ""));
1047
662
  const meta = mod?.meta;
1048
663
  const ssr = mod?.ssr;
1049
664
  if (meta)
@@ -1077,8 +692,8 @@ ${ssrHead}`;
1077
692
  }
1078
693
  if (chosen && typeof chosen.path === "string") {
1079
694
  try {
1080
- const abs = join2(clientDir, "routes", String(chosen.path));
1081
- const mod = await import(pathToFileURL4(abs).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
695
+ const abs = join(clientDir, "routes", String(chosen.path));
696
+ const mod = await import(pathToFileURL3(abs).href + (isWatchMode ? `?t=${Date.now()}` : ""));
1082
697
  const meta = mod?.meta;
1083
698
  const ssr = mod?.ssr;
1084
699
  if (meta)
@@ -1261,10 +876,8 @@ function jsonError(message, status = 500) {
1261
876
  }
1262
877
 
1263
878
  // packages/elysia/src/libs/image.ts
1264
- import { createHash } from "node:crypto";
1265
- import { existsSync as existsSync2 } from "node:fs";
1266
- import { mkdir, readFile, writeFile } from "node:fs/promises";
1267
- import { join as join3 } from "node:path";
879
+ import { existsSync } from "node:fs";
880
+ import { join as join2 } from "node:path";
1268
881
  import sharp from "sharp";
1269
882
  var imageCache = new Map;
1270
883
  var MAX_CACHE_SIZE = 100;
@@ -1274,7 +887,9 @@ function initImageCache(cacheDir) {
1274
887
  }
1275
888
  function getCacheKey(imagePath, options) {
1276
889
  const optionsString = JSON.stringify(options);
1277
- const hash2 = createHash("sha256").update(`${imagePath}:${optionsString}`).digest("hex");
890
+ const hasher = new Bun.CryptoHasher("sha256");
891
+ hasher.update(`${imagePath}:${optionsString}`);
892
+ const hash2 = hasher.digest("hex");
1278
893
  return hash2;
1279
894
  }
1280
895
  function getContentType(format) {
@@ -1305,13 +920,13 @@ async function loadFromDiskCache(cacheKey) {
1305
920
  if (!diskCacheDir)
1306
921
  return null;
1307
922
  try {
1308
- const cachePath = join3(diskCacheDir, `${cacheKey}.json`);
1309
- const imagePath = join3(diskCacheDir, `${cacheKey}.img`);
1310
- if (!existsSync2(cachePath) || !existsSync2(imagePath)) {
923
+ const cachePath = join2(diskCacheDir, `${cacheKey}.json`);
924
+ const imagePath = join2(diskCacheDir, `${cacheKey}.img`);
925
+ if (!existsSync(cachePath) || !existsSync(imagePath)) {
1311
926
  return null;
1312
927
  }
1313
- const metadata2 = JSON.parse(await readFile(cachePath, "utf-8"));
1314
- const buffer = await readFile(imagePath);
928
+ const metadata2 = JSON.parse(await Bun.file(cachePath).text());
929
+ const buffer = Buffer.from(await Bun.file(imagePath).arrayBuffer());
1315
930
  return {
1316
931
  buffer,
1317
932
  contentType: metadata2.contentType,
@@ -1328,17 +943,16 @@ async function saveToDiskCache(cacheKey, result) {
1328
943
  if (!diskCacheDir)
1329
944
  return;
1330
945
  try {
1331
- await mkdir(diskCacheDir, { recursive: true });
1332
- const cachePath = join3(diskCacheDir, `${cacheKey}.json`);
1333
- const imagePath = join3(diskCacheDir, `${cacheKey}.img`);
1334
- await writeFile(cachePath, JSON.stringify({
946
+ const cachePath = join2(diskCacheDir, `${cacheKey}.json`);
947
+ const imagePath = join2(diskCacheDir, `${cacheKey}.img`);
948
+ await Bun.write(cachePath, JSON.stringify({
1335
949
  contentType: result.contentType,
1336
950
  format: result.format,
1337
951
  width: result.width,
1338
952
  height: result.height,
1339
953
  size: result.size
1340
954
  }));
1341
- await writeFile(imagePath, result.buffer);
955
+ await Bun.write(imagePath, result.buffer);
1342
956
  } catch (error) {
1343
957
  console.error("Failed to save image to disk cache:", error);
1344
958
  }
@@ -1369,7 +983,7 @@ async function optimizeImage(imagePath, options, acceptHeader) {
1369
983
  const arrayBuffer = await response.arrayBuffer();
1370
984
  sourceBuffer = Buffer.from(arrayBuffer);
1371
985
  } else {
1372
- sourceBuffer = await readFile(imagePath);
986
+ sourceBuffer = Buffer.from(await Bun.file(imagePath).arrayBuffer());
1373
987
  }
1374
988
  const format = options.format === "auto" || !options.format ? negotiateFormat(acceptHeader, undefined) : options.format;
1375
989
  let transformer = sharp(sourceBuffer);
@@ -1439,31 +1053,72 @@ function isImageFile(path2) {
1439
1053
 
1440
1054
  // packages/elysia/src/routes/artifacts.ts
1441
1055
  import { NotFoundError } from "elysia";
1442
- function registerArtifactsRoutes(app, cwd) {
1443
- app.get("/.reroute/*", async ({ params, headers }) => {
1444
- const sub = String(params["*"] || "").replace(/^\/+/, "");
1445
- if (!sub)
1056
+
1057
+ // packages/elysia/src/libs/cache.ts
1058
+ function getEncoding(acceptEncoding) {
1059
+ return /\bbr\b/i.test(acceptEncoding) ? "br" : /gzip/i.test(acceptEncoding) ? "gz" : "raw";
1060
+ }
1061
+
1062
+ // packages/elysia/src/routes/artifacts.ts
1063
+ async function serveStaticFile(filePath, headers, fileCache, cacheControl) {
1064
+ const acceptEncoding = headers["accept-encoding"] || "";
1065
+ const encoding = getEncoding(acceptEncoding);
1066
+ const cacheKey = `${filePath}:${encoding}`;
1067
+ const cached = fileCache.get(cacheKey);
1068
+ if (cached)
1069
+ return cached.clone();
1070
+ const exists = await Bun.file(filePath).exists();
1071
+ if (!exists)
1072
+ throw new NotFoundError;
1073
+ const buf = await Bun.file(filePath).arrayBuffer();
1074
+ const content2 = new Uint8Array(buf);
1075
+ const contentType = getMimeType(filePath);
1076
+ const { body, extraHeaders } = gzipIfAccepted(content2, contentType, headers["accept-encoding"]);
1077
+ const response = new Response(body, {
1078
+ headers: {
1079
+ "Content-Type": contentType,
1080
+ "Cache-Control": cacheControl,
1081
+ ...extraHeaders
1082
+ }
1083
+ });
1084
+ fileCache.set(cacheKey, response);
1085
+ return response.clone();
1086
+ }
1087
+ function registerArtifactsRoutes(app, cwd, fileCache, options) {
1088
+ const { bundleMaxAge, directive, isWatchMode = false } = options;
1089
+ app.get("/bundles/*", async ({ params, headers }) => {
1090
+ const fileName = String(params["*"] || "").replace(/^\/+/, "");
1091
+ if (!fileName)
1446
1092
  throw new NotFoundError;
1447
- const abs = join2(cwd, ".reroute", sub);
1093
+ const filePath = join(cwd, ".reroute", "bundles", fileName);
1448
1094
  try {
1449
- const exists = await Bun.file(abs).exists();
1450
- if (!exists)
1451
- throw new NotFoundError;
1452
- const buf = await Bun.file(abs).arrayBuffer();
1453
- const content2 = new Uint8Array(buf);
1454
- const contentType = getMimeType(abs);
1455
- const { body, extraHeaders } = gzipIfAccepted(content2, contentType, headers["accept-encoding"]);
1456
- return new Response(body, {
1457
- headers: {
1458
- "Content-Type": contentType,
1459
- "Cache-Control": "public, max-age=31536000, immutable",
1460
- ...extraHeaders
1461
- }
1462
- });
1095
+ let cacheControl;
1096
+ if (isWatchMode) {
1097
+ cacheControl = "no-cache, no-store, must-revalidate";
1098
+ } else {
1099
+ const isContentHashed = /\.([a-z0-9]{8,})\.(js|css)$/i.test(fileName);
1100
+ cacheControl = isContentHashed ? "public, max-age=31536000, immutable" : bundleMaxAge > 0 ? `${directive}, max-age=${bundleMaxAge}` : "no-cache";
1101
+ }
1102
+ return await serveStaticFile(filePath, headers, fileCache, cacheControl);
1463
1103
  } catch (e) {
1464
1104
  if (e instanceof NotFoundError)
1465
1105
  throw e;
1466
- console.error("[reroute] Failed to serve .reroute file:", abs, e);
1106
+ console.error("[reroute] Failed to serve bundle:", filePath, e);
1107
+ throw new NotFoundError;
1108
+ }
1109
+ });
1110
+ app.get("/.reroute/collections/*", async ({ params, headers }) => {
1111
+ const fileName = String(params["*"] || "").replace(/^\/+/, "");
1112
+ if (!fileName)
1113
+ throw new NotFoundError;
1114
+ const filePath = join(cwd, ".reroute", "collections", fileName);
1115
+ try {
1116
+ const cacheControl = isWatchMode ? "no-cache, no-store, must-revalidate" : "public, max-age=31536000, immutable";
1117
+ return await serveStaticFile(filePath, headers, fileCache, cacheControl);
1118
+ } catch (e) {
1119
+ if (e instanceof NotFoundError)
1120
+ throw e;
1121
+ console.error("[reroute] Failed to serve collection file:", filePath, e);
1467
1122
  throw new NotFoundError;
1468
1123
  }
1469
1124
  });
@@ -1472,23 +1127,46 @@ function registerArtifactsRoutes(app, cwd) {
1472
1127
 
1473
1128
  // packages/elysia/src/routes/content.ts
1474
1129
  import { NotFoundError as NotFoundError2 } from "elysia";
1475
- function registerContentRoutes(app, clientDir, prefix, isWatchMode2) {
1476
- app.get("/__content/*", async ({ params, set }) => {
1130
+ function registerContentRoutes(app, cwd, collectionCache, directive, maxAge, isWatchMode) {
1131
+ app.get("/__content/*", async ({ params }) => {
1477
1132
  const collectionPath = String(params["*"] || "").trim();
1478
1133
  if (!collectionPath)
1479
1134
  throw new NotFoundError2;
1480
- const items = await buildContentDTOs(collectionPath, clientDir, prefix, isWatchMode2);
1481
- const body = JSON.stringify({ collection: collectionPath, items });
1482
- set.status = 200;
1483
- set.headers["content-type"] = "application/json; charset=utf-8";
1484
- return new Response(body);
1135
+ const cacheKey = `content:${collectionPath}`;
1136
+ const cached = collectionCache.get(cacheKey);
1137
+ if (cached)
1138
+ return cached.clone();
1139
+ try {
1140
+ const collectionFile = join(cwd, ".reroute", "collections", `${collectionPath}.js`);
1141
+ const exists = await Bun.file(collectionFile).exists();
1142
+ if (!exists)
1143
+ throw new NotFoundError2;
1144
+ const url = `${Bun.pathToFileURL(collectionFile).href}${isWatchMode ? `?t=${Date.now()}` : ""}`;
1145
+ const mod = await import(url);
1146
+ const items = mod.items || [];
1147
+ const body = JSON.stringify({ collection: collectionPath, items });
1148
+ const response = new Response(body, {
1149
+ status: 200,
1150
+ headers: {
1151
+ "content-type": "application/json; charset=utf-8",
1152
+ "cache-control": `${directive}, max-age=${maxAge}`
1153
+ }
1154
+ });
1155
+ collectionCache.set(cacheKey, response);
1156
+ return response.clone();
1157
+ } catch (e) {
1158
+ if (e instanceof NotFoundError2)
1159
+ throw e;
1160
+ console.error(`[reroute] Failed to serve collection ${collectionPath}:`, e);
1161
+ throw new NotFoundError2;
1162
+ }
1485
1163
  });
1486
1164
  return app;
1487
1165
  }
1488
1166
 
1489
1167
  // packages/elysia/src/routes/dev.ts
1490
1168
  import { NotFoundError as NotFoundError3 } from "elysia";
1491
- function registerDevRoutes(app, liveReloadClients, isWatchMode2, opts) {
1169
+ function registerDevRoutes(app, liveReloadClients, isWatchMode, opts) {
1492
1170
  app.get("/__reroute_preload", async ({ query }) => {
1493
1171
  const rawSrc = String(query.src || "").trim();
1494
1172
  const key = String(query.key || "").trim();
@@ -1507,10 +1185,11 @@ function registerDevRoutes(app, liveReloadClients, isWatchMode2, opts) {
1507
1185
  ` + `(globalThis.__REROUTE_MODULES__ ||= {});
1508
1186
  ` + `globalThis.__REROUTE_MODULES__['${key}'] = __C;
1509
1187
  ` + `export {};`;
1188
+ const cacheControl = isWatchMode ? "no-cache, no-store, must-revalidate" : "public, max-age=31536000, immutable";
1510
1189
  return new Response(code, {
1511
1190
  headers: {
1512
1191
  "content-type": "application/javascript; charset=utf-8",
1513
- "cache-control": isWatchMode2 ? "no-cache" : "public, max-age=31536000, immutable"
1192
+ "cache-control": cacheControl
1514
1193
  }
1515
1194
  });
1516
1195
  });
@@ -1524,13 +1203,13 @@ function registerDevRoutes(app, liveReloadClients, isWatchMode2, opts) {
1524
1203
  pathname = String(p);
1525
1204
  }
1526
1205
  try {
1527
- let data2 = isWatchMode2 ? undefined : opts?.dataCache?.get(pathname);
1206
+ let data2 = opts?.dataCache?.get(pathname);
1528
1207
  if (data2 === undefined) {
1529
1208
  data2 = await computeSSRDataForPath({
1530
1209
  pathname,
1531
1210
  clientDir: opts?.clientDir || "",
1532
1211
  cwd: opts?.cwd || "",
1533
- isWatchMode: isWatchMode2
1212
+ isWatchMode
1534
1213
  });
1535
1214
  opts?.dataCache?.set(pathname, data2);
1536
1215
  }
@@ -1539,7 +1218,7 @@ function registerDevRoutes(app, liveReloadClients, isWatchMode2, opts) {
1539
1218
  return jsonError("failed", 500);
1540
1219
  }
1541
1220
  });
1542
- if (!isWatchMode2)
1221
+ if (!isWatchMode)
1543
1222
  return app;
1544
1223
  console.log("[reroute] Registering SSE endpoint at /__reroute_watch");
1545
1224
  app.get("/__reroute_watch", () => {
@@ -1583,7 +1262,7 @@ function registerDevRoutes(app, liveReloadClients, isWatchMode2, opts) {
1583
1262
  ` + `function waitServerThenReload(){
1584
1263
  ` + ` const ping = () => fetch(location.origin, { cache: 'no-store' })
1585
1264
  ` + ` .then(()=>location.reload())
1586
- ` + ` .catch(()=>setTimeout(ping, 300));
1265
+ ` + ` .catch(()=>setTimeout(ping, 50));
1587
1266
  ` + ` ping();
1588
1267
  ` + `}
1589
1268
  ` + `function connect(){
@@ -1605,8 +1284,8 @@ export {};`;
1605
1284
  }
1606
1285
 
1607
1286
  // packages/elysia/src/routes/image.ts
1608
- import { existsSync as existsSync3 } from "node:fs";
1609
- import { join as join4 } from "node:path";
1287
+ import { existsSync as existsSync2 } from "node:fs";
1288
+ import { join as join3 } from "node:path";
1610
1289
  function registerImageRoutes(app, options) {
1611
1290
  const {
1612
1291
  clientDir,
@@ -1654,13 +1333,13 @@ function registerImageRoutes(app, options) {
1654
1333
  imagePath = url;
1655
1334
  } else {
1656
1335
  const cleanUrl = url.startsWith("/") ? url.slice(1) : url;
1657
- imagePath = join4(clientDir, cleanUrl);
1658
- const normalizedPath = join4(clientDir, cleanUrl);
1336
+ imagePath = join3(clientDir, cleanUrl);
1337
+ const normalizedPath = join3(clientDir, cleanUrl);
1659
1338
  if (!normalizedPath.startsWith(clientDir)) {
1660
1339
  set.status = 403;
1661
1340
  return { error: "Access denied" };
1662
1341
  }
1663
- if (!existsSync3(imagePath)) {
1342
+ if (!existsSync2(imagePath)) {
1664
1343
  set.status = 404;
1665
1344
  return { error: "Image not found" };
1666
1345
  }
@@ -1703,7 +1382,7 @@ function registerSSRRoutes(app, options) {
1703
1382
  rootComponent,
1704
1383
  clientDir,
1705
1384
  cwd,
1706
- isWatchMode: isWatchMode2,
1385
+ isWatchMode,
1707
1386
  getBundleUrl,
1708
1387
  head = "",
1709
1388
  lang = "en",
@@ -1716,12 +1395,18 @@ function registerSSRRoutes(app, options) {
1716
1395
  dataCache,
1717
1396
  shouldIgnorePathname
1718
1397
  } = options;
1719
- const SSR_HTML_TTL_MS = isWatchMode2 ? 0 : 5 * 60 * 1000;
1398
+ const SSR_HTML_TTL_MS = 5 * 60 * 1000;
1720
1399
  const htmlCache = new LRUCache(200);
1721
1400
  const makeKey = (pathname, acceptEncoding) => `${pathname}::${acceptEncoding || "identity"}`;
1722
1401
  for (const collection of collections) {
1723
1402
  app.get(`/${collection}/*`, async ({ request, headers }) => {
1724
1403
  const method = request.method || "GET";
1404
+ if (method === "HEAD") {
1405
+ return new Response(null, {
1406
+ status: 200,
1407
+ headers: { "content-type": "text/html; charset=utf-8" }
1408
+ });
1409
+ }
1725
1410
  if (method !== "GET")
1726
1411
  throw new NotFoundError4;
1727
1412
  const accept = request.headers.get?.("accept") || "";
@@ -1731,7 +1416,7 @@ function registerSSRRoutes(app, options) {
1731
1416
  const url = new URL(request.url);
1732
1417
  const pathname = url.pathname;
1733
1418
  const acceptEncoding = headers["accept-encoding"] || "";
1734
- if (SSR_HTML_TTL_MS > 0) {
1419
+ if (!isWatchMode && SSR_HTML_TTL_MS > 0) {
1735
1420
  try {
1736
1421
  const ck = makeKey(pathname, acceptEncoding);
1737
1422
  const cached = htmlCache.get(ck);
@@ -1745,23 +1430,19 @@ function registerSSRRoutes(app, options) {
1745
1430
  }
1746
1431
  const bundleUrl = await getBundleUrl();
1747
1432
  try {
1748
- const deps = getStaticDepsForUrl(bundleUrl);
1749
- const all = [bundleUrl, ...deps];
1750
- if (all.length) {
1751
- const linkValue = all.map((u) => `<${u}>; rel=modulepreload; as=script`).join(", ");
1752
- try {
1753
- const hints = new Headers({ Link: linkValue });
1754
- request?.sendEarlyHints?.(hints);
1755
- } catch {}
1756
- headers.link = headers.link ? `${headers.link}, ${linkValue}` : linkValue;
1757
- }
1433
+ const linkValue = `<${bundleUrl}>; rel=modulepreload; as=script`;
1434
+ try {
1435
+ const hints = new Headers({ Link: linkValue });
1436
+ request?.sendEarlyHints?.(hints);
1437
+ } catch {}
1438
+ headers.link = headers.link ? `${headers.link}, ${linkValue}` : linkValue;
1758
1439
  } catch {}
1759
1440
  const result = await renderSSRDocument({
1760
1441
  pathname,
1761
1442
  rootComponent,
1762
1443
  clientDir,
1763
1444
  cwd,
1764
- isWatchMode: isWatchMode2,
1445
+ isWatchMode,
1765
1446
  bundleUrl,
1766
1447
  head,
1767
1448
  lang,
@@ -1769,9 +1450,10 @@ function registerSSRRoutes(app, options) {
1769
1450
  minify
1770
1451
  });
1771
1452
  const { body, extraHeaders } = gzipIfAccepted(result.html, "text/html; charset=utf-8", acceptEncoding);
1453
+ const cacheControlHeader = isWatchMode ? "no-cache, no-store, must-revalidate" : `${directive}, max-age=${maxAge}`;
1772
1454
  const resHeaders = {
1773
1455
  "content-type": "text/html; charset=utf-8",
1774
- "cache-control": isWatchMode2 ? "no-cache" : `${directive}, max-age=${maxAge}`,
1456
+ "cache-control": cacheControlHeader,
1775
1457
  ...headers.link ? { link: headers.link } : {},
1776
1458
  ...extraHeaders
1777
1459
  };
@@ -1779,7 +1461,7 @@ function registerSSRRoutes(app, options) {
1779
1461
  status: result.status,
1780
1462
  headers: resHeaders
1781
1463
  });
1782
- if (SSR_HTML_TTL_MS > 0 && result.status === 200) {
1464
+ if (!isWatchMode && SSR_HTML_TTL_MS > 0 && result.status === 200) {
1783
1465
  try {
1784
1466
  const ck = makeKey(pathname, acceptEncoding);
1785
1467
  htmlCache.set(ck, {
@@ -1813,13 +1495,13 @@ function registerSSRRoutes(app, options) {
1813
1495
  if (pathname === "/__reroute_data" && method === "GET") {
1814
1496
  try {
1815
1497
  const p = url.searchParams.get("path") || "/";
1816
- let data2 = isWatchMode2 ? undefined : dataCache?.get(p);
1498
+ let data2 = dataCache?.get(p);
1817
1499
  if (data2 === undefined) {
1818
1500
  data2 = await computeSSRDataForPath({
1819
1501
  pathname: p,
1820
1502
  clientDir,
1821
1503
  cwd,
1822
- isWatchMode: isWatchMode2
1504
+ isWatchMode
1823
1505
  });
1824
1506
  dataCache?.set(p, data2);
1825
1507
  }
@@ -1828,13 +1510,15 @@ function registerSSRRoutes(app, options) {
1828
1510
  return jsonError("failed", 500);
1829
1511
  }
1830
1512
  }
1831
- if (method === "GET" && !isInternal) {
1513
+ if ((method === "GET" || method === "HEAD") && !isInternal) {
1514
+ if (method === "HEAD") {
1515
+ set.status = 200;
1516
+ set.headers["content-type"] = "text/html; charset=utf-8";
1517
+ return new Response(null);
1518
+ }
1832
1519
  try {
1833
- if (isWatchMode2) {
1834
- await generateContentRegistry(cwd);
1835
- }
1836
1520
  const acceptEncoding = request.headers.get("accept-encoding") || "";
1837
- if (SSR_HTML_TTL_MS > 0) {
1521
+ if (!isWatchMode && SSR_HTML_TTL_MS > 0) {
1838
1522
  try {
1839
1523
  const ck = makeKey(pathname, acceptEncoding);
1840
1524
  const cached = htmlCache.get(ck);
@@ -1847,23 +1531,19 @@ function registerSSRRoutes(app, options) {
1847
1531
  }
1848
1532
  const bundleUrl = await getBundleUrl();
1849
1533
  try {
1850
- const deps = getStaticDepsForUrl(bundleUrl);
1851
- const all = [bundleUrl, ...deps];
1852
- if (all.length) {
1853
- const linkValue = all.map((u) => `<${u}>; rel=modulepreload; as=script`).join(", ");
1854
- try {
1855
- const hints = new Headers({ Link: linkValue });
1856
- request?.sendEarlyHints?.(hints);
1857
- } catch {}
1858
- set.headers.link = set.headers.link ? `${set.headers.link}, ${linkValue}` : linkValue;
1859
- }
1534
+ const linkValue = `<${bundleUrl}>; rel=modulepreload; as=script`;
1535
+ try {
1536
+ const hints = new Headers({ Link: linkValue });
1537
+ request?.sendEarlyHints?.(hints);
1538
+ } catch {}
1539
+ set.headers.link = set.headers.link ? `${set.headers.link}, ${linkValue}` : linkValue;
1860
1540
  } catch {}
1861
1541
  const result = await renderSSRDocument({
1862
1542
  pathname,
1863
1543
  rootComponent,
1864
1544
  clientDir,
1865
1545
  cwd,
1866
- isWatchMode: isWatchMode2,
1546
+ isWatchMode,
1867
1547
  bundleUrl,
1868
1548
  head,
1869
1549
  lang,
@@ -1873,7 +1553,7 @@ function registerSSRRoutes(app, options) {
1873
1553
  const { body, extraHeaders } = gzipIfAccepted(result.html, "text/html; charset=utf-8", acceptEncoding);
1874
1554
  set.status = result.status;
1875
1555
  set.headers["content-type"] = "text/html; charset=utf-8";
1876
- set.headers["cache-control"] = isWatchMode2 ? "no-cache" : `${directive}, max-age=${maxAge}`;
1556
+ set.headers["cache-control"] = isWatchMode ? "no-cache, no-store, must-revalidate" : `${directive}, max-age=${maxAge}`;
1877
1557
  if (extraHeaders["Content-Encoding"]) {
1878
1558
  set.headers["content-encoding"] = extraHeaders["Content-Encoding"];
1879
1559
  }
@@ -1881,7 +1561,7 @@ function registerSSRRoutes(app, options) {
1881
1561
  set.headers.vary = extraHeaders.Vary;
1882
1562
  }
1883
1563
  const response = new Response(body);
1884
- if (SSR_HTML_TTL_MS > 0 && result.status === 200) {
1564
+ if (!isWatchMode && SSR_HTML_TTL_MS > 0 && result.status === 200) {
1885
1565
  try {
1886
1566
  const ck = makeKey(pathname, acceptEncoding);
1887
1567
  htmlCache.set(ck, {
@@ -1910,220 +1590,52 @@ function registerStaticRoutes(app, options) {
1910
1590
  directive,
1911
1591
  indexHTML,
1912
1592
  staticHeaders,
1913
- minify,
1914
- sourcemap,
1915
1593
  shouldIgnore,
1916
- bundleCache,
1917
1594
  fileCache,
1918
- isWatchMode: isWatchMode2
1595
+ isWatchMode = false
1919
1596
  } = options;
1920
1597
  app.get(`${prefix}/*`, async ({ params, headers }) => {
1921
1598
  const requestPath = params["*"];
1922
- const hashedJsMatch = requestPath.match(/^(.+)\.([a-f0-9]{8})\.js$/);
1923
- if (hashedJsMatch) {
1599
+ const filePath = join(clientDir, requestPath);
1600
+ try {
1924
1601
  const acceptEncoding = headers["accept-encoding"] || "";
1925
- const cacheKey = `${requestPath}:${acceptEncoding}`;
1602
+ const encoding = getEncoding(acceptEncoding);
1603
+ const cacheKey = `${filePath}:${encoding}`;
1926
1604
  const cached = fileCache.get(cacheKey);
1927
- if (cached) {
1605
+ if (cached)
1928
1606
  return cached.clone();
1929
- }
1930
- const [, filename, hash2] = hashedJsMatch;
1931
- const tsxPath = join2(clientDir, `${filename}.tsx`);
1932
- const tsPath = join2(clientDir, `${filename}.ts`);
1933
- let filePath2 = null;
1934
- if (await Bun.file(tsxPath).exists()) {
1935
- filePath2 = tsxPath;
1936
- } else if (await Bun.file(tsPath).exists()) {
1937
- filePath2 = tsPath;
1938
- }
1939
- if (filePath2) {
1940
- try {
1941
- const bundleInfo = await transpileFile(filePath2, `${filename}.tsx`, { minify, sourcemap }, bundleCache);
1942
- if (bundleInfo.hash === hash2) {
1943
- const contentType = "application/javascript; charset=utf-8";
1944
- const { body, extraHeaders } = gzipIfAccepted(bundleInfo.code, contentType, acceptEncoding);
1945
- try {
1946
- if (Array.isArray(bundleInfo.chunks) && bundleInfo.chunks.length) {
1947
- for (const chunk of bundleInfo.chunks) {
1948
- const chunkPath = `${prefix}/${chunk.fileName}`.replace(/\/+/g, "/");
1949
- const identityResp = new Response(chunk.code, {
1950
- headers: {
1951
- "Content-Type": contentType,
1952
- "Cache-Control": `${directive}, max-age=${365 * 24 * 60 * 60}, immutable`,
1953
- ...staticHeaders
1954
- }
1955
- });
1956
- fileCache.set(chunkPath, identityResp);
1957
- const enc = headers["accept-encoding"] || "";
1958
- const comp = gzipIfAccepted(chunk.code, contentType, enc);
1959
- const compressedResp = new Response(comp.body, {
1960
- headers: {
1961
- "Content-Type": contentType,
1962
- "Cache-Control": `${directive}, max-age=${365 * 24 * 60 * 60}, immutable`,
1963
- ...comp.extraHeaders,
1964
- ...staticHeaders
1965
- }
1966
- });
1967
- fileCache.set(`${chunkPath}:${enc}`, compressedResp);
1968
- }
1969
- }
1970
- } catch {}
1971
- const response = new Response(body, {
1972
- headers: {
1973
- "Content-Type": contentType,
1974
- "Cache-Control": `${directive}, max-age=${365 * 24 * 60 * 60}, immutable`,
1975
- ...extraHeaders,
1976
- ...staticHeaders
1977
- }
1978
- });
1979
- fileCache.set(cacheKey, response.clone());
1980
- return response;
1981
- }
1982
- } catch (error) {
1983
- console.error(`[reroute] Error serving bundle:`, error);
1984
- }
1985
- }
1986
- }
1987
- const sourceMapMatch = requestPath.match(/^(.+)\.([a-f0-9]{8})\.js\.map$/);
1988
- if (sourceMapMatch) {
1989
- const [, filename, hash2] = sourceMapMatch;
1990
- const tsxPath = join2(clientDir, `${filename}.tsx`);
1991
- const tsPath = join2(clientDir, `${filename}.ts`);
1992
- let filePath2 = null;
1993
- if (await Bun.file(tsxPath).exists()) {
1994
- filePath2 = tsxPath;
1995
- } else if (await Bun.file(tsPath).exists()) {
1996
- filePath2 = tsPath;
1997
- }
1998
- if (filePath2) {
1999
- try {
2000
- const bundleInfo = await transpileFile(filePath2, `${filename}.tsx`, { minify, sourcemap }, bundleCache);
2001
- if (bundleInfo.hash === hash2 && bundleInfo.sourceMap) {
2002
- const contentType = "application/json; charset=utf-8";
2003
- const { body, extraHeaders } = gzipIfAccepted(bundleInfo.sourceMap, contentType, headers["accept-encoding"]);
2004
- return new Response(body, {
2005
- headers: {
2006
- "Content-Type": contentType,
2007
- "Cache-Control": `${directive}, max-age=${365 * 24 * 60 * 60}, immutable`,
2008
- ...extraHeaders,
2009
- ...staticHeaders
2010
- }
2011
- });
2012
- }
2013
- } catch (error) {
2014
- console.error(`[reroute] Error serving sourcemap:`, error);
2015
- }
2016
- }
2017
- }
2018
- if (requestPath.endsWith(".js")) {
2019
- const acceptEncoding = headers["accept-encoding"] || "";
2020
- const pathWithEnc = `${prefix}/${requestPath}`.replace(/\/+/g, "/");
2021
- const cachedVariant = fileCache.get(`${pathWithEnc}:${acceptEncoding}`) || fileCache.get(pathWithEnc);
2022
- if (cachedVariant) {
2023
- return cachedVariant.clone();
2024
- }
2025
- }
2026
- if (requestPath.endsWith(".tsx") || requestPath.endsWith(".ts")) {
2027
- try {
2028
- const m = requestPath.match(/^routes\/([^/]+)\/content\/([^/]+)\.(tsx|ts)$/);
2029
- if (m) {
2030
- const collection = m[1];
2031
- const name = m[2];
2032
- try {
2033
- const cwd = process.cwd();
2034
- const regPath = join2(cwd, ".reroute", "content.ts");
2035
- const reg = await import((await import("node:url")).pathToFileURL(regPath).href + `?t=${Date.now()}`);
2036
- const get = reg?.getContentEntry;
2037
- const entry = typeof get === "function" ? get(collection, name) : undefined;
2038
- const mod = entry?.module;
2039
- if (mod?.endsWith(".js")) {
2040
- return new Response(null, {
2041
- status: 302,
2042
- headers: { Location: mod }
2043
- });
2044
- }
2045
- } catch {}
2046
- try {
2047
- const chunkDir = join2(process.cwd(), ".reroute", "chunks", collection);
2048
- const files = await (await import("node:fs/promises")).readdir(chunkDir);
2049
- const candidates = files.filter((n) => n.startsWith(`${name}.`) && n.endsWith(".js"));
2050
- if (candidates.length) {
2051
- let latest = candidates[0];
2052
- let latestM = 0;
2053
- const { stat: stat5 } = await import("node:fs/promises");
2054
- for (const f of candidates) {
2055
- try {
2056
- const s = await stat5(join2(chunkDir, f));
2057
- if (s.mtimeMs >= latestM) {
2058
- latestM = s.mtimeMs;
2059
- latest = f;
2060
- }
2061
- } catch {}
2062
- }
2063
- const loc = `/${join2(".reroute", "chunks", collection, latest).replace(/\\+/g, "/")}`;
2064
- return new Response(null, {
2065
- status: 302,
2066
- headers: { Location: loc }
2067
- });
2068
- }
2069
- } catch {}
2070
- }
2071
- } catch {}
2072
- const filePath2 = join2(clientDir, requestPath);
2073
- if (shouldIgnore(filePath2))
2074
- throw new NotFoundError5;
2075
- try {
2076
- const exists = await Bun.file(filePath2).exists();
2077
- if (!exists)
2078
- throw new NotFoundError5;
2079
- const bundleInfo = await transpileFile(filePath2, requestPath, { minify, sourcemap }, bundleCache);
2080
- const contentType = "application/javascript; charset=utf-8";
2081
- const { body, extraHeaders } = gzipIfAccepted(bundleInfo.code, contentType, headers["accept-encoding"]);
2082
- return new Response(body, {
2083
- headers: {
2084
- "Content-Type": contentType,
2085
- "Cache-Control": isWatchMode2 ? "no-cache" : `${directive}, max-age=${maxAge}`,
2086
- ...extraHeaders,
2087
- ...staticHeaders
2088
- }
2089
- });
2090
- } catch (error) {
2091
- if (error instanceof NotFoundError5)
2092
- throw error;
2093
- console.error(`[reroute] Error:`, error);
2094
- throw new NotFoundError5;
2095
- }
2096
- }
2097
- const filePath = join2(clientDir, requestPath);
2098
- try {
2099
1607
  let actualFilePath = filePath;
2100
1608
  let exists = await Bun.file(actualFilePath).exists();
2101
1609
  if (!exists && indexHTML) {
2102
- actualFilePath = join2(filePath, "index.html");
1610
+ actualFilePath = join(filePath, "index.html");
2103
1611
  exists = await Bun.file(actualFilePath).exists();
2104
1612
  }
2105
1613
  if (!exists)
2106
1614
  throw new NotFoundError5;
2107
1615
  if (shouldIgnore(actualFilePath))
2108
1616
  throw new NotFoundError5;
2109
- const cached = fileCache.get(filePath);
2110
- if (cached)
2111
- return cached.clone();
2112
1617
  const contentBuf = await Bun.file(actualFilePath).arrayBuffer();
2113
1618
  const content2 = new Uint8Array(contentBuf);
2114
1619
  const contentType = getMimeType(actualFilePath);
2115
1620
  const { body, extraHeaders } = gzipIfAccepted(content2, contentType, headers["accept-encoding"]);
2116
- const isLongLivedAsset = contentType.startsWith("image/") || contentType.startsWith("font/") || contentType.includes("woff") || contentType.includes("ttf") || contentType.includes("otf");
2117
- const cacheMaxAge = maxAge === 0 ? 0 : isLongLivedAsset ? 31536000 : maxAge;
1621
+ let cacheControl;
1622
+ if (isWatchMode) {
1623
+ const isSourceFile = /\.(tsx?|jsx?|css)$/i.test(actualFilePath);
1624
+ cacheControl = isSourceFile ? "no-cache, no-store, must-revalidate" : `${directive}, max-age=${maxAge}`;
1625
+ } else {
1626
+ const isLongLivedAsset = contentType.startsWith("image/") || contentType.startsWith("font/") || contentType.includes("woff") || contentType.includes("ttf") || contentType.includes("otf");
1627
+ const cacheMaxAge = maxAge === 0 ? 0 : isLongLivedAsset ? 365 * 24 * 60 * 60 : maxAge;
1628
+ cacheControl = cacheMaxAge > 0 ? `${directive}, max-age=${cacheMaxAge}${isLongLivedAsset ? ", immutable" : ""}` : "no-cache";
1629
+ }
2118
1630
  const response = new Response(body, {
2119
1631
  headers: {
2120
1632
  "Content-Type": contentType,
2121
- "Cache-Control": cacheMaxAge > 0 ? `${directive}, max-age=${cacheMaxAge}${isLongLivedAsset ? ", immutable" : ""}` : "no-cache",
1633
+ "Cache-Control": cacheControl,
2122
1634
  ...extraHeaders,
2123
1635
  ...staticHeaders
2124
1636
  }
2125
1637
  });
2126
- fileCache.set(filePath, response);
1638
+ fileCache.set(cacheKey, response);
2127
1639
  return response.clone();
2128
1640
  } catch (error) {
2129
1641
  if (error instanceof NotFoundError5)
@@ -2140,7 +1652,6 @@ var reroute = (options = {}) => async (app) => {
2140
1652
  const ssrHead = options.head || "";
2141
1653
  const ssrLang = options.lang || "en";
2142
1654
  const ssrAppId = options.appId || "root";
2143
- const entrypoint = options.entrypoint || "index.tsx";
2144
1655
  const rootComponent = options.app;
2145
1656
  const assets = options.assets || "src/client";
2146
1657
  let prefix = options.prefix || "/";
@@ -2157,16 +1668,16 @@ var reroute = (options = {}) => async (app) => {
2157
1668
  const directive = options.directive || "public";
2158
1669
  const indexHTML = options.indexHTML ?? true;
2159
1670
  const minify = options.minify ?? true;
2160
- const sourcemap = options.sourcemap ?? true;
2161
1671
  const imageMaxAge = options.imageMaxAge ?? 31536000;
2162
1672
  const imageAllowedDomains = options.imageAllowedDomains || [];
2163
1673
  const imageMaxWidth = options.imageMaxWidth ?? 3840;
2164
1674
  const imageMaxHeight = options.imageMaxHeight ?? 2160;
1675
+ const bundleMaxAge = options.bundleMaxAge ?? 3600;
2165
1676
  if (prefix === "/")
2166
1677
  prefix = "";
2167
1678
  const fileCache = new LRUCache(100);
2168
1679
  const dataCache = new LRUCache(100);
2169
- const bundleCache = new Map;
1680
+ const collectionCache = new LRUCache(50);
2170
1681
  const cwd = typeof process !== "undefined" && typeof process.cwd === "function" ? process.cwd() : "/";
2171
1682
  const liveReloadClients = new Set;
2172
1683
  const notifyReload = () => {
@@ -2184,20 +1695,41 @@ var reroute = (options = {}) => async (app) => {
2184
1695
  };
2185
1696
  const clientDir = assets.startsWith("/") ? assets : `${cwd.replace(/\/$/, "")}/${assets.replace(/^\.\//, "")}`;
2186
1697
  const shouldIgnore = !ignorePatterns.length ? () => false : (file) => ignorePatterns.find((pattern) => typeof pattern === "string" ? file.includes(pattern) : pattern.test(file));
2187
- const isWatchMode2 = Array.isArray(process.execArgv) && process.execArgv.includes("--watch") || Array.isArray(process.argv) && process.argv.includes("--watch");
1698
+ const isWatchMode = Array.isArray(process.execArgv) && process.execArgv.includes("--watch") || Array.isArray(process.argv) && process.argv.includes("--watch");
2188
1699
  const dataCacheControl = `${directive}, max-age=${maxAge}`;
2189
- if (isWatchMode2)
1700
+ if (isWatchMode)
2190
1701
  console.log(`[reroute] Live reload enabled`);
2191
- await generateContentRegistry(cwd);
2192
- let cachedBundleUrlPromise = null;
2193
- const ensureBundleUrl = () => {
2194
- if (!cachedBundleUrlPromise) {
2195
- cachedBundleUrlPromise = getBundleUrlsFor(entrypoint, clientDir, prefix, { minify, sourcemap }, bundleCache).then((u) => u[0]);
2196
- }
2197
- return cachedBundleUrlPromise;
1702
+ const readBundleUrl = async () => {
1703
+ const bundlesDir = `${cwd}/.reroute/bundles`;
1704
+ try {
1705
+ const glob = new Bun.Glob("index.*.js");
1706
+ const files = await Array.fromAsync(glob.scan(bundlesDir));
1707
+ const indexFile = files.find((f) => !f.includes(".stub.")) || files[0];
1708
+ if (indexFile) {
1709
+ return `/bundles/${indexFile}`;
1710
+ } else {
1711
+ throw new Error("Bundle not found. Run `reroute gen` first.");
1712
+ }
1713
+ } catch {}
1714
+ throw new Error("Bundle not found. Run `reroute gen` first.");
2198
1715
  };
2199
- registerContentRoutes(app, clientDir, prefix, isWatchMode2);
2200
- registerDevRoutes(app, liveReloadClients, isWatchMode2, {
1716
+ const initialBundleUrl = await readBundleUrl();
1717
+ console.log(`[reroute] Using pre-built bundle: ${initialBundleUrl}`);
1718
+ app.onError(({ request, set, error }) => {
1719
+ if ("status" in error && error.status === 404) {
1720
+ set.status = 404;
1721
+ return;
1722
+ }
1723
+ if (request.method === "HEAD") {
1724
+ console.log("[reroute] HEAD request received");
1725
+ set.status = 200;
1726
+ set.headers["Content-Type"] = "text/plain";
1727
+ return "";
1728
+ }
1729
+ console.error("[reroute] \uD83D\uDEA8 Server error:", error);
1730
+ });
1731
+ registerContentRoutes(app, cwd, collectionCache, directive, maxAge, isWatchMode);
1732
+ registerDevRoutes(app, liveReloadClients, isWatchMode, {
2201
1733
  clientDir,
2202
1734
  cwd,
2203
1735
  dataCacheControl,
@@ -2213,13 +1745,13 @@ var reroute = (options = {}) => async (app) => {
2213
1745
  pathname = String(p);
2214
1746
  }
2215
1747
  try {
2216
- let data2 = isWatchMode2 ? undefined : dataCache.get(pathname);
1748
+ let data2 = dataCache.get(pathname);
2217
1749
  if (data2 === undefined) {
2218
1750
  data2 = await computeSSRDataForPath({
2219
1751
  pathname,
2220
1752
  clientDir,
2221
1753
  cwd,
2222
- isWatchMode: isWatchMode2
1754
+ isWatchMode
2223
1755
  });
2224
1756
  dataCache.set(pathname, data2);
2225
1757
  }
@@ -2228,23 +1760,21 @@ var reroute = (options = {}) => async (app) => {
2228
1760
  return jsonError("failed", 500);
2229
1761
  }
2230
1762
  });
2231
- if (isWatchMode2) {
1763
+ if (isWatchMode) {
2232
1764
  app.post("/__reroute_reload", () => {
2233
- try {
2234
- dataCache.clear();
2235
- notifyReload();
2236
- return new Response(JSON.stringify({ ok: true }), {
2237
- headers: { "content-type": "application/json" }
2238
- });
2239
- } catch {
2240
- return new Response(JSON.stringify({ ok: false }), {
2241
- status: 500,
2242
- headers: { "content-type": "application/json" }
2243
- });
2244
- }
1765
+ fileCache.clear();
1766
+ dataCache.clear();
1767
+ notifyReload();
1768
+ return new Response(JSON.stringify({ ok: true }), {
1769
+ headers: { "content-type": "application/json" }
1770
+ });
2245
1771
  });
2246
1772
  }
2247
- registerArtifactsRoutes(app, cwd);
1773
+ registerArtifactsRoutes(app, cwd, fileCache, {
1774
+ bundleMaxAge,
1775
+ directive,
1776
+ isWatchMode
1777
+ });
2248
1778
  const imageCacheDir = `${cwd}/.reroute/image-cache`;
2249
1779
  initImageCache(imageCacheDir);
2250
1780
  registerImageRoutes(app, {
@@ -2264,8 +1794,8 @@ var reroute = (options = {}) => async (app) => {
2264
1794
  rootComponent,
2265
1795
  clientDir,
2266
1796
  cwd,
2267
- isWatchMode: isWatchMode2,
2268
- getBundleUrl: ensureBundleUrl,
1797
+ isWatchMode,
1798
+ getBundleUrl: readBundleUrl,
2269
1799
  head: ssrHead,
2270
1800
  lang: ssrLang,
2271
1801
  appId: ssrAppId,
@@ -2293,12 +1823,9 @@ var reroute = (options = {}) => async (app) => {
2293
1823
  directive,
2294
1824
  indexHTML,
2295
1825
  staticHeaders,
2296
- minify,
2297
- sourcemap,
2298
1826
  shouldIgnore,
2299
- bundleCache,
2300
1827
  fileCache,
2301
- isWatchMode: isWatchMode2
1828
+ isWatchMode
2302
1829
  });
2303
1830
  return app;
2304
1831
  };
@@ -2306,4 +1833,4 @@ export {
2306
1833
  reroute
2307
1834
  };
2308
1835
 
2309
- //# debugId=76563F260B520FB764756E2164756E21
1836
+ //# debugId=AD268A47B9D4009364756E2164756E21