reroute-js 0.2.0 → 0.2.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 (141) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +1 -1
  3. package/package.json +4 -5
  4. package/cli/bin.d.ts +0 -3
  5. package/cli/bin.d.ts.map +0 -1
  6. package/cli/bin.js +0 -878
  7. package/cli/bin.js.map +0 -15
  8. package/cli/index.d.ts +0 -2
  9. package/cli/index.d.ts.map +0 -1
  10. package/cli/index.js +0 -147
  11. package/cli/index.js.map +0 -10
  12. package/cli/src/cli.d.ts +0 -8
  13. package/cli/src/cli.d.ts.map +0 -1
  14. package/cli/src/commands/build.d.ts +0 -8
  15. package/cli/src/commands/build.d.ts.map +0 -1
  16. package/cli/src/commands/dev.d.ts +0 -8
  17. package/cli/src/commands/dev.d.ts.map +0 -1
  18. package/cli/src/commands/gen.d.ts +0 -3
  19. package/cli/src/commands/gen.d.ts.map +0 -1
  20. package/cli/src/commands/init.d.ts +0 -8
  21. package/cli/src/commands/init.d.ts.map +0 -1
  22. package/cli/src/libs/index.d.ts +0 -2
  23. package/cli/src/libs/index.d.ts.map +0 -1
  24. package/cli/src/libs/tailwind.d.ts +0 -45
  25. package/cli/src/libs/tailwind.d.ts.map +0 -1
  26. package/core/index.d.ts +0 -2
  27. package/core/index.d.ts.map +0 -1
  28. package/core/index.js +0 -1117
  29. package/core/index.js.map +0 -25
  30. package/core/src/bundler/hash.d.ts +0 -2
  31. package/core/src/bundler/hash.d.ts.map +0 -1
  32. package/core/src/bundler/index.d.ts +0 -3
  33. package/core/src/bundler/index.d.ts.map +0 -1
  34. package/core/src/bundler/transpile.d.ts +0 -4
  35. package/core/src/bundler/transpile.d.ts.map +0 -1
  36. package/core/src/content/discovery.d.ts +0 -5
  37. package/core/src/content/discovery.d.ts.map +0 -1
  38. package/core/src/content/index.d.ts +0 -4
  39. package/core/src/content/index.d.ts.map +0 -1
  40. package/core/src/content/metadata.d.ts +0 -9
  41. package/core/src/content/metadata.d.ts.map +0 -1
  42. package/core/src/content/registry.d.ts +0 -2
  43. package/core/src/content/registry.d.ts.map +0 -1
  44. package/core/src/index.d.ts +0 -7
  45. package/core/src/index.d.ts.map +0 -1
  46. package/core/src/ssr/data.d.ts +0 -9
  47. package/core/src/ssr/data.d.ts.map +0 -1
  48. package/core/src/ssr/index.d.ts +0 -4
  49. package/core/src/ssr/index.d.ts.map +0 -1
  50. package/core/src/ssr/modules.d.ts +0 -8
  51. package/core/src/ssr/modules.d.ts.map +0 -1
  52. package/core/src/ssr/render.d.ts +0 -20
  53. package/core/src/ssr/render.d.ts.map +0 -1
  54. package/core/src/ssr/seed.d.ts +0 -2
  55. package/core/src/ssr/seed.d.ts.map +0 -1
  56. package/core/src/template/html.d.ts +0 -4
  57. package/core/src/template/html.d.ts.map +0 -1
  58. package/core/src/template/index.d.ts +0 -2
  59. package/core/src/template/index.d.ts.map +0 -1
  60. package/core/src/types.d.ts +0 -50
  61. package/core/src/types.d.ts.map +0 -1
  62. package/core/src/utils/cache.d.ts +0 -12
  63. package/core/src/utils/cache.d.ts.map +0 -1
  64. package/core/src/utils/compression.d.ts +0 -5
  65. package/core/src/utils/compression.d.ts.map +0 -1
  66. package/core/src/utils/index.d.ts +0 -5
  67. package/core/src/utils/index.d.ts.map +0 -1
  68. package/core/src/utils/mime.d.ts +0 -3
  69. package/core/src/utils/mime.d.ts.map +0 -1
  70. package/core/src/utils/path.d.ts +0 -6
  71. package/core/src/utils/path.d.ts.map +0 -1
  72. package/elysia/index.d.ts +0 -2
  73. package/elysia/index.d.ts.map +0 -1
  74. package/elysia/index.js +0 -1780
  75. package/elysia/index.js.map +0 -32
  76. package/elysia/src/index.d.ts +0 -3
  77. package/elysia/src/index.d.ts.map +0 -1
  78. package/elysia/src/plugin.d.ts +0 -32
  79. package/elysia/src/plugin.d.ts.map +0 -1
  80. package/elysia/src/routes/artifacts.d.ts +0 -3
  81. package/elysia/src/routes/artifacts.d.ts.map +0 -1
  82. package/elysia/src/routes/content.d.ts +0 -3
  83. package/elysia/src/routes/content.d.ts.map +0 -1
  84. package/elysia/src/routes/dev.d.ts +0 -7
  85. package/elysia/src/routes/dev.d.ts.map +0 -1
  86. package/elysia/src/routes/ssr.d.ts +0 -21
  87. package/elysia/src/routes/ssr.d.ts.map +0 -1
  88. package/elysia/src/routes/static.d.ts +0 -19
  89. package/elysia/src/routes/static.d.ts.map +0 -1
  90. package/elysia/src/types.d.ts +0 -31
  91. package/elysia/src/types.d.ts.map +0 -1
  92. package/elysia/src/utils/http.d.ts +0 -5
  93. package/elysia/src/utils/http.d.ts.map +0 -1
  94. package/react/index.d.ts +0 -2
  95. package/react/index.d.ts.map +0 -1
  96. package/react/index.js +0 -1152
  97. package/react/index.js.map +0 -23
  98. package/react/src/components/ContentRoute.d.ts +0 -13
  99. package/react/src/components/ContentRoute.d.ts.map +0 -1
  100. package/react/src/components/Link.d.ts +0 -8
  101. package/react/src/components/Link.d.ts.map +0 -1
  102. package/react/src/components/Outlet.d.ts +0 -7
  103. package/react/src/components/Outlet.d.ts.map +0 -1
  104. package/react/src/components/index.d.ts +0 -4
  105. package/react/src/components/index.d.ts.map +0 -1
  106. package/react/src/hooks/index.d.ts +0 -7
  107. package/react/src/hooks/index.d.ts.map +0 -1
  108. package/react/src/hooks/useContent.d.ts +0 -26
  109. package/react/src/hooks/useContent.d.ts.map +0 -1
  110. package/react/src/hooks/useData.d.ts +0 -10
  111. package/react/src/hooks/useData.d.ts.map +0 -1
  112. package/react/src/hooks/useNavigate.d.ts +0 -6
  113. package/react/src/hooks/useNavigate.d.ts.map +0 -1
  114. package/react/src/hooks/useParams.d.ts +0 -6
  115. package/react/src/hooks/useParams.d.ts.map +0 -1
  116. package/react/src/hooks/useRouter.d.ts +0 -7
  117. package/react/src/hooks/useRouter.d.ts.map +0 -1
  118. package/react/src/hooks/useSearchParams.d.ts +0 -6
  119. package/react/src/hooks/useSearchParams.d.ts.map +0 -1
  120. package/react/src/index.d.ts +0 -6
  121. package/react/src/index.d.ts.map +0 -1
  122. package/react/src/providers/ContentProvider.d.ts +0 -35
  123. package/react/src/providers/ContentProvider.d.ts.map +0 -1
  124. package/react/src/providers/RerouteProvider.d.ts +0 -25
  125. package/react/src/providers/RerouteProvider.d.ts.map +0 -1
  126. package/react/src/providers/RouterProvider.d.ts +0 -23
  127. package/react/src/providers/RouterProvider.d.ts.map +0 -1
  128. package/react/src/providers/index.d.ts +0 -4
  129. package/react/src/providers/index.d.ts.map +0 -1
  130. package/react/src/types/any.d.ts +0 -3
  131. package/react/src/types/any.d.ts.map +0 -1
  132. package/react/src/types/index.d.ts +0 -3
  133. package/react/src/types/index.d.ts.map +0 -1
  134. package/react/src/types/router.d.ts +0 -32
  135. package/react/src/types/router.d.ts.map +0 -1
  136. package/react/src/utils/content.d.ts +0 -8
  137. package/react/src/utils/content.d.ts.map +0 -1
  138. package/react/src/utils/head.d.ts +0 -6
  139. package/react/src/utils/head.d.ts.map +0 -1
  140. package/react/src/utils/index.d.ts +0 -3
  141. package/react/src/utils/index.d.ts.map +0 -1
package/core/index.js DELETED
@@ -1,1117 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __export = (target, all) => {
3
- for (var name in all)
4
- __defProp(target, name, {
5
- get: all[name],
6
- enumerable: true,
7
- configurable: true,
8
- set: (newValue) => all[name] = () => newValue
9
- });
10
- };
11
-
12
- // packages/core/src/utils/path.ts
13
- var exports_path = {};
14
- __export(exports_path, {
15
- stripStart: () => stripStart,
16
- stripEnd: () => stripEnd,
17
- join: () => join2,
18
- extname: () => extname,
19
- basename: () => basename
20
- });
21
- function join2(...parts) {
22
- return parts.join("/").replace(/\/+/g, "/");
23
- }
24
- function extname(p) {
25
- const i = p.lastIndexOf(".");
26
- return i >= 0 ? p.slice(i) : "";
27
- }
28
- function basename(p, ext) {
29
- const name = p.replace(/\\/g, "/").split("/").pop() || p;
30
- return ext && name.endsWith(ext) ? name.slice(0, -ext.length) : name;
31
- }
32
- function stripStart(p, ch) {
33
- return p.startsWith(ch) ? p.slice(ch.length) : p;
34
- }
35
- function stripEnd(p, ch) {
36
- return p.endsWith(ch) ? p.slice(0, -ch.length) : p;
37
- }
38
-
39
- // packages/core/src/bundler/hash.ts
40
- async function generateContentHash(content) {
41
- const data = new TextEncoder().encode(content);
42
- const buf = await crypto.subtle.digest("SHA-256", data);
43
- let hex = "";
44
- for (const b of new Uint8Array(buf))
45
- hex += b.toString(16).padStart(2, "0");
46
- return hex.slice(0, 8);
47
- }
48
- // packages/cli/src/libs/tailwind.ts
49
- import { spawn } from "node:child_process";
50
- import { existsSync, readFileSync } from "node:fs";
51
- import { join } from "node:path";
52
- function isTailwindAvailable(cwd) {
53
- const packageJsonPath = join(cwd, "package.json");
54
- if (!existsSync(packageJsonPath)) {
55
- return false;
56
- }
57
- try {
58
- const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
59
- const deps = {
60
- ...packageJson.dependencies,
61
- ...packageJson.devDependencies
62
- };
63
- return "@tailwindcss/cli" in deps;
64
- } catch {
65
- return false;
66
- }
67
- }
68
- function getTailwindPaths(cwd) {
69
- const input = join(cwd, "src/client/theme.css");
70
- const output = join(cwd, ".reroute/theme.css");
71
- return { input, output };
72
- }
73
- function hasTailwindInput(cwd) {
74
- const { input } = getTailwindPaths(cwd);
75
- if (!existsSync(input)) {
76
- return false;
77
- }
78
- try {
79
- const content = readFileSync(input, "utf-8");
80
- return content.includes('@import "tailwindcss"');
81
- } catch {
82
- return false;
83
- }
84
- }
85
- function resolveTailwindBin(cwd) {
86
- const pathsToTry = [
87
- join(cwd, "node_modules/.bin/tailwindcss"),
88
- join(cwd, "../node_modules/.bin/tailwindcss"),
89
- join(cwd, "../../node_modules/.bin/tailwindcss"),
90
- join(cwd, "../../../node_modules/.bin/tailwindcss")
91
- ];
92
- for (const binPath of pathsToTry) {
93
- if (existsSync(binPath)) {
94
- return binPath;
95
- }
96
- }
97
- return join(cwd, "node_modules/.bin/tailwindcss");
98
- }
99
- async function buildTailwind(cwd) {
100
- const { input, output } = getTailwindPaths(cwd);
101
- return new Promise((resolve, reject) => {
102
- const tailwindBin = resolveTailwindBin(cwd);
103
- const args = ["-i", input, "-o", output];
104
- console.log(`[reroute/tailwind] build start: -i ${input} -o ${output}`);
105
- const tailwind = spawn(tailwindBin, args, {
106
- cwd,
107
- stdio: "pipe"
108
- });
109
- tailwind.stdout?.on("data", (data) => {
110
- const line = data.toString().trim();
111
- if (line) {
112
- console.log(`[reroute/tailwind] ${line}`);
113
- }
114
- });
115
- tailwind.stderr?.on("data", (data) => {
116
- const line = data.toString().trim();
117
- if (line) {
118
- console.log(`[reroute/tailwind] ${line}`);
119
- }
120
- });
121
- tailwind.on("close", (code) => {
122
- if (code === 0) {
123
- console.log("[reroute/tailwind] build done");
124
- resolve();
125
- } else {
126
- reject(new Error(`Tailwind CSS build failed with code ${code}`));
127
- }
128
- });
129
- tailwind.on("error", (error) => {
130
- reject(error);
131
- });
132
- });
133
- }
134
- // packages/core/src/bundler/transpile.ts
135
- function isWatchMode() {
136
- try {
137
- return Array.isArray(process.execArgv) && process.execArgv.includes("--watch") || Array.isArray(process.argv) && process.argv.includes("--watch");
138
- } catch {
139
- return false;
140
- }
141
- }
142
- async function transpileFile(filePath, originalPath, options, bundleCache) {
143
- const src = await Bun.file(filePath).text();
144
- const cacheKey = `${filePath}-${await generateContentHash(src)}`;
145
- if (bundleCache.has(cacheKey)) {
146
- return bundleCache.get(cacheKey);
147
- }
148
- console.log(`[reroute] Building ${originalPath}${options.minify ? " (minified)" : ""}...`);
149
- try {
150
- if (isWatchMode()) {
151
- const cwd = typeof process !== "undefined" && process.cwd ? process.cwd() : "";
152
- if (cwd && isTailwindAvailable(cwd) && hasTailwindInput(cwd)) {
153
- await buildTailwind(cwd);
154
- }
155
- }
156
- } catch (e) {
157
- console.warn("[reroute/tailwind] rebuild failed:", e);
158
- }
159
- async function doBuild(sm) {
160
- return await Bun.build({
161
- entrypoints: [filePath],
162
- target: "browser",
163
- format: "esm",
164
- minify: options.minify,
165
- splitting: false,
166
- sourcemap: sm,
167
- define: {
168
- "process.env.NODE_ENV": options.minify ? '"production"' : '"development"'
169
- }
170
- });
171
- }
172
- let result;
173
- try {
174
- result = await doBuild(options.sourcemap ? "external" : "none");
175
- } catch (error) {
176
- console.warn(`[reroute] Build errored for ${originalPath} (sourcemap external). Retrying without sourcemap...`, error);
177
- result = await doBuild("none");
178
- }
179
- if (!result.success) {
180
- console.error(`[reroute] Failed to build ${filePath}`);
181
- for (const log of result.logs)
182
- console.error(log);
183
- throw new Error(`Failed to transpile ${filePath}`);
184
- }
185
- const output = result.outputs[0];
186
- const code = await output.text();
187
- let sourceMap;
188
- if (options.sourcemap && result.outputs.length > 1) {
189
- const mapOutput = result.outputs.find((o) => o.path.endsWith(".map"));
190
- if (mapOutput) {
191
- sourceMap = await mapOutput.text();
192
- }
193
- }
194
- const contentHash = await generateContentHash(code);
195
- const bundleInfo = {
196
- hash: contentHash,
197
- code,
198
- sourceMap
199
- };
200
- bundleCache.set(cacheKey, bundleInfo);
201
- const sizeKB = (code.length / 1024).toFixed(2);
202
- const gzippedSize = Bun.gzipSync(new TextEncoder().encode(code)).length;
203
- const gzippedKB = (gzippedSize / 1024).toFixed(2);
204
- console.log(`[reroute] Built ${originalPath} -> ${sizeKB} KB (${gzippedKB} KB gzipped)`);
205
- return bundleInfo;
206
- }
207
- async function getBundleUrlsFor(modules, clientDir, prefix, options, bundleCache) {
208
- const mods = Array.isArray(modules) ? modules : [modules];
209
- const urls = [];
210
- const { join: join3 } = await Promise.resolve().then(() => exports_path);
211
- for (const mod of mods) {
212
- const rel = mod.replace(/^\.\//, "");
213
- const fullPath = join3(clientDir, rel);
214
- try {
215
- const bundleInfo = await transpileFile(fullPath, rel, options, bundleCache);
216
- const base = basename(rel, extname(rel));
217
- urls.push(`${prefix}/${base}.${bundleInfo.hash}.js`);
218
- } catch (error) {
219
- console.error(`[reroute] Error getting bundle URL for ${rel}:`, error);
220
- urls.push(`${prefix}/${rel}`);
221
- }
222
- }
223
- return urls;
224
- }
225
- // packages/core/src/content/discovery.ts
226
- import { readdir, stat as stat2 } from "node:fs/promises";
227
-
228
- // packages/core/src/content/metadata.ts
229
- import { stat } from "node:fs/promises";
230
- import { pathToFileURL } from "node:url";
231
- async function getContentMeta(absPath, isWatchMode2) {
232
- try {
233
- const url = pathToFileURL(absPath).href;
234
- const mod = await import(`${url}${isWatchMode2 ? `?t=${Date.now()}` : ""}`);
235
- const meta = mod.meta || mod.frontmatter || {};
236
- if (meta && typeof meta === "object")
237
- return meta;
238
- return {};
239
- } catch {
240
- try {
241
- const s = await stat(absPath);
242
- return { date: new Date(s.mtimeMs).toISOString() };
243
- } catch {
244
- return {};
245
- }
246
- }
247
- }
248
- function buildHeadFromMeta(meta) {
249
- if (!meta || typeof meta !== "object")
250
- return "";
251
- const parts = [];
252
- const title = typeof meta.title === "string" ? meta.title : undefined;
253
- const description = typeof meta.description === "string" ? meta.description : typeof meta.excerpt === "string" ? meta.excerpt : undefined;
254
- if (title)
255
- parts.push(`<title>${escapeHtml(title)}</title>`);
256
- if (description)
257
- parts.push(`<meta name="description" content="${escapeHtml(description)}" />`);
258
- return parts.length ? `
259
- ${parts.join(`
260
- `)}` : "";
261
- }
262
- function escapeHtml(input) {
263
- return input.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
264
- }
265
-
266
- // packages/core/src/content/discovery.ts
267
- async function listContentFiles(dir, baseRel) {
268
- const out = [];
269
- try {
270
- const entries = await readdir(dir, { withFileTypes: true });
271
- for (const entry of entries) {
272
- const full = join2(dir, entry.name);
273
- const rel = join2(baseRel, entry.name);
274
- if (entry.isDirectory()) {
275
- const nested = await listContentFiles(full, rel);
276
- out.push(...nested);
277
- } else if (entry.isFile()) {
278
- if (/\.(tsx|ts)$/.test(entry.name) && !entry.name.startsWith("_")) {
279
- out.push(rel);
280
- }
281
- }
282
- }
283
- } catch {}
284
- return out;
285
- }
286
- async function buildContentDTOs(collectionPath, clientDir, prefix, isWatchMode2) {
287
- const normalized = stripStart(stripEnd(collectionPath, "/"), "/");
288
- const contentRelDir = join2("routes", normalized, "content");
289
- const contentAbsDir = join2(clientDir, contentRelDir);
290
- const files = await listContentFiles(contentAbsDir, "");
291
- const items = [];
292
- for (const rel of files) {
293
- const fullRelPath = join2(contentRelDir, rel);
294
- const absPath = join2(clientDir, fullRelPath);
295
- const noExt = rel.replace(/\.(tsx|ts)$/, "");
296
- const name = basename(noExt);
297
- const moduleUrl = `${prefix}/${fullRelPath}`.replace(/\/+/g, "/");
298
- const meta = await getContentMeta(absPath, isWatchMode2);
299
- const href = `/${normalized}/${name}`.replace(/\\+/g, "/");
300
- items.push({
301
- slug: noExt,
302
- name,
303
- path: fullRelPath,
304
- module: moduleUrl,
305
- meta,
306
- href
307
- });
308
- }
309
- return items;
310
- }
311
- async function discoverCollections(clientDir) {
312
- const root = join2(clientDir, "routes");
313
- const collections = new Set;
314
- try {
315
- const entries = await readdir(root, { withFileTypes: true });
316
- for (const entry of entries) {
317
- if (entry.isDirectory()) {
318
- const contentDir = join2(root, entry.name, "content");
319
- try {
320
- await stat2(contentDir);
321
- collections.add(entry.name);
322
- } catch {}
323
- }
324
- }
325
- } catch {}
326
- return Array.from(collections);
327
- }
328
- // packages/core/src/content/registry.ts
329
- async function generateContentRegistry(cwd) {
330
- try {
331
- const p = join2(cwd, ".reroute", "content.ts");
332
- const exists = await Bun.file(p).exists();
333
- console.log(exists ? "[reroute] Content registry up-to-date" : "[reroute] Warning: .reroute/content.ts not found");
334
- } catch {}
335
- }
336
- // packages/core/src/ssr/data.ts
337
- import { pathToFileURL as pathToFileURL3 } from "node:url";
338
-
339
- // packages/core/src/ssr/modules.ts
340
- import { readdir as readdir2, stat as stat3 } from "node:fs/promises";
341
- import { pathToFileURL as pathToFileURL2 } from "node:url";
342
- async function importContentModuleForPath(pathname, clientDir, cwd, isWatchMode2) {
343
- try {
344
- const parts = pathname.split("/").filter(Boolean);
345
- if (parts.length < 2)
346
- return null;
347
- const collection = parts[0];
348
- const name = parts[1];
349
- try {
350
- const registryPath = join2(cwd, ".reroute", "content.ts");
351
- const reg = await import(pathToFileURL2(registryPath).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
352
- const get = reg?.getContentEntry;
353
- const entry = typeof get === "function" ? get(collection, name) : undefined;
354
- const moduleUrl = entry?.module;
355
- if (moduleUrl?.endsWith(".js")) {
356
- const abs = join2(cwd, moduleUrl.replace(/^\//, ""));
357
- const href = pathToFileURL2(abs).href + (isWatchMode2 ? `?t=${Date.now()}` : "");
358
- const mod = await import(href);
359
- return mod;
360
- }
361
- } catch {}
362
- try {
363
- const chunkDir = join2(cwd, ".reroute", "chunks", collection);
364
- const files = await readdir2(chunkDir);
365
- const matches = files.filter((n) => n.startsWith(`${name}.`) && n.endsWith(".js"));
366
- if (matches.length) {
367
- let latest = matches[0];
368
- let latestM = 0;
369
- for (const f of matches) {
370
- try {
371
- const s = await stat3(join2(chunkDir, f));
372
- if (s.mtimeMs >= latestM) {
373
- latestM = s.mtimeMs;
374
- latest = f;
375
- }
376
- } catch {}
377
- }
378
- const absChunk = join2(chunkDir, latest);
379
- const href = pathToFileURL2(absChunk).href + (isWatchMode2 ? `?t=${Date.now()}` : "");
380
- const mod = await import(href);
381
- return mod;
382
- }
383
- } catch {}
384
- try {
385
- const srcTsx = join2(clientDir, "routes", collection, "content", `${name}.tsx`);
386
- const srcTs = join2(clientDir, "routes", collection, "content", `${name}.ts`);
387
- let absSrc = null;
388
- if (await Bun.file(srcTsx).exists())
389
- absSrc = srcTsx;
390
- else if (await Bun.file(srcTs).exists())
391
- absSrc = srcTs;
392
- if (absSrc) {
393
- const href = pathToFileURL2(absSrc).href;
394
- const mod = await (isWatchMode2 ? import(`${href}?t=${Date.now()}`) : import(href));
395
- return mod;
396
- }
397
- } catch {}
398
- } catch {}
399
- return null;
400
- }
401
-
402
- // packages/core/src/ssr/seed.ts
403
- async function seedSSRModuleForPath(pathname, clientDir, cwd, isWatchMode2) {
404
- try {
405
- const parts = pathname.split("/").filter(Boolean);
406
- if (parts.length < 2)
407
- return;
408
- const collection = parts[0];
409
- const name = parts[1];
410
- const key = `${collection}:${name}`;
411
- const mod = await importContentModuleForPath(pathname, clientDir, cwd, isWatchMode2);
412
- if (!mod)
413
- return;
414
- const C = mod.default || mod;
415
- globalThis.__REROUTE_SSR_MODULES__ = globalThis.__REROUTE_SSR_MODULES__ || {};
416
- globalThis.__REROUTE_SSR_MODULES__[key] = C;
417
- try {
418
- const pageMeta = mod.meta || mod.frontmatter || {};
419
- const pageSSR = mod.ssr || {};
420
- globalThis.__REROUTE_SSR_EXPORTS__ = globalThis.__REROUTE_SSR_EXPORTS__ || {};
421
- globalThis.__REROUTE_SSR_EXPORTS__[key] = {
422
- meta: pageMeta,
423
- ssr: pageSSR
424
- };
425
- } catch {}
426
- } catch {}
427
- }
428
-
429
- // packages/core/src/ssr/data.ts
430
- async function computeSSRDataForPath(params) {
431
- const { pathname, clientDir, cwd, isWatchMode: isWatchMode2 } = params;
432
- try {
433
- await seedSSRModuleForPath(pathname, clientDir, cwd, isWatchMode2);
434
- } catch {}
435
- try {
436
- const parts = pathname.split("/").filter(Boolean);
437
- if (parts.length >= 2) {
438
- const key = `${parts[0]}:${parts[1]}`;
439
- const g = globalThis;
440
- const exp = g.__REROUTE_SSR_EXPORTS__?.[key];
441
- const dataFn = exp?.ssr?.data;
442
- if (typeof dataFn === "function") {
443
- return await dataFn({ pathname, params: { name: parts[1] } });
444
- }
445
- }
446
- } catch {}
447
- try {
448
- const routesPath = join2(cwd, ".reroute", "routes.ts");
449
- const m = await import(pathToFileURL3(routesPath).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
450
- const match = typeof m.matchRoute === "function" ? m.matchRoute(pathname) : null;
451
- const r = match?.route;
452
- const paramsValue = match?.params || {};
453
- if (r && typeof r.path === "string") {
454
- try {
455
- const abs = join2(clientDir, "routes", String(r.path));
456
- const mod = await import(pathToFileURL3(abs).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
457
- const ssr = mod?.ssr;
458
- const dataFn = ssr?.data;
459
- if (typeof dataFn === "function") {
460
- return await dataFn({ pathname, params: paramsValue });
461
- }
462
- } catch {}
463
- }
464
- } catch {}
465
- return null;
466
- }
467
- // packages/core/src/ssr/render.ts
468
- import { readdir as readdir3, stat as stat4 } from "node:fs/promises";
469
- import { pathToFileURL as pathToFileURL4 } from "node:url";
470
-
471
- // node_modules/dedent/dist/dedent.mjs
472
- function ownKeys(object, enumerableOnly) {
473
- var keys = Object.keys(object);
474
- if (Object.getOwnPropertySymbols) {
475
- var symbols = Object.getOwnPropertySymbols(object);
476
- enumerableOnly && (symbols = symbols.filter(function(sym) {
477
- return Object.getOwnPropertyDescriptor(object, sym).enumerable;
478
- })), keys.push.apply(keys, symbols);
479
- }
480
- return keys;
481
- }
482
- function _objectSpread(target) {
483
- for (var i = 1;i < arguments.length; i++) {
484
- var source = arguments[i] != null ? arguments[i] : {};
485
- i % 2 ? ownKeys(Object(source), true).forEach(function(key) {
486
- _defineProperty(target, key, source[key]);
487
- }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function(key) {
488
- Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
489
- });
490
- }
491
- return target;
492
- }
493
- function _defineProperty(obj, key, value) {
494
- key = _toPropertyKey(key);
495
- if (key in obj) {
496
- Object.defineProperty(obj, key, { value, enumerable: true, configurable: true, writable: true });
497
- } else {
498
- obj[key] = value;
499
- }
500
- return obj;
501
- }
502
- function _toPropertyKey(arg) {
503
- var key = _toPrimitive(arg, "string");
504
- return typeof key === "symbol" ? key : String(key);
505
- }
506
- function _toPrimitive(input, hint) {
507
- if (typeof input !== "object" || input === null)
508
- return input;
509
- var prim = input[Symbol.toPrimitive];
510
- if (prim !== undefined) {
511
- var res = prim.call(input, hint || "default");
512
- if (typeof res !== "object")
513
- return res;
514
- throw new TypeError("@@toPrimitive must return a primitive value.");
515
- }
516
- return (hint === "string" ? String : Number)(input);
517
- }
518
- var dedent = createDedent({});
519
- var dedent_default = dedent;
520
- function createDedent(options) {
521
- dedent2.withOptions = (newOptions) => createDedent(_objectSpread(_objectSpread({}, options), newOptions));
522
- return dedent2;
523
- function dedent2(strings, ...values) {
524
- const raw = typeof strings === "string" ? [strings] : strings.raw;
525
- const {
526
- alignValues = false,
527
- escapeSpecialCharacters = Array.isArray(strings),
528
- trimWhitespace = true
529
- } = options;
530
- let result = "";
531
- for (let i = 0;i < raw.length; i++) {
532
- let next = raw[i];
533
- if (escapeSpecialCharacters) {
534
- next = next.replace(/\\\n[ \t]*/g, "").replace(/\\`/g, "`").replace(/\\\$/g, "$").replace(/\\\{/g, "{");
535
- }
536
- result += next;
537
- if (i < values.length) {
538
- const value = alignValues ? alignValue(values[i], result) : values[i];
539
- result += value;
540
- }
541
- }
542
- const lines = result.split(`
543
- `);
544
- let mindent = null;
545
- for (const l of lines) {
546
- const m = l.match(/^(\s+)\S+/);
547
- if (m) {
548
- const indent = m[1].length;
549
- if (!mindent) {
550
- mindent = indent;
551
- } else {
552
- mindent = Math.min(mindent, indent);
553
- }
554
- }
555
- }
556
- if (mindent !== null) {
557
- const m = mindent;
558
- result = lines.map((l) => l[0] === " " || l[0] === "\t" ? l.slice(m) : l).join(`
559
- `);
560
- }
561
- if (trimWhitespace) {
562
- result = result.trim();
563
- }
564
- if (escapeSpecialCharacters) {
565
- result = result.replace(/\\n/g, `
566
- `);
567
- }
568
- return result;
569
- }
570
- }
571
- function alignValue(value, precedingText) {
572
- if (typeof value !== "string" || !value.includes(`
573
- `)) {
574
- return value;
575
- }
576
- const currentLine = precedingText.slice(precedingText.lastIndexOf(`
577
- `) + 1);
578
- const indentMatch = currentLine.match(/^(\s+)/);
579
- if (indentMatch) {
580
- const indent = indentMatch[1];
581
- return value.replace(/\n/g, `
582
- ${indent}`);
583
- }
584
- return value;
585
- }
586
-
587
- // packages/core/src/ssr/render.ts
588
- import { cloneElement } from "react";
589
- import { renderToString } from "react-dom/server";
590
-
591
- // packages/core/src/template/html.ts
592
- async function loadIndexHtml(clientDir) {
593
- const templatePath = join2(clientDir, "index.html");
594
- try {
595
- const content = await Bun.file(templatePath).text();
596
- return content;
597
- } catch (error) {
598
- console.error(`[reroute] Failed to load template from ${templatePath}:`, error);
599
- return `<!doctype html>
600
- <html lang="en">
601
- <head>
602
- <meta charset="UTF-8" />
603
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
604
- <title>Reroute</title>
605
- </head>
606
- <body>
607
- <div id="root"></div>
608
- </body>
609
- </html>`;
610
- }
611
- }
612
- function applyIndexTemplate(templateHtml, appHtml, {
613
- head = "",
614
- hydrationScript = "",
615
- lang = "en",
616
- appId = "root"
617
- }) {
618
- let html = templateHtml;
619
- html = html.replace(/<html([^>]*)>/i, (_m, attrs) => {
620
- const hasLang = /(^|\s)lang\s*=/.test(attrs);
621
- const newAttrs = hasLang ? attrs.replace(/lang\s*=\s*("[^"]*"|'[^']*'|[^\s>]+)/i, `lang="${lang}"`) : `${attrs} lang="${lang}"`;
622
- return `<html${newAttrs}>`;
623
- });
624
- let headToInject = head || "";
625
- try {
626
- const titleMatch = headToInject.match(/<title[\s\S]*?<\/title>/i);
627
- if (titleMatch) {
628
- const titleTag = titleMatch[0];
629
- if (/<title[\s\S]*?<\/title>/i.test(html)) {
630
- html = html.replace(/<title[\s\S]*?<\/title>/i, titleTag);
631
- } else {}
632
- headToInject = headToInject.replace(titleTag, "");
633
- }
634
- const descRe = /<meta\s+name\s*=\s*['"]description['"][^>]*>/i;
635
- const descMatch = headToInject.match(descRe);
636
- if (descMatch) {
637
- const descTag = descMatch[0];
638
- if (descRe.test(html)) {
639
- html = html.replace(descRe, descTag);
640
- }
641
- headToInject = headToInject.replace(descTag, "");
642
- }
643
- } catch {}
644
- if (headToInject) {
645
- html = html.replace(/<\/head>/i, `${headToInject}
646
- </head>`);
647
- }
648
- html = html.replace(/<script\b[^>]*src\s*=\s*["'][^"']+\.(ts|tsx)(?:[?#][^"']*)?["'][^>]*>\s*<\/script>/gi, "");
649
- const appIdEscaped = appId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
650
- const rootDivRegex = new RegExp(`(<div[^>]*\\bid=(\\"|')${appIdEscaped}\\2[^>]*>)([\\s\\S]*?)(<\\/div>)`, "i");
651
- if (rootDivRegex.test(html)) {
652
- html = html.replace(rootDivRegex, `$1${appHtml}$4`);
653
- } else {
654
- html = html.replace(/<\/body>/i, ` <div id="${appId}">${appHtml}</div>
655
- </body>`);
656
- }
657
- if (hydrationScript) {
658
- html = html.replace(/<\/body>/i, ` ${hydrationScript}
659
- </body>`);
660
- }
661
- return html;
662
- }
663
- // packages/core/src/ssr/render.ts
664
- async function renderSSRDocument(options) {
665
- const {
666
- pathname,
667
- rootComponent,
668
- clientDir,
669
- cwd,
670
- isWatchMode: isWatchMode2,
671
- bundleUrl,
672
- head = "",
673
- lang = "en",
674
- appId = "root",
675
- minify = false
676
- } = options;
677
- const scripts = [bundleUrl];
678
- let hydrationScript = "";
679
- let extraHead = "";
680
- let statusOverride;
681
- try {
682
- globalThis.__REROUTE_SSR_ACCESSED__ = {};
683
- } catch {}
684
- try {
685
- const parts = pathname.split("/").filter(Boolean);
686
- if (parts.length >= 2) {
687
- const collection = parts[0];
688
- const name = parts[1];
689
- let modulePath = "";
690
- let isContentCollection = false;
691
- try {
692
- const maybeDir = join2(clientDir, "routes", collection, "content");
693
- const s = await stat4(maybeDir);
694
- isContentCollection = typeof s?.isDirectory === "function" ? s.isDirectory() : true;
695
- } catch {
696
- isContentCollection = false;
697
- }
698
- if (!isContentCollection) {
699
- throw new Error("skip-content-preload");
700
- }
701
- try {
702
- const registryPath = join2(cwd, ".reroute", "content.ts");
703
- const reg = await import(pathToFileURL4(registryPath).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
704
- const get = reg?.getContentEntry;
705
- const entry = typeof get === "function" ? get(collection, name) : undefined;
706
- const moduleUrl = entry?.module;
707
- if (moduleUrl?.endsWith(".js")) {
708
- modulePath = moduleUrl;
709
- }
710
- } catch {}
711
- if (!modulePath) {
712
- try {
713
- const chunkDir = join2(cwd, ".reroute", "chunks", collection);
714
- const files = await readdir3(chunkDir);
715
- const candidates = files.filter((n) => n.startsWith(`${name}.`) && n.endsWith(".js"));
716
- if (candidates.length) {
717
- let latest = candidates[0];
718
- let latestM = 0;
719
- for (const candidateName of candidates) {
720
- try {
721
- const s = await stat4(join2(chunkDir, candidateName));
722
- if (s.mtimeMs >= latestM) {
723
- latestM = s.mtimeMs;
724
- latest = candidateName;
725
- }
726
- } catch {}
727
- }
728
- modulePath = `/${join2(".reroute", "chunks", collection, latest).replace(/\\+/g, "/")}`;
729
- }
730
- } catch {}
731
- }
732
- if (!modulePath) {
733
- const tsx = join2(clientDir, "routes", collection, "content", `${name}.tsx`);
734
- const ts = join2(clientDir, "routes", collection, "content", `${name}.ts`);
735
- let srcUrl = "";
736
- if (await Bun.file(tsx).exists()) {
737
- srcUrl = `/${join2("routes", collection, "content", `${name}.tsx`).replace(/\\+/g, "/")}`;
738
- } else if (await Bun.file(ts).exists()) {
739
- srcUrl = `/${join2("routes", collection, "content", `${name}.ts`).replace(/\\+/g, "/")}`;
740
- }
741
- if (srcUrl) {
742
- modulePath = srcUrl;
743
- }
744
- }
745
- if (!modulePath) {
746
- statusOverride = 404;
747
- }
748
- if (modulePath) {
749
- const key = `${collection}:${name}`;
750
- extraHead += `
751
- <link rel="modulepreload" href="${modulePath}" />`;
752
- const qs = `src=${encodeURIComponent(modulePath)}&key=${encodeURIComponent(key)}`;
753
- hydrationScript += `<script type="module" src="/__reroute_preload?${qs}"></script>`;
754
- }
755
- }
756
- } catch {}
757
- await seedSSRModuleForPath(pathname, clientDir, cwd, isWatchMode2);
758
- const __SSR_DATA__ = {};
759
- try {
760
- try {
761
- const parts = pathname.split("/").filter(Boolean);
762
- if (parts.length >= 2) {
763
- const g = globalThis;
764
- const key = `${parts[0]}:${parts[1]}`;
765
- const exp = g.__REROUTE_SSR_EXPORTS__?.[key];
766
- const dataFn = exp?.ssr?.data;
767
- if (typeof dataFn === "function") {
768
- const out = await dataFn({
769
- pathname,
770
- params: { name: parts[1] }
771
- });
772
- __SSR_DATA__[pathname] = out;
773
- }
774
- }
775
- } catch {}
776
- try {
777
- const routesPath = join2(cwd, ".reroute", "routes.ts");
778
- const m = await import(pathToFileURL4(routesPath).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
779
- const match = typeof m.matchRoute === "function" ? m.matchRoute(pathname) : null;
780
- const r = match?.route;
781
- const params = match?.params || {};
782
- if (r && typeof r.path === "string") {
783
- try {
784
- const abs = join2(clientDir, "routes", String(r.path));
785
- const mod = await import(pathToFileURL4(abs).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
786
- const ssr = mod?.ssr;
787
- const dataFn = ssr?.data;
788
- if (typeof dataFn === "function") {
789
- const out = await dataFn({ pathname, params });
790
- __SSR_DATA__[pathname] = out;
791
- }
792
- } catch {}
793
- }
794
- } catch {}
795
- } catch {}
796
- try {
797
- globalThis.__REROUTE_DATA__ = __SSR_DATA__;
798
- } catch {}
799
- let __byCollectionForSSR = {};
800
- try {
801
- const p = join2(cwd, ".reroute", "content.ts");
802
- const mod = await import(pathToFileURL4(p).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
803
- __byCollectionForSSR = mod?.byCollection || {};
804
- try {
805
- globalThis.__REROUTE_COLLECTIONS__ = __byCollectionForSSR;
806
- } catch {}
807
- } catch {}
808
- const componentWithPathname = cloneElement(rootComponent, {
809
- pathname
810
- });
811
- const appHtml = renderToString(componentWithPathname);
812
- const baseTemplate = await loadIndexHtml(clientDir);
813
- let inlineStyleTag = "";
814
- try {
815
- const candidates = [
816
- join2(clientDir, "..", ".reroute", "theme.css"),
817
- join2(clientDir, "..", "..", ".reroute", "theme.css"),
818
- join2(clientDir, "..", "..", "..", ".reroute", "theme.css"),
819
- join2(clientDir, "..", "..", "..", "..", ".reroute", "theme.css")
820
- ];
821
- let cssPath = "";
822
- for (const p of candidates) {
823
- if (await Bun.file(p).exists()) {
824
- cssPath = p;
825
- break;
826
- }
827
- }
828
- if (cssPath) {
829
- let css = await Bun.file(cssPath).text();
830
- if (minify) {
831
- css = css.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\s+/g, " ").replace(/\s*([{}:;,>+~])\s*/g, "$1").replace(/;}/g, "}").trim();
832
- }
833
- inlineStyleTag = `<style data-reroute="tailwind">${css}</style>`;
834
- }
835
- } catch {}
836
- try {
837
- const g = globalThis;
838
- const acc = g.__REROUTE_SSR_ACCESSED__;
839
- const sortByDate = (order) => (a, b) => {
840
- const da = a?.meta?.date ? Date.parse(String(a.meta.date)) : 0;
841
- const db = b?.meta?.date ? Date.parse(String(b.meta.date)) : 0;
842
- return order === "asc" ? da - db : db - da;
843
- };
844
- const usage = {};
845
- if (acc && typeof acc.forEach === "function") {
846
- acc.forEach((c) => {
847
- if (typeof c === "string")
848
- usage[c] = { limit: Number.POSITIVE_INFINITY, sort: "custom" };
849
- });
850
- } else if (acc && typeof acc === "object") {
851
- for (const [k, v] of Object.entries(acc)) {
852
- const lim = typeof v?.limit === "number" ? v.limit : Number.POSITIVE_INFINITY;
853
- const s = typeof v?.sort === "string" ? v.sort : "custom";
854
- usage[k] = { limit: lim, sort: s };
855
- }
856
- }
857
- const collections = Object.keys(usage);
858
- if (collections.length) {
859
- const subset = {};
860
- const partial = {};
861
- for (const c of collections) {
862
- const conf = usage[c];
863
- const full = __byCollectionForSSR?.[c] || [];
864
- let arr = full;
865
- if (Number.isFinite(conf.limit) && conf.limit > 0 && conf.sort !== "custom") {
866
- if (conf.sort === "date-desc") {
867
- arr = [...full].sort(sortByDate("desc")).slice(0, conf.limit);
868
- } else if (conf.sort === "date-asc") {
869
- arr = [...full].sort(sortByDate("asc")).slice(0, conf.limit);
870
- } else if (conf.sort === "none") {
871
- arr = full.slice(0, conf.limit);
872
- }
873
- }
874
- subset[c] = arr;
875
- partial[c] = Array.isArray(arr) && Array.isArray(full) ? arr.length < full.length : false;
876
- }
877
- const subsetJson = JSON.stringify(subset);
878
- const partialJson = JSON.stringify(partial);
879
- hydrationScript += `
880
- <script>
881
- (function(){ try {
882
- var w = (typeof window!== 'undefined'? window : globalThis);
883
- w.__REROUTE_COLLECTIONS__ = w.__REROUTE_COLLECTIONS__ || {};
884
- Object.assign(w.__REROUTE_COLLECTIONS__, ${subsetJson});
885
- w.__REROUTE_COLLECTIONS_PARTIAL__ = w.__REROUTE_COLLECTIONS_PARTIAL__ || {};
886
- Object.assign(w.__REROUTE_COLLECTIONS_PARTIAL__, ${partialJson});
887
- } catch(e){} })();
888
- </script>`;
889
- }
890
- } catch {}
891
- try {
892
- const seededJson = JSON.stringify(__SSR_DATA__);
893
- hydrationScript += `
894
- <script>
895
- (function(){ try {
896
- var w = (typeof window!== 'undefined'? window : globalThis);
897
- w.__REROUTE_DATA__ = Object.assign({}, w.__REROUTE_DATA__ || {}, ${seededJson});
898
- } catch(e){} })();
899
- </script>`;
900
- } catch {}
901
- hydrationScript += scripts.map((src) => `<script type="module" src="${src}"></script>`).join("");
902
- if (isWatchMode2) {
903
- hydrationScript += `<script type="module" src="/__reroute_watch.js"></script>`;
904
- }
905
- let perPageHead = "";
906
- let pageLang;
907
- try {
908
- const parts = pathname.split("/").filter(Boolean);
909
- if (parts.length >= 2) {
910
- const key = `${parts[0]}:${parts[1]}`;
911
- const g = globalThis;
912
- const exp = g.__REROUTE_SSR_EXPORTS__?.[key];
913
- const meta = exp?.meta;
914
- const ssr = exp?.ssr;
915
- perPageHead += buildHeadFromMeta(meta);
916
- const ssrHead = typeof ssr?.head === "string" ? ssr.head : Array.isArray(ssr?.head) ? String(ssr.head.join(`
917
- `)) : "";
918
- if (ssrHead)
919
- perPageHead += `
920
- ${ssrHead}`;
921
- if (typeof ssr?.lang === "string" && ssr.lang.trim()) {
922
- pageLang = ssr.lang.trim();
923
- }
924
- }
925
- } catch {}
926
- try {
927
- const routesPath = join2(cwd, ".reroute", "routes.ts");
928
- const m = await import(pathToFileURL4(routesPath).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
929
- const match = typeof m.matchRoute === "function" ? m.matchRoute(pathname) : null;
930
- const r = match?.route;
931
- if (!r) {
932
- statusOverride = statusOverride || 404;
933
- }
934
- if (r && typeof r.path === "string") {
935
- try {
936
- const abs = join2(clientDir, "routes", String(r.path));
937
- const mod = await import(pathToFileURL4(abs).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
938
- const meta = mod?.meta;
939
- const ssr = mod?.ssr;
940
- if (meta)
941
- perPageHead += buildHeadFromMeta(meta);
942
- if (ssr) {
943
- const ssrHead = typeof ssr.head === "string" ? ssr.head : Array.isArray(ssr.head) ? String(ssr.head.join(`
944
- `)) : "";
945
- if (ssrHead)
946
- perPageHead += `
947
- ${ssrHead}`;
948
- if (typeof ssr.lang === "string" && ssr.lang.trim()) {
949
- pageLang = ssr.lang.trim();
950
- }
951
- }
952
- } catch {}
953
- } else {
954
- try {
955
- const list = m?.notFoundRoutes;
956
- if (Array.isArray(list)) {
957
- let chosen;
958
- let bestLen = -1;
959
- for (const nf of list) {
960
- const pat = String(nf?.pattern || "/");
961
- if (!pathname.startsWith(pat))
962
- continue;
963
- const len = pat.split("/").filter(Boolean).length;
964
- if (len >= bestLen) {
965
- bestLen = len;
966
- chosen = nf;
967
- }
968
- }
969
- if (chosen && typeof chosen.path === "string") {
970
- try {
971
- const abs = join2(clientDir, "routes", String(chosen.path));
972
- const mod = await import(pathToFileURL4(abs).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
973
- const meta = mod?.meta;
974
- const ssr = mod?.ssr;
975
- if (meta)
976
- perPageHead += buildHeadFromMeta(meta);
977
- const ssrHead = typeof ssr?.head === "string" ? ssr.head : Array.isArray(ssr?.head) ? String(ssr.head.join(`
978
- `)) : "";
979
- if (ssrHead)
980
- perPageHead += `
981
- ${ssrHead}`;
982
- if (typeof ssr?.lang === "string" && ssr.lang?.trim()) {
983
- pageLang = String(ssr.lang).trim();
984
- }
985
- } catch {}
986
- }
987
- }
988
- } catch {}
989
- }
990
- } catch {}
991
- const combinedHead = dedent_default([dedent_default(head) || "", dedent_default(extraHead), dedent_default(perPageHead)].filter(Boolean).join(`
992
- `));
993
- const html2 = applyIndexTemplate(baseTemplate, appHtml, {
994
- head: [inlineStyleTag, combinedHead].filter(Boolean).join(`
995
- `),
996
- hydrationScript,
997
- lang: pageLang || lang,
998
- appId
999
- });
1000
- return {
1001
- html: html2,
1002
- status: statusOverride || 200
1003
- };
1004
- }
1005
- // packages/core/src/utils/cache.ts
1006
- class LRUCache {
1007
- cache;
1008
- maxSize;
1009
- constructor(maxSize = 100) {
1010
- this.cache = new Map;
1011
- this.maxSize = maxSize;
1012
- }
1013
- get(key) {
1014
- if (!this.cache.has(key)) {
1015
- return;
1016
- }
1017
- const value = this.cache.get(key);
1018
- this.cache.delete(key);
1019
- this.cache.set(key, value);
1020
- return value;
1021
- }
1022
- set(key, value) {
1023
- if (this.cache.has(key)) {
1024
- this.cache.delete(key);
1025
- }
1026
- this.cache.set(key, value);
1027
- if (this.cache.size > this.maxSize) {
1028
- const firstKey = this.cache.keys().next().value;
1029
- this.cache.delete(firstKey);
1030
- }
1031
- }
1032
- has(key) {
1033
- return this.cache.has(key);
1034
- }
1035
- clear() {
1036
- this.cache.clear();
1037
- }
1038
- get size() {
1039
- return this.cache.size;
1040
- }
1041
- }
1042
- // packages/core/src/utils/mime.ts
1043
- function getMimeType(filePath) {
1044
- const ext = filePath.split(".").pop()?.toLowerCase();
1045
- const mimeTypes = {
1046
- html: "text/html",
1047
- css: "text/css",
1048
- js: "application/javascript",
1049
- ts: "application/javascript",
1050
- json: "application/json",
1051
- png: "image/png",
1052
- jpg: "image/jpeg",
1053
- jpeg: "image/jpeg",
1054
- gif: "image/gif",
1055
- svg: "image/svg+xml",
1056
- ico: "image/x-icon",
1057
- woff: "font/woff",
1058
- woff2: "font/woff2",
1059
- ttf: "font/ttf"
1060
- };
1061
- return mimeTypes[ext || ""] || "application/octet-stream";
1062
- }
1063
- function isCompressible(contentType) {
1064
- if (!contentType)
1065
- return false;
1066
- const ct = contentType.split(";")[0].trim();
1067
- return ct.startsWith("text/") || ct === "application/javascript" || ct === "application/json" || ct === "application/xml" || ct === "image/svg+xml";
1068
- }
1069
-
1070
- // packages/core/src/utils/compression.ts
1071
- function acceptsGzip(acceptEncoding) {
1072
- return Boolean(acceptEncoding && /gzip/i.test(acceptEncoding));
1073
- }
1074
- function toBytes(input) {
1075
- return typeof input === "string" ? new TextEncoder().encode(input) : input;
1076
- }
1077
- function gzipIfAccepted(body, contentType, acceptEncoding) {
1078
- const extraHeaders = {};
1079
- if (acceptsGzip(acceptEncoding) && isCompressible(contentType)) {
1080
- try {
1081
- const compressed = Bun.gzipSync(toBytes(body));
1082
- extraHeaders["Content-Encoding"] = "gzip";
1083
- extraHeaders.Vary = "Accept-Encoding";
1084
- return { body: compressed, extraHeaders };
1085
- } catch {}
1086
- }
1087
- return { body, extraHeaders };
1088
- }
1089
- export {
1090
- transpileFile,
1091
- toBytes,
1092
- stripStart,
1093
- stripEnd,
1094
- seedSSRModuleForPath,
1095
- renderSSRDocument,
1096
- loadIndexHtml,
1097
- listContentFiles,
1098
- join2 as join,
1099
- isCompressible,
1100
- gzipIfAccepted,
1101
- getMimeType,
1102
- getContentMeta,
1103
- getBundleUrlsFor,
1104
- generateContentRegistry,
1105
- generateContentHash,
1106
- extname,
1107
- discoverCollections,
1108
- computeSSRDataForPath,
1109
- buildHeadFromMeta,
1110
- buildContentDTOs,
1111
- basename,
1112
- applyIndexTemplate,
1113
- acceptsGzip,
1114
- LRUCache
1115
- };
1116
-
1117
- //# debugId=177D7672E5E8FF1164756E2164756E21