reroute-js 0.5.0 → 0.7.0

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 (121) hide show
  1. package/README.md +142 -0
  2. package/_/basic/package.json +4 -4
  3. package/_/basic/src/client/index.html +1 -1
  4. package/_/basic/src/index.ts +1 -3
  5. package/_/blog/package.json +4 -4
  6. package/_/blog/src/client/App.tsx +1 -0
  7. package/_/blog/src/client/index.html +1 -1
  8. package/_/blog/src/client/routes/blog/content/1-hello-world.tsx +1 -1
  9. package/_/blog/src/client/routes/blog/content/3-markdown-with-syntax-highlighting.mdx +213 -0
  10. package/_/blog/src/client/routes/blog/content/4-content-in-markdown.md +143 -0
  11. package/_/blog/src/client/routes/blog/content/5-mdx-with-components.mdx +267 -0
  12. package/_/blog/src/client/routes/blog/index.tsx +59 -0
  13. package/_/blog/src/client/routes/client.tsx +564 -0
  14. package/_/blog/src/client/routes/docs.tsx +670 -0
  15. package/_/blog/src/client/routes/index.tsx +37 -0
  16. package/_/blog/src/client/routes/markdown-demo.md +169 -0
  17. package/_/blog/src/client/routes/markdown.tsx +160 -0
  18. package/_/blog/src/index.ts +5 -2
  19. package/_/store/package.json +4 -4
  20. package/_/store/src/client/index.html +1 -1
  21. package/_/store/src/index.ts +1 -1
  22. package/cli/bin.d.ts +1 -1
  23. package/cli/bin.js +1313 -74
  24. package/cli/bin.js.map +13 -7
  25. package/cli/index.d.ts +1 -1
  26. package/cli/index.js +428 -17
  27. package/cli/index.js.map +6 -3
  28. package/cli/src/cli.d.ts +1 -1
  29. package/cli/src/commands/boot.d.ts +1 -1
  30. package/cli/src/commands/build.d.ts +19 -0
  31. package/cli/src/commands/build.d.ts.map +1 -0
  32. package/cli/src/commands/dev.d.ts +18 -0
  33. package/cli/src/commands/dev.d.ts.map +1 -0
  34. package/cli/src/commands/gen.d.ts +1 -1
  35. package/cli/src/commands/gen.d.ts.map +1 -1
  36. package/cli/src/commands/init.d.ts +1 -1
  37. package/cli/src/commands/start.d.ts +19 -0
  38. package/cli/src/commands/start.d.ts.map +1 -0
  39. package/cli/src/libs/index.d.ts +4 -1
  40. package/cli/src/libs/index.d.ts.map +1 -1
  41. package/cli/src/libs/log.d.ts +46 -0
  42. package/cli/src/libs/log.d.ts.map +1 -0
  43. package/cli/src/libs/markdown-processor.d.ts +59 -0
  44. package/cli/src/libs/markdown-processor.d.ts.map +1 -0
  45. package/cli/src/libs/markdown.d.ts +33 -0
  46. package/cli/src/libs/markdown.d.ts.map +1 -0
  47. package/cli/src/libs/tailwind.d.ts +1 -1
  48. package/cli/src/libs/version.d.ts +1 -1
  49. package/core/index.d.ts +1 -1
  50. package/core/index.js +4 -4
  51. package/core/index.js.map +2 -2
  52. package/core/src/bundler/hash.d.ts +1 -1
  53. package/core/src/bundler/index.d.ts +1 -1
  54. package/core/src/bundler/transpile.d.ts +1 -1
  55. package/core/src/content/discovery.d.ts +1 -1
  56. package/core/src/content/index.d.ts +1 -1
  57. package/core/src/content/metadata.d.ts +1 -1
  58. package/core/src/content/registry.d.ts +1 -1
  59. package/core/src/index.d.ts +1 -1
  60. package/core/src/ssr/data.d.ts +1 -1
  61. package/core/src/ssr/index.d.ts +1 -1
  62. package/core/src/ssr/modules.d.ts +1 -1
  63. package/core/src/ssr/render.d.ts +1 -1
  64. package/core/src/ssr/seed.d.ts +1 -1
  65. package/core/src/template/html.d.ts +1 -1
  66. package/core/src/template/index.d.ts +1 -1
  67. package/core/src/types.d.ts +1 -1
  68. package/core/src/utils/cache.d.ts +1 -1
  69. package/core/src/utils/compression.d.ts +1 -1
  70. package/core/src/utils/index.d.ts +1 -1
  71. package/core/src/utils/mime.d.ts +1 -1
  72. package/core/src/utils/path.d.ts +1 -1
  73. package/elysia/index.d.ts +1 -1
  74. package/elysia/index.js +4 -4
  75. package/elysia/index.js.map +2 -2
  76. package/elysia/src/index.d.ts +1 -1
  77. package/elysia/src/libs/http.d.ts +1 -1
  78. package/elysia/src/libs/image.d.ts +1 -1
  79. package/elysia/src/plugin.d.ts +1 -1
  80. package/elysia/src/routes/artifacts.d.ts +1 -1
  81. package/elysia/src/routes/content.d.ts +1 -1
  82. package/elysia/src/routes/dev.d.ts +1 -1
  83. package/elysia/src/routes/image.d.ts +1 -1
  84. package/elysia/src/routes/ssr.d.ts +1 -1
  85. package/elysia/src/routes/static.d.ts +1 -1
  86. package/elysia/src/types.d.ts +1 -1
  87. package/package.json +22 -9
  88. package/react/index.d.ts +1 -1
  89. package/react/index.js +141 -36
  90. package/react/index.js.map +7 -6
  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/ContentRoute.d.ts.map +1 -1
  94. package/react/src/components/Image.d.ts +1 -1
  95. package/react/src/components/Link.d.ts +1 -1
  96. package/react/src/components/Link.d.ts.map +1 -1
  97. package/react/src/components/Markdown.d.ts +89 -0
  98. package/react/src/components/Markdown.d.ts.map +1 -0
  99. package/react/src/components/Outlet.d.ts +1 -1
  100. package/react/src/components/index.d.ts +2 -1
  101. package/react/src/components/index.d.ts.map +1 -1
  102. package/react/src/hooks/index.d.ts +1 -1
  103. package/react/src/hooks/useContent.d.ts +1 -1
  104. package/react/src/hooks/useData.d.ts +1 -1
  105. package/react/src/hooks/useNavigate.d.ts +1 -1
  106. package/react/src/hooks/useParams.d.ts +1 -1
  107. package/react/src/hooks/useRouter.d.ts +1 -1
  108. package/react/src/hooks/useSearchParams.d.ts +1 -1
  109. package/react/src/index.d.ts +1 -1
  110. package/react/src/providers/ContentProvider.d.ts +1 -1
  111. package/react/src/providers/RerouteProvider.d.ts +1 -1
  112. package/react/src/providers/RouterProvider.d.ts +1 -1
  113. package/react/src/providers/RouterProvider.d.ts.map +1 -1
  114. package/react/src/providers/index.d.ts +1 -1
  115. package/react/src/types/any.d.ts +1 -1
  116. package/react/src/types/index.d.ts +1 -1
  117. package/react/src/types/router.d.ts +1 -1
  118. package/react/src/utils/content.d.ts +1 -1
  119. package/react/src/utils/head.d.ts +1 -1
  120. package/react/src/utils/index.d.ts +1 -1
  121. package/_/blog/src/client/components/Counter.tsx +0 -14
package/cli/bin.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env bun
2
2
  // @bun
3
3
  /**
4
- * reroute-js v0.5.0
4
+ * reroute-js v0.7.0
5
5
  *
6
6
  * @license MIT
7
7
  * @copyright 2025 stewones <hi@stewan.io>
@@ -9,7 +9,23 @@
9
9
  *
10
10
  * Built with Bun <3
11
11
  */
12
+ import { createRequire } from "node:module";
13
+ var __create = Object.create;
14
+ var __getProtoOf = Object.getPrototypeOf;
12
15
  var __defProp = Object.defineProperty;
16
+ var __getOwnPropNames = Object.getOwnPropertyNames;
17
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
18
+ var __toESM = (mod, isNodeMode, target) => {
19
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
20
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
21
+ for (let key of __getOwnPropNames(mod))
22
+ if (!__hasOwnProp.call(to, key))
23
+ __defProp(to, key, {
24
+ get: () => mod[key],
25
+ enumerable: true
26
+ });
27
+ return to;
28
+ };
13
29
  var __export = (target, all) => {
14
30
  for (var name in all)
15
31
  __defProp(target, name, {
@@ -20,6 +36,7 @@ var __export = (target, all) => {
20
36
  });
21
37
  };
22
38
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
39
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
23
40
 
24
41
  // packages/cli/src/libs/version.ts
25
42
  import path from "node:path";
@@ -30,7 +47,7 @@ async function getVersionString() {
30
47
  }
31
48
  async function getVersion() {
32
49
  if (true) {
33
- return "0.5.0";
50
+ return "0.7.0";
34
51
  }
35
52
  const possiblePaths = [
36
53
  path.join(import.meta.dir, "../../../../package.json"),
@@ -48,7 +65,7 @@ async function getVersion() {
48
65
  }
49
66
  async function getCommit() {
50
67
  if (true) {
51
- return "68dd984";
68
+ return "4b119c0";
52
69
  }
53
70
  return "dev";
54
71
  }
@@ -113,15 +130,53 @@ async function scaffoldProject(options) {
113
130
  console.log(`
114
131
  \uD83D\uDCE6 Template: ${template}
115
132
  `);
116
- const templatePath = join(import.meta.dir, "..", "_", template);
117
- if (!existsSync(templatePath)) {
118
- console.error(`Error: Template directory not found at ${templatePath}`);
133
+ const possibleTemplatePaths = [
134
+ join(import.meta.dir, "..", "_", template),
135
+ join(import.meta.dir, "..", "..", "..", "_", template)
136
+ ];
137
+ let templatePath;
138
+ for (const path2 of possibleTemplatePaths) {
139
+ if (existsSync(path2)) {
140
+ templatePath = path2;
141
+ break;
142
+ }
143
+ }
144
+ if (!templatePath) {
145
+ console.error(`Error: Template directory not found for template "${template}"`);
146
+ console.error(`Tried paths: ${possibleTemplatePaths.join(", ")}`);
119
147
  process.exit(1);
120
148
  }
149
+ const possibleExamplesPaths = [
150
+ join(import.meta.dir, "..", "..", "..", "..", "examples", template, "src"),
151
+ join(import.meta.dir, "..", "..", "..", "..", "..", "examples", template, "src")
152
+ ];
153
+ let examplesPath;
154
+ for (const path2 of possibleExamplesPaths) {
155
+ if (existsSync(path2)) {
156
+ examplesPath = path2;
157
+ break;
158
+ }
159
+ }
121
160
  await mkdir(projectPath, { recursive: true });
122
161
  await copyTemplateFiles(templatePath, projectPath, {
123
162
  PROJECT_NAME: projectName
124
163
  });
164
+ const sourceVariables = {
165
+ PROJECT_NAME: projectName
166
+ };
167
+ if (examplesPath) {
168
+ await copySourceFiles(examplesPath, join(projectPath, "src"), sourceVariables);
169
+ } else {
170
+ const templateSrcPath = join(templatePath, "src");
171
+ if (existsSync(templateSrcPath)) {
172
+ await copySourceFiles(templateSrcPath, join(projectPath, "src"), sourceVariables);
173
+ } else {
174
+ console.error(`Error: No src directory found for template "${template}"`);
175
+ console.error(`Tried examples paths: ${possibleExamplesPaths.join(", ")}`);
176
+ console.error(`Tried template path: ${templateSrcPath}`);
177
+ process.exit(1);
178
+ }
179
+ }
125
180
  console.log(`\uD83D\uDCE5 Installing dependencies...
126
181
  `);
127
182
  const proc = Bun.spawn(["bun", "install"], {
@@ -135,6 +190,9 @@ async function scaffoldProject(options) {
135
190
  async function copyTemplateFiles(templatePath, targetPath, variables) {
136
191
  const entries = await readdir(templatePath, { withFileTypes: true });
137
192
  for (const entry of entries) {
193
+ if (entry.isDirectory() && entry.name === "src") {
194
+ continue;
195
+ }
138
196
  const sourcePath = join(templatePath, entry.name);
139
197
  const destPath = join(targetPath, entry.name);
140
198
  if (entry.isDirectory()) {
@@ -151,6 +209,34 @@ async function copyTemplateFiles(templatePath, targetPath, variables) {
151
209
  }
152
210
  }
153
211
  }
212
+ function applyVariableReplacements(content, fileName, variables) {
213
+ const shouldReplaceVariables = VARIABLE_REPLACEMENT_PATTERNS.some((pattern) => pattern.test(fileName));
214
+ if (!shouldReplaceVariables) {
215
+ return content;
216
+ }
217
+ let processedContent = content;
218
+ if (/\.html$/i.test(fileName)) {
219
+ if (variables.PROJECT_NAME) {
220
+ processedContent = processedContent.replace(/<title>.*?<\/title>/i, `<title>${variables.PROJECT_NAME}</title>`);
221
+ }
222
+ }
223
+ return processedContent;
224
+ }
225
+ async function copySourceFiles(sourcePath, targetPath, variables) {
226
+ const entries = await readdir(sourcePath, { withFileTypes: true });
227
+ await mkdir(targetPath, { recursive: true });
228
+ for (const entry of entries) {
229
+ const sourceEntryPath = join(sourcePath, entry.name);
230
+ const targetEntryPath = join(targetPath, entry.name);
231
+ if (entry.isDirectory()) {
232
+ await copySourceFiles(sourceEntryPath, targetEntryPath, variables);
233
+ } else if (entry.isFile()) {
234
+ const content = await readFile(sourceEntryPath, "utf-8");
235
+ const processedContent = variables ? applyVariableReplacements(content, entry.name, variables) : content;
236
+ await writeFile(targetEntryPath, processedContent);
237
+ }
238
+ }
239
+ }
154
240
  function printSuccess(projectName, template) {
155
241
  console.log(`
156
242
  \uD83C\uDFCE️ Project created successfully!
@@ -203,21 +289,377 @@ async function printHelp() {
203
289
  console.log(" reroute init my-blog --template blog");
204
290
  console.log(" reroute init my-store --template store");
205
291
  }
292
+ var VARIABLE_REPLACEMENT_PATTERNS;
206
293
  var init_init = __esm(() => {
207
294
  init_version();
295
+ VARIABLE_REPLACEMENT_PATTERNS = [
296
+ /\.html$/i
297
+ ];
208
298
  });
209
299
 
300
+ // packages/cli/src/libs/markdown.ts
301
+ import { existsSync as existsSync2, readFileSync } from "node:fs";
302
+ import { dirname, join as join2 } from "node:path";
303
+ function isPackageAvailable(cwd, packageName) {
304
+ let currentDir = cwd;
305
+ for (let i = 0;i < 5; i++) {
306
+ const packageJsonPath = join2(currentDir, "package.json");
307
+ if (existsSync2(packageJsonPath)) {
308
+ try {
309
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
310
+ const deps = {
311
+ ...packageJson.dependencies,
312
+ ...packageJson.devDependencies,
313
+ ...packageJson.peerDependencies
314
+ };
315
+ if (packageName in deps) {
316
+ return true;
317
+ }
318
+ } catch {}
319
+ }
320
+ const parentDir = dirname(currentDir);
321
+ if (parentDir === currentDir) {
322
+ break;
323
+ }
324
+ currentDir = parentDir;
325
+ }
326
+ return false;
327
+ }
328
+ function isReactMarkdownAvailable(cwd) {
329
+ return isPackageAvailable(cwd, "react-markdown");
330
+ }
331
+ function isShikiAvailable(cwd) {
332
+ return isPackageAvailable(cwd, "@shikijs/rehype");
333
+ }
334
+ function isRemarkGfmAvailable(cwd) {
335
+ return isPackageAvailable(cwd, "remark-gfm");
336
+ }
337
+ function isMdxAvailable(cwd) {
338
+ return isPackageAvailable(cwd, "@mdx-js/mdx");
339
+ }
340
+ function getMarkdownConfig(cwd) {
341
+ const hasReactMarkdown = isReactMarkdownAvailable(cwd);
342
+ const hasShiki = isShikiAvailable(cwd);
343
+ const hasRemarkGfm = isRemarkGfmAvailable(cwd);
344
+ const hasMdx = isMdxAvailable(cwd);
345
+ return {
346
+ hasReactMarkdown,
347
+ hasShiki,
348
+ hasRemarkGfm,
349
+ hasMdx,
350
+ isConfigured: hasReactMarkdown
351
+ };
352
+ }
353
+ function logMarkdownStatus(cwd) {
354
+ const config = getMarkdownConfig(cwd);
355
+ if (config.isConfigured) {
356
+ console.log("[reroute/markdown] Markdown rendering available");
357
+ if (config.hasShiki) {
358
+ console.log("[reroute/markdown] ✓ Shiki syntax highlighting enabled");
359
+ }
360
+ if (config.hasRemarkGfm) {
361
+ console.log("[reroute/markdown] ✓ GitHub Flavored Markdown enabled");
362
+ }
363
+ if (config.hasMdx) {
364
+ console.log("[reroute/markdown] ✓ MDX compiler enabled (JSX in markdown)");
365
+ }
366
+ }
367
+ }
368
+ function checkMarkdownIfConfigured(cwd) {
369
+ try {
370
+ const config = getMarkdownConfig(cwd);
371
+ if (config.isConfigured) {
372
+ logMarkdownStatus(cwd);
373
+ }
374
+ return config.isConfigured;
375
+ } catch (e) {
376
+ console.warn("[reroute/markdown] check failed:", e);
377
+ return false;
378
+ }
379
+ }
380
+ var init_markdown = () => {};
381
+
382
+ // packages/cli/src/libs/markdown-processor.ts
383
+ import { existsSync as existsSync3, readFileSync as readFileSync2 } from "node:fs";
384
+ import { basename, dirname as dirname2, extname, join as join3 } from "node:path";
385
+ function parseFrontmatter(content) {
386
+ const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/;
387
+ const match = content.match(frontmatterRegex);
388
+ if (!match) {
389
+ return { data: {}, content };
390
+ }
391
+ const [, frontmatterText, markdownContent] = match;
392
+ const data = {};
393
+ const lines = frontmatterText.split(`
394
+ `);
395
+ for (const line of lines) {
396
+ const colonIndex = line.indexOf(":");
397
+ if (colonIndex === -1)
398
+ continue;
399
+ const key = line.slice(0, colonIndex).trim();
400
+ let value = line.slice(colonIndex + 1).trim();
401
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
402
+ value = value.slice(1, -1);
403
+ }
404
+ if (value.startsWith("[") && value.endsWith("]")) {
405
+ data[key] = value.slice(1, -1).split(",").map((v) => v.trim().replace(/^["']|["']$/g, ""));
406
+ } else if (value === "true" || value === "false") {
407
+ data[key] = value === "true";
408
+ } else if (!Number.isNaN(Number(value))) {
409
+ data[key] = Number(value);
410
+ } else {
411
+ data[key] = value;
412
+ }
413
+ }
414
+ return { data, content: markdownContent };
415
+ }
416
+ function hasJSXSyntax(content) {
417
+ const jsxPatterns = [
418
+ /<[A-Z][a-zA-Z0-9]*/,
419
+ /import\s+{[^}]+}\s+from/,
420
+ /import\s+\w+\s+from/,
421
+ /export\s+(default|const|function)/,
422
+ /<\w+\s+\w+={/
423
+ ];
424
+ return jsxPatterns.some((pattern) => pattern.test(content));
425
+ }
426
+ function processMarkdownFile(filePath) {
427
+ const rawContent = readFileSync2(filePath, "utf-8");
428
+ const { data, content } = parseFrontmatter(rawContent);
429
+ const hasJSX = hasJSXSyntax(content);
430
+ return {
431
+ frontmatter: data,
432
+ content,
433
+ rawContent,
434
+ hasJSX
435
+ };
436
+ }
437
+ function isMdxAvailable2(cwd) {
438
+ let currentDir = cwd;
439
+ for (let i = 0;i < 5; i++) {
440
+ const packageJsonPath = join3(currentDir, "package.json");
441
+ if (existsSync3(packageJsonPath)) {
442
+ try {
443
+ const packageJson = JSON.parse(readFileSync2(packageJsonPath, "utf-8"));
444
+ const deps = {
445
+ ...packageJson.dependencies,
446
+ ...packageJson.devDependencies,
447
+ ...packageJson.peerDependencies
448
+ };
449
+ if ("@mdx-js/mdx" in deps) {
450
+ return true;
451
+ }
452
+ } catch {}
453
+ }
454
+ const parentDir = dirname2(currentDir);
455
+ if (parentDir === currentDir) {
456
+ break;
457
+ }
458
+ currentDir = parentDir;
459
+ }
460
+ return false;
461
+ }
462
+ async function compileMdx(content, cwd, options = {}) {
463
+ if (!isMdxAvailable2(cwd)) {
464
+ console.warn("[reroute/mdx] @mdx-js/mdx not installed. Install with: bun add @mdx-js/mdx");
465
+ return null;
466
+ }
467
+ try {
468
+ let compile;
469
+ const pathsToTry = [
470
+ join3(cwd, "node_modules/@mdx-js/mdx"),
471
+ join3(cwd, "../node_modules/@mdx-js/mdx"),
472
+ join3(cwd, "../../node_modules/@mdx-js/mdx"),
473
+ join3(cwd, "../../../node_modules/@mdx-js/mdx")
474
+ ];
475
+ for (const mdxPath of pathsToTry) {
476
+ try {
477
+ const mdxModule = __require(mdxPath);
478
+ compile = mdxModule.compile;
479
+ break;
480
+ } catch {}
481
+ }
482
+ if (!compile) {
483
+ console.error("[reroute/mdx] Could not load @mdx-js/mdx from any path");
484
+ return null;
485
+ }
486
+ const { enableGfm = true, theme = "github-dark" } = options;
487
+ const remarkPlugins = [];
488
+ const rehypePlugins = [];
489
+ if (enableGfm) {
490
+ const gfmPathsToTry = [
491
+ join3(cwd, "node_modules/remark-gfm"),
492
+ join3(cwd, "../node_modules/remark-gfm"),
493
+ join3(cwd, "../../node_modules/remark-gfm"),
494
+ join3(cwd, "../../../node_modules/remark-gfm")
495
+ ];
496
+ let remarkGfm = null;
497
+ for (const gfmPath of gfmPathsToTry) {
498
+ try {
499
+ remarkGfm = __require(gfmPath);
500
+ break;
501
+ } catch {}
502
+ }
503
+ if (remarkGfm) {
504
+ remarkPlugins.push(remarkGfm.default || remarkGfm);
505
+ } else {
506
+ console.warn("[reroute/mdx] remark-gfm not available, skipping");
507
+ }
508
+ }
509
+ const shikiPathsToTry = [
510
+ join3(cwd, "node_modules/@shikijs/rehype"),
511
+ join3(cwd, "../node_modules/@shikijs/rehype"),
512
+ join3(cwd, "../../node_modules/@shikijs/rehype"),
513
+ join3(cwd, "../../../node_modules/@shikijs/rehype")
514
+ ];
515
+ let rehypeShiki = null;
516
+ for (const shikiPath of shikiPathsToTry) {
517
+ try {
518
+ rehypeShiki = __require(shikiPath);
519
+ break;
520
+ } catch {}
521
+ }
522
+ if (rehypeShiki) {
523
+ rehypePlugins.push([rehypeShiki.default || rehypeShiki, { theme }]);
524
+ } else {
525
+ console.warn("[reroute/mdx] @shikijs/rehype not available, skipping highlighting");
526
+ }
527
+ const result = await compile(content, {
528
+ remarkPlugins,
529
+ rehypePlugins,
530
+ outputFormat: "program",
531
+ development: false
532
+ });
533
+ return String(result);
534
+ } catch (error) {
535
+ console.error("[reroute/mdx] Compilation failed:", error);
536
+ return null;
537
+ }
538
+ }
539
+ async function generateMarkdownModule(processed, cwd, options = {}) {
540
+ const { frontmatter, content } = processed;
541
+ const { enableGfm = true, theme = "github-dark", isMdx = false } = options;
542
+ const compiledMdx = await compileMdx(content, cwd, { enableGfm, theme });
543
+ if (compiledMdx) {
544
+ return `// Generated from ${isMdx ? "MDX" : "Markdown"} file with @mdx-js/mdx
545
+
546
+ // MDX compiled content with imports and component
547
+ ${compiledMdx}
548
+
549
+ // Add metadata exports
550
+ export const meta = ${JSON.stringify(frontmatter, null, 2)};
551
+
552
+ export const ssr = {
553
+ head: [
554
+ '<meta property="og:type" content="article" />',
555
+ '<meta name="twitter:card" content="summary_large_image" />',
556
+ ],
557
+ };
558
+ `;
559
+ }
560
+ console.warn("[reroute/mdx] MDX compile unavailable; falling back to react-markdown");
561
+ const escapedContent = content.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$/g, "\\$");
562
+ const pluginImports = [];
563
+ const remarkPluginsList = [];
564
+ const rehypePluginsList = [];
565
+ if (enableGfm) {
566
+ pluginImports.push("import remarkGfm from 'remark-gfm';");
567
+ remarkPluginsList.push("remarkGfm");
568
+ }
569
+ const pluginImportsStr = pluginImports.length > 0 ? `${pluginImports.join(`
570
+ `)}
571
+ ` : "";
572
+ const remarkPluginsStr = remarkPluginsList.length > 0 ? `remarkPlugins={[${remarkPluginsList.join(", ")}]}` : "";
573
+ const rehypePluginsStr = rehypePluginsList.length > 0 ? `rehypePlugins={[${rehypePluginsList.join(", ")}]}` : "";
574
+ const pluginsPropsStr = [remarkPluginsStr, rehypePluginsStr].filter(Boolean).join(`
575
+ `);
576
+ return `// Generated from markdown file
577
+ import { Markdown } from 'reroute-js/react';
578
+ ${pluginImportsStr}
579
+ const meta = ${JSON.stringify(frontmatter, null, 2)};
580
+
581
+ const ssr = {
582
+ head: [
583
+ '<meta property="og:type" content="article" />',
584
+ '<meta name="twitter:card" content="summary_large_image" />',
585
+ ],
586
+ };
587
+
588
+ const markdownContent = \`${escapedContent}\`;
589
+
590
+ function MarkdownRoute() {
591
+ return (
592
+ <div>
593
+ <Markdown
594
+ ${pluginsPropsStr}
595
+ >
596
+ {markdownContent}
597
+ </Markdown>
598
+ </div>
599
+ );
600
+ }
601
+
602
+ export { meta, ssr };
603
+ export default MarkdownRoute;
604
+ `;
605
+ }
606
+ function generatePlainMarkdownModule(processed) {
607
+ const { frontmatter, content } = processed;
608
+ const escapedContent = content.replace(/\\/g, "\\\\").split(String.fromCharCode(96)).join(`\\${String.fromCharCode(96)}`).split("$").join("\\$");
609
+ return `// Generated from markdown file (plain fallback)
610
+ // No markdown renderer detected; showing raw content.
611
+ export const meta = ${JSON.stringify(frontmatter, null, 2)};
612
+
613
+ export const ssr = {
614
+ head: [
615
+ '<meta property="og:type" content="article" />',
616
+ '<meta name="twitter:card" content="summary_large_image" />',
617
+ ],
618
+ };
619
+
620
+ const markdownContent = \`${escapedContent}\`;
621
+
622
+ export default function MarkdownFallback() {
623
+ return (
624
+ <div style={{ padding: '1rem' }}>
625
+ {meta?.title && (
626
+ <h1 style={{ fontSize: '1.5rem', fontWeight: 600 }}>{meta.title}</h1>
627
+ )}
628
+ <div style={{
629
+ margin: '0.75rem 0',
630
+ padding: '0.75rem',
631
+ borderLeft: '4px solid #eab308',
632
+ background: '#fefce8',
633
+ color: '#713f12'
634
+ }}>
635
+ <strong>Markdown rendering not configured.</strong>
636
+ <div style={{ marginTop: '0.25rem' }}>
637
+ Install: react-markdown (required), remark-gfm (optional), @mdx-js/mdx (optional), @shikijs/rehype (optional).
638
+ </div>
639
+ </div>
640
+ <pre style={{ whiteSpace: 'pre-wrap', lineHeight: 1.6 }}>{markdownContent}</pre>
641
+ </div>
642
+ );
643
+ }
644
+ `;
645
+ }
646
+ function isMarkdownFile(filePath) {
647
+ const ext = extname(filePath).toLowerCase();
648
+ return ext === ".md" || ext === ".mdx";
649
+ }
650
+ var init_markdown_processor = () => {};
651
+
210
652
  // packages/cli/src/libs/tailwind.ts
211
653
  import { spawn } from "node:child_process";
212
- import { existsSync as existsSync2, readFileSync } from "node:fs";
213
- import { join as join2 } from "node:path";
654
+ import { existsSync as existsSync4, readFileSync as readFileSync3 } from "node:fs";
655
+ import { join as join4 } from "node:path";
214
656
  function isTailwindAvailable(cwd) {
215
- const packageJsonPath = join2(cwd, "package.json");
216
- if (!existsSync2(packageJsonPath)) {
657
+ const packageJsonPath = join4(cwd, "package.json");
658
+ if (!existsSync4(packageJsonPath)) {
217
659
  return false;
218
660
  }
219
661
  try {
220
- const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
662
+ const packageJson = JSON.parse(readFileSync3(packageJsonPath, "utf-8"));
221
663
  const deps = {
222
664
  ...packageJson.dependencies,
223
665
  ...packageJson.devDependencies
@@ -228,17 +670,17 @@ function isTailwindAvailable(cwd) {
228
670
  }
229
671
  }
230
672
  function getTailwindPaths(cwd) {
231
- const input = join2(cwd, "src/client/theme.css");
232
- const output = join2(cwd, ".reroute/theme.css");
673
+ const input = join4(cwd, "src/client/theme.css");
674
+ const output = join4(cwd, ".reroute/theme.css");
233
675
  return { input, output };
234
676
  }
235
677
  function hasTailwindInput(cwd) {
236
678
  const { input } = getTailwindPaths(cwd);
237
- if (!existsSync2(input)) {
679
+ if (!existsSync4(input)) {
238
680
  return false;
239
681
  }
240
682
  try {
241
- const content = readFileSync(input, "utf-8");
683
+ const content = readFileSync3(input, "utf-8");
242
684
  return content.includes("tailwindcss");
243
685
  } catch {
244
686
  return false;
@@ -246,16 +688,16 @@ function hasTailwindInput(cwd) {
246
688
  }
247
689
  function resolveTailwindBin(cwd) {
248
690
  const pathsToTry = [
249
- join2(cwd, "../node_modules/.bin/tailwindcss"),
250
- join2(cwd, "../../node_modules/.bin/tailwindcss"),
251
- join2(cwd, "../../../node_modules/.bin/tailwindcss")
691
+ join4(cwd, "../node_modules/.bin/tailwindcss"),
692
+ join4(cwd, "../../node_modules/.bin/tailwindcss"),
693
+ join4(cwd, "../../../node_modules/.bin/tailwindcss")
252
694
  ];
253
695
  for (const binPath of pathsToTry) {
254
- if (existsSync2(binPath)) {
696
+ if (existsSync4(binPath)) {
255
697
  return binPath;
256
698
  }
257
699
  }
258
- return join2(cwd, "node_modules/.bin/tailwindcss");
700
+ return join4(cwd, "node_modules/.bin/tailwindcss");
259
701
  }
260
702
  async function buildTailwind(cwd) {
261
703
  const { input, output } = getTailwindPaths(cwd);
@@ -313,12 +755,12 @@ __export(exports_gen, {
313
755
  });
314
756
  import { watch } from "node:fs";
315
757
  import { mkdir as mkdir2, readdir as readdir2, rm, writeFile as writeFile2 } from "node:fs/promises";
316
- import { join as join3 } from "node:path";
758
+ import { join as join5 } from "node:path";
317
759
  import { pathToFileURL } from "node:url";
318
760
  async function cleanupOutputDir(cwd) {
319
761
  try {
320
- await rm(join3(cwd, OUTPUT_DIR), { force: true });
321
- await mkdir2(join3(cwd, OUTPUT_DIR), { recursive: true });
762
+ await rm(join5(cwd, OUTPUT_DIR), { force: true });
763
+ await mkdir2(join5(cwd, OUTPUT_DIR), { recursive: true });
322
764
  console.log("[reroute/gen] Cleaned up generated artifacts in .reroute");
323
765
  } catch {}
324
766
  }
@@ -326,14 +768,14 @@ async function scanDirectory(dir, base = "") {
326
768
  const files = [];
327
769
  const entries = await readdir2(dir, { withFileTypes: true });
328
770
  for (const entry of entries) {
329
- const fullPath = join3(dir, entry.name);
330
- const relativePath = join3(base, entry.name);
771
+ const fullPath = join5(dir, entry.name);
772
+ const relativePath = join5(base, entry.name);
331
773
  if (entry.isDirectory()) {
332
774
  if (entry.name === "content")
333
775
  continue;
334
776
  const nested = await scanDirectory(fullPath, relativePath);
335
777
  files.push(...nested);
336
- } else if (entry.isFile() && (entry.name.endsWith(".tsx") || entry.name.endsWith(".ts"))) {
778
+ } else if (entry.isFile() && (entry.name.endsWith(".tsx") || entry.name.endsWith(".ts") || entry.name.endsWith(".md") || entry.name.endsWith(".mdx"))) {
337
779
  if (relativePath.includes("/content/") || relativePath.startsWith("content/")) {
338
780
  continue;
339
781
  }
@@ -348,8 +790,8 @@ async function scan404Files(dir, base = "") {
348
790
  const files = [];
349
791
  const entries = await readdir2(dir, { withFileTypes: true });
350
792
  for (const entry of entries) {
351
- const fullPath = join3(dir, entry.name);
352
- const relativePath = join3(base, entry.name);
793
+ const fullPath = join5(dir, entry.name);
794
+ const relativePath = join5(base, entry.name);
353
795
  if (entry.isDirectory()) {
354
796
  const nested = await scan404Files(fullPath, relativePath);
355
797
  files.push(...nested);
@@ -361,8 +803,8 @@ async function scan404Files(dir, base = "") {
361
803
  return files;
362
804
  }
363
805
  function fileToRoute(filePath) {
364
- const isLayout = filePath.endsWith("[layout].tsx") || filePath.endsWith("[layout].ts");
365
- let routePath = filePath.replace(/\.(tsx|ts)$/, "");
806
+ const isLayout = filePath.endsWith("[layout].tsx") || filePath.endsWith("[layout].ts") || filePath.endsWith("[layout].md") || filePath.endsWith("[layout].mdx");
807
+ let routePath = filePath.replace(/\.(tsx|ts|md|mdx)$/, "");
366
808
  if (isLayout) {
367
809
  routePath = routePath.replace(/[layout]$/, "").replace(/\/$/, "");
368
810
  }
@@ -423,11 +865,20 @@ function generateRouteTree(files) {
423
865
  notFoundRoutes
424
866
  };
425
867
  }
868
+ function getImportPath(filePath) {
869
+ const isMarkdown = /\.(md|mdx)$/.test(filePath);
870
+ if (isMarkdown) {
871
+ const pathWithoutExt2 = filePath.replace(/\.(md|mdx)$/, "");
872
+ return `./markdown/${pathWithoutExt2}`;
873
+ }
874
+ const pathWithoutExt = filePath.replace(/\.(tsx|ts)$/, "");
875
+ return `../src/client/routes/${pathWithoutExt}`;
876
+ }
426
877
  function generateTypeScript(tree) {
427
878
  const imports = [
428
- ...tree.routes.map((r, i) => `import Route${i} from '../src/client/routes/${r.filePath.replace(/\.(tsx|ts)$/, "")}';`),
429
- ...tree.layouts.map((l, i) => `import Layout${i} from '../src/client/routes/${l.filePath.replace(/\.(tsx|ts)$/, "")}';`),
430
- ...tree.notFoundRoutes.map((nf, i) => `import NotFound${i} from '../src/client/routes/${nf.filePath.replace(/\.(tsx|ts)$/, "")}';`)
879
+ ...tree.routes.map((r, i) => `import Route${i} from '${getImportPath(r.filePath)}';`),
880
+ ...tree.layouts.map((l, i) => `import Layout${i} from '${getImportPath(l.filePath)}';`),
881
+ ...tree.notFoundRoutes.map((nf, i) => `import NotFound${i} from '${getImportPath(nf.filePath)}';`)
431
882
  ].join(`
432
883
  `);
433
884
  const routesArray = tree.routes.map((r, i) => {
@@ -534,7 +985,7 @@ function matchPattern(pattern: string, pathname: string): Record<string, string>
534
985
  async function listContentFiles(collectionDir) {
535
986
  try {
536
987
  const entries = await readdir2(collectionDir, { withFileTypes: true });
537
- return entries.filter((e) => e.isFile() && /\.(tsx|ts)$/.test(e.name) && !e.name.startsWith("_")).map((e) => e.name);
988
+ return entries.filter((e) => e.isFile() && /\.(tsx|ts|md|mdx)$/.test(e.name) && !e.name.startsWith("_")).map((e) => e.name);
538
989
  } catch {
539
990
  return [];
540
991
  }
@@ -548,7 +999,7 @@ async function sha8(text) {
548
999
  return hex.slice(0, 8);
549
1000
  }
550
1001
  async function buildContentChunks(cwd) {
551
- const routesRoot = join3(cwd, ROUTES_DIR);
1002
+ const routesRoot = join5(cwd, ROUTES_DIR);
552
1003
  console.log(`[reroute/content] scan ${routesRoot}`);
553
1004
  const collections = await readdir2(routesRoot, { withFileTypes: true });
554
1005
  const results = [];
@@ -556,20 +1007,31 @@ async function buildContentChunks(cwd) {
556
1007
  if (!c.isDirectory())
557
1008
  continue;
558
1009
  const collection = c.name;
559
- const contentDir = join3(routesRoot, collection, "content");
1010
+ const contentDir = join5(routesRoot, collection, "content");
560
1011
  console.log(`[reroute/content] collection ${collection} dir ${contentDir}`);
561
1012
  const files = await listContentFiles(contentDir);
562
1013
  console.log(`[reroute/content] files ${files.join(",")}`);
563
1014
  if (!files.length)
564
1015
  continue;
565
1016
  for (const file of files) {
566
- const name = file.replace(/\.(tsx|ts)$/, "");
567
- const absSrc = join3(contentDir, file);
1017
+ const name = file.replace(/\.(tsx|ts|md|mdx)$/, "");
1018
+ const absSrc = join5(contentDir, file);
1019
+ const isMarkdown = /\.(md|mdx)$/.test(file);
1020
+ const buildSrc = isMarkdown ? join5(cwd, ".reroute", "markdown", collection, "content", `${name}.tsx`) : absSrc;
1021
+ if (isMarkdown) {
1022
+ try {
1023
+ const exists = await Bun.file(buildSrc).exists();
1024
+ if (!exists) {
1025
+ console.warn(`[reroute/content] Converted markdown missing, skipping: ${buildSrc}`);
1026
+ continue;
1027
+ }
1028
+ } catch {}
1029
+ }
568
1030
  let code = "";
569
1031
  try {
570
- console.log(`[reroute/content] build ${absSrc}`);
1032
+ console.log(`[reroute/content] build ${buildSrc}`);
571
1033
  const result = await Bun.build({
572
- entrypoints: [absSrc],
1034
+ entrypoints: [buildSrc],
573
1035
  target: "browser",
574
1036
  format: "esm",
575
1037
  splitting: false,
@@ -587,10 +1049,10 @@ async function buildContentChunks(cwd) {
587
1049
  continue;
588
1050
  }
589
1051
  const hash = await sha8(code);
590
- const chunkRelDir = join3(".reroute", "chunks", collection);
591
- const chunkAbsDir = join3(cwd, chunkRelDir);
1052
+ const chunkRelDir = join5(".reroute", "chunks", collection);
1053
+ const chunkAbsDir = join5(cwd, chunkRelDir);
592
1054
  const outFile = `${name}.${hash}.js`;
593
- const absOut = join3(chunkAbsDir, outFile);
1055
+ const absOut = join5(chunkAbsDir, outFile);
594
1056
  await mkdir2(chunkAbsDir, { recursive: true });
595
1057
  try {
596
1058
  const exists = await Bun.file(absOut).exists();
@@ -599,8 +1061,8 @@ async function buildContentChunks(cwd) {
599
1061
  } catch {}
600
1062
  let meta = {};
601
1063
  try {
602
- console.log(`[reroute/content] meta ${absSrc}`);
603
- const url = `${pathToFileURL(absSrc).href}?t=${Date.now()}`;
1064
+ console.log(`[reroute/content] meta ${buildSrc}`);
1065
+ const url = `${pathToFileURL(buildSrc).href}?t=${Date.now()}`;
604
1066
  const m = await import(url);
605
1067
  meta = m.meta || {};
606
1068
  } catch {}
@@ -640,12 +1102,12 @@ async function buildContentChunks(cwd) {
640
1102
  lines.push(" return m ? (m as Record<string, any>)[name] : undefined;");
641
1103
  lines.push("}");
642
1104
  lines.push("");
643
- await mkdir2(join3(cwd, ".reroute"), { recursive: true });
644
- await writeFile2(join3(cwd, OUTPUT_CONTENT_TS), lines.join(`
1105
+ await mkdir2(join5(cwd, ".reroute"), { recursive: true });
1106
+ await writeFile2(join5(cwd, OUTPUT_CONTENT_TS), lines.join(`
645
1107
  `), "utf-8");
646
- console.log(`[reroute/content] wrote ${join3(cwd, OUTPUT_CONTENT_TS)}`);
1108
+ console.log(`[reroute/content] wrote ${join5(cwd, OUTPUT_CONTENT_TS)}`);
647
1109
  const collectionsSet = new Set(results.map((r) => r.collection));
648
- await mkdir2(join3(cwd, OUTPUT_COLLECTIONS_DIR), { recursive: true });
1110
+ await mkdir2(join5(cwd, OUTPUT_COLLECTIONS_DIR), { recursive: true });
649
1111
  for (const collection of collectionsSet) {
650
1112
  const items = results.filter((r) => r.collection === collection);
651
1113
  const js = [];
@@ -665,31 +1127,100 @@ async function buildContentChunks(cwd) {
665
1127
  js.push(" return byName[name];");
666
1128
  js.push("}");
667
1129
  js.push("");
668
- await writeFile2(join3(cwd, OUTPUT_COLLECTIONS_DIR, `${collection}.js`), js.join(`
1130
+ await writeFile2(join5(cwd, OUTPUT_COLLECTIONS_DIR, `${collection}.js`), js.join(`
669
1131
  `), "utf-8");
670
- console.log(`[reroute/content] wrote ${join3(cwd, OUTPUT_COLLECTIONS_DIR, `${collection}.js`)}`);
1132
+ console.log(`[reroute/content] wrote ${join5(cwd, OUTPUT_COLLECTIONS_DIR, `${collection}.js`)}`);
1133
+ }
1134
+ }
1135
+ async function preprocessMarkdownFiles(cwd) {
1136
+ console.log("[reroute/markdown] Starting markdown preprocessing...");
1137
+ const routesPath = join5(cwd, ROUTES_DIR);
1138
+ const markdownDir = join5(cwd, ".reroute", "markdown");
1139
+ try {
1140
+ await rm(markdownDir, { force: true, recursive: true });
1141
+ } catch {}
1142
+ const markdownConfig = getMarkdownConfig(cwd);
1143
+ console.log("[reroute/markdown] Config:", markdownConfig);
1144
+ try {
1145
+ await mkdir2(markdownDir, { recursive: true });
1146
+ } catch {}
1147
+ async function scanMarkdown(dir, base = "") {
1148
+ const files = [];
1149
+ try {
1150
+ const entries = await readdir2(dir, { withFileTypes: true });
1151
+ for (const entry of entries) {
1152
+ const fullPath = join5(dir, entry.name);
1153
+ const relativePath = join5(base, entry.name);
1154
+ if (entry.isDirectory()) {
1155
+ const nested = await scanMarkdown(fullPath, relativePath);
1156
+ files.push(...nested);
1157
+ } else if (entry.isFile() && isMarkdownFile(entry.name)) {
1158
+ console.log(`[reroute/markdown] Found markdown file: ${relativePath}`);
1159
+ files.push(relativePath);
1160
+ }
1161
+ }
1162
+ } catch (err) {
1163
+ console.error(`[reroute/markdown] Error scanning ${dir}:`, err);
1164
+ }
1165
+ return files;
1166
+ }
1167
+ console.log(`[reroute/markdown] Scanning ${routesPath} for markdown files...`);
1168
+ const markdownFiles = await scanMarkdown(routesPath);
1169
+ console.log(`[reroute/markdown] Scan complete. Found files:`, markdownFiles);
1170
+ if (markdownFiles.length === 0) {
1171
+ console.log("[reroute/markdown] No markdown files found, skipping preprocessing");
1172
+ return;
1173
+ }
1174
+ console.log(`[reroute/markdown] Found ${markdownFiles.length} markdown file(s)`);
1175
+ await mkdir2(markdownDir, { recursive: true });
1176
+ for (const file of markdownFiles) {
1177
+ const sourcePath = join5(routesPath, file);
1178
+ const targetPath = join5(markdownDir, file.replace(/\.mdx?$/, ".tsx"));
1179
+ try {
1180
+ const processed = processMarkdownFile(sourcePath);
1181
+ const isMdx = file.endsWith(".mdx");
1182
+ let moduleCode;
1183
+ if (markdownConfig.isConfigured) {
1184
+ moduleCode = await generateMarkdownModule(processed, cwd, {
1185
+ enableGfm: markdownConfig.hasRemarkGfm,
1186
+ theme: "github-dark",
1187
+ isMdx
1188
+ });
1189
+ } else {
1190
+ moduleCode = generatePlainMarkdownModule(processed);
1191
+ }
1192
+ const targetDir = join5(markdownDir, file.split("/").slice(0, -1).join("/"));
1193
+ if (targetDir !== markdownDir) {
1194
+ await mkdir2(targetDir, { recursive: true });
1195
+ }
1196
+ await writeFile2(targetPath, moduleCode, "utf-8");
1197
+ console.log(`[reroute/markdown] Processed ${file} -> ${targetPath}`);
1198
+ } catch (error) {
1199
+ console.error(`[reroute/markdown] Failed to process ${file}:`, error);
1200
+ }
671
1201
  }
672
1202
  }
673
1203
  async function generate(cwd) {
674
1204
  console.log("[reroute/gen] Starting generation...");
675
1205
  await cleanupOutputDir(cwd);
676
- const routesPath = join3(cwd, ROUTES_DIR);
1206
+ await preprocessMarkdownFiles(cwd);
1207
+ const routesPath = join5(cwd, ROUTES_DIR);
677
1208
  try {
678
1209
  const files = await scanDirectory(routesPath);
679
1210
  const nfFiles = await scan404Files(routesPath);
680
1211
  const all = Array.from(new Set([...files, ...nfFiles]));
681
1212
  const tree = generateRouteTree(all.map((f) => f.replace(/\\/g, "/")));
682
1213
  const ts = generateTypeScript(tree);
683
- await mkdir2(join3(cwd, ".reroute"), { recursive: true });
684
- await writeFile2(join3(cwd, OUTPUT_ROUTES), ts, "utf-8");
685
- console.log(`[reroute/gen] Generated routes: ${join3(cwd, OUTPUT_ROUTES)}`);
1214
+ await mkdir2(join5(cwd, ".reroute"), { recursive: true });
1215
+ await writeFile2(join5(cwd, OUTPUT_ROUTES), ts, "utf-8");
1216
+ console.log(`[reroute/gen] Generated routes: ${join5(cwd, OUTPUT_ROUTES)}`);
686
1217
  } catch (error) {
687
1218
  console.error("[reroute/gen] Failed to generate routes:", error);
688
1219
  throw error;
689
1220
  }
690
1221
  try {
691
1222
  await buildContentChunks(cwd);
692
- console.log(`[reroute/gen] Generated content: ${join3(cwd, OUTPUT_CONTENT_TS)} + collections/*.js`);
1223
+ console.log(`[reroute/gen] Generated content: ${join5(cwd, OUTPUT_CONTENT_TS)} + collections/*.js`);
693
1224
  } catch (error) {
694
1225
  console.error("[reroute/gen] Failed to generate content:", error);
695
1226
  throw error;
@@ -709,10 +1240,10 @@ async function generate(cwd) {
709
1240
  indexLines.push("} as const;");
710
1241
  indexLines.push("");
711
1242
  indexLines.push("export type RerouteArtifacts = typeof artifacts;");
712
- await writeFile2(join3(cwd, OUTPUT_INDEX), indexLines.join(`
1243
+ await writeFile2(join5(cwd, OUTPUT_INDEX), indexLines.join(`
713
1244
  `), "utf-8");
714
- console.log(`[reroute/gen] Generated index: ${join3(cwd, OUTPUT_INDEX)}`);
715
- console.log("[reroute/gen] Generation complete!");
1245
+ console.log(`[reroute/gen] Generated index: ${join5(cwd, OUTPUT_INDEX)}`);
1246
+ console.log("[reroute/gen] Generation complete");
716
1247
  }
717
1248
  async function gen(args) {
718
1249
  const cwd = process.cwd();
@@ -720,6 +1251,7 @@ async function gen(args) {
720
1251
  if (!watchMode) {
721
1252
  await generate(cwd);
722
1253
  await buildTailwindIfConfigured(cwd);
1254
+ checkMarkdownIfConfigured(cwd);
723
1255
  return;
724
1256
  }
725
1257
  console.log("[reroute/gen] Watch mode enabled");
@@ -727,6 +1259,7 @@ async function gen(args) {
727
1259
  await generate(cwd);
728
1260
  try {
729
1261
  await buildTailwindIfConfigured(cwd);
1262
+ checkMarkdownIfConfigured(cwd);
730
1263
  } catch {}
731
1264
  const notifyReload = async (reason) => {
732
1265
  const ports = [
@@ -745,7 +1278,7 @@ async function gen(args) {
745
1278
  } catch {}
746
1279
  }
747
1280
  };
748
- const routesPath = join3(cwd, ROUTES_DIR);
1281
+ const routesPath = join5(cwd, ROUTES_DIR);
749
1282
  console.log(`[reroute/gen] Watching ${routesPath} for changes...`);
750
1283
  let debounce = null;
751
1284
  const routesWatcher = watch(routesPath, { recursive: true }, (_ev, filename) => {
@@ -764,7 +1297,7 @@ async function gen(args) {
764
1297
  }
765
1298
  }, 120);
766
1299
  });
767
- const clientPath = join3(cwd, "src", "client");
1300
+ const clientPath = join5(cwd, "src", "client");
768
1301
  console.log(`[reroute/gen] Watching ${clientPath} for Tailwind class changes...`);
769
1302
  let twDebounce = null;
770
1303
  const twWatcher = watch(clientPath, { recursive: true }, (_ev, filename) => {
@@ -800,6 +1333,8 @@ async function gen(args) {
800
1333
  }
801
1334
  var ROUTES_DIR = "src/client/routes", OUTPUT_DIR = ".reroute", OUTPUT_ROUTES = ".reroute/routes.ts", OUTPUT_CONTENT_TS = ".reroute/content.ts", OUTPUT_COLLECTIONS_DIR = ".reroute/collections", OUTPUT_INDEX = ".reroute/index.ts";
802
1335
  var init_gen = __esm(() => {
1336
+ init_markdown();
1337
+ init_markdown_processor();
803
1338
  init_tailwind();
804
1339
  });
805
1340
 
@@ -809,20 +1344,20 @@ __export(exports_boot, {
809
1344
  default: () => boot
810
1345
  });
811
1346
  import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
812
- import { join as join4 } from "node:path";
1347
+ import { join as join6 } from "node:path";
813
1348
  async function boot(_) {
814
1349
  const cwd = process.cwd();
815
1350
  try {
816
1351
  console.log("[reroute/boot] Initializing .reroute directory...");
817
- await mkdir3(join4(cwd, OUTPUT_DIR2), { recursive: true });
818
- await mkdir3(join4(cwd, OUTPUT_COLLECTIONS_DIR2), { recursive: true });
819
- await writeFile3(join4(cwd, OUTPUT_ROUTES2), STUB_ROUTES, "utf-8");
1352
+ await mkdir3(join6(cwd, OUTPUT_DIR2), { recursive: true });
1353
+ await mkdir3(join6(cwd, OUTPUT_COLLECTIONS_DIR2), { recursive: true });
1354
+ await writeFile3(join6(cwd, OUTPUT_ROUTES2), STUB_ROUTES, "utf-8");
820
1355
  console.log(`[reroute/boot] Created stub: ${OUTPUT_ROUTES2}`);
821
- await writeFile3(join4(cwd, OUTPUT_CONTENT_TS2), STUB_CONTENT, "utf-8");
1356
+ await writeFile3(join6(cwd, OUTPUT_CONTENT_TS2), STUB_CONTENT, "utf-8");
822
1357
  console.log(`[reroute/boot] Created stub: ${OUTPUT_CONTENT_TS2}`);
823
- await writeFile3(join4(cwd, OUTPUT_INDEX2), STUB_INDEX, "utf-8");
1358
+ await writeFile3(join6(cwd, OUTPUT_INDEX2), STUB_INDEX, "utf-8");
824
1359
  console.log(`[reroute/boot] Created stub: ${OUTPUT_INDEX2}`);
825
- console.log("[reroute/boot] Initialization complete!");
1360
+ console.log("[reroute/boot] Initialization complete");
826
1361
  console.log('[reroute/boot] Run "reroute gen" to generate actual routes and content.');
827
1362
  } catch (error) {
828
1363
  console.error("[reroute/boot] Failed to initialize:", error);
@@ -866,12 +1401,692 @@ export type RerouteArtifacts = typeof artifacts;
866
1401
  `;
867
1402
  var init_boot = () => {};
868
1403
 
1404
+ // packages/cli/src/libs/log.ts
1405
+ function colorizeLogPrefix(text) {
1406
+ let colored = text;
1407
+ const sortedPrefixes = Object.entries(PREFIX_COLORS).sort(([a], [b]) => b.length - a.length);
1408
+ for (const [prefix, colorTag] of sortedPrefixes) {
1409
+ colored = colored.replace(new RegExp(`(${prefix.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})`, "g"), `${colorTag}$1{/}`);
1410
+ }
1411
+ return colored;
1412
+ }
1413
+ function blessedToAnsi(text) {
1414
+ return text.replace(/\{cyan-fg\}/g, "\x1B[36m").replace(/\{blue-fg\}/g, "\x1B[34m").replace(/\{magenta-fg\}/g, "\x1B[35m").replace(/\{yellow-fg\}/g, "\x1B[33m").replace(/\{green-fg\}/g, "\x1B[32m").replace(/\{red-fg\}/g, "\x1B[31m").replace(/\{bright-cyan-fg\}/g, "\x1B[96m").replace(/\{bright-blue-fg\}/g, "\x1B[94m").replace(/\{bright-magenta-fg\}/g, "\x1B[95m").replace(/\{bright-yellow-fg\}/g, "\x1B[93m").replace(/\{bright-green-fg\}/g, "\x1B[92m").replace(/\{bright-red-fg\}/g, "\x1B[91m").replace(/\{\/\}/g, "\x1B[0m");
1415
+ }
1416
+ function colorizeLogPrefixAnsi(text) {
1417
+ return blessedToAnsi(colorizeLogPrefix(text));
1418
+ }
1419
+ function createServerOutputHandler(buffer) {
1420
+ return (data) => {
1421
+ const text = buffer.current + data.toString();
1422
+ const lines = text.split(`
1423
+ `);
1424
+ buffer.current = lines.pop() || "";
1425
+ for (const line of lines) {
1426
+ const trimmedLine = line.trim();
1427
+ if (!trimmedLine) {
1428
+ continue;
1429
+ }
1430
+ const ansiColored = colorizeLogPrefixAnsi(line);
1431
+ console.log(ansiColored);
1432
+ }
1433
+ };
1434
+ }
1435
+ var PREFIX_COLORS;
1436
+ var init_log = __esm(() => {
1437
+ PREFIX_COLORS = {
1438
+ "[reroute]": "{cyan-fg}",
1439
+ "[reroute/gen]": "{bright-blue-fg}",
1440
+ "[reroute/content]": "{magenta-fg}",
1441
+ "[reroute/markdown]": "{yellow-fg}",
1442
+ "[reroute/tailwind]": "{red-fg}",
1443
+ "[reroute/mdx]": "{bright-red-fg}",
1444
+ "[reroute/boot]": "{bright-yellow-fg}",
1445
+ "[reroute/dev]": "{green-fg}",
1446
+ "[reroute/start]": "{bright-cyan-fg}",
1447
+ "[reroute/build]": "{bright-magenta-fg}",
1448
+ "[api]": "{blue-fg}",
1449
+ "[app]": "{bright-green-fg}"
1450
+ };
1451
+ });
1452
+
1453
+ // packages/cli/src/commands/dev.ts
1454
+ var exports_dev = {};
1455
+ __export(exports_dev, {
1456
+ default: () => dev
1457
+ });
1458
+ import { spawn as spawn2 } from "node:child_process";
1459
+ import { existsSync as existsSync5 } from "node:fs";
1460
+ import { join as join7 } from "node:path";
1461
+ function getRerouteCommand() {
1462
+ const binPath = join7(import.meta.dir, "..", "..", "bin.ts");
1463
+ const isBunDev = existsSync5(binPath);
1464
+ if (isBunDev) {
1465
+ return `bun ${binPath}`;
1466
+ }
1467
+ const cwd = process.cwd();
1468
+ const nodeModulesPaths = [
1469
+ join7(cwd, "node_modules", ".bin", "reroute"),
1470
+ join7(cwd, "..", "node_modules", ".bin", "reroute"),
1471
+ join7(cwd, "..", "..", "node_modules", ".bin", "reroute"),
1472
+ join7(cwd, "..", "..", "..", "node_modules", ".bin", "reroute")
1473
+ ];
1474
+ for (const binPath2 of nodeModulesPaths) {
1475
+ if (existsSync5(binPath2)) {
1476
+ return binPath2;
1477
+ }
1478
+ }
1479
+ return "reroute";
1480
+ }
1481
+ async function dev(args) {
1482
+ const singleColumn = args.includes("--single") || args.includes("-s");
1483
+ try {
1484
+ console.log("[reroute/dev] Running boot...");
1485
+ await boot([]);
1486
+ console.log(`[reroute/dev] Boot complete
1487
+ `);
1488
+ console.log("[reroute/dev] Starting development servers...");
1489
+ console.log(`[reroute/dev] Press Ctrl+C to stop
1490
+ `);
1491
+ const rerouteCmd = getRerouteCommand();
1492
+ const useShell = rerouteCmd.includes(" ");
1493
+ const genCommand = useShell ? `${rerouteCmd} gen --watch` : rerouteCmd;
1494
+ const genArgs = useShell ? [] : ["gen", "--watch"];
1495
+ const genProcess = spawn2(genCommand, genArgs, {
1496
+ stdio: ["ignore", "pipe", "pipe"],
1497
+ shell: useShell
1498
+ });
1499
+ const serverProcess = spawn2("bun", ["--watch", "src/index.ts"], {
1500
+ stdio: ["ignore", "pipe", "pipe"]
1501
+ });
1502
+ if (singleColumn) {
1503
+ const genBuffer = { current: "" };
1504
+ const serverBuffer = { current: "" };
1505
+ const handleGenOutput = (data) => {
1506
+ const text = genBuffer.current + data.toString();
1507
+ const lines = text.split(`
1508
+ `);
1509
+ genBuffer.current = lines.pop() || "";
1510
+ for (const line of lines) {
1511
+ if (!line.trim()) {
1512
+ continue;
1513
+ }
1514
+ const ansiColored = colorizeLogPrefixAnsi(line);
1515
+ console.log(ansiColored);
1516
+ }
1517
+ };
1518
+ const handleServerOutput = createServerOutputHandler(serverBuffer);
1519
+ genProcess.stdout?.on("data", handleGenOutput);
1520
+ genProcess.stderr?.on("data", handleGenOutput);
1521
+ serverProcess.stdout?.on("data", handleServerOutput);
1522
+ serverProcess.stderr?.on("data", handleServerOutput);
1523
+ genProcess.on("exit", (code) => {
1524
+ console.log(`
1525
+ [reroute/gen] Process exited with code ${code}`);
1526
+ });
1527
+ serverProcess.on("exit", (code) => {
1528
+ console.log(`
1529
+ [server] Process exited with code ${code}`);
1530
+ });
1531
+ process.on("SIGINT", () => {
1532
+ console.log(`
1533
+ [reroute/dev] Shutting down...`);
1534
+ genProcess.kill("SIGINT");
1535
+ serverProcess.kill("SIGINT");
1536
+ process.exit(0);
1537
+ });
1538
+ } else {
1539
+ const blessed = await import("blessed");
1540
+ const contrib = await import("blessed-contrib");
1541
+ const screen = blessed.default.screen({
1542
+ smartCSR: true,
1543
+ title: "reroute dev",
1544
+ mouse: true
1545
+ });
1546
+ const grid = new contrib.default.grid({
1547
+ rows: 1,
1548
+ cols: 2,
1549
+ screen
1550
+ });
1551
+ const genBox = grid.set(0, 0, 1, 1, blessed.default.log, {
1552
+ label: " reroute gen --watch ",
1553
+ border: { type: "line" },
1554
+ style: {
1555
+ border: { fg: "cyan" }
1556
+ },
1557
+ scrollable: true,
1558
+ alwaysScroll: true,
1559
+ scrollbar: {
1560
+ ch: " ",
1561
+ inverse: true
1562
+ },
1563
+ tags: true,
1564
+ keys: true,
1565
+ vi: true,
1566
+ mouse: true,
1567
+ input: true,
1568
+ clickable: true
1569
+ });
1570
+ const serverBox = grid.set(0, 1, 1, 1, blessed.default.log, {
1571
+ label: " bun --watch src/index.ts ",
1572
+ border: { type: "line" },
1573
+ style: {
1574
+ border: { fg: "green" }
1575
+ },
1576
+ scrollable: true,
1577
+ alwaysScroll: true,
1578
+ scrollbar: {
1579
+ ch: " ",
1580
+ inverse: true
1581
+ },
1582
+ tags: true,
1583
+ keys: true,
1584
+ vi: true,
1585
+ mouse: true,
1586
+ input: true,
1587
+ clickable: true
1588
+ });
1589
+ genBox.key(["up", "k"], () => {
1590
+ genBox.scroll(-1);
1591
+ screen.render();
1592
+ });
1593
+ genBox.key(["down", "j"], () => {
1594
+ genBox.scroll(1);
1595
+ screen.render();
1596
+ });
1597
+ genBox.key(["pageup"], () => {
1598
+ genBox.scroll(-genBox.height);
1599
+ screen.render();
1600
+ });
1601
+ genBox.key(["pagedown"], () => {
1602
+ genBox.scroll(genBox.height);
1603
+ screen.render();
1604
+ });
1605
+ genBox.key(["home", "g"], () => {
1606
+ genBox.setScrollPerc(0);
1607
+ screen.render();
1608
+ });
1609
+ genBox.key(["end", "G"], () => {
1610
+ genBox.setScrollPerc(100);
1611
+ screen.render();
1612
+ });
1613
+ serverBox.key(["up", "k"], () => {
1614
+ serverBox.scroll(-1);
1615
+ screen.render();
1616
+ });
1617
+ serverBox.key(["down", "j"], () => {
1618
+ serverBox.scroll(1);
1619
+ screen.render();
1620
+ });
1621
+ serverBox.key(["pageup"], () => {
1622
+ serverBox.scroll(-serverBox.height);
1623
+ screen.render();
1624
+ });
1625
+ serverBox.key(["pagedown"], () => {
1626
+ serverBox.scroll(serverBox.height);
1627
+ screen.render();
1628
+ });
1629
+ serverBox.key(["home", "g"], () => {
1630
+ serverBox.setScrollPerc(0);
1631
+ screen.render();
1632
+ });
1633
+ serverBox.key(["end", "G"], () => {
1634
+ serverBox.setScrollPerc(100);
1635
+ screen.render();
1636
+ });
1637
+ genBox.on("wheeldown", () => {
1638
+ genBox.scroll(3);
1639
+ screen.render();
1640
+ });
1641
+ genBox.on("wheelup", () => {
1642
+ genBox.scroll(-3);
1643
+ screen.render();
1644
+ });
1645
+ serverBox.on("wheeldown", () => {
1646
+ serverBox.scroll(3);
1647
+ screen.render();
1648
+ });
1649
+ serverBox.on("wheelup", () => {
1650
+ serverBox.scroll(-3);
1651
+ screen.render();
1652
+ });
1653
+ genBox.on("click", () => {
1654
+ genBox.focus();
1655
+ screen.render();
1656
+ });
1657
+ serverBox.on("click", () => {
1658
+ serverBox.focus();
1659
+ screen.render();
1660
+ });
1661
+ screen.key(["tab"], () => {
1662
+ if (screen.focused === genBox) {
1663
+ serverBox.focus();
1664
+ } else {
1665
+ genBox.focus();
1666
+ }
1667
+ screen.render();
1668
+ });
1669
+ genBox.focus();
1670
+ screen.render();
1671
+ genProcess.stdout?.on("data", (data) => {
1672
+ const text = data.toString();
1673
+ const lines = text.split(`
1674
+ `).filter((line) => line.trim());
1675
+ if (lines.length > 0) {
1676
+ const colored = colorizeLogPrefix(lines.join(`
1677
+ `));
1678
+ genBox.log(colored);
1679
+ screen.render();
1680
+ }
1681
+ });
1682
+ genProcess.stderr?.on("data", (data) => {
1683
+ const text = data.toString();
1684
+ const lines = text.split(`
1685
+ `).filter((line) => line.trim());
1686
+ if (lines.length > 0) {
1687
+ const colored = colorizeLogPrefix(lines.join(`
1688
+ `));
1689
+ genBox.log(colored);
1690
+ screen.render();
1691
+ }
1692
+ });
1693
+ serverProcess.stdout?.on("data", (data) => {
1694
+ const text = data.toString();
1695
+ const filteredText = text.split(`
1696
+ `).filter((line) => line.trim()).join(`
1697
+ `);
1698
+ if (filteredText) {
1699
+ const colored = colorizeLogPrefix(filteredText);
1700
+ serverBox.log(colored);
1701
+ screen.render();
1702
+ }
1703
+ });
1704
+ serverProcess.stderr?.on("data", (data) => {
1705
+ const text = data.toString();
1706
+ const filteredText = text.split(`
1707
+ `).filter((line) => line.trim()).join(`
1708
+ `);
1709
+ if (filteredText) {
1710
+ const colored = colorizeLogPrefix(filteredText);
1711
+ serverBox.log(colored);
1712
+ screen.render();
1713
+ }
1714
+ });
1715
+ genProcess.on("exit", (code) => {
1716
+ genBox.log(`
1717
+ [Process exited with code ${code}]`);
1718
+ screen.render();
1719
+ });
1720
+ serverProcess.on("exit", (code) => {
1721
+ serverBox.log(`
1722
+ [Process exited with code ${code}]`);
1723
+ screen.render();
1724
+ });
1725
+ screen.key(["escape", "q", "C-c"], () => {
1726
+ genProcess.kill("SIGINT");
1727
+ serverProcess.kill("SIGINT");
1728
+ screen.destroy();
1729
+ process.exit(0);
1730
+ });
1731
+ screen.on("resize", () => {
1732
+ screen.render();
1733
+ });
1734
+ }
1735
+ } catch (error) {
1736
+ if (error.code === "SIGINT") {
1737
+ console.log(`
1738
+ [reroute/dev] Shutting down...`);
1739
+ process.exit(0);
1740
+ }
1741
+ console.error("[reroute/dev] Error:", error);
1742
+ throw error;
1743
+ }
1744
+ }
1745
+ var init_dev = __esm(() => {
1746
+ init_log();
1747
+ init_boot();
1748
+ });
1749
+
1750
+ // packages/cli/src/commands/start.ts
1751
+ var exports_start = {};
1752
+ __export(exports_start, {
1753
+ default: () => start
1754
+ });
1755
+ import { spawn as spawn3 } from "node:child_process";
1756
+ import { existsSync as existsSync6 } from "node:fs";
1757
+ import { join as join8 } from "node:path";
1758
+ function getRerouteCommand2() {
1759
+ const binPath = join8(import.meta.dir, "..", "..", "bin.ts");
1760
+ const isBunDev = existsSync6(binPath);
1761
+ if (isBunDev) {
1762
+ return `bun ${binPath}`;
1763
+ }
1764
+ const cwd = process.cwd();
1765
+ const nodeModulesPaths = [
1766
+ join8(cwd, "node_modules", ".bin", "reroute"),
1767
+ join8(cwd, "..", "node_modules", ".bin", "reroute"),
1768
+ join8(cwd, "..", "..", "node_modules", ".bin", "reroute"),
1769
+ join8(cwd, "..", "..", "..", "node_modules", ".bin", "reroute")
1770
+ ];
1771
+ for (const binPath2 of nodeModulesPaths) {
1772
+ if (existsSync6(binPath2)) {
1773
+ return binPath2;
1774
+ }
1775
+ }
1776
+ return "reroute";
1777
+ }
1778
+ async function start(_args) {
1779
+ try {
1780
+ const rerouteCmd = getRerouteCommand2();
1781
+ const useShell = rerouteCmd.includes(" ");
1782
+ const bootBuffer = { current: "" };
1783
+ const genBuffer = { current: "" };
1784
+ const handleBootOutput = (data) => {
1785
+ const text = bootBuffer.current + data.toString();
1786
+ const lines = text.split(`
1787
+ `);
1788
+ bootBuffer.current = lines.pop() || "";
1789
+ for (const line of lines) {
1790
+ if (!line.trim()) {
1791
+ continue;
1792
+ }
1793
+ const ansiColored = colorizeLogPrefixAnsi(line);
1794
+ console.log(ansiColored);
1795
+ }
1796
+ };
1797
+ const handleGenOutput = (data) => {
1798
+ const text = genBuffer.current + data.toString();
1799
+ const lines = text.split(`
1800
+ `);
1801
+ genBuffer.current = lines.pop() || "";
1802
+ for (const line of lines) {
1803
+ if (!line.trim()) {
1804
+ continue;
1805
+ }
1806
+ const ansiColored = colorizeLogPrefixAnsi(line);
1807
+ console.log(ansiColored);
1808
+ }
1809
+ };
1810
+ process.stdout.write(`${colorizeLogPrefixAnsi("[reroute/start] Running boot...")}
1811
+ `);
1812
+ const bootCommand = useShell ? `${rerouteCmd} boot` : rerouteCmd;
1813
+ const bootArgs = useShell ? [] : ["boot"];
1814
+ await new Promise((resolve, reject) => {
1815
+ const bootProcess = spawn3(bootCommand, bootArgs, {
1816
+ stdio: ["ignore", "pipe", "pipe"],
1817
+ shell: useShell
1818
+ });
1819
+ bootProcess.stdout?.on("data", handleBootOutput);
1820
+ bootProcess.stderr?.on("data", handleBootOutput);
1821
+ bootProcess.on("exit", (code) => {
1822
+ if (code !== null && code !== 0) {
1823
+ reject(new Error(`Boot exited with code ${code}`));
1824
+ } else {
1825
+ resolve();
1826
+ }
1827
+ });
1828
+ bootProcess.on("error", (error) => {
1829
+ reject(error);
1830
+ });
1831
+ });
1832
+ process.stdout.write(colorizeLogPrefixAnsi(`[reroute/start] Boot complete
1833
+ `));
1834
+ process.stdout.write(`${colorizeLogPrefixAnsi("[reroute/start] Running gen...")}
1835
+ `);
1836
+ const genCommand = useShell ? `${rerouteCmd} gen` : rerouteCmd;
1837
+ const genArgs = useShell ? [] : ["gen"];
1838
+ await new Promise((resolve, reject) => {
1839
+ const genProcess = spawn3(genCommand, genArgs, {
1840
+ stdio: ["ignore", "pipe", "pipe"],
1841
+ shell: useShell
1842
+ });
1843
+ genProcess.stdout?.on("data", handleGenOutput);
1844
+ genProcess.stderr?.on("data", handleGenOutput);
1845
+ genProcess.on("exit", (code) => {
1846
+ if (code !== null && code !== 0) {
1847
+ reject(new Error(`Gen exited with code ${code}`));
1848
+ } else {
1849
+ resolve();
1850
+ }
1851
+ });
1852
+ genProcess.on("error", (error) => {
1853
+ reject(error);
1854
+ });
1855
+ });
1856
+ process.stdout.write(colorizeLogPrefixAnsi(`[reroute/start] Generation complete
1857
+ `));
1858
+ process.stdout.write(`${colorizeLogPrefixAnsi("[reroute/start] Starting server...")}
1859
+ `);
1860
+ process.stdout.write(colorizeLogPrefixAnsi(`[reroute/start] Press Ctrl+C to stop
1861
+ `));
1862
+ const serverProcess = spawn3("bun", ["src/index.ts"], {
1863
+ stdio: ["ignore", "pipe", "pipe"]
1864
+ });
1865
+ const serverBuffer = { current: "" };
1866
+ const handleServerOutput = createServerOutputHandler(serverBuffer);
1867
+ serverProcess.stdout?.on("data", handleServerOutput);
1868
+ serverProcess.stderr?.on("data", handleServerOutput);
1869
+ process.on("SIGINT", () => {
1870
+ process.stdout.write(`${colorizeLogPrefixAnsi(`
1871
+ [reroute/start] Shutting down...`)}
1872
+ `);
1873
+ serverProcess.kill("SIGINT");
1874
+ process.exit(0);
1875
+ });
1876
+ await new Promise((resolve, reject) => {
1877
+ serverProcess.on("exit", (code) => {
1878
+ if (code !== null && code !== 0) {
1879
+ console.error(colorizeLogPrefixAnsi(`[reroute/start] Server exited with code ${code}`));
1880
+ reject(new Error(`Server exited with code ${code}`));
1881
+ } else {
1882
+ resolve();
1883
+ }
1884
+ });
1885
+ serverProcess.on("error", (error) => {
1886
+ reject(error);
1887
+ });
1888
+ });
1889
+ } catch (error) {
1890
+ if (error.code === "SIGINT") {
1891
+ process.stdout.write(`${colorizeLogPrefixAnsi(`
1892
+ [reroute/start] Shutting down...`)}
1893
+ `);
1894
+ process.exit(0);
1895
+ }
1896
+ process.stderr.write(`${colorizeLogPrefixAnsi("[reroute/start] Error: ") + String(error)}
1897
+ `);
1898
+ throw error;
1899
+ }
1900
+ }
1901
+ var init_start = __esm(() => {
1902
+ init_log();
1903
+ });
1904
+
1905
+ // packages/cli/src/commands/build.ts
1906
+ var exports_build = {};
1907
+ __export(exports_build, {
1908
+ default: () => build
1909
+ });
1910
+ import { spawn as spawn4 } from "node:child_process";
1911
+ import { existsSync as existsSync7, readFileSync as readFileSync4 } from "node:fs";
1912
+ import { join as join9 } from "node:path";
1913
+ function getRerouteCommand3() {
1914
+ const binPath = join9(import.meta.dir, "..", "..", "bin.ts");
1915
+ const isBunDev = existsSync7(binPath);
1916
+ if (isBunDev) {
1917
+ return `bun ${binPath}`;
1918
+ }
1919
+ const cwd = process.cwd();
1920
+ const nodeModulesPaths = [
1921
+ join9(cwd, "node_modules", ".bin", "reroute"),
1922
+ join9(cwd, "..", "node_modules", ".bin", "reroute"),
1923
+ join9(cwd, "..", "..", "node_modules", ".bin", "reroute"),
1924
+ join9(cwd, "..", "..", "..", "node_modules", ".bin", "reroute")
1925
+ ];
1926
+ for (const binPath2 of nodeModulesPaths) {
1927
+ if (existsSync7(binPath2)) {
1928
+ return binPath2;
1929
+ }
1930
+ }
1931
+ return "reroute";
1932
+ }
1933
+ function getOutputName() {
1934
+ const cwd = process.cwd();
1935
+ const packageJsonPath = join9(cwd, "package.json");
1936
+ if (existsSync7(packageJsonPath)) {
1937
+ try {
1938
+ const packageJson = JSON.parse(readFileSync4(packageJsonPath, "utf-8"));
1939
+ const name = packageJson.name;
1940
+ if (name) {
1941
+ const parts = name.split("-");
1942
+ if (parts.length > 1 && parts[parts.length - 1] === "example") {
1943
+ return parts[parts.length - 2] || "app";
1944
+ }
1945
+ return parts[parts.length - 1] || name;
1946
+ }
1947
+ } catch {}
1948
+ }
1949
+ return "app";
1950
+ }
1951
+ async function build(args) {
1952
+ try {
1953
+ const rerouteCmd = getRerouteCommand3();
1954
+ const useShell = rerouteCmd.includes(" ");
1955
+ let outputPath = `./dist/${getOutputName()}`;
1956
+ const outfileIndex = args.indexOf("--outfile");
1957
+ const shortOutfileIndex = args.indexOf("-o");
1958
+ const outfileArgIndex = outfileIndex !== -1 ? outfileIndex : shortOutfileIndex;
1959
+ if (outfileArgIndex !== -1 && args[outfileArgIndex + 1]) {
1960
+ outputPath = args[outfileArgIndex + 1];
1961
+ }
1962
+ const bootBuffer = { current: "" };
1963
+ const genBuffer = { current: "" };
1964
+ const handleBootOutput = (data) => {
1965
+ const text = bootBuffer.current + data.toString();
1966
+ const lines = text.split(`
1967
+ `);
1968
+ bootBuffer.current = lines.pop() || "";
1969
+ for (const line of lines) {
1970
+ if (!line.trim()) {
1971
+ continue;
1972
+ }
1973
+ const ansiColored = colorizeLogPrefixAnsi(line);
1974
+ console.log(ansiColored);
1975
+ }
1976
+ };
1977
+ const handleGenOutput = (data) => {
1978
+ const text = genBuffer.current + data.toString();
1979
+ const lines = text.split(`
1980
+ `);
1981
+ genBuffer.current = lines.pop() || "";
1982
+ for (const line of lines) {
1983
+ if (!line.trim()) {
1984
+ continue;
1985
+ }
1986
+ const ansiColored = colorizeLogPrefixAnsi(line);
1987
+ console.log(ansiColored);
1988
+ }
1989
+ };
1990
+ process.stdout.write(`${colorizeLogPrefixAnsi("[reroute/build] Running boot...")}
1991
+ `);
1992
+ const bootCommand = useShell ? `${rerouteCmd} boot` : rerouteCmd;
1993
+ const bootArgs = useShell ? [] : ["boot"];
1994
+ await new Promise((resolve, reject) => {
1995
+ const bootProcess = spawn4(bootCommand, bootArgs, {
1996
+ stdio: ["ignore", "pipe", "pipe"],
1997
+ shell: useShell
1998
+ });
1999
+ bootProcess.stdout?.on("data", handleBootOutput);
2000
+ bootProcess.stderr?.on("data", handleBootOutput);
2001
+ bootProcess.on("exit", (code) => {
2002
+ if (code !== null && code !== 0) {
2003
+ reject(new Error(`Boot exited with code ${code}`));
2004
+ } else {
2005
+ resolve();
2006
+ }
2007
+ });
2008
+ bootProcess.on("error", (error) => {
2009
+ reject(error);
2010
+ });
2011
+ });
2012
+ process.stdout.write(colorizeLogPrefixAnsi(`[reroute/build] Boot complete
2013
+ `));
2014
+ process.stdout.write(`${colorizeLogPrefixAnsi("[reroute/build] Running gen...")}
2015
+ `);
2016
+ const genCommand = useShell ? `${rerouteCmd} gen` : rerouteCmd;
2017
+ const genArgs = useShell ? [] : ["gen"];
2018
+ await new Promise((resolve, reject) => {
2019
+ const genProcess = spawn4(genCommand, genArgs, {
2020
+ stdio: ["ignore", "pipe", "pipe"],
2021
+ shell: useShell
2022
+ });
2023
+ genProcess.stdout?.on("data", handleGenOutput);
2024
+ genProcess.stderr?.on("data", handleGenOutput);
2025
+ genProcess.on("exit", (code) => {
2026
+ if (code !== null && code !== 0) {
2027
+ reject(new Error(`Gen exited with code ${code}`));
2028
+ } else {
2029
+ resolve();
2030
+ }
2031
+ });
2032
+ genProcess.on("error", (error) => {
2033
+ reject(error);
2034
+ });
2035
+ });
2036
+ process.stdout.write(colorizeLogPrefixAnsi(`[reroute/build] Generation complete
2037
+ `));
2038
+ process.stdout.write(`${colorizeLogPrefixAnsi(`[reroute/build] Building binary to ${outputPath}...`)}
2039
+ `);
2040
+ const isProduction = true;
2041
+ const buildArgs = ["build", "src/index.ts", "--target", "bun", "--compile"];
2042
+ if (isProduction) {
2043
+ buildArgs.push("--minify");
2044
+ }
2045
+ const filteredArgs = args.filter((arg, idx) => {
2046
+ if (outfileArgIndex !== -1) {
2047
+ if (idx === outfileArgIndex || idx === outfileArgIndex + 1) {
2048
+ return false;
2049
+ }
2050
+ }
2051
+ return arg !== "--outfile" && arg !== "-o" && arg !== "--minify" && arg !== "--no-minify";
2052
+ });
2053
+ buildArgs.push(...filteredArgs, "--outfile", outputPath);
2054
+ await new Promise((resolve, reject) => {
2055
+ const buildProcess = spawn4("bun", buildArgs, {
2056
+ stdio: "inherit"
2057
+ });
2058
+ buildProcess.on("exit", (code) => {
2059
+ if (code !== null && code !== 0) {
2060
+ reject(new Error(`Build exited with code ${code}`));
2061
+ } else {
2062
+ process.stdout.write(colorizeLogPrefixAnsi(`[reroute/build] Build complete: ${outputPath}
2063
+ `));
2064
+ resolve();
2065
+ }
2066
+ });
2067
+ buildProcess.on("error", (error) => {
2068
+ reject(error);
2069
+ });
2070
+ });
2071
+ } catch (error) {
2072
+ process.stderr.write(`${colorizeLogPrefixAnsi("[reroute/build] Error: ") + String(error)}
2073
+ `);
2074
+ throw error;
2075
+ }
2076
+ }
2077
+ var init_build = __esm(() => {
2078
+ init_log();
2079
+ });
2080
+
869
2081
  // packages/cli/src/cli.ts
870
2082
  import path2 from "node:path";
871
2083
  var commands = {
872
2084
  init: () => Promise.resolve().then(() => (init_init(), exports_init)),
873
2085
  gen: () => Promise.resolve().then(() => (init_gen(), exports_gen)),
874
- boot: () => Promise.resolve().then(() => (init_boot(), exports_boot))
2086
+ boot: () => Promise.resolve().then(() => (init_boot(), exports_boot)),
2087
+ dev: () => Promise.resolve().then(() => (init_dev(), exports_dev)),
2088
+ start: () => Promise.resolve().then(() => (init_start(), exports_start)),
2089
+ build: () => Promise.resolve().then(() => (init_build(), exports_build))
875
2090
  };
876
2091
  async function main() {
877
2092
  const args = process.argv.slice(2);
@@ -900,25 +2115,49 @@ async function main() {
900
2115
  }
901
2116
  }
902
2117
  async function printHelp2() {
2118
+ console.log("");
903
2119
  console.log(await getVersionString2());
904
2120
  console.log("");
2121
+ console.log("");
905
2122
  console.log("Usage:");
2123
+ console.log("");
906
2124
  console.log(" reroute <command> [options]");
907
2125
  console.log("");
2126
+ console.log("");
908
2127
  console.log("Commands:");
2128
+ console.log("");
2129
+ console.log(" init Scaffold a new Reroute project");
909
2130
  console.log(" boot Initialize .reroute directory with stub files");
910
2131
  console.log(" gen Generate content registry and static assets");
911
- console.log(" init Scaffold a new Reroute project");
2132
+ console.log(" dev Start development environment");
2133
+ console.log(" start Run production-like server locally");
2134
+ console.log(" build Build production binary");
2135
+ console.log("");
912
2136
  console.log("");
913
2137
  console.log("Options:");
2138
+ console.log("");
914
2139
  console.log(" -h, --help Show help");
915
2140
  console.log(" -v, --version Show version");
916
2141
  console.log("");
2142
+ console.log("");
917
2143
  console.log("Examples:");
2144
+ console.log("");
2145
+ console.log(" reroute init my-app");
918
2146
  console.log(" reroute boot");
2147
+ console.log("");
919
2148
  console.log(" reroute gen");
2149
+ console.log(" reroute gen -w");
920
2150
  console.log(" reroute gen --watch");
921
- console.log(" reroute init my-app");
2151
+ console.log("");
2152
+ console.log(" reroute dev");
2153
+ console.log(" reroute dev -s");
2154
+ console.log(" reroute dev --single");
2155
+ console.log("");
2156
+ console.log(" reroute start");
2157
+ console.log("");
2158
+ console.log(" reroute build");
2159
+ console.log(" reroute build -o ./dist/myapp");
2160
+ console.log(" reroute build --outfile ./dist/myapp");
922
2161
  }
923
2162
  async function getVersionString2() {
924
2163
  const version = await getVersion2();
@@ -927,7 +2166,7 @@ async function getVersionString2() {
927
2166
  }
928
2167
  async function getVersion2() {
929
2168
  if (true) {
930
- return "0.5.0";
2169
+ return "0.7.0";
931
2170
  }
932
2171
  const possiblePaths = [
933
2172
  path2.join(import.meta.dir, "../../../package.json"),
@@ -944,10 +2183,10 @@ async function getVersion2() {
944
2183
  }
945
2184
  async function getCommit2() {
946
2185
  if (true) {
947
- return "68dd984";
2186
+ return "4b119c0";
948
2187
  }
949
2188
  return "dev";
950
2189
  }
951
2190
  main();
952
2191
 
953
- //# debugId=4C1324A287CB7DC364756E2164756E21
2192
+ //# debugId=B8066BB70A3F2A9464756E2164756E21