@kosmojs/lib 0.5.0 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,16 +1,23 @@
1
1
  # @kosmojs/lib
2
2
 
3
- TODO: Add package description
3
+ Internal toolkit shared by the CLI and the generators.
4
4
 
5
- ## Installation
5
+ ## Scope
6
6
 
7
- ```sh
8
- npm install -D @kosmojs/lib
9
- ```
7
+ Published because [`@kosmojs/cli`](https://www.npmjs.com/package/@kosmojs/cli),
8
+ [`@kosmojs/dev`](https://www.npmjs.com/package/@kosmojs/dev) and the generators depend on it - **not** intended for direct use.
9
+ It carries no stability guarantee across releases and can change shape in a patch.
10
+
11
+ It holds the pieces those packages need in common: TypeScript AST helpers for resolving validation types,
12
+ the generator base and file-deployment helpers, path and route utilities, the Handlebars render layer, and Vite helpers.
13
+
14
+ If you are writing a generator, depend on the documented contract in `@kosmojs/core/generators` instead.
10
15
 
11
16
  ## Documentation
12
17
 
13
- See [kosmojs.dev](https://kosmojs.dev)
18
+ - [Why code generation](https://kosmojs.dev/essentials/why-codegen.html)
19
+
20
+ Full documentation at [kosmojs.dev](https://kosmojs.dev).
14
21
 
15
22
  ## License
16
23
 
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@kosmojs/lib",
4
- "version": "0.5.0",
4
+ "version": "0.6.2",
5
+ "description": "Shared internals for the KosmoJS CLI and generators (not a public API)",
5
6
  "author": "Slee Woo",
6
7
  "license": "MIT",
7
8
  "repository": {
@@ -16,14 +17,16 @@
16
17
  ".": {
17
18
  "types": "./pkg/index.d.ts",
18
19
  "default": "./pkg/index.js"
19
- }
20
+ },
21
+ "./package.json": "./package.json"
20
22
  },
21
23
  "dependencies": {
22
- "@kosmojs/core": "^0.5.0",
24
+ "@kosmojs/core": "^0.6.2",
23
25
  "@topcli/spinner": "^5.0.0",
24
26
  "crc": "^4.3.2",
25
- "handlebars": "^4.7.9",
27
+ "handlebars": "^4.7.10",
26
28
  "mrmime": "^2.0.1",
29
+ "oxfmt": "^0.72.0",
27
30
  "path-to-regexp": "^8.4.2",
28
31
  "picomatch": "^4.0.7",
29
32
  "tfusion": "^0.2.2",
@@ -32,11 +35,11 @@
32
35
  },
33
36
  "devDependencies": {
34
37
  "@koa/router": "^15.7.0",
35
- "@kosmojs/lib": "^0.5.0",
38
+ "@kosmojs/lib": "^0.6.2",
36
39
  "@types/picomatch": "^4.0.3",
37
- "hono": "^4.13.7",
38
- "rou3": "^0.9.2",
39
- "vite": "^8.2.2"
40
+ "hono": "^4.13.13",
41
+ "rou3": "^1.0.0",
42
+ "vite": "^8.3.4"
40
43
  },
41
44
  "scripts": {
42
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>;
@@ -0,0 +1,2 @@
1
+ import { type FormatConfig } from "oxfmt";
2
+ export declare const formatCode: (code: string, filename: string, config?: FormatConfig) => Promise<string>;
@@ -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;
4
- }) => [R] extends [true] ? ((o: O) => GeneratorSignature<O>) & Pick<GeneratorSignature, "meta" | "dependencies" | "devDependencies"> : ((o?: O) => GeneratorSignature<O>) & Pick<GeneratorSignature<O>, "meta" | "dependencies" | "devDependencies">;
5
- export declare const defineGeneratorFactory: <O extends object>(factory: (f: SourceFolder, o?: O) => GeneratorFactory) => (f: SourceFolder, o?: O) => GeneratorFactory;
3
+ factory: (s: ProjectSettings, f: SourceFolder, o?: O) => GeneratorFactory;
4
+ }) => [R] extends [true] ? (o: O) => GeneratorSignature<O> : (o?: O) => GeneratorSignature<O>;
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,20 @@
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";
11
+ export * from "./format";
2
12
  export * from "./generators";
3
13
  export * from "./generic";
4
14
  export * from "./paths";
15
+ export * from "./ports";
5
16
  export * from "./render";
6
17
  export * from "./routes";
7
18
  export * from "./spinner";
19
+ export * from "./tsconfig";
8
20
  export * from "./vite";
package/pkg/index.js CHANGED
@@ -1,14 +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";
13
+ import { format } from "oxfmt";
14
+ import net from "node:net";
12
15
  import picomatch from "picomatch";
13
16
  import { glob } from "tinyglobby";
14
17
  import { compile, parse as parse$1 } from "path-to-regexp";
@@ -24,15 +27,27 @@ var escapeTemplateLiterals = (origin) => {
24
27
  var containsPathTraversalPatterns = (str) => {
25
28
  return [/\.\.\//, /\/\.\//].some((e) => e.test(str));
26
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
+ };
27
42
  //#endregion
28
43
  //#region src/paths.ts
29
- var pathResolver = (sourceFolder) => {
44
+ var pathResolver = ({ root, distDir = DEFAULT_DIST }, { name }) => {
30
45
  const createPath = (...a) => {
31
- return sourceFolder.root ? resolve(sourceFolder.root, join(...a)) : join(...a);
46
+ return root ? resolve(root, join(...a)) : join(...a);
32
47
  };
33
48
  const createImport = {
34
49
  src(a, { origin }) {
35
- 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);
36
51
  },
37
52
  api(a, o) {
38
53
  return this.src([defaults.apiDir, ...a], o);
@@ -44,7 +59,7 @@ var pathResolver = (sourceFolder) => {
44
59
  return this.src([defaults.pagesDir, ...a], o);
45
60
  },
46
61
  lib(a, { origin }) {
47
- 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);
48
63
  },
49
64
  libCore(a, o) {
50
65
  return this.lib(["core", ...a], o);
@@ -59,7 +74,7 @@ var pathResolver = (sourceFolder) => {
59
74
  return {
60
75
  createPath: {
61
76
  src(...a) {
62
- return createPath(defaults.srcDir, sourceFolder.name, ...a);
77
+ return createPath(defaults.srcDir, name, ...a);
63
78
  },
64
79
  api(...a) {
65
80
  return this.src(defaults.apiDir, ...a);
@@ -71,7 +86,7 @@ var pathResolver = (sourceFolder) => {
71
86
  return this.src(defaults.entryDir, ...a);
72
87
  },
73
88
  lib(...a) {
74
- return createPath(defaults.libDir, sourceFolder.name, ...a);
89
+ return createPath(defaults.libDir, name, ...a);
75
90
  },
76
91
  libCore(...a) {
77
92
  return this.lib("core", ...a);
@@ -86,7 +101,7 @@ var pathResolver = (sourceFolder) => {
86
101
  return this.lib(defaults.pagesDir, ...a);
87
102
  },
88
103
  distDir(...a) {
89
- return createPath(sourceFolder.distDir, sourceFolder.name, ...a);
104
+ return createPath(distDir, name, ...a);
90
105
  }
91
106
  },
92
107
  createImport,
@@ -446,15 +461,15 @@ var astFactory = () => {
446
461
  const extractGenerics = (callExpression) => {
447
462
  return callExpression.getTypeArguments();
448
463
  };
449
- const typeResolverFactory = (sourceFolder) => {
450
- const { createPath } = pathResolver(sourceFolder);
464
+ const typeResolverFactory = (projectSettings, sourceFolder) => {
465
+ const { createPath } = pathResolver(projectSettings, sourceFolder);
451
466
  const project = createProject({ compilerOptions: {
452
467
  moduleResolution: ModuleResolutionKind.Bundler,
453
468
  types: [],
454
469
  noLib: true,
455
470
  skipLibCheck: true,
456
471
  paths: {
457
- [`${defaults.appPrefix}/*`]: [`${sourceFolder.root}/*`],
472
+ [`${defaults.appPrefix}/*`]: [`${projectSettings.root}/*`],
458
473
  [`${defaults.srcPrefix}/*`]: [createPath.src("*")],
459
474
  [`${defaults.libPrefix}/*`]: [createPath.lib("*")]
460
475
  }
@@ -625,23 +640,27 @@ var renderTypeboxSchema = (typeNode, refineTypeName = defaults.refineTypeName) =
625
640
  return escapeTemplateLiterals(traverse(typeNode));
626
641
  };
627
642
  //#endregion
643
+ //#region src/format.ts
644
+ var formatCode = async (code, filename, config) => {
645
+ return format(filename, code, {
646
+ sortImports: true,
647
+ ...config
648
+ }).then((e) => e.errors.length ? code : e.code);
649
+ };
650
+ //#endregion
628
651
  //#region src/generators.ts
629
652
  var defineGenerator = ({ meta, factory, dependencies, devDependencies }) => {
630
- const wrapper = ((options) => {
653
+ return ((options) => {
631
654
  return {
632
655
  meta,
633
- factory: (folder) => factory(folder, options),
656
+ factory: (settings, folder) => {
657
+ return factory(settings, folder, options);
658
+ },
634
659
  dependencies,
635
660
  devDependencies,
636
661
  options
637
662
  };
638
663
  });
639
- Object.assign(wrapper, {
640
- meta,
641
- dependencies,
642
- devDependencies
643
- });
644
- return wrapper;
645
664
  };
646
665
  var defineGeneratorFactory = (factory) => factory;
647
666
  /**
@@ -680,6 +699,51 @@ var createWatchedPageRouteEntriesFilter = (event, eventsOfInterest) => {
680
699
  };
681
700
  };
682
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
683
747
  //#region src/routes/paths.ts
684
748
  /**
685
749
  * Parse a filesystem route path into structured PathToken array.
@@ -813,7 +877,7 @@ var createH3Pattern = (tokens) => {
813
877
  return tokens.flatMap((t) => {
814
878
  if (t.type === "text") return t.value === "/" ? [] : [escapeStatic(t.value)];
815
879
  if (t.type === "param") return [`:${t.name}`];
816
- if (t.type === "wildcard") return [`/**:${t.name}?`];
880
+ if (t.type === "wildcard") return [`/**:${t.name}`];
817
881
  if (t.type === "group") return [`{${tokensToPattern(t.tokens)}}?`];
818
882
  return [];
819
883
  }).join("");
@@ -851,8 +915,8 @@ var ROUTE_FILE_PATTERNS = [
851
915
  `${defaults.pagesDir}/**/${PAGE_INDEX_PATTERN}`,
852
916
  `${defaults.pagesDir}/**/${PAGE_LAYOUT_PATTERN}`
853
917
  ];
854
- var scanRoutes = async (sourceFolder) => {
855
- const { createPath } = pathResolver(sourceFolder);
918
+ var scanRoutes = async (projectSettings, sourceFolder) => {
919
+ const { createPath } = pathResolver(projectSettings, sourceFolder);
856
920
  return glob(ROUTE_FILE_PATTERNS, {
857
921
  cwd: createPath.src(),
858
922
  absolute: true,
@@ -866,8 +930,8 @@ var scanRoutes = async (sourceFolder) => {
866
930
  ]
867
931
  });
868
932
  };
869
- var isRouteFile = (file, sourceFolder) => {
870
- 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("/");
871
935
  /**
872
936
  * Ensure the file:
873
937
  * - is under the correct source root
@@ -889,8 +953,8 @@ var isPageRoute = (file) => {
889
953
  var isPageLayout = (file) => {
890
954
  return picomatch.matchBase(file, `**/${PAGE_LAYOUT_PATTERN}`);
891
955
  };
892
- var createRouteEntry = (fileFullpath, sourceFolder) => {
893
- const resolvedPaths = isRouteFile(fileFullpath, sourceFolder);
956
+ var createRouteEntry = (projectSettings, sourceFolder, fileFullpath) => {
957
+ const resolvedPaths = isRouteFile(projectSettings, sourceFolder, fileFullpath);
894
958
  if (!resolvedPaths) return;
895
959
  const [folder, file] = resolvedPaths;
896
960
  const id = `${file.replace(/\W+/g, "_")}_${crc(file)}`;
@@ -999,12 +1063,12 @@ var sortRoutesForResolution = (a, b) => {
999
1063
  };
1000
1064
  //#endregion
1001
1065
  //#region src/routes/resolve.ts
1002
- var resolverFactory = (sourceFolder, cacheFactory) => {
1003
- const { generators } = sourceFolder.config;
1066
+ var resolverFactory = (projectSettings, sourceFolder, cacheFactory) => {
1067
+ const { generators } = sourceFolder;
1004
1068
  const { refineTypeName = defaults.refineTypeName } = typeof sourceFolder.config.validation === "object" ? { ...sourceFolder.config.validation } : {};
1005
1069
  const { typeResolverFactory, resolveRouteSignature } = astFactory();
1006
1070
  const resolveTypes = generators.some(({ meta }) => meta.resolveTypes);
1007
- const { literalTypesResolver, getSourceFile, refreshSourceFile } = typeResolverFactory(sourceFolder);
1071
+ const { literalTypesResolver, getSourceFile, refreshSourceFile } = typeResolverFactory(projectSettings, sourceFolder);
1008
1072
  return {
1009
1073
  pageLayoutResolver(entry) {
1010
1074
  const { name } = entry;
@@ -1067,11 +1131,11 @@ var resolverFactory = (sourceFolder, cacheFactory) => {
1067
1131
  });
1068
1132
  });
1069
1133
  const optionalParams = paramsSchema.length ? paramsSchema.filter((e) => e.kind === "required").length === 0 : true;
1070
- const cacheStore = cacheFactory ? cacheFactory({
1134
+ const cacheStore = cacheFactory ? cacheFactory(projectSettings, sourceFolder, {
1071
1135
  id,
1072
1136
  file,
1073
1137
  fileFullpath
1074
- }, sourceFolder, { resolveTypes }) : void 0;
1138
+ }, { resolveTypes }) : void 0;
1075
1139
  let cache = cacheStore ? await cacheStore.get({ validate: true }) : void 0;
1076
1140
  if (!cache) {
1077
1141
  if (updatedFile === fileFullpath) await refreshSourceFile(fileFullpath);
@@ -1095,7 +1159,7 @@ var resolverFactory = (sourceFolder, cacheFactory) => {
1095
1159
  }] : [];
1096
1160
  }) : [def.schema];
1097
1161
  });
1098
- const typesFile = pathResolver(sourceFolder).createPath.libApi(dirname(file), "types.ts");
1162
+ const typesFile = pathResolver(projectSettings, sourceFolder).createPath.libApi(dirname(file), "types.ts");
1099
1163
  const params = {
1100
1164
  id: ["ParamsT", crc(name)].join(""),
1101
1165
  schema: paramsSchema,
@@ -1208,7 +1272,7 @@ var resolverFactory = (sourceFolder, cacheFactory) => {
1208
1272
  methods: cache.methods,
1209
1273
  typeDeclarations: cache.typeDeclarations,
1210
1274
  validationDefinitions,
1211
- referencedFiles: Object.keys(cache.referencedFiles).map((e) => resolve(sourceFolder.root, e))
1275
+ referencedFiles: Object.keys(cache.referencedFiles).map((e) => resolve(projectSettings.root, e))
1212
1276
  }
1213
1277
  };
1214
1278
  };
@@ -1288,12 +1352,12 @@ var nestedRoutesFactory = (routeEntries) => {
1288
1352
  };
1289
1353
  //#endregion
1290
1354
  //#region src/routes/index.ts
1291
- var routesFactory = async (sourceFolder, cacheFactory) => {
1292
- 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);
1293
1357
  const resolversFactory = (routeFiles) => {
1294
1358
  const resolvers = /* @__PURE__ */ new Map();
1295
1359
  const entries = routeFiles.flatMap((file) => {
1296
- const entry = createRouteEntry(file, sourceFolder);
1360
+ const entry = createRouteEntry(projectSettings, sourceFolder, file);
1297
1361
  return entry ? [entry] : [];
1298
1362
  });
1299
1363
  for (const entry of entries) if (entry.folder === defaults.apiDir) {
@@ -1306,7 +1370,7 @@ var routesFactory = async (sourceFolder, cacheFactory) => {
1306
1370
  return resolvers;
1307
1371
  };
1308
1372
  return {
1309
- resolvers: resolversFactory(await scanRoutes(sourceFolder)),
1373
+ resolvers: resolversFactory(await scanRoutes(projectSettings, sourceFolder)),
1310
1374
  resolversFactory
1311
1375
  };
1312
1376
  };
@@ -1341,6 +1405,70 @@ var spinnerFactory = (startText) => {
1341
1405
  };
1342
1406
  };
1343
1407
  //#endregion
1408
+ //#region src/tsconfig.ts
1409
+ var generateTsconfig = ({ dependencies, devDependencies }, sourceFolder) => {
1410
+ const rootDir = "${configDir}";
1411
+ const deps = Object.keys({
1412
+ ...dependencies,
1413
+ ...devDependencies
1414
+ });
1415
+ const compilerOptions = {
1416
+ types: ["vite/client", ...[
1417
+ "node",
1418
+ "deno",
1419
+ "bun"
1420
+ ].flatMap((e) => {
1421
+ return deps.includes(`@types/${e}`) ? [`@types/${e}`] : [];
1422
+ })],
1423
+ moduleResolution: "bundler",
1424
+ module: "ESNext",
1425
+ target: "ESNext",
1426
+ strict: true,
1427
+ exactOptionalPropertyTypes: true,
1428
+ noImplicitAny: true,
1429
+ noImplicitThis: true,
1430
+ noImplicitOverride: true,
1431
+ noImplicitReturns: true,
1432
+ noUnusedLocals: false,
1433
+ noUnusedParameters: false,
1434
+ allowArbitraryExtensions: true,
1435
+ allowImportingTsExtensions: true,
1436
+ allowUnreachableCode: false,
1437
+ allowUnusedLabels: false,
1438
+ useUnknownInCatchVariables: true,
1439
+ noFallthroughCasesInSwitch: true,
1440
+ noUncheckedSideEffectImports: true,
1441
+ resolveJsonModule: true,
1442
+ esModuleInterop: true,
1443
+ verbatimModuleSyntax: true,
1444
+ skipLibCheck: true,
1445
+ noEmit: true
1446
+ };
1447
+ if (sourceFolder) return {
1448
+ include: [
1449
+ `${rootDir}/`,
1450
+ `${rootDir}/../../${defaults.libDir}/${sourceFolder}/`,
1451
+ `${rootDir}/../../${defaults.libDir}/*.d.ts`
1452
+ ],
1453
+ compilerOptions: {
1454
+ ...compilerOptions,
1455
+ types: [...compilerOptions.types],
1456
+ paths: {
1457
+ [`${defaults.appPrefix}/*`]: [`${rootDir}/../../*`],
1458
+ [`${defaults.srcPrefix}/*`]: [`${rootDir}/*`],
1459
+ [`${defaults.libPrefix}/*`]: [`${rootDir}/../../${defaults.libDir}/${sourceFolder}/*`]
1460
+ }
1461
+ }
1462
+ };
1463
+ return {
1464
+ exclude: [`${rootDir}/${defaults.srcDir}/`],
1465
+ compilerOptions: {
1466
+ ...compilerOptions,
1467
+ paths: { [`${defaults.appPrefix}/*`]: [`${rootDir}/*`] }
1468
+ }
1469
+ };
1470
+ };
1471
+ //#endregion
1344
1472
  //#region src/vite.ts
1345
1473
  /**
1346
1474
  * Resolves Kosmo's generated import prefixes to absolute file paths.
@@ -1394,7 +1522,7 @@ var spinnerFactory = (startText) => {
1394
1522
  * tsconfig generator uses, so alias resolution here can never drift from the
1395
1523
  * paths that were written into the generated tsconfig.
1396
1524
  * */
1397
- var tsconfigPaths = (sourceFolder) => {
1525
+ var tsconfigPaths = (projectSettings, sourceFolder) => {
1398
1526
  /**
1399
1527
  * Candidate extensions for an extensionless specifier, in resolution priority order.
1400
1528
  * Mirrors the renderable file types the generators emit;
@@ -1412,11 +1540,11 @@ var tsconfigPaths = (sourceFolder) => {
1412
1540
  ".mdx",
1413
1541
  ".json"
1414
1542
  ];
1415
- const { createPath } = pathResolver(sourceFolder);
1543
+ const { createPath } = pathResolver(projectSettings, sourceFolder);
1416
1544
  const table = [
1417
1545
  [`${defaults.srcPrefix}/`, createPath.src()],
1418
1546
  [`${defaults.libPrefix}/`, createPath.lib()],
1419
- [`${defaults.appPrefix}/`, sourceFolder.root]
1547
+ [`${defaults.appPrefix}/`, projectSettings.root]
1420
1548
  ];
1421
1549
  const resolveWithin = async (baseDir, rest) => {
1422
1550
  const target = join(baseDir, rest);
@@ -1463,14 +1591,15 @@ var nodePrefix = () => {
1463
1591
  *
1464
1592
  * Generators declare their modules via `factory.virtualModules()`.
1465
1593
  * */
1466
- var virtualModules = (sourceFolder, { kind, command }) => {
1594
+ var virtualModules = (projectSettings, sourceFolder, { kind, command }) => {
1467
1595
  /**
1468
1596
  * Rollup's / Rolldown's convention for ids owned by a plugin:
1469
1597
  * the NUL prefix keeps other plugins and Node resolution from touching them.
1470
1598
  * */
1471
1599
  const VIRTUAL_PREFIX = "\0";
1472
- const modules = sourceFolder.config.generators.flatMap(({ factory }) => {
1473
- return factory(sourceFolder).virtualModules?.() || [];
1600
+ const modules = sourceFolder.generators.flatMap(({ factory }) => {
1601
+ const { virtualModules } = factory(projectSettings, sourceFolder);
1602
+ return virtualModules ? virtualModules(command) : [];
1474
1603
  });
1475
1604
  const virtualSources = /* @__PURE__ */ new Map();
1476
1605
  for (const { specifier, csr, ssr } of modules) virtualSources.set(specifier, {
@@ -1503,7 +1632,21 @@ var vitePlugins = {
1503
1632
  var isFile = async (path) => {
1504
1633
  return stat(path).then((e) => e.isFile()).catch(() => false);
1505
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"));
1506
1649
  //#endregion
1507
- 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, 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 };
1508
1651
 
1509
1652
  //# sourceMappingURL=index.js.map