@kosmojs/lib 0.5.2 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@kosmojs/lib",
4
- "version": "0.5.2",
4
+ "version": "0.6.3",
5
5
  "description": "Shared internals for the KosmoJS CLI and generators (not a public API)",
6
6
  "author": "Slee Woo",
7
7
  "license": "MIT",
@@ -17,15 +17,16 @@
17
17
  ".": {
18
18
  "types": "./pkg/index.d.ts",
19
19
  "default": "./pkg/index.js"
20
- }
20
+ },
21
+ "./package.json": "./package.json"
21
22
  },
22
23
  "dependencies": {
23
- "@kosmojs/core": "^0.5.2",
24
+ "@kosmojs/core": "^0.6.3",
24
25
  "@topcli/spinner": "^5.0.0",
25
26
  "crc": "^4.3.2",
26
- "handlebars": "^4.7.9",
27
+ "handlebars": "^4.7.10",
27
28
  "mrmime": "^2.0.1",
28
- "oxfmt": "^0.67.0",
29
+ "oxfmt": "^0.72.0",
29
30
  "path-to-regexp": "^8.4.2",
30
31
  "picomatch": "^4.0.7",
31
32
  "tfusion": "^0.2.2",
@@ -34,11 +35,11 @@
34
35
  },
35
36
  "devDependencies": {
36
37
  "@koa/router": "^15.7.0",
37
- "@kosmojs/lib": "^0.5.2",
38
+ "@kosmojs/lib": "^0.6.3",
38
39
  "@types/picomatch": "^4.0.3",
39
- "hono": "^4.13.7",
40
- "rou3": "^0.9.2",
41
- "vite": "^8.2.2"
40
+ "hono": "^4.13.13",
41
+ "rou3": "^1.0.0",
42
+ "vite": "^8.3.4"
42
43
  },
43
44
  "scripts": {
44
45
  "build": "wsbuild src/index.ts",
package/pkg/ast.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import flattener from "tfusion";
2
2
  import { type CallExpression, Project, type ProjectOptions, type SourceFile } from "ts-morph";
3
- import type { ResolvedTypeSignature } from "@kosmojs/core";
3
+ import type { ProjectSettings, ResolvedTypeSignature } from "@kosmojs/core";
4
4
  import { type ApiRoute, type SourceFolder, type TypeDeclaration, type ValidationDefinition } from "@kosmojs/core";
5
5
  import { type HTTPMethod } from "@kosmojs/core/api";
6
6
  type PathResolver = (path: string) => string;
@@ -33,7 +33,7 @@ export declare const astFactory: () => {
33
33
  validationDefinitions: ValidationDefinition[];
34
34
  referencedFiles: string[] | undefined;
35
35
  }>;
36
- typeResolverFactory: (sourceFolder: SourceFolder) => {
36
+ typeResolverFactory: (projectSettings: ProjectSettings, sourceFolder: SourceFolder) => {
37
37
  getSourceFile: (fileFullpath: string) => SourceFile;
38
38
  refreshSourceFile: (fileFullpath: string) => Promise<void>;
39
39
  literalTypesResolver: (literalTypes: string, options: Parameters<typeof flattener>[2]) => Array<ResolvedTypeSignature>;
@@ -1,8 +1,8 @@
1
- import type { GeneratorFactory, GeneratorSignature, ResolvedEntry, SourceFolder, WatcherEvent } from "@kosmojs/core";
1
+ import type { GeneratorFactory, GeneratorSignature, ProjectSettings, ResolvedEntry, SourceFolder, WatcherEvent } from "@kosmojs/core";
2
2
  export declare const defineGenerator: <O extends object, R extends boolean = false>({ meta, factory, dependencies, devDependencies, }: Omit<GeneratorSignature<O>, "factory"> & {
3
- factory: (f: SourceFolder, o?: O) => GeneratorFactory;
3
+ factory: (s: ProjectSettings, f: SourceFolder, o?: O) => GeneratorFactory;
4
4
  }) => [R] extends [true] ? (o: O) => GeneratorSignature<O> : (o?: O) => GeneratorSignature<O>;
5
- export declare const defineGeneratorFactory: <O extends object>(factory: (f: SourceFolder, o?: O) => GeneratorFactory) => (f: SourceFolder, o?: O) => GeneratorFactory;
5
+ export declare const defineGeneratorFactory: <O extends object>(factory: (s: ProjectSettings, f: SourceFolder, o?: O) => GeneratorFactory) => (s: ProjectSettings, f: SourceFolder, o?: O) => GeneratorFactory;
6
6
  /**
7
7
  * Filter watched API routes by event.
8
8
  * Handle 3 cases:
package/pkg/generic.d.ts CHANGED
@@ -1,4 +1,7 @@
1
1
  import { type UserConfig } from "vite";
2
+ import { type KosmoSettings } from "@kosmojs/core";
2
3
  export declare const mergeConfigs: (...configs: Array<UserConfig | undefined>) => UserConfig;
3
4
  export declare const escapeTemplateLiterals: (origin: string) => string;
4
5
  export declare const containsPathTraversalPatterns: (str: string) => boolean;
6
+ export declare const configFilePattern: (folder: string) => string;
7
+ export declare const resolveHostAddress: (settings: KosmoSettings | undefined, key: "devHost" | "previewHost") => string;
package/pkg/index.d.ts CHANGED
@@ -1,8 +1,18 @@
1
+ /**
2
+ * Read the installed package.json at runtime to get the actual version.
3
+ * A static import would be inlined by the bundler with the pre-bump version.
4
+ *
5
+ * INFO: For best compatibility, all packages should share the same version.
6
+ * When bumping the version (even a patch) for a single package,
7
+ * bump it for all packages to keep versions fully synchronized across the project.
8
+ * */
9
+ export declare const VERSION: any;
1
10
  export * from "./ast";
2
11
  export * from "./format";
3
12
  export * from "./generators";
4
13
  export * from "./generic";
5
14
  export * from "./paths";
15
+ export * from "./ports";
6
16
  export * from "./render";
7
17
  export * from "./routes";
8
18
  export * from "./spinner";
package/pkg/index.js CHANGED
@@ -1,15 +1,17 @@
1
- import { builtinModules } from "node:module";
1
+ import { builtinModules, createRequire } from "node:module";
2
+ import { readFileSync } from "node:fs";
2
3
  import { styleText } from "node:util";
3
4
  import crc from "crc/crc32";
4
5
  import flattener from "tfusion";
5
6
  import { ModuleResolutionKind, Project, SyntaxKind } from "ts-morph";
6
- import { RequestValidationTargets, defaults } from "@kosmojs/core";
7
+ import { DEFAULT_DIST, DEFAULT_HOST, DEFAULT_PORT, DEFAULT_PREVIEW_HOST, DEFAULT_PREVIEW_PORT, RequestValidationTargets, defaults } from "@kosmojs/core";
7
8
  import { HTTPMethods } from "@kosmojs/core/api";
9
+ import { basename, dirname, isAbsolute, join, parse, posix, resolve } from "node:path";
8
10
  import { mergeConfig } from "vite";
9
11
  import { access, constants, mkdir, readFile, stat, writeFile } from "node:fs/promises";
10
- import { basename, dirname, isAbsolute, join, parse, posix, resolve } from "node:path";
11
12
  import handlebars from "handlebars";
12
13
  import { format } from "oxfmt";
14
+ import net from "node:net";
13
15
  import picomatch from "picomatch";
14
16
  import { glob } from "tinyglobby";
15
17
  import { compile, parse as parse$1 } from "path-to-regexp";
@@ -25,15 +27,27 @@ var escapeTemplateLiterals = (origin) => {
25
27
  var containsPathTraversalPatterns = (str) => {
26
28
  return [/\.\.\//, /\/\.\//].some((e) => e.test(str));
27
29
  };
30
+ var configFilePattern = (folder) => {
31
+ return posix.join(defaults.srcDir, folder, "kosmo.config.ts");
32
+ };
33
+ var resolveHostAddress = (settings, key) => {
34
+ let [host, port] = key === "devHost" ? [DEFAULT_HOST, DEFAULT_PORT] : [DEFAULT_PREVIEW_HOST, DEFAULT_PREVIEW_PORT];
35
+ if (settings?.[key]) {
36
+ const url = new URL(`http://${settings[key]}`);
37
+ if (url.hostname) host = url.hostname;
38
+ if (url.port) port = Number(url.port);
39
+ }
40
+ return [host, port].join(":");
41
+ };
28
42
  //#endregion
29
43
  //#region src/paths.ts
30
- var pathResolver = (sourceFolder) => {
44
+ var pathResolver = ({ root, distDir = DEFAULT_DIST }, { name }) => {
31
45
  const createPath = (...a) => {
32
- return sourceFolder.root ? resolve(sourceFolder.root, join(...a)) : join(...a);
46
+ return root ? resolve(root, join(...a)) : join(...a);
33
47
  };
34
48
  const createImport = {
35
49
  src(a, { origin }) {
36
- return origin === "src" ? join(defaults.srcPrefix, ...a) : join(defaults.appPrefix, defaults.srcDir, sourceFolder.name, ...a);
50
+ return origin === "src" ? join(defaults.srcPrefix, ...a) : join(defaults.appPrefix, defaults.srcDir, name, ...a);
37
51
  },
38
52
  api(a, o) {
39
53
  return this.src([defaults.apiDir, ...a], o);
@@ -45,7 +59,7 @@ var pathResolver = (sourceFolder) => {
45
59
  return this.src([defaults.pagesDir, ...a], o);
46
60
  },
47
61
  lib(a, { origin }) {
48
- return origin === "src" ? join(defaults.libPrefix, ...a) : join(defaults.appPrefix, defaults.libDir, sourceFolder.name, ...a);
62
+ return origin === "src" ? join(defaults.libPrefix, ...a) : join(defaults.appPrefix, defaults.libDir, name, ...a);
49
63
  },
50
64
  libCore(a, o) {
51
65
  return this.lib(["core", ...a], o);
@@ -60,7 +74,7 @@ var pathResolver = (sourceFolder) => {
60
74
  return {
61
75
  createPath: {
62
76
  src(...a) {
63
- return createPath(defaults.srcDir, sourceFolder.name, ...a);
77
+ return createPath(defaults.srcDir, name, ...a);
64
78
  },
65
79
  api(...a) {
66
80
  return this.src(defaults.apiDir, ...a);
@@ -72,7 +86,7 @@ var pathResolver = (sourceFolder) => {
72
86
  return this.src(defaults.entryDir, ...a);
73
87
  },
74
88
  lib(...a) {
75
- return createPath(defaults.libDir, sourceFolder.name, ...a);
89
+ return createPath(defaults.libDir, name, ...a);
76
90
  },
77
91
  libCore(...a) {
78
92
  return this.lib("core", ...a);
@@ -87,7 +101,7 @@ var pathResolver = (sourceFolder) => {
87
101
  return this.lib(defaults.pagesDir, ...a);
88
102
  },
89
103
  distDir(...a) {
90
- return createPath(sourceFolder.distDir, sourceFolder.name, ...a);
104
+ return createPath(distDir, name, ...a);
91
105
  }
92
106
  },
93
107
  createImport,
@@ -447,15 +461,15 @@ var astFactory = () => {
447
461
  const extractGenerics = (callExpression) => {
448
462
  return callExpression.getTypeArguments();
449
463
  };
450
- const typeResolverFactory = (sourceFolder) => {
451
- const { createPath } = pathResolver(sourceFolder);
464
+ const typeResolverFactory = (projectSettings, sourceFolder) => {
465
+ const { createPath } = pathResolver(projectSettings, sourceFolder);
452
466
  const project = createProject({ compilerOptions: {
453
467
  moduleResolution: ModuleResolutionKind.Bundler,
454
468
  types: [],
455
469
  noLib: true,
456
470
  skipLibCheck: true,
457
471
  paths: {
458
- [`${defaults.appPrefix}/*`]: [`${sourceFolder.root}/*`],
472
+ [`${defaults.appPrefix}/*`]: [`${projectSettings.root}/*`],
459
473
  [`${defaults.srcPrefix}/*`]: [createPath.src("*")],
460
474
  [`${defaults.libPrefix}/*`]: [createPath.lib("*")]
461
475
  }
@@ -639,7 +653,9 @@ var defineGenerator = ({ meta, factory, dependencies, devDependencies }) => {
639
653
  return ((options) => {
640
654
  return {
641
655
  meta,
642
- factory: (folder) => factory(folder, options),
656
+ factory: (settings, folder) => {
657
+ return factory(settings, folder, options);
658
+ },
643
659
  dependencies,
644
660
  devDependencies,
645
661
  options
@@ -683,6 +699,51 @@ var createWatchedPageRouteEntriesFilter = (event, eventsOfInterest) => {
683
699
  };
684
700
  };
685
701
  //#endregion
702
+ //#region src/ports.ts
703
+ /**
704
+ * Probe whether a single TCP port is free on given host.
705
+ *
706
+ * Resolves `true` only after the probe server has fully closed,
707
+ * so the caller can immediately rebind without racing the OS.
708
+ * `unref()` keeps a dangling probe from holding the event loop open.
709
+ * */
710
+ var isPortFree = (host, port, timeoutMs = 2e3) => {
711
+ return new Promise((resolve) => {
712
+ const server = net.createServer();
713
+ const done = (result) => {
714
+ clearTimeout(timer);
715
+ resolve(result);
716
+ };
717
+ const timer = setTimeout(() => {
718
+ server.close(() => done(false));
719
+ }, timeoutMs);
720
+ server.unref();
721
+ server.once("error", () => done(false));
722
+ server.once("listening", () => server.close(() => done(true)));
723
+ server.listen({
724
+ host,
725
+ port
726
+ });
727
+ });
728
+ };
729
+ /**
730
+ * Find `count` consecutive free ports by probing random offsets within minPort..maxPort.
731
+ * Each attempt picks a uniformly random start, probes the whole window,
732
+ * and returns it only if every port is free.
733
+ * Failed attempts are cheap because only the window is probed - no full-range scan.
734
+ * */
735
+ var findFreePortRange = async (host, count, { minPort = 2e4, maxPort = 29e3, attempts = 32 } = {}) => {
736
+ if (count < 1) throw new Error("count must be >= 1");
737
+ const span = maxPort - minPort - count + 1;
738
+ if (span <= 0) throw new Error(`Port range ${minPort}-${maxPort} is too small for a window of ${count}`);
739
+ for (let attempt = 0; attempt < attempts; attempt++) {
740
+ const start = minPort + Math.floor(Math.random() * span);
741
+ const range = Array.from({ length: count }, (_, i) => start + i);
742
+ if ((await Promise.all(range.map((p) => isPortFree(host, p)))).every(Boolean)) return range;
743
+ }
744
+ throw new Error(`No run of ${count} free ports found in range ${minPort}-${maxPort} after ${attempts} random attempts`);
745
+ };
746
+ //#endregion
686
747
  //#region src/routes/paths.ts
687
748
  /**
688
749
  * Parse a filesystem route path into structured PathToken array.
@@ -816,7 +877,7 @@ var createH3Pattern = (tokens) => {
816
877
  return tokens.flatMap((t) => {
817
878
  if (t.type === "text") return t.value === "/" ? [] : [escapeStatic(t.value)];
818
879
  if (t.type === "param") return [`:${t.name}`];
819
- if (t.type === "wildcard") return [`/**:${t.name}?`];
880
+ if (t.type === "wildcard") return [`/**:${t.name}`];
820
881
  if (t.type === "group") return [`{${tokensToPattern(t.tokens)}}?`];
821
882
  return [];
822
883
  }).join("");
@@ -854,8 +915,8 @@ var ROUTE_FILE_PATTERNS = [
854
915
  `${defaults.pagesDir}/**/${PAGE_INDEX_PATTERN}`,
855
916
  `${defaults.pagesDir}/**/${PAGE_LAYOUT_PATTERN}`
856
917
  ];
857
- var scanRoutes = async (sourceFolder) => {
858
- const { createPath } = pathResolver(sourceFolder);
918
+ var scanRoutes = async (projectSettings, sourceFolder) => {
919
+ const { createPath } = pathResolver(projectSettings, sourceFolder);
859
920
  return glob(ROUTE_FILE_PATTERNS, {
860
921
  cwd: createPath.src(),
861
922
  absolute: true,
@@ -869,8 +930,8 @@ var scanRoutes = async (sourceFolder) => {
869
930
  ]
870
931
  });
871
932
  };
872
- var isRouteFile = (file, sourceFolder) => {
873
- const [_sourceFolder, _folder, ...rest] = resolve(sourceFolder.root, file).replace(`${sourceFolder.root}/${defaults.srcDir}/`, "").split("/");
933
+ var isRouteFile = (projectSettings, sourceFolder, file) => {
934
+ const [_sourceFolder, _folder, ...rest] = resolve(projectSettings.root, file).replace(`${projectSettings.root}/${defaults.srcDir}/`, "").split("/");
874
935
  /**
875
936
  * Ensure the file:
876
937
  * - is under the correct source root
@@ -892,8 +953,8 @@ var isPageRoute = (file) => {
892
953
  var isPageLayout = (file) => {
893
954
  return picomatch.matchBase(file, `**/${PAGE_LAYOUT_PATTERN}`);
894
955
  };
895
- var createRouteEntry = (fileFullpath, sourceFolder) => {
896
- const resolvedPaths = isRouteFile(fileFullpath, sourceFolder);
956
+ var createRouteEntry = (projectSettings, sourceFolder, fileFullpath) => {
957
+ const resolvedPaths = isRouteFile(projectSettings, sourceFolder, fileFullpath);
897
958
  if (!resolvedPaths) return;
898
959
  const [folder, file] = resolvedPaths;
899
960
  const id = `${file.replace(/\W+/g, "_")}_${crc(file)}`;
@@ -1002,12 +1063,12 @@ var sortRoutesForResolution = (a, b) => {
1002
1063
  };
1003
1064
  //#endregion
1004
1065
  //#region src/routes/resolve.ts
1005
- var resolverFactory = (sourceFolder, cacheFactory) => {
1066
+ var resolverFactory = (projectSettings, sourceFolder, cacheFactory) => {
1006
1067
  const { generators } = sourceFolder;
1007
1068
  const { refineTypeName = defaults.refineTypeName } = typeof sourceFolder.config.validation === "object" ? { ...sourceFolder.config.validation } : {};
1008
1069
  const { typeResolverFactory, resolveRouteSignature } = astFactory();
1009
1070
  const resolveTypes = generators.some(({ meta }) => meta.resolveTypes);
1010
- const { literalTypesResolver, getSourceFile, refreshSourceFile } = typeResolverFactory(sourceFolder);
1071
+ const { literalTypesResolver, getSourceFile, refreshSourceFile } = typeResolverFactory(projectSettings, sourceFolder);
1011
1072
  return {
1012
1073
  pageLayoutResolver(entry) {
1013
1074
  const { name } = entry;
@@ -1070,11 +1131,11 @@ var resolverFactory = (sourceFolder, cacheFactory) => {
1070
1131
  });
1071
1132
  });
1072
1133
  const optionalParams = paramsSchema.length ? paramsSchema.filter((e) => e.kind === "required").length === 0 : true;
1073
- const cacheStore = cacheFactory ? cacheFactory({
1134
+ const cacheStore = cacheFactory ? cacheFactory(projectSettings, sourceFolder, {
1074
1135
  id,
1075
1136
  file,
1076
1137
  fileFullpath
1077
- }, sourceFolder, { resolveTypes }) : void 0;
1138
+ }, { resolveTypes }) : void 0;
1078
1139
  let cache = cacheStore ? await cacheStore.get({ validate: true }) : void 0;
1079
1140
  if (!cache) {
1080
1141
  if (updatedFile === fileFullpath) await refreshSourceFile(fileFullpath);
@@ -1098,7 +1159,7 @@ var resolverFactory = (sourceFolder, cacheFactory) => {
1098
1159
  }] : [];
1099
1160
  }) : [def.schema];
1100
1161
  });
1101
- const typesFile = pathResolver(sourceFolder).createPath.libApi(dirname(file), "types.ts");
1162
+ const typesFile = pathResolver(projectSettings, sourceFolder).createPath.libApi(dirname(file), "types.ts");
1102
1163
  const params = {
1103
1164
  id: ["ParamsT", crc(name)].join(""),
1104
1165
  schema: paramsSchema,
@@ -1211,7 +1272,7 @@ var resolverFactory = (sourceFolder, cacheFactory) => {
1211
1272
  methods: cache.methods,
1212
1273
  typeDeclarations: cache.typeDeclarations,
1213
1274
  validationDefinitions,
1214
- referencedFiles: Object.keys(cache.referencedFiles).map((e) => resolve(sourceFolder.root, e))
1275
+ referencedFiles: Object.keys(cache.referencedFiles).map((e) => resolve(projectSettings.root, e))
1215
1276
  }
1216
1277
  };
1217
1278
  };
@@ -1291,12 +1352,12 @@ var nestedRoutesFactory = (routeEntries) => {
1291
1352
  };
1292
1353
  //#endregion
1293
1354
  //#region src/routes/index.ts
1294
- var routesFactory = async (sourceFolder, cacheFactory) => {
1295
- const { apiRouteResolver, apiUseResolver, pageRouteResolver, pageLayoutResolver } = resolverFactory(sourceFolder, cacheFactory);
1355
+ var routesFactory = async (projectSettings, sourceFolder, cacheFactory) => {
1356
+ const { apiRouteResolver, apiUseResolver, pageRouteResolver, pageLayoutResolver } = resolverFactory(projectSettings, sourceFolder, cacheFactory);
1296
1357
  const resolversFactory = (routeFiles) => {
1297
1358
  const resolvers = /* @__PURE__ */ new Map();
1298
1359
  const entries = routeFiles.flatMap((file) => {
1299
- const entry = createRouteEntry(file, sourceFolder);
1360
+ const entry = createRouteEntry(projectSettings, sourceFolder, file);
1300
1361
  return entry ? [entry] : [];
1301
1362
  });
1302
1363
  for (const entry of entries) if (entry.folder === defaults.apiDir) {
@@ -1309,7 +1370,7 @@ var routesFactory = async (sourceFolder, cacheFactory) => {
1309
1370
  return resolvers;
1310
1371
  };
1311
1372
  return {
1312
- resolvers: resolversFactory(await scanRoutes(sourceFolder)),
1373
+ resolvers: resolversFactory(await scanRoutes(projectSettings, sourceFolder)),
1313
1374
  resolversFactory
1314
1375
  };
1315
1376
  };
@@ -1461,7 +1522,7 @@ var generateTsconfig = ({ dependencies, devDependencies }, sourceFolder) => {
1461
1522
  * tsconfig generator uses, so alias resolution here can never drift from the
1462
1523
  * paths that were written into the generated tsconfig.
1463
1524
  * */
1464
- var tsconfigPaths = (sourceFolder) => {
1525
+ var tsconfigPaths = (projectSettings, sourceFolder) => {
1465
1526
  /**
1466
1527
  * Candidate extensions for an extensionless specifier, in resolution priority order.
1467
1528
  * Mirrors the renderable file types the generators emit;
@@ -1479,11 +1540,11 @@ var tsconfigPaths = (sourceFolder) => {
1479
1540
  ".mdx",
1480
1541
  ".json"
1481
1542
  ];
1482
- const { createPath } = pathResolver(sourceFolder);
1543
+ const { createPath } = pathResolver(projectSettings, sourceFolder);
1483
1544
  const table = [
1484
1545
  [`${defaults.srcPrefix}/`, createPath.src()],
1485
1546
  [`${defaults.libPrefix}/`, createPath.lib()],
1486
- [`${defaults.appPrefix}/`, sourceFolder.root]
1547
+ [`${defaults.appPrefix}/`, projectSettings.root]
1487
1548
  ];
1488
1549
  const resolveWithin = async (baseDir, rest) => {
1489
1550
  const target = join(baseDir, rest);
@@ -1530,14 +1591,15 @@ var nodePrefix = () => {
1530
1591
  *
1531
1592
  * Generators declare their modules via `factory.virtualModules()`.
1532
1593
  * */
1533
- var virtualModules = (sourceFolder, { kind, command }) => {
1594
+ var virtualModules = (projectSettings, sourceFolder, { kind, command }) => {
1534
1595
  /**
1535
1596
  * Rollup's / Rolldown's convention for ids owned by a plugin:
1536
1597
  * the NUL prefix keeps other plugins and Node resolution from touching them.
1537
1598
  * */
1538
1599
  const VIRTUAL_PREFIX = "\0";
1539
1600
  const modules = sourceFolder.generators.flatMap(({ factory }) => {
1540
- return factory(sourceFolder).virtualModules?.() || [];
1601
+ const { virtualModules } = factory(projectSettings, sourceFolder);
1602
+ return virtualModules ? virtualModules(command) : [];
1541
1603
  });
1542
1604
  const virtualSources = /* @__PURE__ */ new Map();
1543
1605
  for (const { specifier, csr, ssr } of modules) virtualSources.set(specifier, {
@@ -1570,7 +1632,21 @@ var vitePlugins = {
1570
1632
  var isFile = async (path) => {
1571
1633
  return stat(path).then((e) => e.isFile()).catch(() => false);
1572
1634
  };
1635
+ var cacheDir = ({ root }, { name }, target) => {
1636
+ return join(root, defaults.varDir, ".vite", name, target);
1637
+ };
1638
+ //#endregion
1639
+ //#region src/index.ts
1640
+ /**
1641
+ * Read the installed package.json at runtime to get the actual version.
1642
+ * A static import would be inlined by the bundler with the pre-bump version.
1643
+ *
1644
+ * INFO: For best compatibility, all packages should share the same version.
1645
+ * When bumping the version (even a patch) for a single package,
1646
+ * bump it for all packages to keep versions fully synchronized across the project.
1647
+ * */
1648
+ var { version: VERSION } = JSON.parse(readFileSync(createRequire(import.meta.url).resolve("@kosmojs/lib/package.json"), "utf-8"));
1573
1649
  //#endregion
1574
- export { API_INDEX_BASENAME, API_INDEX_PATTERN, API_USE_BASENAME, API_USE_PATTERN, PAGE_INDEX_BASENAME, PAGE_INDEX_PATTERN, PAGE_LAYOUT_BASENAME, PAGE_LAYOUT_PATTERN, astFactory, containsPathTraversalPatterns, createAliasPatterns, createH3Pattern, createHonoPattern, createPathPattern, createRouteEntry, createWatchedApiRouteEntriesFilter, createWatchedPageRouteEntriesFilter, defineGenerator, defineGeneratorFactory, escapeTemplateLiterals, formatCode, generateTsconfig, isApiRoute, isApiUse, isPageLayout, isPageRoute, isRouteFile, mergeConfigs, nestedRoutesFactory, pathExists, pathResolver, pathTokensFactory, render, renderFactory, renderToFile, routesFactory, scanRoutes, sortRoutes, sortRoutesForResolution, spinnerFactory, tsconfigPaths, virtualModules, vitePlugins };
1650
+ export { API_INDEX_BASENAME, API_INDEX_PATTERN, API_USE_BASENAME, API_USE_PATTERN, PAGE_INDEX_BASENAME, PAGE_INDEX_PATTERN, PAGE_LAYOUT_BASENAME, PAGE_LAYOUT_PATTERN, VERSION, astFactory, cacheDir, configFilePattern, containsPathTraversalPatterns, createAliasPatterns, createH3Pattern, createHonoPattern, createPathPattern, createRouteEntry, createWatchedApiRouteEntriesFilter, createWatchedPageRouteEntriesFilter, defineGenerator, defineGeneratorFactory, escapeTemplateLiterals, findFreePortRange, formatCode, generateTsconfig, isApiRoute, isApiUse, isPageLayout, isPageRoute, isPortFree, isRouteFile, mergeConfigs, nestedRoutesFactory, pathExists, pathResolver, pathTokensFactory, render, renderFactory, renderToFile, resolveHostAddress, routesFactory, scanRoutes, sortRoutes, sortRoutesForResolution, spinnerFactory, tsconfigPaths, virtualModules, vitePlugins };
1575
1651
 
1576
1652
  //# sourceMappingURL=index.js.map
package/pkg/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/generic.ts","../src/paths.ts","../src/render.ts","../src/ast.ts","../src/format.ts","../src/generators.ts","../src/routes/paths.ts","../src/routes/base.ts","../src/routes/resolve.ts","../src/routes/nesting.ts","../src/routes/index.ts","../src/spinner.ts","../src/tsconfig.ts","../src/vite.ts"],"sourcesContent":["import { mergeConfig, type UserConfig } from \"vite\";\n\nexport const mergeConfigs = (\n ...configs: Array<UserConfig | undefined>\n): UserConfig => {\n return [{ configFile: false }, ...configs].reduce<UserConfig>(\n (config, prev) => mergeConfig(config || {}, prev || {}),\n {},\n );\n};\n\nexport const escapeTemplateLiterals = (origin: string) => {\n return [\n // Escape backticks for safe use in template literals\n [/(?<!\\\\)`/g, \"\\\\`\"],\n // Escape $ for safe use in template literals\n [/(?<!\\\\)\\$\\{/g, \"\\\\${\"],\n ].reduce((text, [a, b]) => text.replace(a, b as never), origin);\n};\n\nexport const containsPathTraversalPatterns = (str: string): boolean => {\n return [\n // path traversal patterns\n /\\.\\.\\//,\n /\\/\\.\\//,\n ].some((e) => e.test(str));\n};\n","import { access, constants } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\n\nimport { defaults, type SourceFolder } from \"@kosmojs/core\";\n\ntype Options = { origin: \"src\" | \"lib\" };\n\ntype CreateImport = Record<\n \"src\" | \"api\" | \"entry\" | \"pages\" | \"lib\" | \"libCore\" | \"libApi\" | \"libEntry\",\n (a: Array<string>, o: Options) => string\n>;\n\nexport const pathResolver = (\n sourceFolder: Omit<SourceFolder, \"root\"> & { root?: string | undefined },\n): {\n createPath: Record<\n | \"src\"\n | \"api\"\n | \"pages\"\n | \"entry\"\n | \"lib\"\n | \"libCore\"\n | \"libApi\"\n | \"libEntry\"\n | \"libPages\"\n | \"distDir\",\n (...a: Array<string>) => string\n >;\n createImport: CreateImport;\n createImportHelpers: (o: Options) => {\n createImport: (k: keyof CreateImport, ...a: Array<string>) => string;\n };\n} => {\n const createPath = (...a: Array<string>) => {\n return sourceFolder.root\n ? resolve(sourceFolder.root, join(...a))\n : join(...a);\n };\n\n const createImport: CreateImport = {\n src(a, { origin }) {\n return origin === \"src\"\n ? join(defaults.srcPrefix, ...a)\n : join(defaults.appPrefix, defaults.srcDir, sourceFolder.name, ...a);\n },\n api(a, o) {\n return this.src([defaults.apiDir, ...a], o);\n },\n entry(a, o) {\n return this.src([defaults.entryDir, ...a], o);\n },\n pages(a, o) {\n return this.src([defaults.pagesDir, ...a], o);\n },\n lib(a, { origin }) {\n return origin === \"src\"\n ? join(defaults.libPrefix, ...a)\n : join(defaults.appPrefix, defaults.libDir, sourceFolder.name, ...a);\n },\n libCore(a, o) {\n return this.lib([\"core\", ...a], o);\n },\n libApi(a, o) {\n return this.lib([defaults.apiDir, ...a], o);\n },\n libEntry(a, o) {\n return this.lib([defaults.entryDir, ...a], o);\n },\n };\n\n return {\n createPath: {\n src(...a) {\n return createPath(defaults.srcDir, sourceFolder.name, ...a);\n },\n api(...a) {\n return this.src(defaults.apiDir, ...a);\n },\n pages(...a) {\n return this.src(defaults.pagesDir, ...a);\n },\n entry(...a) {\n return this.src(defaults.entryDir, ...a);\n },\n lib(...a) {\n return createPath(defaults.libDir, sourceFolder.name, ...a);\n },\n libCore(...a) {\n return this.lib(\"core\", ...a);\n },\n libApi(...a) {\n return this.lib(defaults.apiDir, ...a);\n },\n libEntry(...a) {\n return this.lib(defaults.entryDir, ...a);\n },\n libPages(...a) {\n return this.lib(defaults.pagesDir, ...a);\n },\n distDir(...a) {\n return createPath(sourceFolder.distDir, sourceFolder.name, ...a);\n },\n },\n createImport,\n createImportHelpers(o) {\n if (![\"src\", \"lib\"].includes(o?.origin)) {\n throw new Error(\n `createImportHelpers: required exactly one argument of shape { origin: \"src|lib\" }`,\n );\n }\n return {\n createImport(key, ...a) {\n // Handlebars appends an options object as the last argument,\n // slice it off before passing args to createImport\n return createImport[key](a.slice(0, -1), o);\n },\n };\n },\n };\n};\n\nexport const pathExists = async (path: string): Promise<boolean> => {\n return access(path, constants.F_OK).then(\n () => true,\n () => false,\n );\n};\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\n\nimport crc from \"crc/crc32\";\nimport handlebars from \"handlebars\";\n\nimport { pathExists } from \"./paths\";\n\nexport type RenderOptions = {\n noEscape?: boolean;\n // handlebars instance\n renderer?: typeof handlebars;\n};\n\nexport type FactoryOptions = RenderOptions & {\n partials?: Record<string, string>;\n helpers?: Record<string, (...a: Array<never>) => unknown>;\n outdir?: string;\n /**\n * Controls whether to overwrite an existing file.\n * - `false`: skip writing if the file already exists\n * - `true` (default): always overwrite\n * - function: custom logic to decide whether to overwrite, based on current file content\n * */\n overwrite?: boolean | ((fileContent: string) => boolean);\n};\n\nexport const render = <Context = object>(\n template: string,\n context: Context,\n options?: RenderOptions,\n): string => {\n const { noEscape = true, renderer = handlebars } = { ...options };\n return renderer.compile(template, { noEscape })(context);\n};\n\nexport const renderToFile = async <Context = object>(\n file: string,\n template: string,\n context: Context,\n options?: RenderOptions &\n Pick<FactoryOptions, \"overwrite\"> & {\n render?: typeof render;\n },\n): Promise<void> => {\n const content = options?.render\n ? options.render(template, context, options)\n : render(template, context, options);\n\n /**\n * Two fs calls (exists + read) are worth it to avoid touching the file\n * and triggering watchers unnecessarily.\n * */\n if (await pathExists(file)) {\n const { overwrite = true } = { ...options };\n if (overwrite === false) {\n return;\n }\n const fileContent = await readFile(file, \"utf8\");\n if (typeof overwrite === \"function\" && !overwrite(fileContent)) {\n return;\n }\n if (crc(content) === crc(fileContent)) {\n return;\n }\n }\n\n await mkdir(dirname(file), { recursive: true });\n await writeFile(file, content, \"utf8\");\n};\n\nexport const renderFactory = (options?: FactoryOptions) => {\n const createRenderer = (selfOoptions?: FactoryOptions) => {\n const renderer = handlebars.create();\n\n renderer.registerPartial({\n ...options?.partials,\n ...selfOoptions?.partials,\n } as never);\n\n renderer.registerHelper({\n ...options?.helpers,\n ...selfOoptions?.helpers,\n } as never);\n\n return renderer;\n };\n\n return {\n render<Context = object>(\n template: string,\n context: Context,\n selfOoptions?: FactoryOptions,\n ) {\n return render(template, context, {\n ...options,\n ...selfOoptions,\n renderer: createRenderer(selfOoptions),\n });\n },\n async renderToFile<Context = object>(\n file: string,\n template: string,\n context: Context,\n selfOoptions?: FactoryOptions,\n ) {\n return renderToFile(\n options?.outdir ? join(options.outdir, file) : file,\n template,\n context,\n {\n ...options,\n ...selfOoptions,\n renderer: createRenderer(selfOoptions),\n },\n );\n },\n };\n};\n","import { styleText } from \"node:util\";\n\nimport crc from \"crc/crc32\";\nimport flattener, { type ResolvedType } from \"tfusion\";\nimport {\n type CallExpression,\n type Identifier,\n ModuleResolutionKind,\n Project,\n type ProjectOptions,\n type PropertySignature,\n type SourceFile,\n SyntaxKind,\n type TypeNode,\n} from \"ts-morph\";\n\nimport type { ResolvedTypeSignature } from \"@kosmojs/core\";\nimport {\n type ApiRoute,\n defaults,\n RequestValidationTargets,\n type SourceFolder,\n type TypeDeclaration,\n type ValidationDefinition,\n type ValidationTarget,\n} from \"@kosmojs/core\";\nimport { type HTTPMethod, HTTPMethods } from \"@kosmojs/core/api\";\n\nimport { escapeTemplateLiterals } from \"./generic\";\nimport { pathResolver } from \"./paths\";\nimport { render } from \"./render\";\nimport * as templates from \"./templates\";\n\ntype PathResolver = (path: string) => string;\n\nexport const astFactory = () => {\n const createProject = (opts?: ProjectOptions) => new Project(opts);\n\n const resolveRouteSignature = async (\n route: Pick<ApiRoute, \"id\" | \"name\" | \"fileFullpath\" | \"optionalParams\">,\n opts?: {\n relpathResolver?: PathResolver;\n sourceFile?: SourceFile;\n withReferencedFiles?: boolean;\n },\n ) => {\n const {\n sourceFile = createProject().addSourceFileAtPath(route.fileFullpath),\n } = { ...opts };\n\n const [typeDeclarations, referencedFiles] = extractTypeDeclarations(\n sourceFile,\n opts,\n );\n\n const defaultExport = extractDefaultExport(sourceFile);\n\n const paramsRefinements = defaultExport\n ? extractParamsRefinements(defaultExport)\n : undefined;\n\n const methods = defaultExport\n ? extractRouteMethods(route, defaultExport)\n : [];\n\n return {\n typeDeclarations,\n paramsRefinements,\n methods: methods.map((e) => e.method),\n validationDefinitions: methods.flatMap((e) => e.validationDefinitions),\n referencedFiles,\n };\n };\n\n const extractDefaultExport = (\n sourceFile: SourceFile,\n ): CallExpression | undefined => {\n const [defaultExport] = sourceFile\n .getExportAssignments()\n .flatMap((exportAssignment) => {\n if (exportAssignment.isExportEquals()) {\n return [];\n }\n const callExpression = exportAssignment.getExpression();\n return callExpression.isKind(SyntaxKind.CallExpression)\n ? [callExpression]\n : [];\n });\n return defaultExport;\n };\n\n const extractParamsRefinements = (\n callExpression: CallExpression,\n ): Array<{ index: number; text: string }> | undefined => {\n const [\n _routeName, // first generic - the route name\n paramsGeneric, // second generic - params refinements\n ] = extractGenerics(callExpression);\n\n if (!paramsGeneric?.isKind(SyntaxKind.TupleType)) {\n return;\n }\n\n return paramsGeneric.getElements().map((node, index) => {\n return {\n index,\n text: node.getText(),\n };\n });\n };\n\n const extractRouteMethods = (\n route: Pick<ApiRoute, \"id\" | \"name\">,\n callExpression: CallExpression,\n ): Array<{\n method: HTTPMethod;\n validationDefinitions: Array<ValidationDefinition>;\n }> => {\n const funcDeclaration =\n callExpression.getFirstChildByKind(SyntaxKind.ArrowFunction) ||\n callExpression.getFirstChildByKind(SyntaxKind.FunctionExpression);\n\n if (!funcDeclaration) {\n return [];\n }\n\n const arrayLiteralExpression = funcDeclaration.getFirstChildByKind(\n SyntaxKind.ArrayLiteralExpression,\n );\n\n if (!arrayLiteralExpression) {\n return [];\n }\n\n const callExpressions: Array<[CallExpression, HTTPMethod]> = [];\n\n for (const e of arrayLiteralExpression.getChildrenOfKind(\n SyntaxKind.CallExpression,\n )) {\n const name = e.getExpression().getText() as HTTPMethod;\n if (HTTPMethods[name]) {\n callExpressions.push([e, name]);\n }\n }\n\n const methods: ReturnType<typeof extractRouteMethods> = [];\n\n for (const [callExpression, method] of callExpressions) {\n const [vDefs, vOpts] = extractGenerics(callExpression);\n methods.push({\n method,\n validationDefinitions: extractValidationDefinitions(\n route,\n method,\n vDefs,\n vOpts,\n ),\n });\n }\n\n return methods;\n };\n\n /** Parse a boolean literal type node */\n const parseRuntimeValidation = (typeNode: TypeNode) => {\n if (typeNode.isKind(SyntaxKind.LiteralType)) {\n const literal = typeNode.getFirstChild();\n if (literal?.isKind(SyntaxKind.TrueKeyword)) {\n return true;\n } else if (literal?.isKind(SyntaxKind.FalseKeyword)) {\n return false;\n }\n }\n return undefined;\n };\n\n const extractResponseVariant = (\n typeNode: TypeNode,\n ):\n | {\n status: number;\n contentType?: string | undefined;\n body?: string | undefined;\n }\n | undefined => {\n if (!typeNode.isKind(SyntaxKind.TupleType)) {\n return;\n }\n\n let status = 200; // default\n let contentType: string | undefined;\n let body: string | undefined;\n\n const [statusNode, contentTypeNode, bodyNode] = typeNode.getElements();\n\n // Status (index 0) - should be a LiteralType with NumericLiteral\n if (statusNode?.isKind(SyntaxKind.LiteralType)) {\n const literal = statusNode.getFirstChildByKind(SyntaxKind.NumericLiteral);\n if (literal) {\n status = Number(literal.getText());\n }\n }\n\n // ContentType (index 1) - should be a LiteralType with StringLiteral\n if (contentTypeNode) {\n contentType = extractStringLiteral(contentTypeNode);\n }\n\n // Response type text (index 2)\n if (bodyNode) {\n body = bodyNode.getText();\n if ([\"object\"].includes(body)) {\n body = \"{}\";\n }\n }\n\n return { status, contentType, body };\n };\n\n /** Parse opts TypeLiteral into a map keyed by target */\n const parseValidationOptions = (typeNode: TypeNode | undefined) => {\n const opts: Partial<\n Record<\n ValidationTarget,\n {\n contentType: string | undefined;\n runtimeValidation: boolean | undefined;\n customErrors: Record<string, string> | undefined;\n }\n >\n > = {};\n\n if (!typeNode?.isKind(SyntaxKind.TypeLiteral)) {\n return opts;\n }\n\n for (const prop of typeNode.getMembers()) {\n if (!prop.isKind(SyntaxKind.PropertySignature)) {\n continue;\n }\n\n const target = prop.getName() as ValidationTarget;\n const typeNode = prop.getTypeNodeOrThrow();\n\n if (!typeNode.isKind(SyntaxKind.TypeLiteral)) {\n continue;\n }\n\n let contentType: string | undefined;\n let runtimeValidation: boolean | undefined;\n const customErrors: Record<string, string> = {};\n\n for (const member of typeNode.getMembers()) {\n if (!member.isKind(SyntaxKind.PropertySignature)) {\n continue;\n }\n\n const name = propertyName(member);\n const node = member.getTypeNodeOrThrow();\n\n if (name === \"contentType\") {\n contentType = extractStringLiteral(node);\n } else if (name === \"runtimeValidation\") {\n runtimeValidation = parseRuntimeValidation(node);\n } else if (name.startsWith(\"error\")) {\n const literal = extractStringLiteral(node);\n if (literal) {\n customErrors[name] = literal;\n }\n }\n }\n\n opts[target] = {\n contentType,\n runtimeValidation,\n customErrors,\n };\n }\n\n return opts;\n };\n\n const extractStringLiteral = (typeNode: TypeNode) => {\n const literal = typeNode.isKind(SyntaxKind.LiteralType)\n ? typeNode.getFirstChildByKind(SyntaxKind.StringLiteral)\n : undefined;\n return literal ? literal.getLiteralText() : undefined;\n };\n\n /**\n * Extract validation definitions from route handler generics.\n * Merges defs (schemas) and opts (validation options) into a flat array.\n * */\n const extractValidationDefinitions = (\n route: Pick<ApiRoute, \"id\" | \"name\">,\n method: HTTPMethod,\n defsNode: TypeNode,\n optsNode: TypeNode | undefined,\n ) => {\n const definitions: Array<ValidationDefinition> = [];\n\n if (!defsNode?.isKind(SyntaxKind.TypeLiteral)) {\n return definitions;\n }\n\n const optsMap = parseValidationOptions(optsNode);\n\n const createId = (target: string, hash?: string) => {\n return [\n target.replace(/^./, (c) => c.toUpperCase()),\n \"T\",\n method,\n crc(route.id + hash),\n ].join(\"\");\n };\n\n for (const prop of defsNode.getMembers()) {\n if (!prop.isKind(SyntaxKind.PropertySignature)) {\n continue;\n }\n\n const target = prop.getName() as ValidationTarget;\n const typeNode = prop.getTypeNodeOrThrow();\n\n if (target === \"response\") {\n const variants = typeNode.isKind(SyntaxKind.UnionType)\n ? typeNode.getChildrenOfKind(SyntaxKind.TupleType)\n : [typeNode];\n\n definitions.push({\n ...optsMap[target],\n method,\n target,\n variants: variants.flatMap((e, i) => {\n const { status, contentType, body } = {\n ...extractResponseVariant(e),\n };\n\n if (!status) {\n return [];\n }\n\n if (contentType && typeof contentType !== \"string\") {\n console.warn(\n styleText(\n [\"bold\", \"red\"],\n `✗ The second element of a response variant should specify the Response Content Type`,\n ),\n );\n console.warn(\n styleText([\"blue\"], ` Example: [200, \"json\", Schema]`),\n );\n console.warn(\n ` Route: ${route.name}; Method: ${method}; Response Variant: #${i}`,\n );\n console.warn();\n }\n\n return [\n {\n id: createId(\n target,\n JSON.stringify([status, contentType, body]),\n ),\n status,\n contentType,\n body,\n },\n ];\n }),\n });\n } else if (Object.keys(RequestValidationTargets).includes(target)) {\n definitions.push({\n ...optsMap[target],\n method,\n target,\n schema: {\n id: createId(target),\n text: typeNode.getText(),\n },\n });\n }\n }\n\n return definitions;\n };\n\n const extractTypeDeclarations = (\n sourceFile: SourceFile,\n opts?: {\n relpathResolver?: PathResolver;\n withReferencedFiles?: boolean;\n },\n ): [d: Array<TypeDeclaration>, f?: Array<string>] => {\n const declarations: Array<TypeDeclaration> = [];\n\n const referencedFiles: Array<string> | undefined = opts?.withReferencedFiles\n ? []\n : undefined;\n\n for (const declaration of sourceFile.getImportDeclarations()) {\n const modulePath = declaration.getModuleSpecifierValue();\n\n const path = /^\\.\\.?\\/?/.test(modulePath)\n ? opts?.relpathResolver\n ? opts.relpathResolver(modulePath)\n : modulePath\n : modulePath;\n\n const typeOnlyDeclaration = declaration.isTypeOnly();\n\n const defaultImport = typeOnlyDeclaration\n ? declaration.getDefaultImport()\n : undefined;\n\n if (defaultImport) {\n const name = defaultImport.getText();\n const text = `import type ${name} from \"${path}\";`;\n declarations.push({\n importDeclaration: {\n name,\n path,\n },\n text,\n });\n if (referencedFiles) {\n referencedFiles.push(...getReferencedFiles(defaultImport));\n }\n }\n\n const namespaceImport = typeOnlyDeclaration\n ? declaration.getNamespaceImport()\n : undefined;\n\n if (namespaceImport) {\n const name = namespaceImport.getText();\n const text = `import type * as ${name} from \"${path}\";`;\n declarations.push({\n importDeclaration: {\n name,\n path,\n },\n text,\n });\n if (referencedFiles) {\n referencedFiles.push(...getReferencedFiles(namespaceImport));\n }\n }\n\n for (const namedImport of declaration.getNamedImports()) {\n if (namedImport.isTypeOnly() || typeOnlyDeclaration) {\n const nameNode = namedImport.getNameNode();\n const name = nameNode.getText();\n const alias = namedImport.getAliasNode()?.getText();\n const nameText = alias ? `${name} as ${alias}` : name;\n\n declarations.push({\n importDeclaration: {\n name,\n alias,\n path,\n },\n text: `import type { ${nameText} } from \"${path}\";`,\n });\n\n if (referencedFiles) {\n if (nameNode.isKind(SyntaxKind.Identifier)) {\n referencedFiles.push(...getReferencedFiles(nameNode));\n }\n }\n }\n }\n }\n\n for (const declaration of sourceFile.getTypeAliases()) {\n const name = declaration.getName();\n const text = declaration.getFullText().trim();\n declarations.push({\n typeAliasDeclaration: { name },\n text,\n });\n }\n\n for (const declaration of sourceFile.getInterfaces()) {\n const name = declaration.getName();\n const text = declaration.getFullText().trim();\n declarations.push({\n interfaceDeclaration: { name },\n text,\n });\n }\n\n for (const declaration of sourceFile.getEnums()) {\n const name = declaration.getName();\n const text = declaration.getFullText().trim();\n declarations.push({\n enumDeclaration: { name },\n text,\n });\n }\n\n for (const declaration of sourceFile.getExportDeclarations()) {\n const typeOnlyDeclaration = declaration.isTypeOnly();\n\n const modulePath = declaration.getModuleSpecifierValue();\n\n const path = modulePath\n ? /^\\.\\.?\\/?/.test(modulePath)\n ? opts?.relpathResolver\n ? opts.relpathResolver(modulePath)\n : modulePath\n : modulePath\n : undefined;\n\n for (const namedExport of declaration.getNamedExports()) {\n if (namedExport.isTypeOnly() || typeOnlyDeclaration) {\n const nameNode = namedExport.getNameNode();\n const name = nameNode.getText();\n const alias = namedExport.getAliasNode()?.getText();\n const nameText = alias ? `${name} as ${alias}` : name;\n\n declarations.push({\n exportDeclaration: {\n name,\n alias: alias ?? name,\n path,\n },\n text: path\n ? `export type { ${nameText} } from \"${path}\";`\n : `export type { ${nameText} };`,\n });\n\n if (referencedFiles) {\n if (nameNode.isKind(SyntaxKind.Identifier)) {\n referencedFiles.push(...getReferencedFiles(nameNode));\n }\n }\n }\n }\n }\n\n return referencedFiles\n ? [declarations, [...new Set<string>(referencedFiles)]]\n : [declarations];\n };\n\n const getReferencedFiles = (importIdentifier: Identifier): Array<string> => {\n // ambient modules may have declarations in multiple files\n const declarations =\n importIdentifier //\n ?.getSymbol()\n ?.getAliasedSymbol()\n ?.getDeclarations() || [];\n\n return declarations.flatMap((e) => {\n const sourceFile = e.getSourceFile();\n return sourceFile //\n ? [sourceFile.getFilePath()]\n : [];\n });\n };\n\n const extractGenerics = (callExpression: CallExpression) => {\n return callExpression.getTypeArguments();\n };\n\n const typeResolverFactory = (sourceFolder: SourceFolder) => {\n const { createPath } = pathResolver(sourceFolder);\n\n const project = createProject({\n compilerOptions: {\n moduleResolution: ModuleResolutionKind.Bundler,\n types: [],\n noLib: true,\n skipLibCheck: true,\n paths: {\n [`${defaults.appPrefix}/*`]: [`${sourceFolder.root}/*`],\n [`${defaults.srcPrefix}/*`]: [createPath.src(\"*\")],\n [`${defaults.libPrefix}/*`]: [createPath.lib(\"*\")],\n },\n },\n });\n\n const withTypeboxSchema = (resolvedTypes: Array<ResolvedType>) => {\n const materializedTypes = render(templates.resolvedTypes, {\n resolvedTypes,\n });\n\n // NOTE: file name should be unique as it will stay during project's life cycle.\n const sourceFile = project.createSourceFile(\n `${crc(materializedTypes)}-${Date.now()}.ts`,\n materializedTypes,\n { overwrite: true },\n );\n\n const types = resolvedTypes.map<ResolvedTypeSignature>((type) => {\n const typeNode = sourceFile.getTypeAlias(type.name)?.getTypeNode();\n\n if (!typeNode) {\n return type;\n }\n\n const properties = [];\n const numericProperties = [];\n const booleanProperties = [];\n\n for (const prop of type.properties || []) {\n const propNode = typeNode.isKind(SyntaxKind.TypeLiteral)\n ? typeNode.getProperty(prop.nameDeclaration)?.getTypeNode()\n : undefined;\n\n if (!propNode) {\n continue;\n }\n\n properties.push({\n ...prop,\n typeboxSchema: renderTypeboxSchema(propNode),\n });\n\n if (isNumericTypeNode(propNode)) {\n numericProperties.push(prop.name);\n }\n\n if (isBooleanTypeNode(propNode)) {\n booleanProperties.push(prop.name);\n }\n }\n\n return {\n ...type,\n properties,\n numericProperties,\n booleanProperties,\n typeboxSchema: renderTypeboxSchema(typeNode),\n };\n });\n\n // NOTE: do not removeSourceFile, that invalidates proejct's cache,\n // triggering cache rebuild on next call.\n\n return types;\n };\n\n const literalTypesResolver = (\n literalTypes: string,\n options: Parameters<typeof flattener>[2],\n ): Array<ResolvedTypeSignature> => {\n // NOTE: file name should be unique as it will stay during project's life cycle.\n const sourceFile = project.createSourceFile(\n `${crc(literalTypes)}-${Date.now()}.ts`,\n literalTypes,\n { overwrite: true },\n );\n\n const resolvedTypes = flattener(project, sourceFile, {\n ...options,\n stripComments: true,\n });\n\n // NOTE: do not removeSourceFile, that invalidates proejct's cache,\n // triggering cache rebuild on next call.\n\n return withTypeboxSchema(resolvedTypes);\n };\n\n return {\n getSourceFile: (fileFullpath: string) => {\n return (\n project.getSourceFile(fileFullpath) ||\n project.addSourceFileAtPath(fileFullpath)\n );\n },\n refreshSourceFile: async (fileFullpath: string) => {\n const sourceFile = project.getSourceFile(fileFullpath);\n if (sourceFile) {\n await sourceFile.refreshFromFileSystem();\n }\n },\n literalTypesResolver,\n };\n };\n\n return {\n createProject,\n extractDefaultExport,\n extractParamsRefinements,\n extractRouteMethods,\n extractTypeDeclarations,\n resolveRouteSignature,\n typeResolverFactory,\n };\n};\n\n/**\n * Property name as declared, stripping quotes for string-literal keys.\n * */\nconst propertyName = (property: PropertySignature): string => {\n const nameNode = property.getNameNode();\n return nameNode.isKind(SyntaxKind.StringLiteral)\n ? nameNode.getLiteralValue()\n : nameNode.getText();\n};\n\n/**\n * Whether type node reduces to `number`.\n *\n * number -> true\n * VRefine<number, {}> -> true (peel to first type argument)\n * Array<number> -> true (peel to first type argument)\n * number[] -> true (peel to element type)\n * readonly number[] -> true (peel the type operator, then array)\n * VRefine<Array<number>, {}> -> true (peels compose)\n * 2, -2 -> true (literal types, sign included)\n * 1 | -2 | 3 -> true (union with every member numeric)\n * number | string -> false (mixed unions are not numeric)\n *\n * Does NOT descend into object properties or nested tuple elements.\n * */\nconst isNumericTypeNode = (\n typeNode: TypeNode,\n refineTypeName = defaults.refineTypeName,\n): boolean => {\n // (T) -> T (peel off parentheses)\n if (typeNode.isKind(SyntaxKind.ParenthesizedType)) {\n return isNumericTypeNode(typeNode.getTypeNode(), refineTypeName);\n }\n\n // VRefine<T, Opts> -> T\n // Array<T> -> T\n if (typeNode.isKind(SyntaxKind.TypeReference)) {\n const name = typeNode.getTypeName().getText();\n return name === refineTypeName || name === \"Array\"\n ? isNumericTypeNode(typeNode.getTypeArguments()[0], refineTypeName)\n : false;\n }\n\n // T[] -> T\n if (typeNode.isKind(SyntaxKind.ArrayType)) {\n return isNumericTypeNode(typeNode.getElementTypeNode(), refineTypeName);\n }\n\n // readonly T[] -> T\n if (typeNode.isKind(SyntaxKind.TypeOperator)) {\n return typeNode.getOperator() === SyntaxKind.ReadonlyKeyword\n ? isNumericTypeNode(typeNode.getTypeNode(), refineTypeName)\n : false;\n }\n\n // 1 | -2 | 3 - numeric when every member is numeric\n if (typeNode.isKind(SyntaxKind.UnionType)) {\n return typeNode\n .getTypeNodes()\n .every((node) => isNumericTypeNode(node, refineTypeName));\n }\n\n // literal 2, -2 (the only prefix allowed in a literal type is the sign)\n if (typeNode.isKind(SyntaxKind.LiteralType)) {\n const literal = typeNode.getLiteral();\n return literal.isKind(SyntaxKind.PrefixUnaryExpression)\n ? literal.getOperand().isKind(SyntaxKind.NumericLiteral)\n : literal.isKind(SyntaxKind.NumericLiteral);\n }\n\n // plain `number` keyword\n return typeNode.isKind(SyntaxKind.NumberKeyword);\n};\n\n/**\n * Whether type node reduces to `boolean`.\n *\n * boolean -> true\n * Array<boolean> -> true\n * boolean[] -> true\n * readonly boolean[] -> true\n * true, false -> true (literal types)\n *\n * Does NOT descend into object properties or nested tuple elements.\n * */\nconst isBooleanTypeNode = (typeNode: TypeNode): boolean => {\n // (T) -> T (peel off parentheses)\n if (typeNode.isKind(SyntaxKind.ParenthesizedType)) {\n return isBooleanTypeNode(typeNode.getTypeNode());\n }\n\n // Array<T> -> T\n if (typeNode.isKind(SyntaxKind.TypeReference)) {\n return typeNode.getTypeName().getText() === \"Array\"\n ? isBooleanTypeNode(typeNode.getTypeArguments()[0])\n : false;\n }\n\n // T[] -> T\n if (typeNode.isKind(SyntaxKind.ArrayType)) {\n return isBooleanTypeNode(typeNode.getElementTypeNode());\n }\n\n // readonly T[] -> T\n if (typeNode.isKind(SyntaxKind.TypeOperator)) {\n return typeNode.getOperator() === SyntaxKind.ReadonlyKeyword\n ? isBooleanTypeNode(typeNode.getTypeNode())\n : false;\n }\n\n // literal true / false\n if (typeNode.isKind(SyntaxKind.LiteralType)) {\n const literal = typeNode.getLiteral();\n return (\n literal.isKind(SyntaxKind.TrueKeyword) ||\n literal.isKind(SyntaxKind.FalseKeyword)\n );\n }\n\n // plain boolean\n return typeNode.isKind(SyntaxKind.BooleanKeyword);\n};\n\n/**\n * Render a ts-morph TypeNode to TypeBox Script text, replacing every VRefine\n * occurrence (at any depth) with the infix `with` form.\n *\n * VRefine<string, { format: \"email\" }> -> (string with { format: \"email\" })\n * VRefine<string, { format: \"email\" }>[] -> (string with { format: \"email\" })[]\n * VRefine<Array<string>, { minItems: 1 }> -> (Array<string> with { minItems: 1 })\n * VRefine<Record<string, string>, { maxProperties: 20 }>\n * -> (Record<string, string> with { maxProperties: 20 })\n *\n * The parentheses matter: for an array element the `with` clause must bind to the element,\n * not the array, so a VRefine that is the element of an array is wrapped.\n * So, wrapping unconditionally - harmless when not nested, required when it is.\n *\n * @param typeNode the node to render\n * @param refineTypeName the configured refine type name\n * */\nconst renderTypeboxSchema = (\n typeNode: TypeNode,\n refineTypeName = defaults.refineTypeName,\n) => {\n const traverse = (typeNode: TypeNode): string => {\n // 1) VRefine<T, Opts> -> `(<render T> with <opts text>)`\n if (\n typeNode.isKind(SyntaxKind.TypeReference) &&\n typeNode.getTypeName().getText() === refineTypeName\n ) {\n const [inner, opts] = typeNode.getTypeArguments();\n if (!inner || !opts) {\n // Malformed VRefine, emit its raw text unchanged\n return typeNode.getText();\n }\n const innerText = traverse(inner);\n // Options is a single TypeLiteral; its raw text is exactly what `with`\n // expects. getText() preserves nested braces and quoted `}>` verbatim.\n return `(${innerText} with ${opts.getText()})`;\n }\n\n // 2) T[] -> `<render T>[]` (element may itself be a VRefine)\n if (typeNode.isKind(SyntaxKind.ArrayType)) {\n const element = traverse(typeNode.getElementTypeNode());\n return `${element}[]`;\n }\n\n // 3) Object type literal -> recurse into each property's type node\n if (typeNode.isKind(SyntaxKind.TypeLiteral)) {\n const members: string[] = [];\n for (const member of typeNode.getMembers()) {\n if (member.isKind(SyntaxKind.PropertySignature)) {\n const name = member.getName();\n const optional = member.hasQuestionToken() ? \"?\" : \"\";\n const t = member.getTypeNode();\n const rendered = t ? traverse(t) : \"unknown\";\n members.push(`${name}${optional}: ${rendered}`);\n } else {\n // index signatures, call signatures, etc: pass through raw\n members.push(member.getText());\n }\n }\n return `{ ${members.join(\", \")} }`;\n }\n\n // 4) Tuple -> recurse into each element\n if (typeNode.isKind(SyntaxKind.TupleType)) {\n const elements = typeNode.getElements().map((el) => traverse(el));\n return `[${elements.join(\", \")}]`;\n }\n\n // 5) Parenthesized -> recurse, keep the parens\n if (typeNode.isKind(SyntaxKind.ParenthesizedType)) {\n return `(${traverse(typeNode.getTypeNode())})`;\n }\n\n // 6) Union / Intersection -> recurse into each constituent\n if (typeNode.isKind(SyntaxKind.UnionType)) {\n return typeNode\n .getTypeNodes()\n .map((t) => traverse(t))\n .join(\" | \");\n }\n if (typeNode.isKind(SyntaxKind.IntersectionType)) {\n return typeNode\n .getTypeNodes()\n .map((t) => traverse(t))\n .join(\" & \");\n }\n\n // 7) A non-VRefine type reference that carries type arguments -\n // this covers the refined bases Array<T> and Record<K, V>\n // (which stay as-is and get a trailing `with` clause from case 1),\n // as well as any generic wrapper around a VRefine.\n // Recurse into the arguments so a nested VRefine is still rewritten,\n // and keep the head name unchanged.\n if (typeNode.isKind(SyntaxKind.TypeReference)) {\n const args = typeNode.getTypeArguments();\n if (args.length === 0) {\n return typeNode.getText();\n }\n const name = typeNode.getTypeName().getText();\n const rendered = args.map((a) => traverse(a));\n return `${name}<${rendered.join(\", \")}>`;\n }\n\n // 8) Anything else (primitive keyword, literal, etc): raw text is correct.\n return typeNode.getText();\n };\n\n return escapeTemplateLiterals(traverse(typeNode));\n};\n","import { type FormatConfig, format } from \"oxfmt\";\n\nexport const formatCode = async (\n code: string,\n filename: string,\n config?: FormatConfig,\n) => {\n return format(filename, code, {\n sortImports: true,\n ...config,\n }).then((e) => (e.errors.length ? code : e.code));\n};\n","import type {\n ApiRoute,\n GeneratorFactory,\n GeneratorSignature,\n ResolvedEntry,\n SourceFolder,\n WatcherEvent,\n} from \"@kosmojs/core\";\n\nexport const defineGenerator = <O extends object, R extends boolean = false>({\n meta,\n factory,\n dependencies,\n devDependencies,\n}: Omit<GeneratorSignature<O>, \"factory\"> & {\n factory: (f: SourceFolder, o?: O) => GeneratorFactory;\n}): [R] extends [true]\n ? (o: O) => GeneratorSignature<O>\n : (o?: O) => GeneratorSignature<O> => {\n return ((options?: O) => {\n return {\n meta,\n factory: (folder: SourceFolder) => factory(folder, options),\n dependencies,\n devDependencies,\n options,\n };\n }) as never;\n};\n\nexport const defineGeneratorFactory = <O extends object>(\n factory: (f: SourceFolder, o?: O) => GeneratorFactory,\n) => factory;\n\n/**\n * Filter watched API routes by event.\n * Handle 3 cases:\n * - event is undefined (means initial call): process all routes.\n * - `create` event given: process newly added route.\n * Files can arrive already containing content (git checkout, cp) -\n * clients must generate on create, not only on a subsequent update.\n * - `update` event given: process the updated route,\n * and any route referencing the updated file (shared types).\n * */\nexport const createWatchedApiRouteEntriesFilter = (\n event: WatcherEvent | undefined,\n eventsOfInterest: Array<WatcherEvent[\"kind\"]>,\n) => {\n return ({ kind, entry }: ResolvedEntry) => {\n if (!event) {\n // no event (initial call), process all routes\n return true;\n }\n if (!eventsOfInterest.includes(event.kind)) {\n return false;\n }\n if (kind === \"apiRoute\" || kind === \"apiUse\") {\n return entry.fileFullpath !== event.file\n ? (entry as ApiRoute).referencedFiles?.includes(event.file)\n : true;\n }\n return false;\n };\n};\n/**\n * Filter watched page routes by event.\n * Handle 3 cases:\n * - event is undefined (means initial call): process all routes.\n * - `create` event given: process newly added route.\n * Files can arrive already containing content (git checkout, cp) -\n * clients must generate on create, not only on a subsequent update.\n * - `update` event given: process the updated route,\n * and any route referencing the updated file (shared types).\n * */\nexport const createWatchedPageRouteEntriesFilter = (\n event: WatcherEvent | undefined,\n eventsOfInterest: Array<WatcherEvent[\"kind\"]>,\n) => {\n return ({ kind, entry }: ResolvedEntry) => {\n if (!event) {\n // no event (initial call), process all routes\n return true;\n }\n if (!eventsOfInterest.includes(event.kind)) {\n return false;\n }\n return kind === \"pageRoute\" || kind === \"pageLayout\"\n ? entry.fileFullpath === event.file\n : false;\n };\n};\n","import crc from \"crc/crc32\";\nimport { compile, parse, type Token } from \"path-to-regexp\";\n\nimport type {\n PathToken,\n PathTokenParamPart,\n PathTokenStaticPart,\n} from \"@kosmojs/core\";\n\n/**\n * Parse a filesystem route path into structured PathToken array.\n *\n * Uses path-to-regexp v8 AST for parsing, with directory-friendly syntax:\n * - [param] => required param - :param\n * - {param} => optional param - {:param}\n * - {...param} => splat - {*param}\n *\n * Direct :param syntax is prohibited outside {} to avoid ambiguity.\n * Inside {} it is treated as path-to-regexp power syntax and used as-is.\n *\n * Throw error if path can not be compiled into path-to-regexp pattern.\n *\n * Examples:\n * Required: [id], [name]\n * Optional: {name}, {format}\n * Splat: {...path}\n * Mixed segments: shop/[id]-{name}\n * Power syntax: {-v:version{-:pre}}, :name{@:version{.:min}}.js\n * */\nexport const pathTokensFactory = (path: string): Array<PathToken> => {\n /**\n * Recursively extract parts from path-to-regexp AST tokens.\n * A param inside a group is optional; top-level params are required.\n * Wildcard tokens are always splat.\n * Slash-only text nodes (restored for parsing) are skipped.\n * */\n const extractParts = (\n tokens: Array<Token>,\n createConst: (value: string) => string,\n insideGroup = false,\n ): Array<PathTokenStaticPart | PathTokenParamPart> => {\n const parts: Array<PathTokenStaticPart | PathTokenParamPart> = [];\n\n for (const token of tokens) {\n switch (token.type) {\n case \"text\":\n // Skip slash-only text nodes (restored it via transformers for parsing)\n if (token.value !== \"/\") {\n parts.push({\n type: \"static\",\n value: token.value,\n });\n }\n break;\n case \"param\":\n parts.push({\n type: \"param\",\n kind: insideGroup ? \"optional\" : \"required\",\n name: token.name,\n const: createConst(token.name),\n });\n break;\n case \"wildcard\":\n parts.push({\n type: \"param\",\n kind: \"splat\",\n name: token.name,\n const: createConst(token.name),\n });\n break;\n case \"group\":\n parts.push(...extractParts(token.tokens, createConst, true));\n break;\n }\n }\n\n return parts;\n };\n\n const patternTransforms: Array<(s: string) => string> = [\n // Transform required params: [id] => :id\n // Only pure \\w param names,\n // [some-id] used as is, not treated as param,\n // use [some_id] instead.\n (s) => s.replace(/\\[(\\w+)\\]/g, \":$1\"),\n\n // Transform optional params: {id} => {:id}\n // Only pure \\w param names,\n // anything else treated as a path-to-regexp pattern and used as is.\n // {some-id} treated as an optional static segment.\n // use {some_id} for simple param syntax\n // or {:some-id} pattern where :some is the param name and -id is a static segment.\n (s) => s.replace(/\\{(\\w+)\\}/g, \"{:$1}\"),\n\n // Transform splat params: {...param} => {*param}\n (s) => s.replace(/\\{\\.\\.\\./g, \"{*\"),\n\n // Insert leading slash inside optional/splat groups.\n // {:name} => {/:name}\n // {*name} => {/*name}\n (s) => {\n return s.startsWith(\"{\") // keep this check for intention clarity\n ? s.replace(/^\\{/, \"{/\")\n : s;\n },\n ];\n\n // detect :param used outside {}\n const detectBareParams = (s: string): \":\" | string | undefined => {\n let depth = 0;\n for (const [i, ch] of [...s].entries()) {\n if (ch === \"{\") {\n depth += 1;\n } else if (ch === \"}\") {\n depth -= 1;\n } else if (ch === \":\" && depth === 0) {\n const match = s.slice(i + 1).match(/^\\w+/);\n return match?.[0] || \":\";\n }\n }\n return;\n };\n\n const tokens = path\n .replace(/^index\\/?/, \"\")\n .split(\"/\")\n .flatMap<PathToken>((orig) => {\n if (!orig.length) {\n return [];\n }\n\n const bareParam = detectBareParams(orig);\n\n if (bareParam === \":\") {\n throw new Error(\n `${path} contains colons outside braces, use : only within {}`,\n );\n } else if (bareParam) {\n throw new Error(\n `${path} contains bare params, use [${bareParam}] instead of :${bareParam}`,\n );\n }\n\n const pattern = patternTransforms.reduce((src, fn) => fn(src), orig);\n\n const { tokens } = parse(\n pattern.replace(/\\{[^}]*\\}|(\\+)/g, (m, p1) => (p1 ? \"\\\\+\" : m)),\n );\n\n const parts = extractParts(tokens, (val) => {\n // Sanitize param name into a valid JS identifier\n return /\\W/.test(val) || /^\\d/.test(val)\n ? [val.replace(/^\\d+|\\W/g, \"_\"), crc(orig)].join(\"_\")\n : val;\n });\n\n const isStatic = parts.length === 1 ? parts[0].type === \"static\" : false;\n const isParam = parts.length === 1 ? parts[0].type === \"param\" : false;\n\n const kind: PathToken[\"kind\"] = isStatic\n ? \"static\"\n : isParam\n ? \"param\"\n : \"mixed\";\n\n return [\n {\n kind,\n orig,\n pattern,\n parts,\n },\n ];\n });\n\n // final path should compile, throw otherwise\n compile(tokens.map((e) => e.pattern).join(\"/\"));\n\n return tokens;\n};\n\nexport const createPathPattern = (tokens: Array<PathToken>) => {\n return tokens\n .map(({ pattern }, i) => {\n const next = tokens[i + 1];\n\n if (!next || next.pattern.includes(\"/\")) {\n return pattern;\n }\n\n const slashRequired = tokens.slice(i + 1).some((e) => {\n return e.parts.some((e) => {\n return e.type === \"static\" || e.kind === \"required\";\n });\n });\n\n return slashRequired ? `${pattern}/` : pattern;\n })\n .join(\"\");\n};\n\nexport const createHonoPattern = (tokens: Array<PathToken>) => {\n const escapeStatic = (s: string) => s.replace(/[*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n\n const tokensToPattern = (tokens: Array<Token>): string => {\n return tokens\n .flatMap((t) => {\n if (t.type === \"text\") {\n return t.value === \"/\" ? [] : [escapeStatic(t.value)];\n }\n if (t.type === \"param\") {\n return [\"[^/]+\"];\n }\n if (t.type === \"wildcard\") {\n return [\".+\"];\n }\n if (t.type === \"group\") {\n return [`(?:${tokensToPattern(t.tokens)})?`];\n }\n return [];\n })\n .join(\"\");\n };\n\n return tokens\n .flatMap((token, i) => {\n // static segment\n if (token.kind === \"static\") {\n return [(token.parts[0] as PathTokenStaticPart).value];\n }\n\n // pure param segment\n if (token.kind === \"param\") {\n const part = token.parts[0] as PathTokenParamPart;\n if (part.kind === \"splat\") {\n return [\"*\"];\n }\n if (part.kind === \"optional\") {\n return [`:${part.name}?`];\n }\n return [`:${part.name}`];\n }\n\n // mixed segment - convert path-to-regexp pattern to hono regex pattern\n const { tokens } = parse(token.pattern);\n\n return [`:_${i}{${tokensToPattern(tokens)}}`];\n })\n .join(\"/\");\n};\n\nexport const createH3Pattern = (tokens: Array<PathToken>): string => {\n // WARN: escaping the dash is essential for correct param matching\n const escapeStatic = (s: string) => s.replace(/[-*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n\n const tokensToPattern = (tokens: Array<Token>): string => {\n return tokens\n .flatMap((t) => {\n if (t.type === \"text\") {\n return t.value === \"/\" ? [] : [escapeStatic(t.value)];\n }\n if (t.type === \"param\") {\n return [`:${t.name}`];\n }\n if (t.type === \"wildcard\") {\n return [`/**:${t.name}?`];\n }\n if (t.type === \"group\") {\n return [`{${tokensToPattern(t.tokens)}}?`];\n }\n return [];\n })\n .join(\"\");\n };\n\n return tokens\n .flatMap((token) => {\n // static segment\n if (token.kind === \"static\") {\n return [(token.parts[0] as PathTokenStaticPart).value];\n }\n\n // pure param segment\n if (token.kind === \"param\") {\n const part = token.parts[0] as PathTokenParamPart;\n if (part.kind === \"splat\") {\n return [\"**\"];\n }\n if (part.kind === \"optional\") {\n return [\"*\"];\n }\n return [`:${part.name}`];\n }\n\n // mixed segment - convert path-to-regexp pattern to rou3 regex pattern\n const { tokens } = parse(token.pattern);\n\n return [tokensToPattern(tokens)];\n })\n .join(\"/\");\n};\n\nexport const createAliasPatterns = (\n aliasMap: Record<string, string> | undefined,\n) => {\n return Object.keys(aliasMap || {}).map((alias) => {\n return createPathPattern(pathTokensFactory(alias));\n });\n};\n","import { dirname, join, resolve } from \"node:path\";\nimport { styleText } from \"node:util\";\n\nimport crc from \"crc/crc32\";\nimport picomatch from \"picomatch\";\nimport { glob } from \"tinyglobby\";\n\nimport {\n defaults,\n type PathToken,\n type PathTokenParamPart,\n type ResolvedEntry,\n type RouteEntry,\n type SourceFolder,\n} from \"@kosmojs/core\";\n\nimport { pathResolver } from \"../paths\";\nimport {\n createH3Pattern,\n createHonoPattern,\n createPathPattern,\n pathTokensFactory,\n} from \"./paths\";\n\nexport type ResolverSignature = {\n name: string;\n handler: (updatedFile?: string) => Promise<ResolvedEntry>;\n};\n\nexport const API_INDEX_BASENAME = \"index\";\nexport const API_INDEX_PATTERN = `${API_INDEX_BASENAME}.ts`;\n\nexport const API_USE_BASENAME = \"use\";\nexport const API_USE_PATTERN = `${API_USE_BASENAME}.ts`;\n\nexport const PAGE_INDEX_BASENAME = \"index\";\nexport const PAGE_INDEX_PATTERN = `${PAGE_INDEX_BASENAME}.{tsx,vue,svelte,mdx,md}`;\n\nexport const PAGE_LAYOUT_BASENAME = \"layout\";\nexport const PAGE_LAYOUT_PATTERN = `${PAGE_LAYOUT_BASENAME}.{tsx,vue,svelte,mdx}`;\n\nconst ROUTE_FILE_PATTERNS = [\n // match index files in api dir\n `${defaults.apiDir}/**/${API_INDEX_PATTERN}`,\n // match use files in api dir\n `${defaults.apiDir}/**/${API_USE_PATTERN}`,\n // match index files in pages dir\n `${defaults.pagesDir}/**/${PAGE_INDEX_PATTERN}`,\n // match layout files in pages dir\n `${defaults.pagesDir}/**/${PAGE_LAYOUT_PATTERN}`,\n];\n\nexport const scanRoutes = async (sourceFolder: SourceFolder) => {\n const { createPath } = pathResolver(sourceFolder);\n return glob(ROUTE_FILE_PATTERNS, {\n cwd: createPath.src(),\n absolute: true,\n onlyFiles: true,\n followSymbolicLinks: false,\n ignore: [\n // ignore top-level matches, routes resides in folders, even index route\n `${defaults.apiDir}/${API_INDEX_PATTERN}`,\n `${defaults.apiDir}/${API_USE_PATTERN}`,\n `${defaults.pagesDir}/${PAGE_INDEX_PATTERN}`,\n `${defaults.pagesDir}/${PAGE_LAYOUT_PATTERN}`,\n ],\n });\n};\n\nexport const isRouteFile = (\n file: string,\n sourceFolder: SourceFolder,\n):\n | [\n // Either `apiDir` or `pagesDir`\n folder: string,\n // Path to a file within the folder, nested at least one level deep\n file: string,\n ]\n | false => {\n const [\n // source folder name\n _sourceFolder,\n // route folder, api or pages\n _folder,\n ...rest\n ] = resolve(sourceFolder.root, file)\n .replace(`${sourceFolder.root}/${defaults.srcDir}/`, \"\")\n .split(\"/\");\n\n /**\n * Ensure the file:\n * - is under the correct source root\n * - belongs to a known route folder (`api/` or `pages/`)\n * - is nested at least one level deep (not a direct child of the folder)\n * */\n if (!_folder || _sourceFolder !== sourceFolder.name || rest.length < 2) {\n return false;\n }\n\n return picomatch.isMatch(join(_folder, ...rest), ROUTE_FILE_PATTERNS)\n ? [_folder, rest.join(\"/\")]\n : false;\n};\n\nexport const isApiRoute = (file: string) => {\n return picomatch.matchBase(file, `**/${API_INDEX_PATTERN}`);\n};\n\nexport const isApiUse = (file: string) => {\n return picomatch.matchBase(file, `**/${API_USE_PATTERN}`);\n};\n\nexport const isPageRoute = (file: string) => {\n return picomatch.matchBase(file, `**/${PAGE_INDEX_PATTERN}`);\n};\n\nexport const isPageLayout = (file: string) => {\n return picomatch.matchBase(file, `**/${PAGE_LAYOUT_PATTERN}`);\n};\n\nexport const createRouteEntry = (\n fileFullpath: string,\n sourceFolder: SourceFolder,\n): RouteEntry | undefined => {\n // scanner already is doing a great job on matching only relevant files\n // but doing a double check here to make sure only needed files added to stack\n const resolvedPaths = isRouteFile(fileFullpath, sourceFolder);\n\n if (!resolvedPaths) {\n return;\n }\n\n const [folder, file] = resolvedPaths;\n\n const id = `${file.replace(/\\W+/g, \"_\")}_${crc(file)}`;\n const name = dirname(file);\n\n try {\n const pathTokens = pathTokensFactory(dirname(file));\n return {\n id,\n name,\n folder,\n file,\n fileFullpath,\n pathTokens,\n pathPattern: createPathPattern(pathTokens),\n honoPattern: createHonoPattern(pathTokens),\n h3Pattern: createH3Pattern(pathTokens),\n };\n } catch (\n // biome-ignore lint: any\n error: any\n ) {\n console.error(\n `❗${styleText(\"red\", \"ERROR\")}: Failed parsing path for \"${styleText(\"cyan\", file)}\"`,\n );\n console.error(error.message);\n return;\n }\n};\n\n/**\n * Weight of a single path segment.\n *\n * Fixed values per kind prevent complex mixed segments\n * from outscoring multiple statics.\n *\n * static: 4 (exact match, most specific)\n * mixed: 3+ (static + param parts; more statics = slightly higher)\n * required: 2 (matches any single segment)\n * optional: 1 (may or may not match)\n * splat: 0 (matches anything, least specific)\n * */\nconst segmentWeight = (token: PathToken): number => {\n if (token.kind === \"static\") {\n return 4;\n }\n\n if (token.kind === \"mixed\") {\n let statics = 0;\n let optionals = 0;\n\n for (const part of token.parts) {\n if (part.type === \"static\") {\n statics += 1;\n } else if (part.kind === \"optional\" || part.kind === \"splat\") {\n optionals += 1;\n }\n }\n\n // unconditional statics contribute positively,\n // optionals penalize to avoid beating fully-static mixed routes\n return 3 + statics * 0.01 - optionals * 0.005;\n }\n\n const part = token.parts[0] as PathTokenParamPart;\n\n switch (part.kind) {\n case \"required\":\n return 2;\n case \"optional\":\n return 1;\n case \"splat\":\n return 0;\n }\n};\n\n/**\n * Compare two route entries for registration order.\n *\n * More specific routes sort first (higher priority).\n * Segments are compared left-to-right; first difference wins.\n *\n * When one route is a prefix of the other, the trailing segment\n * determines order: a trailing splat loses (shorter sibling first),\n * anything else wins (longer route is more specific).\n *\n * At equal weight and length, lexicographic tiebreak ensures\n * deterministic ordering across JS engines.\n * */\nexport const sortRoutes = (\n a: Pick<RouteEntry, \"pathPattern\" | \"pathTokens\">,\n b: Pick<RouteEntry, \"pathPattern\" | \"pathTokens\">,\n): number => {\n const pairs = Array.from(\n { length: Math.max(a.pathTokens.length, b.pathTokens.length) },\n (_, i) => [a.pathTokens[i], b.pathTokens[i]] as const,\n );\n\n for (const [at, bt] of pairs) {\n if (!at || !bt) {\n // one route ran out of segments - check what the extra segment is\n const extra = at ?? bt;\n\n const isSplat =\n extra?.kind === \"param\"\n ? (extra.parts[0] as PathTokenParamPart).kind === \"splat\"\n : false;\n\n if (isSplat) {\n // trailing splat: shorter sibling registers first\n return at ? 1 : -1;\n }\n\n // trailing non-splat: longer route is more specific, registers first\n return at ? -1 : 1;\n }\n\n const aw = segmentWeight(at);\n const bw = segmentWeight(bt);\n\n if (aw !== bw) {\n return bw - aw;\n }\n }\n\n // same weight profile, same length: deterministic tiebreak\n return a.pathPattern.localeCompare(b.pathPattern);\n};\n\n/**\n * Compare two route entries for first-match resolution order,\n * as used by the generated svelte/mdx routers.\n *\n * Identical to `sortRoutes` except when one route is a prefix of the other\n * and the trailing extra segment is an optional parameter: there the SHORTER route goes first.\n * The longer route's pattern also matches the bare path (optional omitted),\n * but only the shorter route can serve it - deeper URLs never match the shorter one's pattern,\n * so it must get the first shot:\n *\n * /blog -> `blog`, not `blog/{category}/{tag}`\n * /admin/x/resources -> `admin/[tenant]/resources`, not `.../resources/{type}`\n *\n * Trailing splats already sort shorter-first in `sortRoutes`;\n * trailing static or required segments make the two patterns disjoint,\n * so their relative order is immaterial for first-match and stays as registration order.\n * */\nexport const sortRoutesForResolution = (\n a: Pick<RouteEntry, \"pathPattern\" | \"pathTokens\">,\n b: Pick<RouteEntry, \"pathPattern\" | \"pathTokens\">,\n): number => {\n const shorter = a.pathTokens.length < b.pathTokens.length ? a : b;\n const longer = shorter === a ? b : a;\n\n // Equal-weight shared prefix approximates \"no earlier difference decides\":\n // when prefix weights differ, sortRoutes orders by that difference anyway,\n // and same-weight-different-static prefixes are disjoint patterns,\n // where relative order is immaterial for first-match.\n if (\n a.pathTokens.length !== b.pathTokens.length &&\n shorter.pathTokens.every((token, i) => {\n const counterpart = longer.pathTokens[i] as PathToken;\n return segmentWeight(token) === segmentWeight(counterpart);\n })\n ) {\n const extra = longer.pathTokens[shorter.pathTokens.length] as PathToken;\n\n if (\n extra.kind === \"param\" &&\n (extra.parts[0] as PathTokenParamPart).kind === \"optional\"\n ) {\n return shorter === a ? -1 : 1;\n }\n }\n\n return sortRoutes(a, b);\n};\n","import { dirname, join, resolve } from \"node:path\";\nimport { styleText } from \"node:util\";\n\nimport crc from \"crc/crc32\";\nimport { lookup } from \"mrmime\";\n\nimport {\n type ApiRoute,\n defaults,\n type PageRoute,\n type PathTokenParamPart,\n type RouteEntry,\n type RouteResolverCacheFactory,\n type SourceFolder,\n type TypeboxOptions,\n type ValidationDefinition,\n} from \"@kosmojs/core\";\n\nimport { astFactory } from \"../ast\";\nimport { pathResolver } from \"../paths\";\nimport { render, renderToFile } from \"../render\";\nimport * as templates from \"../templates\";\nimport type { ResolverSignature } from \"./base\";\n\nexport const resolverFactory = (\n sourceFolder: SourceFolder,\n cacheFactory?: RouteResolverCacheFactory,\n): Record<\n | \"pageLayoutResolver\"\n | \"pageRouteResolver\"\n | \"apiUseResolver\"\n | \"apiRouteResolver\",\n (entry: RouteEntry) => ResolverSignature\n> => {\n const { generators } = sourceFolder;\n\n const { refineTypeName = defaults.refineTypeName } =\n typeof sourceFolder.config.validation === \"object\"\n ? ({ ...sourceFolder.config.validation } as TypeboxOptions)\n : {};\n\n const { typeResolverFactory, resolveRouteSignature } = astFactory();\n\n const resolveTypes = generators.some(({ meta }) => meta.resolveTypes);\n\n const {\n //\n literalTypesResolver,\n getSourceFile,\n refreshSourceFile,\n } = typeResolverFactory(sourceFolder);\n\n return {\n pageLayoutResolver(entry) {\n const { name } = entry;\n\n const handler: ResolverSignature[\"handler\"] = async () => {\n return {\n kind: \"pageLayout\",\n entry,\n };\n };\n\n return { name, handler };\n },\n\n pageRouteResolver(entry) {\n const {\n id,\n name,\n folder,\n file,\n fileFullpath,\n pathTokens,\n pathPattern,\n honoPattern,\n h3Pattern,\n } = entry;\n\n const handler: ResolverSignature[\"handler\"] = async () => {\n const entry: PageRoute = {\n id,\n name,\n pathTokens,\n pathPattern,\n honoPattern,\n h3Pattern,\n params: {\n schema: pathTokens.flatMap((e) => {\n return e.parts.filter((p) => p.type === \"param\");\n }),\n },\n folder,\n file,\n fileFullpath,\n };\n\n return {\n kind: \"pageRoute\",\n entry,\n };\n };\n\n return { name, handler };\n },\n\n apiUseResolver(entry) {\n const { name } = entry;\n\n const handler: ResolverSignature[\"handler\"] = async () => {\n return {\n kind: \"apiUse\",\n entry,\n };\n };\n\n return { name, handler };\n },\n\n apiRouteResolver(entry) {\n const {\n id,\n name,\n file,\n folder,\n fileFullpath,\n pathTokens,\n pathPattern,\n honoPattern,\n h3Pattern,\n } = entry;\n\n const handler: ResolverSignature[\"handler\"] = async (updatedFile) => {\n const paramsSchema: Array<PathTokenParamPart> = pathTokens.flatMap(\n (e) => {\n return e.parts.flatMap((p) => {\n return p.type === \"param\" ? [p] : [];\n });\n },\n );\n\n const optionalParams = paramsSchema.length\n ? paramsSchema.filter((e) => e.kind === \"required\").length === 0\n : true;\n\n const cacheStore = cacheFactory\n ? cacheFactory({ id, file, fileFullpath }, sourceFolder, {\n resolveTypes,\n })\n : undefined;\n\n let cache = cacheStore\n ? await cacheStore.get({ validate: true })\n : undefined;\n\n if (!cache) {\n if (updatedFile === fileFullpath) {\n await refreshSourceFile(fileFullpath);\n }\n\n const {\n typeDeclarations,\n paramsRefinements,\n methods,\n validationDefinitions,\n referencedFiles = [],\n } = await resolveRouteSignature(\n { id, name, fileFullpath, optionalParams },\n {\n withReferencedFiles: true,\n sourceFile: getSourceFile(fileFullpath),\n relpathResolver(path) {\n return join(\n defaults.srcPrefix,\n defaults.apiDir,\n dirname(file),\n path,\n );\n },\n },\n );\n\n const validationTypes = validationDefinitions.flatMap<{\n id: string;\n text: string;\n }>((def) => {\n return def.target === \"response\"\n ? def.variants.flatMap(({ id, body }) => {\n return body ? [{ id, text: body }] : [];\n })\n : [def.schema];\n });\n\n const typesFile = pathResolver(sourceFolder).createPath.libApi(\n dirname(file),\n \"types.ts\",\n );\n\n const params: ApiRoute[\"params\"] = {\n id: [\"ParamsT\", crc(name)].join(\"\"),\n schema: paramsSchema,\n resolvedType: undefined,\n };\n\n const typesFileContent = render(templates.typesFile, {\n params,\n paramsSchema: paramsSchema.map((param, index) => {\n return {\n ...param,\n isRequired: param.kind === \"required\",\n isSplat: param.kind === \"splat\",\n refinement: paramsRefinements?.at(index),\n };\n }),\n typeDeclarations,\n validationTypes,\n });\n\n const resolvedTypes = resolveTypes\n ? literalTypesResolver(typesFileContent, {\n stripComments: true,\n overrides: { [refineTypeName]: refineTypeName },\n withProperties: [\n params.id,\n ...validationTypes.map(({ id }) => id),\n ],\n })\n : undefined;\n\n /**\n * Deploy types.ts file; required by core generators (like fetch).\n * If types resolved, write resolved types;\n * otherwise write original types extracted from API route.\n * */\n await renderToFile(\n typesFile,\n resolvedTypes ? templates.resolvedTypes : typesFileContent,\n { resolvedTypes },\n );\n\n params.resolvedType = resolvedTypes?.find(\n (e) => e.name === params.id,\n );\n\n cache = {\n // placeholder values, if cacheFactory given,\n // they will be replaced by persistCache\n hash: 0,\n referencedFiles: {},\n // real values\n params,\n methods,\n typeDeclarations,\n validationDefinitions: validationDefinitions.map((def) => {\n return {\n ...def,\n ...(def.target === \"response\"\n ? {\n variants: def.variants.map((variant) => {\n return {\n ...variant,\n resolvedType: resolvedTypes?.find(\n (e) => e.name === variant.id,\n ),\n };\n }),\n }\n : {\n schema: {\n ...def.schema,\n resolvedType: resolvedTypes?.find(\n (e) => e.name === def.schema.id,\n ),\n },\n }),\n };\n }),\n };\n\n if (cacheStore) {\n const { referencedFiles: _void, ...rest } = cache;\n cache = await cacheStore.set({ ...rest, referencedFiles });\n }\n }\n\n const validationDefinitions = cache.validationDefinitions.flatMap(\n (def) => {\n let augmentedDef: ValidationDefinition | undefined = def;\n\n if (def.target === \"response\") {\n augmentedDef = {\n ...def,\n variants: def.variants.flatMap((variant, i) => {\n if (typeof variant.contentType !== \"string\") {\n return [variant];\n }\n\n if (variant.contentType.includes(\"/\")) {\n return [variant];\n }\n\n const contentType = lookup(variant.contentType);\n\n if (!contentType) {\n console.warn(\n styleText(\n [\"bold\", \"red\"],\n \"✗ Failed resolving Response Content Type\",\n ),\n );\n console.warn(\n ` Invalid value provided for mime-types lookup - ${variant.contentType}`,\n );\n console.warn(\n styleText(\n [\"cyan\"],\n ` Response variant #${i} excluded from route schemas`,\n ),\n );\n console.warn(` Route: ${name}; Method: ${def.method}`);\n console.warn();\n return [];\n }\n\n return [{ ...variant, contentType }];\n }),\n };\n } else if (def.contentType && !def.contentType.includes(\"/\")) {\n const contentType = lookup(def.contentType);\n if (!contentType) {\n console.warn(\n styleText(\n [\"bold\", \"red\"],\n \"✗ Failed resolving Response Content Type\",\n ),\n );\n console.warn(\n ` Invalid value provided for mime-types lookup - ${def.contentType}`,\n );\n console.warn(` Route: ${name}; Method: ${def.method}`);\n console.warn();\n } else {\n augmentedDef = { ...def, contentType };\n }\n }\n\n return augmentedDef ? [augmentedDef] : [];\n },\n );\n\n const entry: ApiRoute = {\n id,\n name,\n pathTokens,\n pathPattern,\n honoPattern,\n h3Pattern,\n params: cache.params,\n optionalParams,\n folder,\n file,\n fileFullpath,\n methods: cache.methods,\n typeDeclarations: cache.typeDeclarations,\n validationDefinitions,\n referencedFiles: Object.keys(cache.referencedFiles).map(\n // expand referenced files path,\n // they are stored as relative in cache\n (e) => resolve(sourceFolder.root, e),\n ),\n };\n\n return {\n kind: \"apiRoute\",\n entry,\n };\n };\n\n return { name, handler };\n },\n };\n};\n","import { basename, posix } from \"node:path\";\n\nimport type { NestedRouteEntry, RouteEntry } from \"@kosmojs/core\";\n\nimport { PAGE_INDEX_BASENAME, PAGE_LAYOUT_BASENAME, sortRoutes } from \"./base\";\n\nexport const nestedRoutesFactory = (routeEntries: Array<RouteEntry>) => {\n const entryStack = structuredClone(routeEntries).sort(sortRoutes);\n\n /**\n * Group entries by name (at the same level, both layout and index share same name).\n *\n * Handle 3 cases:\n * - both index and layout exists\n * - only index exists\n * - only layout exists\n *\n * */\n const transformEntries = (\n entries: Array<RouteEntry>,\n parent?: RouteEntry,\n ): Array<NestedRouteEntry> => {\n return [...new Set(entries.map((e) => e.name))].flatMap((name) => {\n const nameEntries = entryStack.flatMap(({ fileFullpath, ...entry }) => {\n return entry.name === name ? [entry] : [];\n });\n\n const index = nameEntries.find((e) =>\n basename(e.file).startsWith(PAGE_INDEX_BASENAME),\n ) as RouteEntry;\n\n const layout = nameEntries.find((e) =>\n basename(e.file).startsWith(PAGE_LAYOUT_BASENAME),\n ) as RouteEntry;\n\n if (index || layout) {\n return [\n {\n index: index\n ? {\n ...index,\n pathTokens: index.pathTokens.slice(\n parent?.pathTokens.length || 0,\n ),\n }\n : undefined,\n layout: layout\n ? {\n ...layout,\n pathTokens: layout.pathTokens.slice(\n parent?.pathTokens.length || 0,\n ),\n }\n : undefined,\n parent: parent?.name,\n children: transformEntries(\n findDescendantEntries(index || layout),\n index || layout,\n ),\n },\n ];\n }\n\n return [];\n });\n };\n\n /**\n * Recursively finds direct descendant routes.\n *\n * \"Direct\" means the next existing route in the path hierarchy,\n * skipping intermediate path segments that don't have index/layout files.\n *\n * Example: blog/post/[slug]/index.tsx is a direct child of blog/index.tsx\n * even though \"post\" segment exists (it has no index.tsx).\n * */\n const findDescendantEntries = ({\n name,\n pathTokens,\n }: RouteEntry): Array<RouteEntry> => {\n // Find all potential children - BOTH indexes AND layouts\n const potentialChildren = entryStack.filter((entry) => {\n // Must be deeper than current entry\n if (entry.pathTokens.length <= pathTokens.length) {\n return false;\n }\n // Must be a descendant path\n if (!entry.name.startsWith(posix.join(name, \"/\"))) {\n return false;\n }\n return true;\n });\n\n // Filter to direct children (no intermediate route between parent and child)\n return potentialChildren.filter((child) => {\n // Check if any route exists between parent and child\n const hasIntermediateRoute = potentialChildren.some((intermediate) => {\n if (intermediate === child) {\n return false;\n }\n // Intermediate must be between parent and child in depth\n if (intermediate.pathTokens.length <= pathTokens.length) {\n return false;\n }\n if (intermediate.pathTokens.length >= child.pathTokens.length) {\n return false;\n }\n // Child must be descendant of intermediate\n return child.name.startsWith(posix.join(intermediate.name, \"/\"));\n });\n\n return !hasIntermediateRoute;\n });\n };\n\n // Find root entries - entries that have no parent route\n const rootEntries = entryStack.filter((entry) => {\n // Check if any other entry could be its parent\n const hasParent = entryStack.some((potential) => {\n if (potential === entry) {\n return false;\n }\n if (potential.pathTokens.length >= entry.pathTokens.length) {\n return false;\n }\n return entry.name.startsWith(posix.join(potential.name, \"/\"));\n });\n\n return !hasParent;\n });\n\n return transformEntries(rootEntries);\n};\n","import {\n defaults,\n type RouteEntry,\n type RouteResolverCacheFactory,\n type SourceFolder,\n} from \"@kosmojs/core\";\n\nimport {\n createRouteEntry,\n isApiRoute,\n isApiUse,\n isPageLayout,\n isPageRoute,\n type ResolverSignature,\n scanRoutes,\n} from \"./base\";\nimport { resolverFactory } from \"./resolve\";\n\nexport * from \"./base\";\nexport * from \"./nesting\";\nexport * from \"./paths\";\n\nexport const routesFactory = async (\n sourceFolder: SourceFolder,\n cacheFactory?: RouteResolverCacheFactory,\n) => {\n const {\n apiRouteResolver,\n apiUseResolver,\n pageRouteResolver,\n pageLayoutResolver,\n } = resolverFactory(sourceFolder, cacheFactory);\n\n const resolversFactory = (routeFiles: Array<string>) => {\n const resolvers = new Map<\n string, // fileFullpath\n ResolverSignature\n >();\n\n const entries: Array<RouteEntry> = routeFiles.flatMap((file) => {\n const entry = createRouteEntry(file, sourceFolder);\n return entry ? [entry] : [];\n });\n\n for (const entry of entries) {\n if (entry.folder === defaults.apiDir) {\n if (isApiRoute(entry.file)) {\n resolvers.set(entry.fileFullpath, apiRouteResolver(entry));\n } else if (isApiUse(entry.file)) {\n resolvers.set(entry.fileFullpath, apiUseResolver(entry));\n }\n } else if (entry.folder === defaults.pagesDir) {\n if (isPageRoute(entry.file)) {\n resolvers.set(entry.fileFullpath, pageRouteResolver(entry));\n } else if (isPageLayout(entry.file)) {\n resolvers.set(entry.fileFullpath, pageLayoutResolver(entry));\n }\n }\n }\n\n return resolvers;\n };\n\n const routeFiles = await scanRoutes(sourceFolder);\n\n return {\n resolvers: resolversFactory(routeFiles),\n resolversFactory,\n };\n};\n","import { Spinner } from \"@topcli/spinner\";\n\nexport type SpinnerFactory = {\n text: (text: string) => void;\n append: (text: string) => void;\n succeed: (text?: string) => void;\n failed: (text?: string) => void;\n};\n\nexport const spinnerFactory = (startText: string): SpinnerFactory => {\n if (!process.stdout.isTTY || process.env.CI || process.env.TERM === \"dumb\") {\n // stub for non-TTY / CI runners\n return {\n text() {},\n append() {},\n succeed() {},\n failed() {},\n };\n }\n\n const spinner = new Spinner().start(startText);\n\n let _text = startText;\n\n return {\n text(text) {\n _text = text;\n spinner.text = text;\n },\n append(text) {\n spinner.text = `${_text} › ${text}`;\n },\n succeed(text) {\n if (text) {\n this.append(text);\n } else {\n this.text(_text);\n }\n spinner.succeed();\n },\n failed(text) {\n if (text) {\n this.text([_text, text].join(\"\\n\"));\n }\n spinner.failed();\n },\n };\n};\n","import { defaults } from \"@kosmojs/core\";\n\nexport const generateTsconfig = (\n {\n dependencies,\n devDependencies,\n }: Record<\"dependencies\" | \"devDependencies\", Record<string, string>>,\n sourceFolder?: string,\n) => {\n // biome-ignore lint: noTemplateCurlyInString\n const rootDir = \"${configDir}\";\n\n const deps = Object.keys({ ...dependencies, ...devDependencies });\n\n const compilerOptions = {\n types: [\n \"vite/client\",\n ...[\"node\", \"deno\", \"bun\"].flatMap((e) => {\n return deps.includes(`@types/${e}`) ? [`@types/${e}`] : [];\n }),\n ],\n moduleResolution: \"bundler\",\n module: \"ESNext\",\n target: \"ESNext\",\n strict: true,\n exactOptionalPropertyTypes: true,\n noImplicitAny: true,\n noImplicitThis: true,\n noImplicitOverride: true,\n noImplicitReturns: true,\n noUnusedLocals: false,\n noUnusedParameters: false,\n allowArbitraryExtensions: true,\n allowImportingTsExtensions: true,\n allowUnreachableCode: false,\n allowUnusedLabels: false,\n useUnknownInCatchVariables: true,\n noFallthroughCasesInSwitch: true,\n noUncheckedSideEffectImports: true,\n resolveJsonModule: true,\n esModuleInterop: true,\n verbatimModuleSyntax: true,\n skipLibCheck: true,\n noEmit: true,\n };\n\n if (sourceFolder) {\n return {\n include: [\n `${rootDir}/`,\n `${rootDir}/../../${defaults.libDir}/${sourceFolder}/`,\n `${rootDir}/../../${defaults.libDir}/*.d.ts`,\n ],\n compilerOptions: {\n ...compilerOptions,\n types: [...compilerOptions.types],\n paths: {\n [`${defaults.appPrefix}/*`]: [`${rootDir}/../../*`],\n [`${defaults.srcPrefix}/*`]: [`${rootDir}/*`],\n [`${defaults.libPrefix}/*`]: [\n `${rootDir}/../../${defaults.libDir}/${sourceFolder}/*`,\n ],\n },\n },\n };\n }\n\n return {\n exclude: [`${rootDir}/${defaults.srcDir}/`],\n compilerOptions: {\n ...compilerOptions,\n paths: {\n [`${defaults.appPrefix}/*`]: [`${rootDir}/*`],\n },\n },\n };\n};\n","import { stat } from \"node:fs/promises\";\nimport { builtinModules } from \"node:module\";\nimport { isAbsolute, join, parse } from \"node:path\";\n\nimport type { Plugin } from \"vite\";\n\nimport {\n defaults,\n type ProjectSettings,\n type SourceFolder,\n} from \"@kosmojs/core\";\n\nimport { pathResolver } from \"./paths\";\n\n/**\n * Resolves Kosmo's generated import prefixes to absolute file paths.\n *\n * WHY THIS EXISTS\n * ---------------\n * Every source folder is scaffolded with three tsconfig `paths` prefixes\n * that let generated and user code import across\n * the folder's layout without long relative chains:\n *\n * appPrefix \"@\" -> the project root (<root>/*)\n * srcPrefix \"~\" -> the folder's src dir (<root>/src/<name>/*)\n * libPrefix \"_\" -> the folder's lib dir (<root>/lib/<name>/*)\n *\n * These are the backbone of the generated code: `defineRoute` and friends are\n * emitted with `_/...` imports, pages import layouts and components via `~/...`,\n * and `@/...` reaches shared app-level modules. If a bundler cannot resolve\n * them, nothing the framework generates can be loaded.\n *\n * Historically Vite resolved these through its built-in `resolve.tsconfigPaths: true`,\n * reading the `paths` straight from the generated tsconfig. That option\n * regressed in Vite 8.1.0 (still broken as of 8.1.3): it stops resolving\n * `paths` mappings, especially those defined in an extended / referenced base\n * config - which is exactly Kosmo's structure, where a source folder's\n * tsconfig `extends` `lib/<name>/tsconfig.json` and the paths use the\n * TypeScript `${configDir}` variable. The failure surfaces as:\n *\n * [vite] Failed to resolve import \"_/pageSamples/welcome.vue\" from\n * \"src/<name>/pages/index/index.vue\". Does the file exist?\n *\n * (Upstream: vitejs/vite #22139, #22047, #22371, #21889, #21856.)\n *\n * Rather than pin Vite to 8.0.x indefinitely, or depend on the general-purpose\n * `vite-tsconfig-paths` plugin, this internal plugin resolves ONLY\n * known prefixes against dirs derived from the source folder. That makes it:\n *\n * - Correct on 8.1.x, where native `tsconfigPaths` is broken.\n * - Faster: no tsconfig discovery, no `extends` chain walking, no glob\n * matching - just a prefix check and a handful of `stat` probes,\n * cached by Vite per specifier.\n * - Non-blocking: probes via async `fs/promises` `stat`, so `resolveId` never\n * stalls the event loop.\n * - `.vue` / `.mdx`-aware: `resolveId` sees every specifier regardless of the\n * importer's type, so imports from non-JS files resolve without the\n * `loose` / `allowJs` escape hatches `vite-tsconfig-paths` needs.\n *\n * A project with custom `paths` beyond these three prefixes should install\n * `vite-tsconfig-paths`; this plugin is internal and intentionally narrow.\n *\n * The prefix -> dir bases come from `pathResolver`, the same source of truth the\n * tsconfig generator uses, so alias resolution here can never drift from the\n * paths that were written into the generated tsconfig.\n * */\nexport const tsconfigPaths = (sourceFolder: SourceFolder): Plugin => {\n /**\n * Candidate extensions for an extensionless specifier, in resolution priority order.\n * Mirrors the renderable file types the generators emit;\n * a new page type (e.g. `.svelte`) must be added here or its aliased imports won't resolve.\n * */\n const EXTENSIONS = [\n \".ts\",\n \".tsx\",\n \".js\",\n \".jsx\",\n \".mjs\",\n \".vue\",\n \".svelte\",\n \".md\",\n \".mdx\",\n \".json\",\n ];\n\n const { createPath } = pathResolver(sourceFolder);\n\n const table: Array<[prefix: string, baseDir: string]> = [\n [`${defaults.srcPrefix}/`, createPath.src()],\n [`${defaults.libPrefix}/`, createPath.lib()],\n [`${defaults.appPrefix}/`, sourceFolder.root],\n ];\n\n const resolveWithin = async (\n baseDir: string,\n rest: string,\n ): Promise<string> => {\n const target = join(baseDir, rest);\n const { ext } = parse(rest);\n\n // Specifier already carries a known extension: the target IS the candidate\n // (an explicit `foo.js` must not be probed as `foo.js.js`). Only fall back\n // to its `/index.<ext>` for a directory import that happens to end in a\n // known extension (rare, but keeps behaviour total).\n if (EXTENSIONS.includes(ext)) {\n for (const candidate of [target, `${target}/index${ext}`]) {\n if (await isFile(candidate)) {\n return candidate;\n }\n }\n return target;\n }\n\n // No known extension: probe each, plus its index form.\n for (const e of EXTENSIONS) {\n for (const candidate of [`${target}${e}`, `${target}/index${e}`]) {\n if (await isFile(candidate)) {\n return candidate;\n }\n }\n }\n\n return target;\n };\n\n return {\n name: \"kosmo:tsconfigPaths\",\n enforce: \"pre\",\n async resolveId(source) {\n if (isAbsolute(source) || source.startsWith(\".\")) {\n return;\n }\n for (const [prefix, baseDir] of table) {\n if (source.startsWith(prefix)) {\n return resolveWithin(baseDir, source.replace(prefix, \"\"));\n }\n }\n return;\n },\n };\n};\n\nconst nodePrefix = (): Plugin => {\n return {\n name: \"kosmojs:node-prefix\",\n enforce: \"pre\",\n resolveId(source) {\n return builtinModules.includes(source)\n ? { id: `node:${source}`, external: true }\n : undefined;\n },\n };\n};\n\n/**\n * Resolves the CSR/SSR variant of env-sensitive modules.\n *\n * WHY THIS EXISTS\n * ---------------\n * A handful of generated modules must differ between the client graph and the SSR bundle -\n * the fetch transport (a no-op in the browser, an in-process dispatch on the server)\n * and the TanStack Query client (a singleton in the browser, per-request on the server).\n *\n * Every build installs this plugin; but only the SSR bundle installs it with `kind: \"ssr\"`.\n * Nothing is written, so concurrent processes cannot disturb each other.\n *\n * Generators declare their modules via `factory.virtualModules()`.\n * */\nexport const virtualModules = (\n sourceFolder: SourceFolder,\n {\n kind,\n command,\n }: { kind: \"csr\" | \"ssr\"; command: ProjectSettings[\"command\"] },\n): Plugin => {\n /**\n * Rollup's / Rolldown's convention for ids owned by a plugin:\n * the NUL prefix keeps other plugins and Node resolution from touching them.\n * */\n const VIRTUAL_PREFIX = \"\\0\";\n\n const modules = sourceFolder.generators.flatMap(({ factory }) => {\n return factory(sourceFolder).virtualModules?.() || [];\n });\n\n const virtualSources = new Map<string, { csr: string; ssr: string }>();\n\n for (const { specifier, csr, ssr } of modules) {\n virtualSources.set(specifier, { csr, ssr });\n }\n\n // Built-in build context, importable from any graph.\n // Given modules should not override it.\n {\n const source = `export const command = \"${command}\";`;\n virtualSources.set(\"virtual:kosmo/env\", { csr: source, ssr: source });\n }\n\n return {\n name: \"kosmo:virtualModules\",\n enforce: \"pre\",\n\n resolveId(source) {\n return virtualSources.has(source) ? VIRTUAL_PREFIX + source : undefined;\n },\n\n load(id) {\n return id.startsWith(VIRTUAL_PREFIX)\n ? virtualSources.get(id.slice(VIRTUAL_PREFIX.length))?.[kind]\n : undefined;\n },\n };\n};\n\nexport const vitePlugins = {\n tsconfigPaths,\n nodePrefix,\n virtualModules,\n};\n\nconst isFile = async (path: string) => {\n return stat(path)\n .then((e) => e.isFile())\n .catch(() => false);\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["templates.resolvedTypes","parse","templates.typesFile","templates.resolvedTypes"],"sources":["../src/generic.ts","../src/paths.ts","../src/render.ts","../src/ast.ts","../src/format.ts","../src/generators.ts","../src/ports.ts","../src/routes/paths.ts","../src/routes/base.ts","../src/routes/resolve.ts","../src/routes/nesting.ts","../src/routes/index.ts","../src/spinner.ts","../src/tsconfig.ts","../src/vite.ts","../src/index.ts"],"sourcesContent":["import { posix } from \"node:path\";\n\nimport { mergeConfig, type UserConfig } from \"vite\";\n\nimport {\n DEFAULT_HOST,\n DEFAULT_PORT,\n DEFAULT_PREVIEW_HOST,\n DEFAULT_PREVIEW_PORT,\n defaults,\n type KosmoSettings,\n} from \"@kosmojs/core\";\n\nexport const mergeConfigs = (\n ...configs: Array<UserConfig | undefined>\n): UserConfig => {\n return [{ configFile: false }, ...configs].reduce<UserConfig>(\n (config, prev) => mergeConfig(config || {}, prev || {}),\n {},\n );\n};\n\nexport const escapeTemplateLiterals = (origin: string) => {\n return [\n // Escape backticks for safe use in template literals\n [/(?<!\\\\)`/g, \"\\\\`\"],\n // Escape $ for safe use in template literals\n [/(?<!\\\\)\\$\\{/g, \"\\\\${\"],\n ].reduce((text, [a, b]) => text.replace(a, b as never), origin);\n};\n\nexport const containsPathTraversalPatterns = (str: string): boolean => {\n return [\n // path traversal patterns\n /\\.\\.\\//,\n /\\/\\.\\//,\n ].some((e) => e.test(str));\n};\n\nexport const configFilePattern = (folder: string) => {\n return posix.join(defaults.srcDir, folder, \"kosmo.config.ts\");\n};\n\nexport const resolveHostAddress = (\n settings: KosmoSettings | undefined,\n key: \"devHost\" | \"previewHost\",\n) => {\n let [host, port] =\n key === \"devHost\"\n ? [DEFAULT_HOST, DEFAULT_PORT]\n : [DEFAULT_PREVIEW_HOST, DEFAULT_PREVIEW_PORT];\n if (settings?.[key]) {\n const url = new URL(`http://${settings[key]}`);\n if (url.hostname) {\n host = url.hostname;\n }\n if (url.port) {\n port = Number(url.port);\n }\n }\n return [host, port].join(\":\");\n};\n","import { access, constants } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\n\nimport {\n DEFAULT_DIST,\n defaults,\n type ProjectSettings,\n type SourceFolder,\n} from \"@kosmojs/core\";\n\ntype Options = { origin: \"src\" | \"lib\" };\n\ntype CreateImport = Record<\n \"src\" | \"api\" | \"entry\" | \"pages\" | \"lib\" | \"libCore\" | \"libApi\" | \"libEntry\",\n (a: Array<string>, o: Options) => string\n>;\n\nexport const pathResolver = (\n { root, distDir = DEFAULT_DIST }: ProjectSettings,\n { name }: SourceFolder,\n): {\n createPath: Record<\n | \"src\"\n | \"api\"\n | \"pages\"\n | \"entry\"\n | \"lib\"\n | \"libCore\"\n | \"libApi\"\n | \"libEntry\"\n | \"libPages\"\n | \"distDir\",\n (...a: Array<string>) => string\n >;\n createImport: CreateImport;\n createImportHelpers: (o: Options) => {\n createImport: (k: keyof CreateImport, ...a: Array<string>) => string;\n };\n} => {\n const createPath = (...a: Array<string>) => {\n return root ? resolve(root, join(...a)) : join(...a);\n };\n\n const createImport: CreateImport = {\n src(a, { origin }) {\n return origin === \"src\"\n ? join(defaults.srcPrefix, ...a)\n : join(defaults.appPrefix, defaults.srcDir, name, ...a);\n },\n api(a, o) {\n return this.src([defaults.apiDir, ...a], o);\n },\n entry(a, o) {\n return this.src([defaults.entryDir, ...a], o);\n },\n pages(a, o) {\n return this.src([defaults.pagesDir, ...a], o);\n },\n lib(a, { origin }) {\n return origin === \"src\"\n ? join(defaults.libPrefix, ...a)\n : join(defaults.appPrefix, defaults.libDir, name, ...a);\n },\n libCore(a, o) {\n return this.lib([\"core\", ...a], o);\n },\n libApi(a, o) {\n return this.lib([defaults.apiDir, ...a], o);\n },\n libEntry(a, o) {\n return this.lib([defaults.entryDir, ...a], o);\n },\n };\n\n return {\n createPath: {\n src(...a) {\n return createPath(defaults.srcDir, name, ...a);\n },\n api(...a) {\n return this.src(defaults.apiDir, ...a);\n },\n pages(...a) {\n return this.src(defaults.pagesDir, ...a);\n },\n entry(...a) {\n return this.src(defaults.entryDir, ...a);\n },\n lib(...a) {\n return createPath(defaults.libDir, name, ...a);\n },\n libCore(...a) {\n return this.lib(\"core\", ...a);\n },\n libApi(...a) {\n return this.lib(defaults.apiDir, ...a);\n },\n libEntry(...a) {\n return this.lib(defaults.entryDir, ...a);\n },\n libPages(...a) {\n return this.lib(defaults.pagesDir, ...a);\n },\n distDir(...a) {\n return createPath(distDir, name, ...a);\n },\n },\n createImport,\n createImportHelpers(o) {\n if (![\"src\", \"lib\"].includes(o?.origin)) {\n throw new Error(\n `createImportHelpers: required exactly one argument of shape { origin: \"src|lib\" }`,\n );\n }\n return {\n createImport(key, ...a) {\n // Handlebars appends an options object as the last argument,\n // slice it off before passing args to createImport\n return createImport[key](a.slice(0, -1), o);\n },\n };\n },\n };\n};\n\nexport const pathExists = async (path: string): Promise<boolean> => {\n return access(path, constants.F_OK).then(\n () => true,\n () => false,\n );\n};\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\n\nimport crc from \"crc/crc32\";\nimport handlebars from \"handlebars\";\n\nimport { pathExists } from \"./paths\";\n\nexport type RenderOptions = {\n noEscape?: boolean;\n // handlebars instance\n renderer?: typeof handlebars;\n};\n\nexport type FactoryOptions = RenderOptions & {\n partials?: Record<string, string>;\n helpers?: Record<string, (...a: Array<never>) => unknown>;\n outdir?: string;\n /**\n * Controls whether to overwrite an existing file.\n * - `false`: skip writing if the file already exists\n * - `true` (default): always overwrite\n * - function: custom logic to decide whether to overwrite, based on current file content\n * */\n overwrite?: boolean | ((fileContent: string) => boolean);\n};\n\nexport const render = <Context = object>(\n template: string,\n context: Context,\n options?: RenderOptions,\n): string => {\n const { noEscape = true, renderer = handlebars } = { ...options };\n return renderer.compile(template, { noEscape })(context);\n};\n\nexport const renderToFile = async <Context = object>(\n file: string,\n template: string,\n context: Context,\n options?: RenderOptions &\n Pick<FactoryOptions, \"overwrite\"> & {\n render?: typeof render;\n },\n): Promise<void> => {\n const content = options?.render\n ? options.render(template, context, options)\n : render(template, context, options);\n\n /**\n * Two fs calls (exists + read) are worth it to avoid touching the file\n * and triggering watchers unnecessarily.\n * */\n if (await pathExists(file)) {\n const { overwrite = true } = { ...options };\n if (overwrite === false) {\n return;\n }\n const fileContent = await readFile(file, \"utf8\");\n if (typeof overwrite === \"function\" && !overwrite(fileContent)) {\n return;\n }\n if (crc(content) === crc(fileContent)) {\n return;\n }\n }\n\n await mkdir(dirname(file), { recursive: true });\n await writeFile(file, content, \"utf8\");\n};\n\nexport const renderFactory = (options?: FactoryOptions) => {\n const createRenderer = (selfOoptions?: FactoryOptions) => {\n const renderer = handlebars.create();\n\n renderer.registerPartial({\n ...options?.partials,\n ...selfOoptions?.partials,\n } as never);\n\n renderer.registerHelper({\n ...options?.helpers,\n ...selfOoptions?.helpers,\n } as never);\n\n return renderer;\n };\n\n return {\n render<Context = object>(\n template: string,\n context: Context,\n selfOoptions?: FactoryOptions,\n ) {\n return render(template, context, {\n ...options,\n ...selfOoptions,\n renderer: createRenderer(selfOoptions),\n });\n },\n async renderToFile<Context = object>(\n file: string,\n template: string,\n context: Context,\n selfOoptions?: FactoryOptions,\n ) {\n return renderToFile(\n options?.outdir ? join(options.outdir, file) : file,\n template,\n context,\n {\n ...options,\n ...selfOoptions,\n renderer: createRenderer(selfOoptions),\n },\n );\n },\n };\n};\n","import { styleText } from \"node:util\";\n\nimport crc from \"crc/crc32\";\nimport flattener, { type ResolvedType } from \"tfusion\";\nimport {\n type CallExpression,\n type Identifier,\n ModuleResolutionKind,\n Project,\n type ProjectOptions,\n type PropertySignature,\n type SourceFile,\n SyntaxKind,\n type TypeNode,\n} from \"ts-morph\";\n\nimport type { ProjectSettings, ResolvedTypeSignature } from \"@kosmojs/core\";\nimport {\n type ApiRoute,\n defaults,\n RequestValidationTargets,\n type SourceFolder,\n type TypeDeclaration,\n type ValidationDefinition,\n type ValidationTarget,\n} from \"@kosmojs/core\";\nimport { type HTTPMethod, HTTPMethods } from \"@kosmojs/core/api\";\n\nimport { escapeTemplateLiterals } from \"./generic\";\nimport { pathResolver } from \"./paths\";\nimport { render } from \"./render\";\nimport * as templates from \"./templates\";\n\ntype PathResolver = (path: string) => string;\n\nexport const astFactory = () => {\n const createProject = (opts?: ProjectOptions) => new Project(opts);\n\n const resolveRouteSignature = async (\n route: Pick<ApiRoute, \"id\" | \"name\" | \"fileFullpath\" | \"optionalParams\">,\n opts?: {\n relpathResolver?: PathResolver;\n sourceFile?: SourceFile;\n withReferencedFiles?: boolean;\n },\n ) => {\n const {\n sourceFile = createProject().addSourceFileAtPath(route.fileFullpath),\n } = { ...opts };\n\n const [typeDeclarations, referencedFiles] = extractTypeDeclarations(\n sourceFile,\n opts,\n );\n\n const defaultExport = extractDefaultExport(sourceFile);\n\n const paramsRefinements = defaultExport\n ? extractParamsRefinements(defaultExport)\n : undefined;\n\n const methods = defaultExport\n ? extractRouteMethods(route, defaultExport)\n : [];\n\n return {\n typeDeclarations,\n paramsRefinements,\n methods: methods.map((e) => e.method),\n validationDefinitions: methods.flatMap((e) => e.validationDefinitions),\n referencedFiles,\n };\n };\n\n const extractDefaultExport = (\n sourceFile: SourceFile,\n ): CallExpression | undefined => {\n const [defaultExport] = sourceFile\n .getExportAssignments()\n .flatMap((exportAssignment) => {\n if (exportAssignment.isExportEquals()) {\n return [];\n }\n const callExpression = exportAssignment.getExpression();\n return callExpression.isKind(SyntaxKind.CallExpression)\n ? [callExpression]\n : [];\n });\n return defaultExport;\n };\n\n const extractParamsRefinements = (\n callExpression: CallExpression,\n ): Array<{ index: number; text: string }> | undefined => {\n const [\n _routeName, // first generic - the route name\n paramsGeneric, // second generic - params refinements\n ] = extractGenerics(callExpression);\n\n if (!paramsGeneric?.isKind(SyntaxKind.TupleType)) {\n return;\n }\n\n return paramsGeneric.getElements().map((node, index) => {\n return {\n index,\n text: node.getText(),\n };\n });\n };\n\n const extractRouteMethods = (\n route: Pick<ApiRoute, \"id\" | \"name\">,\n callExpression: CallExpression,\n ): Array<{\n method: HTTPMethod;\n validationDefinitions: Array<ValidationDefinition>;\n }> => {\n const funcDeclaration =\n callExpression.getFirstChildByKind(SyntaxKind.ArrowFunction) ||\n callExpression.getFirstChildByKind(SyntaxKind.FunctionExpression);\n\n if (!funcDeclaration) {\n return [];\n }\n\n const arrayLiteralExpression = funcDeclaration.getFirstChildByKind(\n SyntaxKind.ArrayLiteralExpression,\n );\n\n if (!arrayLiteralExpression) {\n return [];\n }\n\n const callExpressions: Array<[CallExpression, HTTPMethod]> = [];\n\n for (const e of arrayLiteralExpression.getChildrenOfKind(\n SyntaxKind.CallExpression,\n )) {\n const name = e.getExpression().getText() as HTTPMethod;\n if (HTTPMethods[name]) {\n callExpressions.push([e, name]);\n }\n }\n\n const methods: ReturnType<typeof extractRouteMethods> = [];\n\n for (const [callExpression, method] of callExpressions) {\n const [vDefs, vOpts] = extractGenerics(callExpression);\n methods.push({\n method,\n validationDefinitions: extractValidationDefinitions(\n route,\n method,\n vDefs,\n vOpts,\n ),\n });\n }\n\n return methods;\n };\n\n /** Parse a boolean literal type node */\n const parseRuntimeValidation = (typeNode: TypeNode) => {\n if (typeNode.isKind(SyntaxKind.LiteralType)) {\n const literal = typeNode.getFirstChild();\n if (literal?.isKind(SyntaxKind.TrueKeyword)) {\n return true;\n } else if (literal?.isKind(SyntaxKind.FalseKeyword)) {\n return false;\n }\n }\n return undefined;\n };\n\n const extractResponseVariant = (\n typeNode: TypeNode,\n ):\n | {\n status: number;\n contentType?: string | undefined;\n body?: string | undefined;\n }\n | undefined => {\n if (!typeNode.isKind(SyntaxKind.TupleType)) {\n return;\n }\n\n let status = 200; // default\n let contentType: string | undefined;\n let body: string | undefined;\n\n const [statusNode, contentTypeNode, bodyNode] = typeNode.getElements();\n\n // Status (index 0) - should be a LiteralType with NumericLiteral\n if (statusNode?.isKind(SyntaxKind.LiteralType)) {\n const literal = statusNode.getFirstChildByKind(SyntaxKind.NumericLiteral);\n if (literal) {\n status = Number(literal.getText());\n }\n }\n\n // ContentType (index 1) - should be a LiteralType with StringLiteral\n if (contentTypeNode) {\n contentType = extractStringLiteral(contentTypeNode);\n }\n\n // Response type text (index 2)\n if (bodyNode) {\n body = bodyNode.getText();\n if ([\"object\"].includes(body)) {\n body = \"{}\";\n }\n }\n\n return { status, contentType, body };\n };\n\n /** Parse opts TypeLiteral into a map keyed by target */\n const parseValidationOptions = (typeNode: TypeNode | undefined) => {\n const opts: Partial<\n Record<\n ValidationTarget,\n {\n contentType: string | undefined;\n runtimeValidation: boolean | undefined;\n customErrors: Record<string, string> | undefined;\n }\n >\n > = {};\n\n if (!typeNode?.isKind(SyntaxKind.TypeLiteral)) {\n return opts;\n }\n\n for (const prop of typeNode.getMembers()) {\n if (!prop.isKind(SyntaxKind.PropertySignature)) {\n continue;\n }\n\n const target = prop.getName() as ValidationTarget;\n const typeNode = prop.getTypeNodeOrThrow();\n\n if (!typeNode.isKind(SyntaxKind.TypeLiteral)) {\n continue;\n }\n\n let contentType: string | undefined;\n let runtimeValidation: boolean | undefined;\n const customErrors: Record<string, string> = {};\n\n for (const member of typeNode.getMembers()) {\n if (!member.isKind(SyntaxKind.PropertySignature)) {\n continue;\n }\n\n const name = propertyName(member);\n const node = member.getTypeNodeOrThrow();\n\n if (name === \"contentType\") {\n contentType = extractStringLiteral(node);\n } else if (name === \"runtimeValidation\") {\n runtimeValidation = parseRuntimeValidation(node);\n } else if (name.startsWith(\"error\")) {\n const literal = extractStringLiteral(node);\n if (literal) {\n customErrors[name] = literal;\n }\n }\n }\n\n opts[target] = {\n contentType,\n runtimeValidation,\n customErrors,\n };\n }\n\n return opts;\n };\n\n const extractStringLiteral = (typeNode: TypeNode) => {\n const literal = typeNode.isKind(SyntaxKind.LiteralType)\n ? typeNode.getFirstChildByKind(SyntaxKind.StringLiteral)\n : undefined;\n return literal ? literal.getLiteralText() : undefined;\n };\n\n /**\n * Extract validation definitions from route handler generics.\n * Merges defs (schemas) and opts (validation options) into a flat array.\n * */\n const extractValidationDefinitions = (\n route: Pick<ApiRoute, \"id\" | \"name\">,\n method: HTTPMethod,\n defsNode: TypeNode,\n optsNode: TypeNode | undefined,\n ) => {\n const definitions: Array<ValidationDefinition> = [];\n\n if (!defsNode?.isKind(SyntaxKind.TypeLiteral)) {\n return definitions;\n }\n\n const optsMap = parseValidationOptions(optsNode);\n\n const createId = (target: string, hash?: string) => {\n return [\n target.replace(/^./, (c) => c.toUpperCase()),\n \"T\",\n method,\n crc(route.id + hash),\n ].join(\"\");\n };\n\n for (const prop of defsNode.getMembers()) {\n if (!prop.isKind(SyntaxKind.PropertySignature)) {\n continue;\n }\n\n const target = prop.getName() as ValidationTarget;\n const typeNode = prop.getTypeNodeOrThrow();\n\n if (target === \"response\") {\n const variants = typeNode.isKind(SyntaxKind.UnionType)\n ? typeNode.getChildrenOfKind(SyntaxKind.TupleType)\n : [typeNode];\n\n definitions.push({\n ...optsMap[target],\n method,\n target,\n variants: variants.flatMap((e, i) => {\n const { status, contentType, body } = {\n ...extractResponseVariant(e),\n };\n\n if (!status) {\n return [];\n }\n\n if (contentType && typeof contentType !== \"string\") {\n console.warn(\n styleText(\n [\"bold\", \"red\"],\n `✗ The second element of a response variant should specify the Response Content Type`,\n ),\n );\n console.warn(\n styleText([\"blue\"], ` Example: [200, \"json\", Schema]`),\n );\n console.warn(\n ` Route: ${route.name}; Method: ${method}; Response Variant: #${i}`,\n );\n console.warn();\n }\n\n return [\n {\n id: createId(\n target,\n JSON.stringify([status, contentType, body]),\n ),\n status,\n contentType,\n body,\n },\n ];\n }),\n });\n } else if (Object.keys(RequestValidationTargets).includes(target)) {\n definitions.push({\n ...optsMap[target],\n method,\n target,\n schema: {\n id: createId(target),\n text: typeNode.getText(),\n },\n });\n }\n }\n\n return definitions;\n };\n\n const extractTypeDeclarations = (\n sourceFile: SourceFile,\n opts?: {\n relpathResolver?: PathResolver;\n withReferencedFiles?: boolean;\n },\n ): [d: Array<TypeDeclaration>, f?: Array<string>] => {\n const declarations: Array<TypeDeclaration> = [];\n\n const referencedFiles: Array<string> | undefined = opts?.withReferencedFiles\n ? []\n : undefined;\n\n for (const declaration of sourceFile.getImportDeclarations()) {\n const modulePath = declaration.getModuleSpecifierValue();\n\n const path = /^\\.\\.?\\/?/.test(modulePath)\n ? opts?.relpathResolver\n ? opts.relpathResolver(modulePath)\n : modulePath\n : modulePath;\n\n const typeOnlyDeclaration = declaration.isTypeOnly();\n\n const defaultImport = typeOnlyDeclaration\n ? declaration.getDefaultImport()\n : undefined;\n\n if (defaultImport) {\n const name = defaultImport.getText();\n const text = `import type ${name} from \"${path}\";`;\n declarations.push({\n importDeclaration: {\n name,\n path,\n },\n text,\n });\n if (referencedFiles) {\n referencedFiles.push(...getReferencedFiles(defaultImport));\n }\n }\n\n const namespaceImport = typeOnlyDeclaration\n ? declaration.getNamespaceImport()\n : undefined;\n\n if (namespaceImport) {\n const name = namespaceImport.getText();\n const text = `import type * as ${name} from \"${path}\";`;\n declarations.push({\n importDeclaration: {\n name,\n path,\n },\n text,\n });\n if (referencedFiles) {\n referencedFiles.push(...getReferencedFiles(namespaceImport));\n }\n }\n\n for (const namedImport of declaration.getNamedImports()) {\n if (namedImport.isTypeOnly() || typeOnlyDeclaration) {\n const nameNode = namedImport.getNameNode();\n const name = nameNode.getText();\n const alias = namedImport.getAliasNode()?.getText();\n const nameText = alias ? `${name} as ${alias}` : name;\n\n declarations.push({\n importDeclaration: {\n name,\n alias,\n path,\n },\n text: `import type { ${nameText} } from \"${path}\";`,\n });\n\n if (referencedFiles) {\n if (nameNode.isKind(SyntaxKind.Identifier)) {\n referencedFiles.push(...getReferencedFiles(nameNode));\n }\n }\n }\n }\n }\n\n for (const declaration of sourceFile.getTypeAliases()) {\n const name = declaration.getName();\n const text = declaration.getFullText().trim();\n declarations.push({\n typeAliasDeclaration: { name },\n text,\n });\n }\n\n for (const declaration of sourceFile.getInterfaces()) {\n const name = declaration.getName();\n const text = declaration.getFullText().trim();\n declarations.push({\n interfaceDeclaration: { name },\n text,\n });\n }\n\n for (const declaration of sourceFile.getEnums()) {\n const name = declaration.getName();\n const text = declaration.getFullText().trim();\n declarations.push({\n enumDeclaration: { name },\n text,\n });\n }\n\n for (const declaration of sourceFile.getExportDeclarations()) {\n const typeOnlyDeclaration = declaration.isTypeOnly();\n\n const modulePath = declaration.getModuleSpecifierValue();\n\n const path = modulePath\n ? /^\\.\\.?\\/?/.test(modulePath)\n ? opts?.relpathResolver\n ? opts.relpathResolver(modulePath)\n : modulePath\n : modulePath\n : undefined;\n\n for (const namedExport of declaration.getNamedExports()) {\n if (namedExport.isTypeOnly() || typeOnlyDeclaration) {\n const nameNode = namedExport.getNameNode();\n const name = nameNode.getText();\n const alias = namedExport.getAliasNode()?.getText();\n const nameText = alias ? `${name} as ${alias}` : name;\n\n declarations.push({\n exportDeclaration: {\n name,\n alias: alias ?? name,\n path,\n },\n text: path\n ? `export type { ${nameText} } from \"${path}\";`\n : `export type { ${nameText} };`,\n });\n\n if (referencedFiles) {\n if (nameNode.isKind(SyntaxKind.Identifier)) {\n referencedFiles.push(...getReferencedFiles(nameNode));\n }\n }\n }\n }\n }\n\n return referencedFiles\n ? [declarations, [...new Set<string>(referencedFiles)]]\n : [declarations];\n };\n\n const getReferencedFiles = (importIdentifier: Identifier): Array<string> => {\n // ambient modules may have declarations in multiple files\n const declarations =\n importIdentifier //\n ?.getSymbol()\n ?.getAliasedSymbol()\n ?.getDeclarations() || [];\n\n return declarations.flatMap((e) => {\n const sourceFile = e.getSourceFile();\n return sourceFile //\n ? [sourceFile.getFilePath()]\n : [];\n });\n };\n\n const extractGenerics = (callExpression: CallExpression) => {\n return callExpression.getTypeArguments();\n };\n\n const typeResolverFactory = (\n projectSettings: ProjectSettings,\n sourceFolder: SourceFolder,\n ) => {\n const { createPath } = pathResolver(projectSettings, sourceFolder);\n\n const project = createProject({\n compilerOptions: {\n moduleResolution: ModuleResolutionKind.Bundler,\n types: [],\n noLib: true,\n skipLibCheck: true,\n paths: {\n [`${defaults.appPrefix}/*`]: [`${projectSettings.root}/*`],\n [`${defaults.srcPrefix}/*`]: [createPath.src(\"*\")],\n [`${defaults.libPrefix}/*`]: [createPath.lib(\"*\")],\n },\n },\n });\n\n const withTypeboxSchema = (resolvedTypes: Array<ResolvedType>) => {\n const materializedTypes = render(templates.resolvedTypes, {\n resolvedTypes,\n });\n\n // NOTE: file name should be unique as it will stay during project's life cycle.\n const sourceFile = project.createSourceFile(\n `${crc(materializedTypes)}-${Date.now()}.ts`,\n materializedTypes,\n { overwrite: true },\n );\n\n const types = resolvedTypes.map<ResolvedTypeSignature>((type) => {\n const typeNode = sourceFile.getTypeAlias(type.name)?.getTypeNode();\n\n if (!typeNode) {\n return type;\n }\n\n const properties = [];\n const numericProperties = [];\n const booleanProperties = [];\n\n for (const prop of type.properties || []) {\n const propNode = typeNode.isKind(SyntaxKind.TypeLiteral)\n ? typeNode.getProperty(prop.nameDeclaration)?.getTypeNode()\n : undefined;\n\n if (!propNode) {\n continue;\n }\n\n properties.push({\n ...prop,\n typeboxSchema: renderTypeboxSchema(propNode),\n });\n\n if (isNumericTypeNode(propNode)) {\n numericProperties.push(prop.name);\n }\n\n if (isBooleanTypeNode(propNode)) {\n booleanProperties.push(prop.name);\n }\n }\n\n return {\n ...type,\n properties,\n numericProperties,\n booleanProperties,\n typeboxSchema: renderTypeboxSchema(typeNode),\n };\n });\n\n // NOTE: do not removeSourceFile, that invalidates proejct's cache,\n // triggering cache rebuild on next call.\n\n return types;\n };\n\n const literalTypesResolver = (\n literalTypes: string,\n options: Parameters<typeof flattener>[2],\n ): Array<ResolvedTypeSignature> => {\n // NOTE: file name should be unique as it will stay during project's life cycle.\n const sourceFile = project.createSourceFile(\n `${crc(literalTypes)}-${Date.now()}.ts`,\n literalTypes,\n { overwrite: true },\n );\n\n const resolvedTypes = flattener(project, sourceFile, {\n ...options,\n stripComments: true,\n });\n\n // NOTE: do not removeSourceFile, that invalidates proejct's cache,\n // triggering cache rebuild on next call.\n\n return withTypeboxSchema(resolvedTypes);\n };\n\n return {\n getSourceFile: (fileFullpath: string) => {\n return (\n project.getSourceFile(fileFullpath) ||\n project.addSourceFileAtPath(fileFullpath)\n );\n },\n refreshSourceFile: async (fileFullpath: string) => {\n const sourceFile = project.getSourceFile(fileFullpath);\n if (sourceFile) {\n await sourceFile.refreshFromFileSystem();\n }\n },\n literalTypesResolver,\n };\n };\n\n return {\n createProject,\n extractDefaultExport,\n extractParamsRefinements,\n extractRouteMethods,\n extractTypeDeclarations,\n resolveRouteSignature,\n typeResolverFactory,\n };\n};\n\n/**\n * Property name as declared, stripping quotes for string-literal keys.\n * */\nconst propertyName = (property: PropertySignature): string => {\n const nameNode = property.getNameNode();\n return nameNode.isKind(SyntaxKind.StringLiteral)\n ? nameNode.getLiteralValue()\n : nameNode.getText();\n};\n\n/**\n * Whether type node reduces to `number`.\n *\n * number -> true\n * VRefine<number, {}> -> true (peel to first type argument)\n * Array<number> -> true (peel to first type argument)\n * number[] -> true (peel to element type)\n * readonly number[] -> true (peel the type operator, then array)\n * VRefine<Array<number>, {}> -> true (peels compose)\n * 2, -2 -> true (literal types, sign included)\n * 1 | -2 | 3 -> true (union with every member numeric)\n * number | string -> false (mixed unions are not numeric)\n *\n * Does NOT descend into object properties or nested tuple elements.\n * */\nconst isNumericTypeNode = (\n typeNode: TypeNode,\n refineTypeName = defaults.refineTypeName,\n): boolean => {\n // (T) -> T (peel off parentheses)\n if (typeNode.isKind(SyntaxKind.ParenthesizedType)) {\n return isNumericTypeNode(typeNode.getTypeNode(), refineTypeName);\n }\n\n // VRefine<T, Opts> -> T\n // Array<T> -> T\n if (typeNode.isKind(SyntaxKind.TypeReference)) {\n const name = typeNode.getTypeName().getText();\n return name === refineTypeName || name === \"Array\"\n ? isNumericTypeNode(typeNode.getTypeArguments()[0], refineTypeName)\n : false;\n }\n\n // T[] -> T\n if (typeNode.isKind(SyntaxKind.ArrayType)) {\n return isNumericTypeNode(typeNode.getElementTypeNode(), refineTypeName);\n }\n\n // readonly T[] -> T\n if (typeNode.isKind(SyntaxKind.TypeOperator)) {\n return typeNode.getOperator() === SyntaxKind.ReadonlyKeyword\n ? isNumericTypeNode(typeNode.getTypeNode(), refineTypeName)\n : false;\n }\n\n // 1 | -2 | 3 - numeric when every member is numeric\n if (typeNode.isKind(SyntaxKind.UnionType)) {\n return typeNode\n .getTypeNodes()\n .every((node) => isNumericTypeNode(node, refineTypeName));\n }\n\n // literal 2, -2 (the only prefix allowed in a literal type is the sign)\n if (typeNode.isKind(SyntaxKind.LiteralType)) {\n const literal = typeNode.getLiteral();\n return literal.isKind(SyntaxKind.PrefixUnaryExpression)\n ? literal.getOperand().isKind(SyntaxKind.NumericLiteral)\n : literal.isKind(SyntaxKind.NumericLiteral);\n }\n\n // plain `number` keyword\n return typeNode.isKind(SyntaxKind.NumberKeyword);\n};\n\n/**\n * Whether type node reduces to `boolean`.\n *\n * boolean -> true\n * Array<boolean> -> true\n * boolean[] -> true\n * readonly boolean[] -> true\n * true, false -> true (literal types)\n *\n * Does NOT descend into object properties or nested tuple elements.\n * */\nconst isBooleanTypeNode = (typeNode: TypeNode): boolean => {\n // (T) -> T (peel off parentheses)\n if (typeNode.isKind(SyntaxKind.ParenthesizedType)) {\n return isBooleanTypeNode(typeNode.getTypeNode());\n }\n\n // Array<T> -> T\n if (typeNode.isKind(SyntaxKind.TypeReference)) {\n return typeNode.getTypeName().getText() === \"Array\"\n ? isBooleanTypeNode(typeNode.getTypeArguments()[0])\n : false;\n }\n\n // T[] -> T\n if (typeNode.isKind(SyntaxKind.ArrayType)) {\n return isBooleanTypeNode(typeNode.getElementTypeNode());\n }\n\n // readonly T[] -> T\n if (typeNode.isKind(SyntaxKind.TypeOperator)) {\n return typeNode.getOperator() === SyntaxKind.ReadonlyKeyword\n ? isBooleanTypeNode(typeNode.getTypeNode())\n : false;\n }\n\n // literal true / false\n if (typeNode.isKind(SyntaxKind.LiteralType)) {\n const literal = typeNode.getLiteral();\n return (\n literal.isKind(SyntaxKind.TrueKeyword) ||\n literal.isKind(SyntaxKind.FalseKeyword)\n );\n }\n\n // plain boolean\n return typeNode.isKind(SyntaxKind.BooleanKeyword);\n};\n\n/**\n * Render a ts-morph TypeNode to TypeBox Script text, replacing every VRefine\n * occurrence (at any depth) with the infix `with` form.\n *\n * VRefine<string, { format: \"email\" }> -> (string with { format: \"email\" })\n * VRefine<string, { format: \"email\" }>[] -> (string with { format: \"email\" })[]\n * VRefine<Array<string>, { minItems: 1 }> -> (Array<string> with { minItems: 1 })\n * VRefine<Record<string, string>, { maxProperties: 20 }>\n * -> (Record<string, string> with { maxProperties: 20 })\n *\n * The parentheses matter: for an array element the `with` clause must bind to the element,\n * not the array, so a VRefine that is the element of an array is wrapped.\n * So, wrapping unconditionally - harmless when not nested, required when it is.\n *\n * @param typeNode the node to render\n * @param refineTypeName the configured refine type name\n * */\nconst renderTypeboxSchema = (\n typeNode: TypeNode,\n refineTypeName = defaults.refineTypeName,\n) => {\n const traverse = (typeNode: TypeNode): string => {\n // 1) VRefine<T, Opts> -> `(<render T> with <opts text>)`\n if (\n typeNode.isKind(SyntaxKind.TypeReference) &&\n typeNode.getTypeName().getText() === refineTypeName\n ) {\n const [inner, opts] = typeNode.getTypeArguments();\n if (!inner || !opts) {\n // Malformed VRefine, emit its raw text unchanged\n return typeNode.getText();\n }\n const innerText = traverse(inner);\n // Options is a single TypeLiteral; its raw text is exactly what `with`\n // expects. getText() preserves nested braces and quoted `}>` verbatim.\n return `(${innerText} with ${opts.getText()})`;\n }\n\n // 2) T[] -> `<render T>[]` (element may itself be a VRefine)\n if (typeNode.isKind(SyntaxKind.ArrayType)) {\n const element = traverse(typeNode.getElementTypeNode());\n return `${element}[]`;\n }\n\n // 3) Object type literal -> recurse into each property's type node\n if (typeNode.isKind(SyntaxKind.TypeLiteral)) {\n const members: string[] = [];\n for (const member of typeNode.getMembers()) {\n if (member.isKind(SyntaxKind.PropertySignature)) {\n const name = member.getName();\n const optional = member.hasQuestionToken() ? \"?\" : \"\";\n const t = member.getTypeNode();\n const rendered = t ? traverse(t) : \"unknown\";\n members.push(`${name}${optional}: ${rendered}`);\n } else {\n // index signatures, call signatures, etc: pass through raw\n members.push(member.getText());\n }\n }\n return `{ ${members.join(\", \")} }`;\n }\n\n // 4) Tuple -> recurse into each element\n if (typeNode.isKind(SyntaxKind.TupleType)) {\n const elements = typeNode.getElements().map((el) => traverse(el));\n return `[${elements.join(\", \")}]`;\n }\n\n // 5) Parenthesized -> recurse, keep the parens\n if (typeNode.isKind(SyntaxKind.ParenthesizedType)) {\n return `(${traverse(typeNode.getTypeNode())})`;\n }\n\n // 6) Union / Intersection -> recurse into each constituent\n if (typeNode.isKind(SyntaxKind.UnionType)) {\n return typeNode\n .getTypeNodes()\n .map((t) => traverse(t))\n .join(\" | \");\n }\n if (typeNode.isKind(SyntaxKind.IntersectionType)) {\n return typeNode\n .getTypeNodes()\n .map((t) => traverse(t))\n .join(\" & \");\n }\n\n // 7) A non-VRefine type reference that carries type arguments -\n // this covers the refined bases Array<T> and Record<K, V>\n // (which stay as-is and get a trailing `with` clause from case 1),\n // as well as any generic wrapper around a VRefine.\n // Recurse into the arguments so a nested VRefine is still rewritten,\n // and keep the head name unchanged.\n if (typeNode.isKind(SyntaxKind.TypeReference)) {\n const args = typeNode.getTypeArguments();\n if (args.length === 0) {\n return typeNode.getText();\n }\n const name = typeNode.getTypeName().getText();\n const rendered = args.map((a) => traverse(a));\n return `${name}<${rendered.join(\", \")}>`;\n }\n\n // 8) Anything else (primitive keyword, literal, etc): raw text is correct.\n return typeNode.getText();\n };\n\n return escapeTemplateLiterals(traverse(typeNode));\n};\n","import { type FormatConfig, format } from \"oxfmt\";\n\nexport const formatCode = async (\n code: string,\n filename: string,\n config?: FormatConfig,\n) => {\n return format(filename, code, {\n sortImports: true,\n ...config,\n }).then((e) => (e.errors.length ? code : e.code));\n};\n","import type {\n ApiRoute,\n GeneratorFactory,\n GeneratorSignature,\n ProjectSettings,\n ResolvedEntry,\n SourceFolder,\n WatcherEvent,\n} from \"@kosmojs/core\";\n\nexport const defineGenerator = <O extends object, R extends boolean = false>({\n meta,\n factory,\n dependencies,\n devDependencies,\n}: Omit<GeneratorSignature<O>, \"factory\"> & {\n factory: (s: ProjectSettings, f: SourceFolder, o?: O) => GeneratorFactory;\n}): [R] extends [true]\n ? (o: O) => GeneratorSignature<O>\n : (o?: O) => GeneratorSignature<O> => {\n return ((options?: O) => {\n return {\n meta,\n factory: (settings: ProjectSettings, folder: SourceFolder) => {\n return factory(settings, folder, options);\n },\n dependencies,\n devDependencies,\n options,\n };\n }) as never;\n};\n\nexport const defineGeneratorFactory = <O extends object>(\n factory: (s: ProjectSettings, f: SourceFolder, o?: O) => GeneratorFactory,\n) => factory;\n\n/**\n * Filter watched API routes by event.\n * Handle 3 cases:\n * - event is undefined (means initial call): process all routes.\n * - `create` event given: process newly added route.\n * Files can arrive already containing content (git checkout, cp) -\n * clients must generate on create, not only on a subsequent update.\n * - `update` event given: process the updated route,\n * and any route referencing the updated file (shared types).\n * */\nexport const createWatchedApiRouteEntriesFilter = (\n event: WatcherEvent | undefined,\n eventsOfInterest: Array<WatcherEvent[\"kind\"]>,\n) => {\n return ({ kind, entry }: ResolvedEntry) => {\n if (!event) {\n // no event (initial call), process all routes\n return true;\n }\n if (!eventsOfInterest.includes(event.kind)) {\n return false;\n }\n if (kind === \"apiRoute\" || kind === \"apiUse\") {\n return entry.fileFullpath !== event.file\n ? (entry as ApiRoute).referencedFiles?.includes(event.file)\n : true;\n }\n return false;\n };\n};\n/**\n * Filter watched page routes by event.\n * Handle 3 cases:\n * - event is undefined (means initial call): process all routes.\n * - `create` event given: process newly added route.\n * Files can arrive already containing content (git checkout, cp) -\n * clients must generate on create, not only on a subsequent update.\n * - `update` event given: process the updated route,\n * and any route referencing the updated file (shared types).\n * */\nexport const createWatchedPageRouteEntriesFilter = (\n event: WatcherEvent | undefined,\n eventsOfInterest: Array<WatcherEvent[\"kind\"]>,\n) => {\n return ({ kind, entry }: ResolvedEntry) => {\n if (!event) {\n // no event (initial call), process all routes\n return true;\n }\n if (!eventsOfInterest.includes(event.kind)) {\n return false;\n }\n return kind === \"pageRoute\" || kind === \"pageLayout\"\n ? entry.fileFullpath === event.file\n : false;\n };\n};\n","import net from \"node:net\";\n\n/**\n * Probe whether a single TCP port is free on given host.\n *\n * Resolves `true` only after the probe server has fully closed,\n * so the caller can immediately rebind without racing the OS.\n * `unref()` keeps a dangling probe from holding the event loop open.\n * */\nexport const isPortFree = (host: string, port: number, timeoutMs = 2000) => {\n return new Promise<boolean>((resolve) => {\n const server = net.createServer();\n\n const done = (result: boolean) => {\n clearTimeout(timer);\n resolve(result);\n };\n\n const timer = setTimeout(() => {\n server.close(() => done(false));\n }, timeoutMs);\n\n server.unref();\n server.once(\"error\", () => done(false));\n server.once(\"listening\", () => server.close(() => done(true)));\n\n server.listen({ host, port });\n });\n};\n\n/**\n * Find `count` consecutive free ports by probing random offsets within minPort..maxPort.\n * Each attempt picks a uniformly random start, probes the whole window,\n * and returns it only if every port is free.\n * Failed attempts are cheap because only the window is probed - no full-range scan.\n * */\nexport const findFreePortRange = async (\n host: string,\n count: number,\n {\n minPort = 20_000,\n maxPort = 29_000,\n attempts = 32,\n }: {\n minPort?: number;\n maxPort?: number;\n attempts?: number;\n } = {},\n): Promise<Array<number>> => {\n if (count < 1) {\n throw new Error(\"count must be >= 1\");\n }\n\n const span = maxPort - minPort - count + 1;\n\n if (span <= 0) {\n throw new Error(\n `Port range ${minPort}-${maxPort} is too small for a window of ${count}`,\n );\n }\n\n for (let attempt = 0; attempt < attempts; attempt++) {\n const start = minPort + Math.floor(Math.random() * span);\n const range = Array.from({ length: count }, (_, i) => start + i);\n\n const results = await Promise.all(range.map((p) => isPortFree(host, p)));\n\n if (results.every(Boolean)) {\n return range;\n }\n }\n\n throw new Error(\n `No run of ${count} free ports found in range ${minPort}-${maxPort} after ${attempts} random attempts`,\n );\n};\n","import crc from \"crc/crc32\";\nimport { compile, parse, type Token } from \"path-to-regexp\";\n\nimport type {\n PathToken,\n PathTokenParamPart,\n PathTokenStaticPart,\n} from \"@kosmojs/core\";\n\n/**\n * Parse a filesystem route path into structured PathToken array.\n *\n * Uses path-to-regexp v8 AST for parsing, with directory-friendly syntax:\n * - [param] => required param - :param\n * - {param} => optional param - {:param}\n * - {...param} => splat - {*param}\n *\n * Direct :param syntax is prohibited outside {} to avoid ambiguity.\n * Inside {} it is treated as path-to-regexp power syntax and used as-is.\n *\n * Throw error if path can not be compiled into path-to-regexp pattern.\n *\n * Examples:\n * Required: [id], [name]\n * Optional: {name}, {format}\n * Splat: {...path}\n * Mixed segments: shop/[id]-{name}\n * Power syntax: {-v:version{-:pre}}, :name{@:version{.:min}}.js\n * */\nexport const pathTokensFactory = (path: string): Array<PathToken> => {\n /**\n * Recursively extract parts from path-to-regexp AST tokens.\n * A param inside a group is optional; top-level params are required.\n * Wildcard tokens are always splat.\n * Slash-only text nodes (restored for parsing) are skipped.\n * */\n const extractParts = (\n tokens: Array<Token>,\n createConst: (value: string) => string,\n insideGroup = false,\n ): Array<PathTokenStaticPart | PathTokenParamPart> => {\n const parts: Array<PathTokenStaticPart | PathTokenParamPart> = [];\n\n for (const token of tokens) {\n switch (token.type) {\n case \"text\":\n // Skip slash-only text nodes (restored it via transformers for parsing)\n if (token.value !== \"/\") {\n parts.push({\n type: \"static\",\n value: token.value,\n });\n }\n break;\n case \"param\":\n parts.push({\n type: \"param\",\n kind: insideGroup ? \"optional\" : \"required\",\n name: token.name,\n const: createConst(token.name),\n });\n break;\n case \"wildcard\":\n parts.push({\n type: \"param\",\n kind: \"splat\",\n name: token.name,\n const: createConst(token.name),\n });\n break;\n case \"group\":\n parts.push(...extractParts(token.tokens, createConst, true));\n break;\n }\n }\n\n return parts;\n };\n\n const patternTransforms: Array<(s: string) => string> = [\n // Transform required params: [id] => :id\n // Only pure \\w param names,\n // [some-id] used as is, not treated as param,\n // use [some_id] instead.\n (s) => s.replace(/\\[(\\w+)\\]/g, \":$1\"),\n\n // Transform optional params: {id} => {:id}\n // Only pure \\w param names,\n // anything else treated as a path-to-regexp pattern and used as is.\n // {some-id} treated as an optional static segment.\n // use {some_id} for simple param syntax\n // or {:some-id} pattern where :some is the param name and -id is a static segment.\n (s) => s.replace(/\\{(\\w+)\\}/g, \"{:$1}\"),\n\n // Transform splat params: {...param} => {*param}\n (s) => s.replace(/\\{\\.\\.\\./g, \"{*\"),\n\n // Insert leading slash inside optional/splat groups.\n // {:name} => {/:name}\n // {*name} => {/*name}\n (s) => {\n return s.startsWith(\"{\") // keep this check for intention clarity\n ? s.replace(/^\\{/, \"{/\")\n : s;\n },\n ];\n\n // detect :param used outside {}\n const detectBareParams = (s: string): \":\" | string | undefined => {\n let depth = 0;\n for (const [i, ch] of [...s].entries()) {\n if (ch === \"{\") {\n depth += 1;\n } else if (ch === \"}\") {\n depth -= 1;\n } else if (ch === \":\" && depth === 0) {\n const match = s.slice(i + 1).match(/^\\w+/);\n return match?.[0] || \":\";\n }\n }\n return;\n };\n\n const tokens = path\n .replace(/^index\\/?/, \"\")\n .split(\"/\")\n .flatMap<PathToken>((orig) => {\n if (!orig.length) {\n return [];\n }\n\n const bareParam = detectBareParams(orig);\n\n if (bareParam === \":\") {\n throw new Error(\n `${path} contains colons outside braces, use : only within {}`,\n );\n } else if (bareParam) {\n throw new Error(\n `${path} contains bare params, use [${bareParam}] instead of :${bareParam}`,\n );\n }\n\n const pattern = patternTransforms.reduce((src, fn) => fn(src), orig);\n\n const { tokens } = parse(\n pattern.replace(/\\{[^}]*\\}|(\\+)/g, (m, p1) => (p1 ? \"\\\\+\" : m)),\n );\n\n const parts = extractParts(tokens, (val) => {\n // Sanitize param name into a valid JS identifier\n return /\\W/.test(val) || /^\\d/.test(val)\n ? [val.replace(/^\\d+|\\W/g, \"_\"), crc(orig)].join(\"_\")\n : val;\n });\n\n const isStatic = parts.length === 1 ? parts[0].type === \"static\" : false;\n const isParam = parts.length === 1 ? parts[0].type === \"param\" : false;\n\n const kind: PathToken[\"kind\"] = isStatic\n ? \"static\"\n : isParam\n ? \"param\"\n : \"mixed\";\n\n return [\n {\n kind,\n orig,\n pattern,\n parts,\n },\n ];\n });\n\n // final path should compile, throw otherwise\n compile(tokens.map((e) => e.pattern).join(\"/\"));\n\n return tokens;\n};\n\nexport const createPathPattern = (tokens: Array<PathToken>) => {\n return tokens\n .map(({ pattern }, i) => {\n const next = tokens[i + 1];\n\n if (!next || next.pattern.includes(\"/\")) {\n return pattern;\n }\n\n const slashRequired = tokens.slice(i + 1).some((e) => {\n return e.parts.some((e) => {\n return e.type === \"static\" || e.kind === \"required\";\n });\n });\n\n return slashRequired ? `${pattern}/` : pattern;\n })\n .join(\"\");\n};\n\nexport const createHonoPattern = (tokens: Array<PathToken>) => {\n const escapeStatic = (s: string) => s.replace(/[*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n\n const tokensToPattern = (tokens: Array<Token>): string => {\n return tokens\n .flatMap((t) => {\n if (t.type === \"text\") {\n return t.value === \"/\" ? [] : [escapeStatic(t.value)];\n }\n if (t.type === \"param\") {\n return [\"[^/]+\"];\n }\n if (t.type === \"wildcard\") {\n return [\".+\"];\n }\n if (t.type === \"group\") {\n return [`(?:${tokensToPattern(t.tokens)})?`];\n }\n return [];\n })\n .join(\"\");\n };\n\n return tokens\n .flatMap((token, i) => {\n // static segment\n if (token.kind === \"static\") {\n return [(token.parts[0] as PathTokenStaticPart).value];\n }\n\n // pure param segment\n if (token.kind === \"param\") {\n const part = token.parts[0] as PathTokenParamPart;\n if (part.kind === \"splat\") {\n return [\"*\"];\n }\n if (part.kind === \"optional\") {\n return [`:${part.name}?`];\n }\n return [`:${part.name}`];\n }\n\n // mixed segment - convert path-to-regexp pattern to hono regex pattern\n const { tokens } = parse(token.pattern);\n\n return [`:_${i}{${tokensToPattern(tokens)}}`];\n })\n .join(\"/\");\n};\n\nexport const createH3Pattern = (tokens: Array<PathToken>): string => {\n // WARN: escaping the dash is essential for correct param matching\n const escapeStatic = (s: string) => s.replace(/[-*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n\n const tokensToPattern = (tokens: Array<Token>): string => {\n return tokens\n .flatMap((t) => {\n if (t.type === \"text\") {\n return t.value === \"/\" ? [] : [escapeStatic(t.value)];\n }\n if (t.type === \"param\") {\n return [`:${t.name}`];\n }\n if (t.type === \"wildcard\") {\n return [`/**:${t.name}`];\n }\n if (t.type === \"group\") {\n return [`{${tokensToPattern(t.tokens)}}?`];\n }\n return [];\n })\n .join(\"\");\n };\n\n return tokens\n .flatMap((token) => {\n // static segment\n if (token.kind === \"static\") {\n return [(token.parts[0] as PathTokenStaticPart).value];\n }\n\n // pure param segment\n if (token.kind === \"param\") {\n const part = token.parts[0] as PathTokenParamPart;\n if (part.kind === \"splat\") {\n return [\"**\"];\n }\n if (part.kind === \"optional\") {\n return [\"*\"];\n }\n return [`:${part.name}`];\n }\n\n // mixed segment - convert path-to-regexp pattern to rou3 regex pattern\n const { tokens } = parse(token.pattern);\n\n return [tokensToPattern(tokens)];\n })\n .join(\"/\");\n};\n\nexport const createAliasPatterns = (\n aliasMap: Record<string, string> | undefined,\n) => {\n return Object.keys(aliasMap || {}).map((alias) => {\n return createPathPattern(pathTokensFactory(alias));\n });\n};\n","import { dirname, join, resolve } from \"node:path\";\nimport { styleText } from \"node:util\";\n\nimport crc from \"crc/crc32\";\nimport picomatch from \"picomatch\";\nimport { glob } from \"tinyglobby\";\n\nimport {\n defaults,\n type PathToken,\n type PathTokenParamPart,\n type ProjectSettings,\n type ResolvedEntry,\n type RouteEntry,\n type SourceFolder,\n} from \"@kosmojs/core\";\n\nimport { pathResolver } from \"../paths\";\nimport {\n createH3Pattern,\n createHonoPattern,\n createPathPattern,\n pathTokensFactory,\n} from \"./paths\";\n\nexport type ResolverSignature = {\n name: string;\n handler: (updatedFile?: string) => Promise<ResolvedEntry>;\n};\n\nexport const API_INDEX_BASENAME = \"index\";\nexport const API_INDEX_PATTERN = `${API_INDEX_BASENAME}.ts`;\n\nexport const API_USE_BASENAME = \"use\";\nexport const API_USE_PATTERN = `${API_USE_BASENAME}.ts`;\n\nexport const PAGE_INDEX_BASENAME = \"index\";\nexport const PAGE_INDEX_PATTERN = `${PAGE_INDEX_BASENAME}.{tsx,vue,svelte,mdx,md}`;\n\nexport const PAGE_LAYOUT_BASENAME = \"layout\";\nexport const PAGE_LAYOUT_PATTERN = `${PAGE_LAYOUT_BASENAME}.{tsx,vue,svelte,mdx}`;\n\nconst ROUTE_FILE_PATTERNS = [\n // match index files in api dir\n `${defaults.apiDir}/**/${API_INDEX_PATTERN}`,\n // match use files in api dir\n `${defaults.apiDir}/**/${API_USE_PATTERN}`,\n // match index files in pages dir\n `${defaults.pagesDir}/**/${PAGE_INDEX_PATTERN}`,\n // match layout files in pages dir\n `${defaults.pagesDir}/**/${PAGE_LAYOUT_PATTERN}`,\n];\n\nexport const scanRoutes = async (\n projectSettings: ProjectSettings,\n sourceFolder: SourceFolder,\n) => {\n const { createPath } = pathResolver(projectSettings, sourceFolder);\n return glob(ROUTE_FILE_PATTERNS, {\n cwd: createPath.src(),\n absolute: true,\n onlyFiles: true,\n followSymbolicLinks: false,\n ignore: [\n // ignore top-level matches, routes resides in folders, even index route\n `${defaults.apiDir}/${API_INDEX_PATTERN}`,\n `${defaults.apiDir}/${API_USE_PATTERN}`,\n `${defaults.pagesDir}/${PAGE_INDEX_PATTERN}`,\n `${defaults.pagesDir}/${PAGE_LAYOUT_PATTERN}`,\n ],\n });\n};\n\nexport const isRouteFile = (\n projectSettings: ProjectSettings,\n sourceFolder: SourceFolder,\n file: string,\n):\n | [\n // Either `apiDir` or `pagesDir`\n folder: string,\n // Path to a file within the folder, nested at least one level deep\n file: string,\n ]\n | false => {\n const [\n // source folder name\n _sourceFolder,\n // route folder, api or pages\n _folder,\n ...rest\n ] = resolve(projectSettings.root, file)\n .replace(`${projectSettings.root}/${defaults.srcDir}/`, \"\")\n .split(\"/\");\n\n /**\n * Ensure the file:\n * - is under the correct source root\n * - belongs to a known route folder (`api/` or `pages/`)\n * - is nested at least one level deep (not a direct child of the folder)\n * */\n if (!_folder || _sourceFolder !== sourceFolder.name || rest.length < 2) {\n return false;\n }\n\n return picomatch.isMatch(join(_folder, ...rest), ROUTE_FILE_PATTERNS)\n ? [_folder, rest.join(\"/\")]\n : false;\n};\n\nexport const isApiRoute = (file: string) => {\n return picomatch.matchBase(file, `**/${API_INDEX_PATTERN}`);\n};\n\nexport const isApiUse = (file: string) => {\n return picomatch.matchBase(file, `**/${API_USE_PATTERN}`);\n};\n\nexport const isPageRoute = (file: string) => {\n return picomatch.matchBase(file, `**/${PAGE_INDEX_PATTERN}`);\n};\n\nexport const isPageLayout = (file: string) => {\n return picomatch.matchBase(file, `**/${PAGE_LAYOUT_PATTERN}`);\n};\n\nexport const createRouteEntry = (\n projectSettings: ProjectSettings,\n sourceFolder: SourceFolder,\n fileFullpath: string,\n): RouteEntry | undefined => {\n // scanner already is doing a great job on matching only relevant files\n // but doing a double check here to make sure only needed files added to stack\n const resolvedPaths = isRouteFile(\n projectSettings,\n sourceFolder,\n fileFullpath,\n );\n\n if (!resolvedPaths) {\n return;\n }\n\n const [folder, file] = resolvedPaths;\n\n const id = `${file.replace(/\\W+/g, \"_\")}_${crc(file)}`;\n const name = dirname(file);\n\n try {\n const pathTokens = pathTokensFactory(dirname(file));\n return {\n id,\n name,\n folder,\n file,\n fileFullpath,\n pathTokens,\n pathPattern: createPathPattern(pathTokens),\n honoPattern: createHonoPattern(pathTokens),\n h3Pattern: createH3Pattern(pathTokens),\n };\n } catch (\n // biome-ignore lint: any\n error: any\n ) {\n console.error(\n `❗${styleText(\"red\", \"ERROR\")}: Failed parsing path for \"${styleText(\"cyan\", file)}\"`,\n );\n console.error(error.message);\n return;\n }\n};\n\n/**\n * Weight of a single path segment.\n *\n * Fixed values per kind prevent complex mixed segments\n * from outscoring multiple statics.\n *\n * static: 4 (exact match, most specific)\n * mixed: 3+ (static + param parts; more statics = slightly higher)\n * required: 2 (matches any single segment)\n * optional: 1 (may or may not match)\n * splat: 0 (matches anything, least specific)\n * */\nconst segmentWeight = (token: PathToken): number => {\n if (token.kind === \"static\") {\n return 4;\n }\n\n if (token.kind === \"mixed\") {\n let statics = 0;\n let optionals = 0;\n\n for (const part of token.parts) {\n if (part.type === \"static\") {\n statics += 1;\n } else if (part.kind === \"optional\" || part.kind === \"splat\") {\n optionals += 1;\n }\n }\n\n // unconditional statics contribute positively,\n // optionals penalize to avoid beating fully-static mixed routes\n return 3 + statics * 0.01 - optionals * 0.005;\n }\n\n const part = token.parts[0] as PathTokenParamPart;\n\n switch (part.kind) {\n case \"required\":\n return 2;\n case \"optional\":\n return 1;\n case \"splat\":\n return 0;\n }\n};\n\n/**\n * Compare two route entries for registration order.\n *\n * More specific routes sort first (higher priority).\n * Segments are compared left-to-right; first difference wins.\n *\n * When one route is a prefix of the other, the trailing segment\n * determines order: a trailing splat loses (shorter sibling first),\n * anything else wins (longer route is more specific).\n *\n * At equal weight and length, lexicographic tiebreak ensures\n * deterministic ordering across JS engines.\n * */\nexport const sortRoutes = (\n a: Pick<RouteEntry, \"pathPattern\" | \"pathTokens\">,\n b: Pick<RouteEntry, \"pathPattern\" | \"pathTokens\">,\n): number => {\n const pairs = Array.from(\n { length: Math.max(a.pathTokens.length, b.pathTokens.length) },\n (_, i) => [a.pathTokens[i], b.pathTokens[i]] as const,\n );\n\n for (const [at, bt] of pairs) {\n if (!at || !bt) {\n // one route ran out of segments - check what the extra segment is\n const extra = at ?? bt;\n\n const isSplat =\n extra?.kind === \"param\"\n ? (extra.parts[0] as PathTokenParamPart).kind === \"splat\"\n : false;\n\n if (isSplat) {\n // trailing splat: shorter sibling registers first\n return at ? 1 : -1;\n }\n\n // trailing non-splat: longer route is more specific, registers first\n return at ? -1 : 1;\n }\n\n const aw = segmentWeight(at);\n const bw = segmentWeight(bt);\n\n if (aw !== bw) {\n return bw - aw;\n }\n }\n\n // same weight profile, same length: deterministic tiebreak\n return a.pathPattern.localeCompare(b.pathPattern);\n};\n\n/**\n * Compare two route entries for first-match resolution order,\n * as used by the generated svelte/mdx routers.\n *\n * Identical to `sortRoutes` except when one route is a prefix of the other\n * and the trailing extra segment is an optional parameter: there the SHORTER route goes first.\n * The longer route's pattern also matches the bare path (optional omitted),\n * but only the shorter route can serve it - deeper URLs never match the shorter one's pattern,\n * so it must get the first shot:\n *\n * /blog -> `blog`, not `blog/{category}/{tag}`\n * /admin/x/resources -> `admin/[tenant]/resources`, not `.../resources/{type}`\n *\n * Trailing splats already sort shorter-first in `sortRoutes`;\n * trailing static or required segments make the two patterns disjoint,\n * so their relative order is immaterial for first-match and stays as registration order.\n * */\nexport const sortRoutesForResolution = (\n a: Pick<RouteEntry, \"pathPattern\" | \"pathTokens\">,\n b: Pick<RouteEntry, \"pathPattern\" | \"pathTokens\">,\n): number => {\n const shorter = a.pathTokens.length < b.pathTokens.length ? a : b;\n const longer = shorter === a ? b : a;\n\n // Equal-weight shared prefix approximates \"no earlier difference decides\":\n // when prefix weights differ, sortRoutes orders by that difference anyway,\n // and same-weight-different-static prefixes are disjoint patterns,\n // where relative order is immaterial for first-match.\n if (\n a.pathTokens.length !== b.pathTokens.length &&\n shorter.pathTokens.every((token, i) => {\n const counterpart = longer.pathTokens[i] as PathToken;\n return segmentWeight(token) === segmentWeight(counterpart);\n })\n ) {\n const extra = longer.pathTokens[shorter.pathTokens.length] as PathToken;\n\n if (\n extra.kind === \"param\" &&\n (extra.parts[0] as PathTokenParamPart).kind === \"optional\"\n ) {\n return shorter === a ? -1 : 1;\n }\n }\n\n return sortRoutes(a, b);\n};\n","import { dirname, join, resolve } from \"node:path\";\nimport { styleText } from \"node:util\";\n\nimport crc from \"crc/crc32\";\nimport { lookup } from \"mrmime\";\n\nimport {\n type ApiRoute,\n defaults,\n type PageRoute,\n type PathTokenParamPart,\n type ProjectSettings,\n type RouteEntry,\n type RouteResolverCacheFactory,\n type SourceFolder,\n type TypeboxOptions,\n type ValidationDefinition,\n} from \"@kosmojs/core\";\n\nimport { astFactory } from \"../ast\";\nimport { pathResolver } from \"../paths\";\nimport { render, renderToFile } from \"../render\";\nimport * as templates from \"../templates\";\nimport type { ResolverSignature } from \"./base\";\n\nexport const resolverFactory = (\n projectSettings: ProjectSettings,\n sourceFolder: SourceFolder,\n cacheFactory?: RouteResolverCacheFactory,\n): Record<\n | \"pageLayoutResolver\"\n | \"pageRouteResolver\"\n | \"apiUseResolver\"\n | \"apiRouteResolver\",\n (entry: RouteEntry) => ResolverSignature\n> => {\n const { generators } = sourceFolder;\n\n const { refineTypeName = defaults.refineTypeName } =\n typeof sourceFolder.config.validation === \"object\"\n ? ({ ...sourceFolder.config.validation } as TypeboxOptions)\n : {};\n\n const { typeResolverFactory, resolveRouteSignature } = astFactory();\n\n const resolveTypes = generators.some(({ meta }) => meta.resolveTypes);\n\n const {\n //\n literalTypesResolver,\n getSourceFile,\n refreshSourceFile,\n } = typeResolverFactory(projectSettings, sourceFolder);\n\n return {\n pageLayoutResolver(entry) {\n const { name } = entry;\n\n const handler: ResolverSignature[\"handler\"] = async () => {\n return {\n kind: \"pageLayout\",\n entry,\n };\n };\n\n return { name, handler };\n },\n\n pageRouteResolver(entry) {\n const {\n id,\n name,\n folder,\n file,\n fileFullpath,\n pathTokens,\n pathPattern,\n honoPattern,\n h3Pattern,\n } = entry;\n\n const handler: ResolverSignature[\"handler\"] = async () => {\n const entry: PageRoute = {\n id,\n name,\n pathTokens,\n pathPattern,\n honoPattern,\n h3Pattern,\n params: {\n schema: pathTokens.flatMap((e) => {\n return e.parts.filter((p) => p.type === \"param\");\n }),\n },\n folder,\n file,\n fileFullpath,\n };\n\n return {\n kind: \"pageRoute\",\n entry,\n };\n };\n\n return { name, handler };\n },\n\n apiUseResolver(entry) {\n const { name } = entry;\n\n const handler: ResolverSignature[\"handler\"] = async () => {\n return {\n kind: \"apiUse\",\n entry,\n };\n };\n\n return { name, handler };\n },\n\n apiRouteResolver(entry) {\n const {\n id,\n name,\n file,\n folder,\n fileFullpath,\n pathTokens,\n pathPattern,\n honoPattern,\n h3Pattern,\n } = entry;\n\n const handler: ResolverSignature[\"handler\"] = async (updatedFile) => {\n const paramsSchema: Array<PathTokenParamPart> = pathTokens.flatMap(\n (e) => {\n return e.parts.flatMap((p) => {\n return p.type === \"param\" ? [p] : [];\n });\n },\n );\n\n const optionalParams = paramsSchema.length\n ? paramsSchema.filter((e) => e.kind === \"required\").length === 0\n : true;\n\n const cacheStore = cacheFactory\n ? cacheFactory(\n projectSettings,\n sourceFolder,\n { id, file, fileFullpath },\n { resolveTypes },\n )\n : undefined;\n\n let cache = cacheStore\n ? await cacheStore.get({ validate: true })\n : undefined;\n\n if (!cache) {\n if (updatedFile === fileFullpath) {\n await refreshSourceFile(fileFullpath);\n }\n\n const {\n typeDeclarations,\n paramsRefinements,\n methods,\n validationDefinitions,\n referencedFiles = [],\n } = await resolveRouteSignature(\n { id, name, fileFullpath, optionalParams },\n {\n withReferencedFiles: true,\n sourceFile: getSourceFile(fileFullpath),\n relpathResolver(path) {\n return join(\n defaults.srcPrefix,\n defaults.apiDir,\n dirname(file),\n path,\n );\n },\n },\n );\n\n const validationTypes = validationDefinitions.flatMap<{\n id: string;\n text: string;\n }>((def) => {\n return def.target === \"response\"\n ? def.variants.flatMap(({ id, body }) => {\n return body ? [{ id, text: body }] : [];\n })\n : [def.schema];\n });\n\n const typesFile = pathResolver(\n projectSettings,\n sourceFolder,\n ).createPath.libApi(dirname(file), \"types.ts\");\n\n const params: ApiRoute[\"params\"] = {\n id: [\"ParamsT\", crc(name)].join(\"\"),\n schema: paramsSchema,\n resolvedType: undefined,\n };\n\n const typesFileContent = render(templates.typesFile, {\n params,\n paramsSchema: paramsSchema.map((param, index) => {\n return {\n ...param,\n isRequired: param.kind === \"required\",\n isSplat: param.kind === \"splat\",\n refinement: paramsRefinements?.at(index),\n };\n }),\n typeDeclarations,\n validationTypes,\n });\n\n const resolvedTypes = resolveTypes\n ? literalTypesResolver(typesFileContent, {\n stripComments: true,\n overrides: { [refineTypeName]: refineTypeName },\n withProperties: [\n params.id,\n ...validationTypes.map(({ id }) => id),\n ],\n })\n : undefined;\n\n /**\n * Deploy types.ts file; required by core generators (like fetch).\n * If types resolved, write resolved types;\n * otherwise write original types extracted from API route.\n * */\n await renderToFile(\n typesFile,\n resolvedTypes ? templates.resolvedTypes : typesFileContent,\n { resolvedTypes },\n );\n\n params.resolvedType = resolvedTypes?.find(\n (e) => e.name === params.id,\n );\n\n cache = {\n // placeholder values, if cacheFactory given,\n // they will be replaced by persistCache\n hash: 0,\n referencedFiles: {},\n // real values\n params,\n methods,\n typeDeclarations,\n validationDefinitions: validationDefinitions.map((def) => {\n return {\n ...def,\n ...(def.target === \"response\"\n ? {\n variants: def.variants.map((variant) => {\n return {\n ...variant,\n resolvedType: resolvedTypes?.find(\n (e) => e.name === variant.id,\n ),\n };\n }),\n }\n : {\n schema: {\n ...def.schema,\n resolvedType: resolvedTypes?.find(\n (e) => e.name === def.schema.id,\n ),\n },\n }),\n };\n }),\n };\n\n if (cacheStore) {\n const { referencedFiles: _void, ...rest } = cache;\n cache = await cacheStore.set({ ...rest, referencedFiles });\n }\n }\n\n const validationDefinitions = cache.validationDefinitions.flatMap(\n (def) => {\n let augmentedDef: ValidationDefinition | undefined = def;\n\n if (def.target === \"response\") {\n augmentedDef = {\n ...def,\n variants: def.variants.flatMap((variant, i) => {\n if (typeof variant.contentType !== \"string\") {\n return [variant];\n }\n\n if (variant.contentType.includes(\"/\")) {\n return [variant];\n }\n\n const contentType = lookup(variant.contentType);\n\n if (!contentType) {\n console.warn(\n styleText(\n [\"bold\", \"red\"],\n \"✗ Failed resolving Response Content Type\",\n ),\n );\n console.warn(\n ` Invalid value provided for mime-types lookup - ${variant.contentType}`,\n );\n console.warn(\n styleText(\n [\"cyan\"],\n ` Response variant #${i} excluded from route schemas`,\n ),\n );\n console.warn(` Route: ${name}; Method: ${def.method}`);\n console.warn();\n return [];\n }\n\n return [{ ...variant, contentType }];\n }),\n };\n } else if (def.contentType && !def.contentType.includes(\"/\")) {\n const contentType = lookup(def.contentType);\n if (!contentType) {\n console.warn(\n styleText(\n [\"bold\", \"red\"],\n \"✗ Failed resolving Response Content Type\",\n ),\n );\n console.warn(\n ` Invalid value provided for mime-types lookup - ${def.contentType}`,\n );\n console.warn(` Route: ${name}; Method: ${def.method}`);\n console.warn();\n } else {\n augmentedDef = { ...def, contentType };\n }\n }\n\n return augmentedDef ? [augmentedDef] : [];\n },\n );\n\n const entry: ApiRoute = {\n id,\n name,\n pathTokens,\n pathPattern,\n honoPattern,\n h3Pattern,\n params: cache.params,\n optionalParams,\n folder,\n file,\n fileFullpath,\n methods: cache.methods,\n typeDeclarations: cache.typeDeclarations,\n validationDefinitions,\n referencedFiles: Object.keys(cache.referencedFiles).map(\n // expand referenced files path,\n // they are stored as relative in cache\n (e) => resolve(projectSettings.root, e),\n ),\n };\n\n return {\n kind: \"apiRoute\",\n entry,\n };\n };\n\n return { name, handler };\n },\n };\n};\n","import { basename, posix } from \"node:path\";\n\nimport type { NestedRouteEntry, RouteEntry } from \"@kosmojs/core\";\n\nimport { PAGE_INDEX_BASENAME, PAGE_LAYOUT_BASENAME, sortRoutes } from \"./base\";\n\nexport const nestedRoutesFactory = (routeEntries: Array<RouteEntry>) => {\n const entryStack = structuredClone(routeEntries).sort(sortRoutes);\n\n /**\n * Group entries by name (at the same level, both layout and index share same name).\n *\n * Handle 3 cases:\n * - both index and layout exists\n * - only index exists\n * - only layout exists\n *\n * */\n const transformEntries = (\n entries: Array<RouteEntry>,\n parent?: RouteEntry,\n ): Array<NestedRouteEntry> => {\n return [...new Set(entries.map((e) => e.name))].flatMap((name) => {\n const nameEntries = entryStack.flatMap(({ fileFullpath, ...entry }) => {\n return entry.name === name ? [entry] : [];\n });\n\n const index = nameEntries.find((e) =>\n basename(e.file).startsWith(PAGE_INDEX_BASENAME),\n ) as RouteEntry;\n\n const layout = nameEntries.find((e) =>\n basename(e.file).startsWith(PAGE_LAYOUT_BASENAME),\n ) as RouteEntry;\n\n if (index || layout) {\n return [\n {\n index: index\n ? {\n ...index,\n pathTokens: index.pathTokens.slice(\n parent?.pathTokens.length || 0,\n ),\n }\n : undefined,\n layout: layout\n ? {\n ...layout,\n pathTokens: layout.pathTokens.slice(\n parent?.pathTokens.length || 0,\n ),\n }\n : undefined,\n parent: parent?.name,\n children: transformEntries(\n findDescendantEntries(index || layout),\n index || layout,\n ),\n },\n ];\n }\n\n return [];\n });\n };\n\n /**\n * Recursively finds direct descendant routes.\n *\n * \"Direct\" means the next existing route in the path hierarchy,\n * skipping intermediate path segments that don't have index/layout files.\n *\n * Example: blog/post/[slug]/index.tsx is a direct child of blog/index.tsx\n * even though \"post\" segment exists (it has no index.tsx).\n * */\n const findDescendantEntries = ({\n name,\n pathTokens,\n }: RouteEntry): Array<RouteEntry> => {\n // Find all potential children - BOTH indexes AND layouts\n const potentialChildren = entryStack.filter((entry) => {\n // Must be deeper than current entry\n if (entry.pathTokens.length <= pathTokens.length) {\n return false;\n }\n // Must be a descendant path\n if (!entry.name.startsWith(posix.join(name, \"/\"))) {\n return false;\n }\n return true;\n });\n\n // Filter to direct children (no intermediate route between parent and child)\n return potentialChildren.filter((child) => {\n // Check if any route exists between parent and child\n const hasIntermediateRoute = potentialChildren.some((intermediate) => {\n if (intermediate === child) {\n return false;\n }\n // Intermediate must be between parent and child in depth\n if (intermediate.pathTokens.length <= pathTokens.length) {\n return false;\n }\n if (intermediate.pathTokens.length >= child.pathTokens.length) {\n return false;\n }\n // Child must be descendant of intermediate\n return child.name.startsWith(posix.join(intermediate.name, \"/\"));\n });\n\n return !hasIntermediateRoute;\n });\n };\n\n // Find root entries - entries that have no parent route\n const rootEntries = entryStack.filter((entry) => {\n // Check if any other entry could be its parent\n const hasParent = entryStack.some((potential) => {\n if (potential === entry) {\n return false;\n }\n if (potential.pathTokens.length >= entry.pathTokens.length) {\n return false;\n }\n return entry.name.startsWith(posix.join(potential.name, \"/\"));\n });\n\n return !hasParent;\n });\n\n return transformEntries(rootEntries);\n};\n","import {\n defaults,\n type ProjectSettings,\n type RouteEntry,\n type RouteResolverCacheFactory,\n type SourceFolder,\n} from \"@kosmojs/core\";\n\nimport {\n createRouteEntry,\n isApiRoute,\n isApiUse,\n isPageLayout,\n isPageRoute,\n type ResolverSignature,\n scanRoutes,\n} from \"./base\";\nimport { resolverFactory } from \"./resolve\";\n\nexport * from \"./base\";\nexport * from \"./nesting\";\nexport * from \"./paths\";\n\nexport const routesFactory = async (\n projectSettings: ProjectSettings,\n sourceFolder: SourceFolder,\n cacheFactory?: RouteResolverCacheFactory,\n) => {\n const {\n apiRouteResolver,\n apiUseResolver,\n pageRouteResolver,\n pageLayoutResolver,\n } = resolverFactory(projectSettings, sourceFolder, cacheFactory);\n\n const resolversFactory = (routeFiles: Array<string>) => {\n const resolvers = new Map<\n string, // fileFullpath\n ResolverSignature\n >();\n\n const entries: Array<RouteEntry> = routeFiles.flatMap((file) => {\n const entry = createRouteEntry(projectSettings, sourceFolder, file);\n return entry ? [entry] : [];\n });\n\n for (const entry of entries) {\n if (entry.folder === defaults.apiDir) {\n if (isApiRoute(entry.file)) {\n resolvers.set(entry.fileFullpath, apiRouteResolver(entry));\n } else if (isApiUse(entry.file)) {\n resolvers.set(entry.fileFullpath, apiUseResolver(entry));\n }\n } else if (entry.folder === defaults.pagesDir) {\n if (isPageRoute(entry.file)) {\n resolvers.set(entry.fileFullpath, pageRouteResolver(entry));\n } else if (isPageLayout(entry.file)) {\n resolvers.set(entry.fileFullpath, pageLayoutResolver(entry));\n }\n }\n }\n\n return resolvers;\n };\n\n const routeFiles = await scanRoutes(projectSettings, sourceFolder);\n\n return {\n resolvers: resolversFactory(routeFiles),\n resolversFactory,\n };\n};\n","import { Spinner } from \"@topcli/spinner\";\n\nexport type SpinnerFactory = {\n text: (text: string) => void;\n append: (text: string) => void;\n succeed: (text?: string) => void;\n failed: (text?: string) => void;\n};\n\nexport const spinnerFactory = (startText: string): SpinnerFactory => {\n if (!process.stdout.isTTY || process.env.CI || process.env.TERM === \"dumb\") {\n // stub for non-TTY / CI runners\n return {\n text() {},\n append() {},\n succeed() {},\n failed() {},\n };\n }\n\n const spinner = new Spinner().start(startText);\n\n let _text = startText;\n\n return {\n text(text) {\n _text = text;\n spinner.text = text;\n },\n append(text) {\n spinner.text = `${_text} › ${text}`;\n },\n succeed(text) {\n if (text) {\n this.append(text);\n } else {\n this.text(_text);\n }\n spinner.succeed();\n },\n failed(text) {\n if (text) {\n this.text([_text, text].join(\"\\n\"));\n }\n spinner.failed();\n },\n };\n};\n","import { defaults } from \"@kosmojs/core\";\n\nexport const generateTsconfig = (\n {\n dependencies,\n devDependencies,\n }: Record<\"dependencies\" | \"devDependencies\", Record<string, string>>,\n sourceFolder?: string,\n) => {\n // biome-ignore lint: noTemplateCurlyInString\n const rootDir = \"${configDir}\";\n\n const deps = Object.keys({ ...dependencies, ...devDependencies });\n\n const compilerOptions = {\n types: [\n \"vite/client\",\n ...[\"node\", \"deno\", \"bun\"].flatMap((e) => {\n return deps.includes(`@types/${e}`) ? [`@types/${e}`] : [];\n }),\n ],\n moduleResolution: \"bundler\",\n module: \"ESNext\",\n target: \"ESNext\",\n strict: true,\n exactOptionalPropertyTypes: true,\n noImplicitAny: true,\n noImplicitThis: true,\n noImplicitOverride: true,\n noImplicitReturns: true,\n noUnusedLocals: false,\n noUnusedParameters: false,\n allowArbitraryExtensions: true,\n allowImportingTsExtensions: true,\n allowUnreachableCode: false,\n allowUnusedLabels: false,\n useUnknownInCatchVariables: true,\n noFallthroughCasesInSwitch: true,\n noUncheckedSideEffectImports: true,\n resolveJsonModule: true,\n esModuleInterop: true,\n verbatimModuleSyntax: true,\n skipLibCheck: true,\n noEmit: true,\n };\n\n if (sourceFolder) {\n return {\n include: [\n `${rootDir}/`,\n `${rootDir}/../../${defaults.libDir}/${sourceFolder}/`,\n `${rootDir}/../../${defaults.libDir}/*.d.ts`,\n ],\n compilerOptions: {\n ...compilerOptions,\n types: [...compilerOptions.types],\n paths: {\n [`${defaults.appPrefix}/*`]: [`${rootDir}/../../*`],\n [`${defaults.srcPrefix}/*`]: [`${rootDir}/*`],\n [`${defaults.libPrefix}/*`]: [\n `${rootDir}/../../${defaults.libDir}/${sourceFolder}/*`,\n ],\n },\n },\n };\n }\n\n return {\n exclude: [`${rootDir}/${defaults.srcDir}/`],\n compilerOptions: {\n ...compilerOptions,\n paths: {\n [`${defaults.appPrefix}/*`]: [`${rootDir}/*`],\n },\n },\n };\n};\n","import { stat } from \"node:fs/promises\";\nimport { builtinModules } from \"node:module\";\nimport { isAbsolute, join, parse } from \"node:path\";\n\nimport type { Plugin } from \"vite\";\n\nimport type {\n ChassisCommand,\n ProjectSettings,\n SourceFolder,\n} from \"@kosmojs/core\";\nimport { defaults } from \"@kosmojs/core\";\n\nimport { pathResolver } from \"./paths\";\n\n/**\n * Resolves Kosmo's generated import prefixes to absolute file paths.\n *\n * WHY THIS EXISTS\n * ---------------\n * Every source folder is scaffolded with three tsconfig `paths` prefixes\n * that let generated and user code import across\n * the folder's layout without long relative chains:\n *\n * appPrefix \"@\" -> the project root (<root>/*)\n * srcPrefix \"~\" -> the folder's src dir (<root>/src/<name>/*)\n * libPrefix \"_\" -> the folder's lib dir (<root>/lib/<name>/*)\n *\n * These are the backbone of the generated code: `defineRoute` and friends are\n * emitted with `_/...` imports, pages import layouts and components via `~/...`,\n * and `@/...` reaches shared app-level modules. If a bundler cannot resolve\n * them, nothing the framework generates can be loaded.\n *\n * Historically Vite resolved these through its built-in `resolve.tsconfigPaths: true`,\n * reading the `paths` straight from the generated tsconfig. That option\n * regressed in Vite 8.1.0 (still broken as of 8.1.3): it stops resolving\n * `paths` mappings, especially those defined in an extended / referenced base\n * config - which is exactly Kosmo's structure, where a source folder's\n * tsconfig `extends` `lib/<name>/tsconfig.json` and the paths use the\n * TypeScript `${configDir}` variable. The failure surfaces as:\n *\n * [vite] Failed to resolve import \"_/pageSamples/welcome.vue\" from\n * \"src/<name>/pages/index/index.vue\". Does the file exist?\n *\n * (Upstream: vitejs/vite #22139, #22047, #22371, #21889, #21856.)\n *\n * Rather than pin Vite to 8.0.x indefinitely, or depend on the general-purpose\n * `vite-tsconfig-paths` plugin, this internal plugin resolves ONLY\n * known prefixes against dirs derived from the source folder. That makes it:\n *\n * - Correct on 8.1.x, where native `tsconfigPaths` is broken.\n * - Faster: no tsconfig discovery, no `extends` chain walking, no glob\n * matching - just a prefix check and a handful of `stat` probes,\n * cached by Vite per specifier.\n * - Non-blocking: probes via async `fs/promises` `stat`, so `resolveId` never\n * stalls the event loop.\n * - `.vue` / `.mdx`-aware: `resolveId` sees every specifier regardless of the\n * importer's type, so imports from non-JS files resolve without the\n * `loose` / `allowJs` escape hatches `vite-tsconfig-paths` needs.\n *\n * A project with custom `paths` beyond these three prefixes should install\n * `vite-tsconfig-paths`; this plugin is internal and intentionally narrow.\n *\n * The prefix -> dir bases come from `pathResolver`, the same source of truth the\n * tsconfig generator uses, so alias resolution here can never drift from the\n * paths that were written into the generated tsconfig.\n * */\nexport const tsconfigPaths = (\n projectSettings: ProjectSettings,\n sourceFolder: SourceFolder,\n): Plugin => {\n /**\n * Candidate extensions for an extensionless specifier, in resolution priority order.\n * Mirrors the renderable file types the generators emit;\n * a new page type (e.g. `.svelte`) must be added here or its aliased imports won't resolve.\n * */\n const EXTENSIONS = [\n \".ts\",\n \".tsx\",\n \".js\",\n \".jsx\",\n \".mjs\",\n \".vue\",\n \".svelte\",\n \".md\",\n \".mdx\",\n \".json\",\n ];\n\n const { createPath } = pathResolver(projectSettings, sourceFolder);\n\n const table: Array<[prefix: string, baseDir: string]> = [\n [`${defaults.srcPrefix}/`, createPath.src()],\n [`${defaults.libPrefix}/`, createPath.lib()],\n [`${defaults.appPrefix}/`, projectSettings.root],\n ];\n\n const resolveWithin = async (\n baseDir: string,\n rest: string,\n ): Promise<string> => {\n const target = join(baseDir, rest);\n const { ext } = parse(rest);\n\n // Specifier already carries a known extension: the target IS the candidate\n // (an explicit `foo.js` must not be probed as `foo.js.js`). Only fall back\n // to its `/index.<ext>` for a directory import that happens to end in a\n // known extension (rare, but keeps behaviour total).\n if (EXTENSIONS.includes(ext)) {\n for (const candidate of [target, `${target}/index${ext}`]) {\n if (await isFile(candidate)) {\n return candidate;\n }\n }\n return target;\n }\n\n // No known extension: probe each, plus its index form.\n for (const e of EXTENSIONS) {\n for (const candidate of [`${target}${e}`, `${target}/index${e}`]) {\n if (await isFile(candidate)) {\n return candidate;\n }\n }\n }\n\n return target;\n };\n\n return {\n name: \"kosmo:tsconfigPaths\",\n enforce: \"pre\",\n async resolveId(source) {\n if (isAbsolute(source) || source.startsWith(\".\")) {\n return;\n }\n for (const [prefix, baseDir] of table) {\n if (source.startsWith(prefix)) {\n return resolveWithin(baseDir, source.replace(prefix, \"\"));\n }\n }\n return;\n },\n };\n};\n\nconst nodePrefix = (): Plugin => {\n return {\n name: \"kosmojs:node-prefix\",\n enforce: \"pre\",\n resolveId(source) {\n return builtinModules.includes(source)\n ? { id: `node:${source}`, external: true }\n : undefined;\n },\n };\n};\n\n/**\n * Resolves the CSR/SSR variant of env-sensitive modules.\n *\n * WHY THIS EXISTS\n * ---------------\n * A handful of generated modules must differ between the client graph and the SSR bundle -\n * the fetch transport (a no-op in the browser, an in-process dispatch on the server)\n * and the TanStack Query client (a singleton in the browser, per-request on the server).\n *\n * Every build installs this plugin; but only the SSR bundle installs it with `kind: \"ssr\"`.\n * Nothing is written, so concurrent processes cannot disturb each other.\n *\n * Generators declare their modules via `factory.virtualModules()`.\n * */\nexport const virtualModules = (\n projectSettings: ProjectSettings,\n sourceFolder: SourceFolder,\n { kind, command }: { kind: \"csr\" | \"ssr\"; command: ChassisCommand },\n): Plugin => {\n /**\n * Rollup's / Rolldown's convention for ids owned by a plugin:\n * the NUL prefix keeps other plugins and Node resolution from touching them.\n * */\n const VIRTUAL_PREFIX = \"\\0\";\n\n const modules = sourceFolder.generators.flatMap(({ factory }) => {\n const { virtualModules } = factory(projectSettings, sourceFolder);\n return virtualModules ? virtualModules(command) : [];\n });\n\n const virtualSources = new Map<string, { csr: string; ssr: string }>();\n\n for (const { specifier, csr, ssr } of modules) {\n virtualSources.set(specifier, { csr, ssr });\n }\n\n // Built-in build context, importable from any graph.\n // Given modules should not override it.\n {\n const source = `export const command = \"${command}\";`;\n virtualSources.set(\"virtual:kosmo/env\", { csr: source, ssr: source });\n }\n\n return {\n name: \"kosmo:virtualModules\",\n enforce: \"pre\",\n\n resolveId(source) {\n return virtualSources.has(source) ? VIRTUAL_PREFIX + source : undefined;\n },\n\n load(id) {\n return id.startsWith(VIRTUAL_PREFIX)\n ? virtualSources.get(id.slice(VIRTUAL_PREFIX.length))?.[kind]\n : undefined;\n },\n };\n};\n\nexport const vitePlugins = {\n tsconfigPaths,\n nodePrefix,\n virtualModules,\n};\n\nconst isFile = async (path: string) => {\n return stat(path)\n .then((e) => e.isFile())\n .catch(() => false);\n};\n\nexport const cacheDir = (\n { root }: ProjectSettings,\n { name }: SourceFolder,\n target:\n | `frontend:${ChassisCommand}`\n | `backend:${ChassisCommand}`\n | \"sidecar\",\n) => {\n return join(root, defaults.varDir, \".vite\", name, target);\n};\n","import { readFileSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\n\n/**\n * Read the installed package.json at runtime to get the actual version.\n * A static import would be inlined by the bundler with the pre-bump version.\n *\n * INFO: For best compatibility, all packages should share the same version.\n * When bumping the version (even a patch) for a single package,\n * bump it for all packages to keep versions fully synchronized across the project.\n * */\nexport const { version: VERSION } = JSON.parse(\n readFileSync(\n createRequire(import.meta.url).resolve(\"@kosmojs/lib/package.json\"),\n \"utf-8\",\n ),\n);\n\nexport * from \"./ast\";\nexport * from \"./format\";\nexport * from \"./generators\";\nexport * from \"./generic\";\nexport * from \"./paths\";\nexport * from \"./ports\";\nexport * from \"./render\";\nexport * from \"./routes\";\nexport * from \"./spinner\";\nexport * from \"./tsconfig\";\nexport * from \"./vite\";\n"],"mappings":"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"}
package/pkg/paths.d.ts CHANGED
@@ -1,11 +1,9 @@
1
- import { type SourceFolder } from "@kosmojs/core";
1
+ import { type ProjectSettings, type SourceFolder } from "@kosmojs/core";
2
2
  type Options = {
3
3
  origin: "src" | "lib";
4
4
  };
5
5
  type CreateImport = Record<"src" | "api" | "entry" | "pages" | "lib" | "libCore" | "libApi" | "libEntry", (a: Array<string>, o: Options) => string>;
6
- export declare const pathResolver: (sourceFolder: Omit<SourceFolder, "root"> & {
7
- root?: string | undefined;
8
- }) => {
6
+ export declare const pathResolver: ({ root, distDir }: ProjectSettings, { name }: SourceFolder) => {
9
7
  createPath: Record<"src" | "api" | "pages" | "entry" | "lib" | "libCore" | "libApi" | "libEntry" | "libPages" | "distDir", (...a: Array<string>) => string>;
10
8
  createImport: CreateImport;
11
9
  createImportHelpers: (o: Options) => {
package/pkg/ports.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Probe whether a single TCP port is free on given host.
3
+ *
4
+ * Resolves `true` only after the probe server has fully closed,
5
+ * so the caller can immediately rebind without racing the OS.
6
+ * `unref()` keeps a dangling probe from holding the event loop open.
7
+ * */
8
+ export declare const isPortFree: (host: string, port: number, timeoutMs?: number) => Promise<boolean>;
9
+ /**
10
+ * Find `count` consecutive free ports by probing random offsets within minPort..maxPort.
11
+ * Each attempt picks a uniformly random start, probes the whole window,
12
+ * and returns it only if every port is free.
13
+ * Failed attempts are cheap because only the window is probed - no full-range scan.
14
+ * */
15
+ export declare const findFreePortRange: (host: string, count: number, { minPort, maxPort, attempts, }?: {
16
+ minPort?: number;
17
+ maxPort?: number;
18
+ attempts?: number;
19
+ }) => Promise<Array<number>>;
@@ -1,4 +1,4 @@
1
- import { type ResolvedEntry, type RouteEntry, type SourceFolder } from "@kosmojs/core";
1
+ import { type ProjectSettings, type ResolvedEntry, type RouteEntry, type SourceFolder } from "@kosmojs/core";
2
2
  export type ResolverSignature = {
3
3
  name: string;
4
4
  handler: (updatedFile?: string) => Promise<ResolvedEntry>;
@@ -11,13 +11,13 @@ export declare const PAGE_INDEX_BASENAME = "index";
11
11
  export declare const PAGE_INDEX_PATTERN = "index.{tsx,vue,svelte,mdx,md}";
12
12
  export declare const PAGE_LAYOUT_BASENAME = "layout";
13
13
  export declare const PAGE_LAYOUT_PATTERN = "layout.{tsx,vue,svelte,mdx}";
14
- export declare const scanRoutes: (sourceFolder: SourceFolder) => Promise<string[]>;
15
- export declare const isRouteFile: (file: string, sourceFolder: SourceFolder) => [folder: string, file: string] | false;
14
+ export declare const scanRoutes: (projectSettings: ProjectSettings, sourceFolder: SourceFolder) => Promise<string[]>;
15
+ export declare const isRouteFile: (projectSettings: ProjectSettings, sourceFolder: SourceFolder, file: string) => [folder: string, file: string] | false;
16
16
  export declare const isApiRoute: (file: string) => boolean;
17
17
  export declare const isApiUse: (file: string) => boolean;
18
18
  export declare const isPageRoute: (file: string) => boolean;
19
19
  export declare const isPageLayout: (file: string) => boolean;
20
- export declare const createRouteEntry: (fileFullpath: string, sourceFolder: SourceFolder) => RouteEntry | undefined;
20
+ export declare const createRouteEntry: (projectSettings: ProjectSettings, sourceFolder: SourceFolder, fileFullpath: string) => RouteEntry | undefined;
21
21
  /**
22
22
  * Compare two route entries for registration order.
23
23
  *
@@ -1,9 +1,9 @@
1
- import { type RouteResolverCacheFactory, type SourceFolder } from "@kosmojs/core";
1
+ import { type ProjectSettings, type RouteResolverCacheFactory, type SourceFolder } from "@kosmojs/core";
2
2
  import { type ResolverSignature } from "./base";
3
3
  export * from "./base";
4
4
  export * from "./nesting";
5
5
  export * from "./paths";
6
- export declare const routesFactory: (sourceFolder: SourceFolder, cacheFactory?: RouteResolverCacheFactory) => Promise<{
6
+ export declare const routesFactory: (projectSettings: ProjectSettings, sourceFolder: SourceFolder, cacheFactory?: RouteResolverCacheFactory) => Promise<{
7
7
  resolvers: Map<string, ResolverSignature>;
8
8
  resolversFactory: (routeFiles: Array<string>) => Map<string, ResolverSignature>;
9
9
  }>;
@@ -1,3 +1,3 @@
1
- import { type RouteEntry, type RouteResolverCacheFactory, type SourceFolder } from "@kosmojs/core";
1
+ import { type ProjectSettings, type RouteEntry, type RouteResolverCacheFactory, type SourceFolder } from "@kosmojs/core";
2
2
  import type { ResolverSignature } from "./base";
3
- export declare const resolverFactory: (sourceFolder: SourceFolder, cacheFactory?: RouteResolverCacheFactory) => Record<"pageLayoutResolver" | "pageRouteResolver" | "apiUseResolver" | "apiRouteResolver", (entry: RouteEntry) => ResolverSignature>;
3
+ export declare const resolverFactory: (projectSettings: ProjectSettings, sourceFolder: SourceFolder, cacheFactory?: RouteResolverCacheFactory) => Record<"pageLayoutResolver" | "pageRouteResolver" | "apiUseResolver" | "apiRouteResolver", (entry: RouteEntry) => ResolverSignature>;
package/pkg/vite.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { Plugin } from "vite";
2
- import { type ProjectSettings, type SourceFolder } from "@kosmojs/core";
2
+ import type { ChassisCommand, ProjectSettings, SourceFolder } from "@kosmojs/core";
3
3
  /**
4
4
  * Resolves Kosmo's generated import prefixes to absolute file paths.
5
5
  *
@@ -52,7 +52,7 @@ import { type ProjectSettings, type SourceFolder } from "@kosmojs/core";
52
52
  * tsconfig generator uses, so alias resolution here can never drift from the
53
53
  * paths that were written into the generated tsconfig.
54
54
  * */
55
- export declare const tsconfigPaths: (sourceFolder: SourceFolder) => Plugin;
55
+ export declare const tsconfigPaths: (projectSettings: ProjectSettings, sourceFolder: SourceFolder) => Plugin;
56
56
  declare const nodePrefix: () => Plugin;
57
57
  /**
58
58
  * Resolves the CSR/SSR variant of env-sensitive modules.
@@ -68,13 +68,14 @@ declare const nodePrefix: () => Plugin;
68
68
  *
69
69
  * Generators declare their modules via `factory.virtualModules()`.
70
70
  * */
71
- export declare const virtualModules: (sourceFolder: SourceFolder, { kind, command, }: {
71
+ export declare const virtualModules: (projectSettings: ProjectSettings, sourceFolder: SourceFolder, { kind, command }: {
72
72
  kind: "csr" | "ssr";
73
- command: ProjectSettings["command"];
73
+ command: ChassisCommand;
74
74
  }) => Plugin;
75
75
  export declare const vitePlugins: {
76
76
  tsconfigPaths: typeof tsconfigPaths;
77
77
  nodePrefix: typeof nodePrefix;
78
78
  virtualModules: typeof virtualModules;
79
79
  };
80
+ export declare const cacheDir: ({ root }: ProjectSettings, { name }: SourceFolder, target: `frontend:${ChassisCommand}` | `backend:${ChassisCommand}` | "sidecar") => string;
80
81
  export {};