@kosmojs/dev 0.1.9 → 0.2.1

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/dev",
4
- "version": "0.1.9",
4
+ "version": "0.2.1",
5
5
  "cacheVersion": "001",
6
6
  "author": "Slee Woo",
7
7
  "license": "MIT",
@@ -21,21 +21,22 @@
21
21
  },
22
22
  "dependencies": {
23
23
  "crc": "^4.3.2",
24
- "vite": "^8.1.4",
25
- "@kosmojs/core-generator": "^0.1.9",
26
- "@kosmojs/core": "^0.1.9",
27
- "@kosmojs/lib": "^0.1.9",
28
- "@kosmojs/fetch-generator": "^0.1.9",
29
- "@kosmojs/hono-generator": "^0.1.9",
30
- "@kosmojs/openapi-generator": "^0.1.9",
31
- "@kosmojs/react-generator": "^0.1.9",
32
- "@kosmojs/mdx-generator": "^0.1.9",
33
- "@kosmojs/solid-generator": "^0.1.9",
34
- "@kosmojs/ssg-generator": "^0.1.9",
35
- "@kosmojs/ssr-generator": "^0.1.9",
36
- "@kosmojs/typebox-generator": "^0.1.9",
37
- "@kosmojs/vue-generator": "^0.1.9",
38
- "@kosmojs/koa-generator": "^0.1.9"
24
+ "vite": "^8.1.5",
25
+ "@kosmojs/core": "^0.2.1",
26
+ "@kosmojs/core-generator": "^0.2.1",
27
+ "@kosmojs/fetch-generator": "^0.2.1",
28
+ "@kosmojs/koa-generator": "^0.2.1",
29
+ "@kosmojs/hono-generator": "^0.2.1",
30
+ "@kosmojs/lib": "^0.2.1",
31
+ "@kosmojs/openapi-generator": "^0.2.1",
32
+ "@kosmojs/react-generator": "^0.2.1",
33
+ "@kosmojs/mdx-generator": "^0.2.1",
34
+ "@kosmojs/solid-generator": "^0.2.1",
35
+ "@kosmojs/ssg-generator": "^0.2.1",
36
+ "@kosmojs/ssr-generator": "^0.2.1",
37
+ "@kosmojs/typebox-generator": "^0.2.1",
38
+ "@kosmojs/vue-generator": "^0.2.1",
39
+ "@kosmojs/svelte-generator": "^0.2.1"
39
40
  },
40
41
  "scripts": {
41
42
  "build": "wsbuild src/index.ts src/chassis.ts"
package/pkg/chassis.js CHANGED
@@ -5,7 +5,7 @@ import { defaults } from "@kosmojs/core";
5
5
  import http from "node:http";
6
6
  import net from "node:net";
7
7
  import { build, createServer } from "vite";
8
- import { pathExists, pathResolver, routesFactory, spinnerFactory, vitePlugins } from "@kosmojs/lib";
8
+ import { mergeConfigs, pathExists, pathResolver, routesFactory, spinnerFactory, vitePlugins } from "@kosmojs/lib";
9
9
  import coreGenerator from "@kosmojs/core-generator";
10
10
  import { readFileSync } from "node:fs";
11
11
  import { mkdir, readFile, writeFile } from "node:fs/promises";
@@ -81,7 +81,6 @@ var chassis_default = async (projectSettings) => {
81
81
  }
82
82
  if (command === "build") {
83
83
  for (const sourceFolder of projectSettings.sourceFolders) {
84
- const { config } = sourceFolder;
85
84
  const { createPath } = pathResolver(sourceFolder);
86
85
  const resolvedRoutes = [];
87
86
  {
@@ -94,55 +93,37 @@ var chassis_default = async (projectSettings) => {
94
93
  spinner.succeed("ready ✨");
95
94
  }
96
95
  const generators = folderGenerators(sourceFolder);
97
- const plugins = [vitePlugins.tsconfigPaths(sourceFolder), ...config.plugins || []];
98
- for (const base of generators) {
99
- await base.factory(sourceFolder).build?.(resolvedRoutes);
100
- plugins.push(...base.plugins?.(sourceFolder, command) || []);
101
- }
102
- {
103
- const outDir = createPath.distDir("client");
104
- await build({
105
- ...config,
106
- configFile: false,
107
- root: createPath.src(),
108
- base: join(config.base, "/"),
109
- plugins,
110
- resolve: { ...config.resolve },
111
- build: {
112
- ...config?.build,
113
- outDir,
114
- manifest: true,
115
- emptyOutDir: true
116
- },
117
- cacheDir: cacheDir(sourceFolder, command, "client")
96
+ for (const generator of generators) await generator.factory(sourceFolder).build?.(resolvedRoutes);
97
+ const plugins = [vitePlugins.tsconfigPaths(sourceFolder), vitePlugins.nodePrefix()];
98
+ await build(mergeConfigs(sourceFolder.config, ...generators.map(({ factory }) => {
99
+ return factory(sourceFolder).config?.({
100
+ kind: "client",
101
+ command
118
102
  });
119
- }
103
+ }), {
104
+ root: createPath.src(),
105
+ cacheDir: cacheDir(sourceFolder, command, "client"),
106
+ plugins,
107
+ build: {
108
+ outDir: createPath.distDir("client"),
109
+ manifest: true,
110
+ emptyOutDir: true
111
+ }
112
+ }));
120
113
  const apiGenerator = generators.find((e) => e.meta.slot === "api");
121
114
  if (apiGenerator) {
122
115
  const dir = createPath.distDir("api");
123
- const apiGeneratorOptions = { ...apiGenerator.options };
124
- const { emitAssets = false } = apiGeneratorOptions;
125
- const externalizeOptions = Object.entries(apiGeneratorOptions).flatMap(([k, v]) => {
126
- return k === "external" || k === "noExternal" ? [[k, v]] : [];
127
- });
128
- await build({
116
+ await build(mergeConfigs(apiGenerator.options, apiGenerator.factory(sourceFolder).config?.({
117
+ kind: "backend",
118
+ command
119
+ }), {
129
120
  base: "./",
130
- configFile: false,
131
121
  root: createPath.src(),
132
122
  appType: "custom",
133
- plugins: [vitePlugins.tsconfigPaths(sourceFolder), ...apiGenerator.plugins?.(sourceFolder, command) || []],
134
- define: {
135
- ...config.define,
136
- KOSMO_PRODUCTION_BUILD: "true"
137
- },
138
- ssr: externalizeOptions.length ? Object.fromEntries(externalizeOptions) : { external: true },
139
- resolve: {
140
- ...config.resolve,
141
- conditions: ["node"]
142
- },
123
+ plugins,
124
+ resolve: { conditions: ["node"] },
143
125
  build: {
144
126
  ssr: true,
145
- ssrEmitAssets: emitAssets,
146
127
  target: "esnext",
147
128
  sourcemap: true,
148
129
  emptyOutDir: true,
@@ -154,13 +135,10 @@ var chassis_default = async (projectSettings) => {
154
135
  }
155
136
  }
156
137
  },
157
- experimental: { renderBuiltUrl(filename, { type }) {
158
- return type === "asset" ? filename : void 0;
159
- } },
160
138
  cacheDir: cacheDir(sourceFolder, command, "backend")
161
- });
139
+ }));
162
140
  }
163
- for (const base of generators) await base.factory(sourceFolder).postBuild?.(resolvedRoutes);
141
+ for (const generator of generators) await generator.factory(sourceFolder).postBuild?.(resolvedRoutes);
164
142
  }
165
143
  return async () => {};
166
144
  }
@@ -170,77 +148,72 @@ var chassis_default = async (projectSettings) => {
170
148
  for (const sourceFolder of projectSettings.sourceFolders) eventMap[sourceFolder.name] = await eventFactory(sourceFolder);
171
149
  let port = await findFreePort(devPort);
172
150
  for (const sourceFolder of projectSettings.sourceFolders) {
173
- const { config } = sourceFolder;
174
151
  const { createPath } = pathResolver(sourceFolder);
175
152
  const requestMatchers = matchersFactory(sourceFolder);
176
153
  const generators = folderGenerators(sourceFolder);
177
- const plugins = [vitePlugins.tsconfigPaths(sourceFolder), ...config.plugins || []];
178
- for (const base of generators) plugins.push(...base.plugins?.(sourceFolder, command) || []);
179
- const viteServer = await createServer({
180
- ...config,
181
- configFile: false,
182
- root: createPath.src(),
183
- base: join(config.base, "/"),
184
- plugins,
185
- server: {
186
- ...config.server,
187
- port: port++,
188
- middlewareMode: true,
189
- hmr: { port: port++ }
190
- },
191
- resolve: { ...config.resolve },
192
- define: { ...config.define },
193
- cacheDir: cacheDir(sourceFolder, command, "client")
194
- });
195
- for (const [evt, handler] of Object.entries(eventMap[sourceFolder.name])) viteServer.watcher.on(evt, handler);
196
- requestHandlers.push([
197
- [sourceFolder.config.base],
198
- () => requestMatchers.base,
199
- () => viteServer.middlewares
200
- ]);
201
- teardownHandlers.push(viteServer.close);
202
- }
203
- for (const sourceFolder of projectSettings.sourceFolders) {
204
- const { config } = sourceFolder;
205
- if (!folderGenerators(sourceFolder).find((e) => e.meta.slot === "api")) continue;
206
- const { createPath } = pathResolver(sourceFolder);
207
- const requestMatchers = matchersFactory(sourceFolder);
208
- const viteServer = await createServer({
209
- configFile: false,
210
- root: createPath.src(),
211
- appType: "custom",
212
- plugins: [vitePlugins.tsconfigPaths(sourceFolder)],
213
- server: {
214
- port: port++,
215
- middlewareMode: true,
216
- hmr: { port: port++ }
217
- },
218
- define: {
219
- ...config?.define,
220
- KOSMO_PRODUCTION_BUILD: "false"
221
- },
222
- environments: { api: { resolve: { conditions: ["node"] } } },
223
- cacheDir: cacheDir(sourceFolder, command, "backend")
224
- });
225
- const env = viteServer.environments.api;
226
- const loadDevSetup = async () => {
227
- env.runner.clearCache();
228
- return env.runner.import(join(defaults.apiDir, "dev.ts")).then((e) => e.default);
229
- };
230
- let devSetup = await loadDevSetup();
231
- for (const [evt, handler] of Object.entries(eventMap[sourceFolder.name])) viteServer.watcher.on(evt, async (file) => {
232
- if (env.moduleGraph.getModulesByFile(file)?.size) {
233
- await handler(file);
234
- await devSetup?.teardownHandler?.();
235
- devSetup = await loadDevSetup();
236
- }
237
- });
238
- requestHandlers.push([
239
- [sourceFolder.config.base, sourceFolder.config.apiBase],
240
- () => devSetup.requestMatcher || requestMatchers.api,
241
- () => devSetup.requestHandler()
242
- ]);
243
- teardownHandlers.push(viteServer.close);
154
+ const plugins = [vitePlugins.tsconfigPaths(sourceFolder), vitePlugins.nodePrefix()];
155
+ {
156
+ const viteServer = await createServer(mergeConfigs(sourceFolder.config, ...generators.map(({ factory }) => {
157
+ return factory(sourceFolder).config?.({
158
+ kind: "client",
159
+ command
160
+ });
161
+ }), {
162
+ root: createPath.src(),
163
+ cacheDir: cacheDir(sourceFolder, command, "client"),
164
+ plugins,
165
+ server: {
166
+ port: port++,
167
+ middlewareMode: true,
168
+ hmr: { port: port++ }
169
+ }
170
+ }));
171
+ for (const [evt, handler] of Object.entries(eventMap[sourceFolder.name])) viteServer.watcher.on(evt, handler);
172
+ requestHandlers.push([
173
+ [sourceFolder.config.base],
174
+ () => requestMatchers.base,
175
+ () => viteServer.middlewares
176
+ ]);
177
+ teardownHandlers.push(viteServer.close);
178
+ }
179
+ const apiGenerator = generators.find((e) => e.meta.slot === "api");
180
+ if (apiGenerator) {
181
+ const viteServer = await createServer(mergeConfigs(apiGenerator.options, apiGenerator.factory(sourceFolder).config?.({
182
+ kind: "backend",
183
+ command
184
+ }), {
185
+ root: createPath.src(),
186
+ appType: "custom",
187
+ cacheDir: cacheDir(sourceFolder, command, "backend"),
188
+ plugins,
189
+ server: {
190
+ port: port++,
191
+ middlewareMode: true,
192
+ hmr: { port: port++ }
193
+ },
194
+ resolve: { conditions: ["node"] },
195
+ environments: { api: { resolve: { conditions: ["node"] } } }
196
+ }));
197
+ const env = viteServer.environments.api;
198
+ const loadDevSetup = async () => {
199
+ env.runner.clearCache();
200
+ return env.runner.import(join(defaults.apiDir, "dev.ts")).then((e) => e.default);
201
+ };
202
+ let devSetup = await loadDevSetup();
203
+ for (const [evt, handler] of Object.entries(eventMap[sourceFolder.name])) viteServer.watcher.on(evt, async (file) => {
204
+ if (env.moduleGraph.getModulesByFile(file)?.size) {
205
+ await handler(file);
206
+ await devSetup?.teardownHandler?.();
207
+ devSetup = await loadDevSetup();
208
+ }
209
+ });
210
+ requestHandlers.push([
211
+ [sourceFolder.config.base, sourceFolder.config.apiBase],
212
+ () => devSetup.requestMatcher || requestMatchers.api,
213
+ () => devSetup.requestHandler()
214
+ ]);
215
+ teardownHandlers.push(viteServer.close);
216
+ }
244
217
  }
245
218
  /**
246
219
  * Sorting is essential to ensure more specific paths are matched before broader ones.
@@ -1 +1 @@
1
- {"version":3,"file":"chassis.js","names":[],"sources":["../src/cache.ts","../src/chassis.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport { dirname, resolve } from \"node:path\";\n\nimport crc from \"crc/crc32\";\n\nimport type {\n RouteResolverCache,\n RouteResolverCacheFactory,\n} from \"@kosmojs/core\";\nimport { pathExists, pathResolver } from \"@kosmojs/lib\";\n\n/**\n * Read the installed package.json at runtime to get the actual version.\n * A static `import ... with { type: \"json\" }` would be inlined by the\n * bundler with the pre-bump version, defeating the point.\n * */\nconst self = JSON.parse(\n readFileSync(\n createRequire(import.meta.url).resolve(\"@kosmojs/dev/package.json\"),\n \"utf-8\",\n ),\n);\n\nexport const cacheFactory: RouteResolverCacheFactory = (\n route,\n sourceFolder,\n extraContext,\n) => {\n const cacheFile = pathResolver(sourceFolder).createPath.libApi(\n dirname(route.file),\n \"cache.json\",\n );\n\n const validateCache = async (cache: RouteResolverCache) => {\n if (!cache?.hash) {\n return;\n }\n\n if (!cache.typeDeclarations || !cache.referencedFiles) {\n // incomplete cache\n return;\n }\n\n const hash = await generateFileHash(route.fileFullpath, {\n ...extraContext,\n });\n\n if (!identicalHashSum(cache.hash, hash)) {\n // route itself updated\n return;\n }\n\n for (const [file, hash] of Object.entries(cache.referencedFiles)) {\n if (\n !identicalHashSum(\n hash,\n await generateFileHash(resolve(sourceFolder.root, file)),\n )\n ) {\n // some referenced file updated\n return;\n }\n }\n\n return cache;\n };\n\n return {\n async get(opt?: { validate?: boolean }) {\n if (await pathExists(cacheFile)) {\n try {\n const cache = JSON.parse(await readFile(cacheFile, \"utf8\"));\n return opt?.validate //\n ? validateCache(cache)\n : cache;\n } catch (_e) {}\n }\n return undefined;\n },\n\n async set(cache) {\n const hash = await generateFileHash(route.fileFullpath, {\n ...extraContext,\n });\n\n const referencedFiles: Record<string, number> = {};\n\n for (const file of cache.referencedFiles) {\n referencedFiles[\n // Strip project root to ensure cached paths are relative\n // and portable across environments (CI, local, etc.)\n file.replace(`${sourceFolder.root}/`, \"\")\n ] = await generateFileHash(file);\n }\n\n const value = { ...cache, hash, referencedFiles };\n\n await mkdir(dirname(cacheFile), { recursive: true });\n await writeFile(cacheFile, JSON.stringify(value, null, 2), \"utf8\");\n\n return value;\n },\n };\n};\n\nconst generateFileHash = async (\n file: string,\n extraContext?: object,\n): Promise<number> => {\n let fileContent: string | undefined;\n try {\n fileContent = await readFile(file, \"utf8\");\n } catch (_e) {\n // file could be deleted since last build\n return 0;\n }\n return fileContent\n ? crc(\n JSON.stringify({\n ...extraContext,\n [self.cacheVersion]: fileContent,\n }),\n )\n : 0;\n};\n\n// return true if sums are identical\nconst identicalHashSum = (a: number, b: number) => {\n return a === b;\n};\n","import http, { type IncomingMessage, type ServerResponse } from \"node:http\";\nimport net from \"node:net\";\nimport { join, resolve } from \"node:path\";\nimport { styleText } from \"node:util\";\n\nimport { build, createServer, type RunnableDevEnvironment } from \"vite\";\n\nimport {\n defaults,\n type GeneratorBase,\n type GeneratorFactoryInstance,\n type GeneratorMeta,\n type ProjectSettings,\n type ResolvedEntry,\n type SourceFolder,\n type WatcherEvent,\n} from \"@kosmojs/core\";\nimport type { DevSetup } from \"@kosmojs/core/api\";\nimport {\n pathResolver,\n routesFactory,\n spinnerFactory,\n vitePlugins,\n} from \"@kosmojs/lib\";\n\nimport coreGenerator from \"@kosmojs/core-generator\";\n\nimport { cacheFactory } from \"./cache\";\n\nexport default async (\n projectSettings: ProjectSettings,\n): Promise<() => Promise<void>> => {\n const { devPort, command } = projectSettings;\n\n // NOTE: initialize generators before anything else, regardless command\n for (const sourceFolder of projectSettings.sourceFolders) {\n for (const base of folderGenerators(sourceFolder)) {\n if (!base.meta?.name || typeof base.factory !== \"function\") {\n throw new Error(\n `${sourceFolder.name}: Unrecognized generator - must be created via defineGenerator()`,\n );\n }\n\n const factory = base.factory(sourceFolder);\n\n if (!factory.meta?.name) {\n throw new Error(\n `${sourceFolder.name}: ${base.meta.name} generator is missing meta property`,\n );\n }\n\n try {\n await factory.start?.();\n } catch (error) {\n console.error(\n styleText(\n \"red\",\n `${sourceFolder.name}: ${base.meta.name} generator failed to initialize`,\n ),\n );\n throw error;\n }\n }\n }\n\n if (command === \"build\") {\n for (const sourceFolder of projectSettings.sourceFolders) {\n const { config } = sourceFolder;\n const { createPath } = pathResolver(sourceFolder);\n\n const resolvedRoutes = [];\n\n {\n const { resolvers } = await routesFactory(sourceFolder, cacheFactory);\n\n const spinner = spinnerFactory(\n `${sourceFolder.name}: resolving routes`,\n );\n\n for (const { name, handler } of resolvers.values()) {\n spinner.append(\n `[ ${resolvedRoutes.length + 1} of ${resolvers.size} ] ${name}`,\n );\n resolvedRoutes.push(await handler());\n }\n\n spinner.succeed(\"ready ✨\");\n }\n\n const generators = folderGenerators(sourceFolder);\n\n const plugins = [\n vitePlugins.tsconfigPaths(sourceFolder),\n ...(config.plugins || []),\n ];\n\n for (const base of generators) {\n await base.factory(sourceFolder).build?.(resolvedRoutes);\n plugins.push(...(base.plugins?.(sourceFolder, command) || []));\n }\n\n // build client\n {\n const outDir = createPath.distDir(\"client\");\n\n await build({\n ...config,\n configFile: false,\n root: createPath.src(),\n base: join(config.base, \"/\"),\n plugins,\n resolve: { ...config.resolve },\n build: {\n ...config?.build,\n outDir,\n manifest: true,\n emptyOutDir: true,\n },\n cacheDir: cacheDir(sourceFolder, command, \"client\"),\n });\n }\n\n // build backend\n const apiGenerator = generators.find((e) => e.meta.slot === \"api\");\n\n if (apiGenerator) {\n const dir = createPath.distDir(\"api\");\n\n const apiGeneratorOptions = { ...apiGenerator.options };\n const { emitAssets = false } = apiGeneratorOptions;\n\n const externalizeOptions = Object.entries(apiGeneratorOptions).flatMap(\n ([k, v]) => {\n return k === \"external\" || k === \"noExternal\" ? [[k, v]] : [];\n },\n );\n\n await build({\n base: \"./\",\n configFile: false,\n root: createPath.src(),\n appType: \"custom\",\n plugins: [\n vitePlugins.tsconfigPaths(sourceFolder),\n ...(apiGenerator.plugins?.(sourceFolder, command) || []),\n ],\n define: {\n ...config.define,\n KOSMO_PRODUCTION_BUILD: \"true\",\n },\n ssr: externalizeOptions.length\n ? Object.fromEntries(externalizeOptions)\n : { external: true },\n resolve: {\n ...config.resolve,\n conditions: [\"node\"],\n },\n build: {\n ssr: true,\n ssrEmitAssets: emitAssets as boolean,\n target: \"esnext\",\n sourcemap: true,\n emptyOutDir: true,\n rolldownOptions: {\n input: [createPath.api(\"app.ts\"), createPath.api(\"server.ts\")],\n output: {\n dir,\n format: \"esm\",\n },\n },\n },\n experimental: {\n renderBuiltUrl(filename, { type }) {\n // emit bare relative asset paths (no leading \"/\") so call\n // sites can resolve them against import.meta.url at runtime.\n return type === \"asset\" ? filename : undefined;\n },\n },\n cacheDir: cacheDir(sourceFolder, command, \"backend\"),\n });\n }\n\n for (const base of generators) {\n await base.factory(sourceFolder).postBuild?.(resolvedRoutes);\n }\n }\n\n return async () => {};\n }\n\n type RequestMatcher = (req: IncomingMessage) => boolean;\n type RequestHandler = (req: IncomingMessage, res: ServerResponse) => void;\n\n const requestHandlers: Array<\n [\n segments: [base: string, api?: string],\n matcherFactory: () => RequestMatcher,\n handlerFactory: () => RequestHandler,\n ]\n > = [];\n\n const teardownHandlers: Array<() => Promise<unknown>> = [];\n\n const eventMap: Record<string, Awaited<ReturnType<typeof eventFactory>>> = {};\n\n // WARN: call this before starting any server!\n for (const sourceFolder of projectSettings.sourceFolders) {\n eventMap[sourceFolder.name] = await eventFactory(sourceFolder);\n }\n\n let port = await findFreePort(devPort);\n\n // start client servers\n for (const sourceFolder of projectSettings.sourceFolders) {\n const { config } = sourceFolder;\n\n const { createPath } = pathResolver(sourceFolder);\n const requestMatchers = matchersFactory(sourceFolder);\n\n const generators = folderGenerators(sourceFolder);\n\n const plugins = [\n vitePlugins.tsconfigPaths(sourceFolder),\n ...(config.plugins || []),\n ];\n\n for (const base of generators) {\n plugins.push(...(base.plugins?.(sourceFolder, command) || []));\n }\n\n const viteServer = await createServer({\n ...config,\n configFile: false,\n root: createPath.src(),\n base: join(config.base, \"/\"),\n plugins,\n server: {\n ...config.server,\n port: port++,\n middlewareMode: true,\n hmr: { port: port++ },\n },\n resolve: {\n ...config.resolve,\n },\n define: {\n ...config.define,\n },\n cacheDir: cacheDir(sourceFolder, command, \"client\"),\n });\n\n for (const [evt, handler] of Object.entries(eventMap[sourceFolder.name])) {\n viteServer.watcher.on(evt, handler);\n }\n\n requestHandlers.push([\n [sourceFolder.config.base],\n () => requestMatchers.base,\n () => viteServer.middlewares,\n ]);\n\n teardownHandlers.push(viteServer.close);\n }\n\n // start backend servers\n for (const sourceFolder of projectSettings.sourceFolders) {\n const { config } = sourceFolder;\n\n if (!folderGenerators(sourceFolder).find((e) => e.meta.slot === \"api\")) {\n continue;\n }\n\n const { createPath } = pathResolver(sourceFolder);\n\n const requestMatchers = matchersFactory(sourceFolder);\n\n const viteServer = await createServer({\n configFile: false,\n root: createPath.src(),\n appType: \"custom\",\n plugins: [vitePlugins.tsconfigPaths(sourceFolder)],\n server: {\n port: port++,\n middlewareMode: true,\n hmr: { port: port++ },\n },\n define: {\n ...config?.define,\n KOSMO_PRODUCTION_BUILD: \"false\",\n },\n environments: {\n api: {\n resolve: {\n conditions: [\"node\"],\n },\n },\n },\n cacheDir: cacheDir(sourceFolder, command, \"backend\"),\n });\n\n const env = viteServer.environments.api as RunnableDevEnvironment;\n\n const loadDevSetup = async () => {\n env.runner.clearCache();\n return env.runner\n .import<{ default: DevSetup }>(join(defaults.apiDir, \"dev.ts\"))\n .then((e) => e.default);\n };\n\n let devSetup = await loadDevSetup();\n\n for (const [evt, handler] of Object.entries(eventMap[sourceFolder.name])) {\n viteServer.watcher.on(evt, async (file) => {\n const mods = env.moduleGraph.getModulesByFile(file);\n if (mods?.size) {\n await handler(file);\n await devSetup?.teardownHandler?.();\n devSetup = await loadDevSetup();\n }\n });\n }\n\n requestHandlers.push([\n [sourceFolder.config.base, sourceFolder.config.apiBase],\n () => devSetup.requestMatcher || requestMatchers.api,\n () => devSetup.requestHandler(),\n ]);\n\n teardownHandlers.push(viteServer.close);\n }\n\n /**\n * Sorting is essential to ensure more specific paths are matched before broader ones.\n *\n * Given source folders:\n * - main app: baseurl=/ apiurl=/api\n * - admin app: baseurl=/admin apiurl=/admin/api\n *\n * Correct sort order:\n * 1. /admin/api — most specific\n * 2. /api\n * 3. /admin\n * 4. /\n * */\n const requestHandlerWeight = ([\n segments,\n ]: (typeof requestHandlers)[number]) => {\n const [base, api] = segments;\n /**\n * set weight to number of non-empty segments:\n * \"/\" weight is 0\n * \"/admin\" weight is 1\n * */\n const weight = base.split(\"/\").filter(Boolean).length;\n return api ? weight + 5 : weight;\n };\n\n const handlers = requestHandlers.sort(\n (a, b) => requestHandlerWeight(b) - requestHandlerWeight(a),\n );\n\n const httpServer = http.createServer((req, res) => {\n for (const [, matcherFactory, handlerFactory] of handlers) {\n // should be called on every request\n const [matcher, handler] = [matcherFactory(), handlerFactory()];\n if (matcher(req)) {\n handler(req, res);\n return;\n }\n }\n res.writeHead(404, { \"Content-Type\": \"text/html\" });\n res.end(\"<h1>404: Not Found</h1>\");\n });\n\n httpServer.on(\"error\", (error) => {\n console.error(\n styleText(\"red\", `Failed to start dev server on port ${devPort}`),\n );\n console.error(error.message);\n process.exit(1);\n });\n\n httpServer.listen(devPort);\n\n teardownHandlers.push(async () => {\n httpServer.close();\n });\n\n return async () => {\n for (const handler of teardownHandlers) {\n await handler();\n }\n // Let chokidar fully release file handles\n await new Promise((resolve) => setTimeout(resolve, 100));\n };\n};\n\nconst cacheDir = (\n { root, name }: SourceFolder,\n command: ProjectSettings[\"command\"],\n mode: \"client\" | \"backend\",\n) => {\n return resolve(root, `var/.vite/${name}/${command}/${mode}`);\n};\n\nconst folderGenerators = (sourceFolder: SourceFolder): Array<GeneratorBase> => {\n const { generators = [] } = sourceFolder.config;\n\n const coreGenerators: Partial<\n Record<NonNullable<GeneratorMeta[\"slot\"]>, GeneratorBase>\n > = {};\n\n const userGenerators: Array<GeneratorBase> = [];\n\n for (const base of generators) {\n if (base.meta.slot) {\n coreGenerators[base.meta.slot] = base;\n } else {\n userGenerators.push(base);\n }\n }\n\n return [\n // core generator should run first\n coreGenerator(),\n // then api generator\n ...(coreGenerators.api ? [coreGenerators.api] : []),\n // then fetch generator, only if api generator also enabled\n ...(coreGenerators.fetch && coreGenerators.api\n ? [coreGenerators.fetch]\n : []),\n // then user generators in the order they were added\n ...userGenerators,\n // then ssr generator should run after user generators\n ...(coreGenerators.ssr ? [coreGenerators.ssr] : []),\n // and ssg generator should run last\n ...(coreGenerators.ssg ? [coreGenerators.ssg] : []),\n ];\n};\n\nconst eventFactory = async (\n sourceFolder: SourceFolder,\n): Promise<\n Record<\"add\" | \"change\" | \"unlink\", (f: string) => Promise<void>>\n> => {\n const { resolvers, resolversFactory } = await routesFactory(\n sourceFolder,\n cacheFactory,\n );\n\n const { createPath } = pathResolver(sourceFolder);\n\n const generators: Array<{\n name: string | undefined;\n factory: GeneratorFactoryInstance;\n }> = [];\n\n for (const base of folderGenerators(sourceFolder)) {\n const factory = base.factory(sourceFolder);\n generators.push({ name: base.meta.name, factory });\n }\n\n const resolvedRoutes = new Map<\n string, // fileFullpath\n ResolvedEntry\n >();\n\n const runGenerators = async (event?: WatcherEvent) => {\n /**\n * Watch handlers receive the full list of entries\n * and should process only those whose source file or dependencies were updated.\n * */\n const entries = Array.from(resolvedRoutes.values());\n\n for (const { name, factory } of generators) {\n try {\n await factory.watch?.(entries, event);\n } catch (error) {\n console.error(\n styleText(\"red\", `${sourceFolder.name}: ${name} generator failed`),\n );\n if (event) {\n console.error(event);\n }\n console.error(error);\n }\n }\n };\n\n const updateResolvedEntry = async (file: string) => {\n const resolver = resolvers.get(file);\n\n if (!resolver) {\n return;\n }\n\n try {\n const resolvedEntry = await resolver.handler(file);\n resolvedRoutes.set(resolvedEntry.entry.fileFullpath, resolvedEntry);\n return resolvedEntry;\n } catch (error) {\n const route = file.replace(`${createPath.api()}/`, \"\");\n console.error(\n styleText(\n \"red\",\n `${sourceFolder.name}: ${route} route resolution failed`,\n ),\n );\n console.error(error);\n return;\n }\n };\n\n {\n const spinner = spinnerFactory(`${sourceFolder.name}: resolving routes`);\n for (const { name, handler } of resolvers.values()) {\n spinner.append(\n `[ ${resolvedRoutes.size + 1} of ${resolvers.size} ] ${name}`,\n );\n const route = await handler();\n resolvedRoutes.set(route.entry.fileFullpath, route);\n }\n spinner.succeed(\"ready ✨\");\n }\n\n // NOTE: call only after routes resolved\n await runGenerators();\n\n return {\n async add(file: string) {\n const [resolver] = resolversFactory([file]).values();\n\n if (!resolver) {\n return;\n }\n\n resolvers.set(file, resolver);\n\n // call only after `resolvers.set(file)`\n const resolvedEntry = await updateResolvedEntry(file);\n\n if (resolvedEntry) {\n await runGenerators({ kind: \"create\", file });\n }\n },\n\n async change(file: string) {\n if (resolvedRoutes.has(file)) {\n // route updated\n await updateResolvedEntry(file);\n } else {\n // updating entries that are referencing updated file\n const relatedRoutes = resolvedRoutes\n .values()\n .flatMap(({ kind, entry }) => {\n return kind === \"apiRoute\"\n ? entry.referencedFiles.includes(file)\n ? [entry]\n : []\n : [];\n });\n\n for (const route of relatedRoutes) {\n await updateResolvedEntry(route.fileFullpath);\n }\n }\n\n await runGenerators({ kind: \"update\", file });\n },\n\n async unlink(file) {\n // route deleted\n resolvers.delete(file);\n resolvedRoutes.delete(file);\n await runGenerators({ kind: \"delete\", file });\n },\n };\n};\n\nconst matchersFactory: (\n sourceFolder: SourceFolder,\n) => Record<\"base\" | \"api\", (req: IncomingMessage) => boolean> = ({\n config,\n}) => {\n const basePattern = new RegExp(`^${config.base}($|/*)`);\n const apiPattern = new RegExp(`^${join(config.base, config.apiBase)}($|/*)`);\n return {\n base(req) {\n return apiPattern.test(req.url as string)\n ? false\n : basePattern.test(req.url as string);\n },\n api(req) {\n return apiPattern.test(req.url as string);\n },\n };\n};\n\nconst findFreePort = async (devPort: number): Promise<number> => {\n let minPort = 0;\n let maxPort = 0;\n\n for (const n of [3, 2, 1, \"\"]) {\n minPort = Number(`${n}${devPort}`) + 100;\n maxPort = minPort + 100;\n if (maxPort < 65000) {\n break;\n }\n }\n\n if (maxPort >= 65000) {\n throw new Error(\"the devPort in package.json should be less than 64000\");\n }\n\n const range = maxPort - minPort + 1;\n const startOffset = Math.floor(Math.random() * range);\n\n const ports = Array.from({ length: range }, (_, i) => {\n return minPort + ((startOffset + i) % range);\n });\n\n const freePort = await ports.reduce(\n async (prevPromise, port) => {\n const freePort = await prevPromise;\n if (freePort) {\n return freePort;\n }\n const isFree = await isPortFree(port);\n return isFree ? port : undefined;\n },\n Promise.resolve(undefined as number | undefined),\n );\n\n if (!freePort) {\n throw new Error(`No free ports found in range ${minPort}-${maxPort}`);\n }\n\n return freePort;\n};\n\nconst isPortFree = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", () => resolve(false));\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port, \"127.0.0.1\");\n });\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAkBA,IAAM,OAAO,KAAK,MAChB,aACE,cAAc,OAAO,KAAK,GAAG,CAAC,CAAC,QAAQ,2BAA2B,GAClE,OACF,CACF;AAEA,IAAa,gBACX,OACA,cACA,iBACG;CACH,MAAM,YAAY,aAAa,YAAY,CAAC,CAAC,WAAW,OACtD,QAAQ,MAAM,IAAI,GAClB,YACF;CAEA,MAAM,gBAAgB,OAAO,UAA8B;EACzD,IAAI,CAAC,OAAO,MACV;EAGF,IAAI,CAAC,MAAM,oBAAoB,CAAC,MAAM,iBAEpC;EAGF,MAAM,OAAO,MAAM,iBAAiB,MAAM,cAAc,EACtD,GAAG,aACL,CAAC;EAED,IAAI,CAAC,iBAAiB,MAAM,MAAM,IAAI,GAEpC;EAGF,KAAK,MAAM,CAAC,MAAM,SAAS,OAAO,QAAQ,MAAM,eAAe,GAC7D,IACE,CAAC,iBACC,MACA,MAAM,iBAAiB,QAAQ,aAAa,MAAM,IAAI,CAAC,CACzD,GAGA;EAIJ,OAAO;CACT;CAEA,OAAO;EACL,MAAM,IAAI,KAA8B;GACtC,IAAI,MAAM,WAAW,SAAS,GAC5B,IAAI;IACF,MAAM,QAAQ,KAAK,MAAM,MAAM,SAAS,WAAW,MAAM,CAAC;IAC1D,OAAO,KAAK,WACR,cAAc,KAAK,IACnB;GACN,SAAS,IAAI,CAAC;EAGlB;EAEA,MAAM,IAAI,OAAO;GACf,MAAM,OAAO,MAAM,iBAAiB,MAAM,cAAc,EACtD,GAAG,aACL,CAAC;GAED,MAAM,kBAA0C,CAAC;GAEjD,KAAK,MAAM,QAAQ,MAAM,iBACvB,gBAGE,KAAK,QAAQ,GAAG,aAAa,KAAK,IAAI,EAAE,KACtC,MAAM,iBAAiB,IAAI;GAGjC,MAAM,QAAQ;IAAE,GAAG;IAAO;IAAM;GAAgB;GAEhD,MAAM,MAAM,QAAQ,SAAS,GAAG,EAAE,WAAW,KAAK,CAAC;GACnD,MAAM,UAAU,WAAW,KAAK,UAAU,OAAO,MAAM,CAAC,GAAG,MAAM;GAEjE,OAAO;EACT;CACF;AACF;AAEA,IAAM,mBAAmB,OACvB,MACA,iBACoB;CACpB,IAAI;CACJ,IAAI;EACF,cAAc,MAAM,SAAS,MAAM,MAAM;CAC3C,SAAS,IAAI;EAEX,OAAO;CACT;CACA,OAAO,cACH,IACE,KAAK,UAAU;EACb,GAAG;GACF,KAAK,eAAe;CACvB,CAAC,CACH,IACA;AACN;AAGA,IAAM,oBAAoB,GAAW,MAAc;CACjD,OAAO,MAAM;AACf;;;ACtGA,IAAA,kBAAe,OACb,oBACiC;CACjC,MAAM,EAAE,SAAS,YAAY;CAG7B,KAAK,MAAM,gBAAgB,gBAAgB,eACzC,KAAK,MAAM,QAAQ,iBAAiB,YAAY,GAAG;EACjD,IAAI,CAAC,KAAK,MAAM,QAAQ,OAAO,KAAK,YAAY,YAC9C,MAAM,IAAI,MACR,GAAG,aAAa,KAAK,iEACvB;EAGF,MAAM,UAAU,KAAK,QAAQ,YAAY;EAEzC,IAAI,CAAC,QAAQ,MAAM,MACjB,MAAM,IAAI,MACR,GAAG,aAAa,KAAK,IAAI,KAAK,KAAK,KAAK,oCAC1C;EAGF,IAAI;GACF,MAAM,QAAQ,QAAQ;EACxB,SAAS,OAAO;GACd,QAAQ,MACN,UACE,OACA,GAAG,aAAa,KAAK,IAAI,KAAK,KAAK,KAAK,gCAC1C,CACF;GACA,MAAM;EACR;CACF;CAGF,IAAI,YAAY,SAAS;EACvB,KAAK,MAAM,gBAAgB,gBAAgB,eAAe;GACxD,MAAM,EAAE,WAAW;GACnB,MAAM,EAAE,eAAe,aAAa,YAAY;GAEhD,MAAM,iBAAiB,CAAC;GAExB;IACE,MAAM,EAAE,cAAc,MAAM,cAAc,cAAc,YAAY;IAEpE,MAAM,UAAU,eACd,GAAG,aAAa,KAAK,mBACvB;IAEA,KAAK,MAAM,EAAE,MAAM,aAAa,UAAU,OAAO,GAAG;KAClD,QAAQ,OACN,KAAK,eAAe,SAAS,EAAE,MAAM,UAAU,KAAK,KAAK,MAC3D;KACA,eAAe,KAAK,MAAM,QAAQ,CAAC;IACrC;IAEA,QAAQ,QAAQ,SAAS;GAC3B;GAEA,MAAM,aAAa,iBAAiB,YAAY;GAEhD,MAAM,UAAU,CACd,YAAY,cAAc,YAAY,GACtC,GAAI,OAAO,WAAW,CAAC,CACzB;GAEA,KAAK,MAAM,QAAQ,YAAY;IAC7B,MAAM,KAAK,QAAQ,YAAY,CAAC,CAAC,QAAQ,cAAc;IACvD,QAAQ,KAAK,GAAI,KAAK,UAAU,cAAc,OAAO,KAAK,CAAC,CAAE;GAC/D;GAGA;IACE,MAAM,SAAS,WAAW,QAAQ,QAAQ;IAE1C,MAAM,MAAM;KACV,GAAG;KACH,YAAY;KACZ,MAAM,WAAW,IAAI;KACrB,MAAM,KAAK,OAAO,MAAM,GAAG;KAC3B;KACA,SAAS,EAAE,GAAG,OAAO,QAAQ;KAC7B,OAAO;MACL,GAAG,QAAQ;MACX;MACA,UAAU;MACV,aAAa;KACf;KACA,UAAU,SAAS,cAAc,SAAS,QAAQ;IACpD,CAAC;GACH;GAGA,MAAM,eAAe,WAAW,MAAM,MAAM,EAAE,KAAK,SAAS,KAAK;GAEjE,IAAI,cAAc;IAChB,MAAM,MAAM,WAAW,QAAQ,KAAK;IAEpC,MAAM,sBAAsB,EAAE,GAAG,aAAa,QAAQ;IACtD,MAAM,EAAE,aAAa,UAAU;IAE/B,MAAM,qBAAqB,OAAO,QAAQ,mBAAmB,CAAC,CAAC,SAC5D,CAAC,GAAG,OAAO;KACV,OAAO,MAAM,cAAc,MAAM,eAAe,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;IAC9D,CACF;IAEA,MAAM,MAAM;KACV,MAAM;KACN,YAAY;KACZ,MAAM,WAAW,IAAI;KACrB,SAAS;KACT,SAAS,CACP,YAAY,cAAc,YAAY,GACtC,GAAI,aAAa,UAAU,cAAc,OAAO,KAAK,CAAC,CACxD;KACA,QAAQ;MACN,GAAG,OAAO;MACV,wBAAwB;KAC1B;KACA,KAAK,mBAAmB,SACpB,OAAO,YAAY,kBAAkB,IACrC,EAAE,UAAU,KAAK;KACrB,SAAS;MACP,GAAG,OAAO;MACV,YAAY,CAAC,MAAM;KACrB;KACA,OAAO;MACL,KAAK;MACL,eAAe;MACf,QAAQ;MACR,WAAW;MACX,aAAa;MACb,iBAAiB;OACf,OAAO,CAAC,WAAW,IAAI,QAAQ,GAAG,WAAW,IAAI,WAAW,CAAC;OAC7D,QAAQ;QACN;QACA,QAAQ;OACV;MACF;KACF;KACA,cAAc,EACZ,eAAe,UAAU,EAAE,QAAQ;MAGjC,OAAO,SAAS,UAAU,WAAW,KAAA;KACvC,EACF;KACA,UAAU,SAAS,cAAc,SAAS,SAAS;IACrD,CAAC;GACH;GAEA,KAAK,MAAM,QAAQ,YACjB,MAAM,KAAK,QAAQ,YAAY,CAAC,CAAC,YAAY,cAAc;EAE/D;EAEA,OAAO,YAAY,CAAC;CACtB;CAKA,MAAM,kBAMF,CAAC;CAEL,MAAM,mBAAkD,CAAC;CAEzD,MAAM,WAAqE,CAAC;CAG5E,KAAK,MAAM,gBAAgB,gBAAgB,eACzC,SAAS,aAAa,QAAQ,MAAM,aAAa,YAAY;CAG/D,IAAI,OAAO,MAAM,aAAa,OAAO;CAGrC,KAAK,MAAM,gBAAgB,gBAAgB,eAAe;EACxD,MAAM,EAAE,WAAW;EAEnB,MAAM,EAAE,eAAe,aAAa,YAAY;EAChD,MAAM,kBAAkB,gBAAgB,YAAY;EAEpD,MAAM,aAAa,iBAAiB,YAAY;EAEhD,MAAM,UAAU,CACd,YAAY,cAAc,YAAY,GACtC,GAAI,OAAO,WAAW,CAAC,CACzB;EAEA,KAAK,MAAM,QAAQ,YACjB,QAAQ,KAAK,GAAI,KAAK,UAAU,cAAc,OAAO,KAAK,CAAC,CAAE;EAG/D,MAAM,aAAa,MAAM,aAAa;GACpC,GAAG;GACH,YAAY;GACZ,MAAM,WAAW,IAAI;GACrB,MAAM,KAAK,OAAO,MAAM,GAAG;GAC3B;GACA,QAAQ;IACN,GAAG,OAAO;IACV,MAAM;IACN,gBAAgB;IAChB,KAAK,EAAE,MAAM,OAAO;GACtB;GACA,SAAS,EACP,GAAG,OAAO,QACZ;GACA,QAAQ,EACN,GAAG,OAAO,OACZ;GACA,UAAU,SAAS,cAAc,SAAS,QAAQ;EACpD,CAAC;EAED,KAAK,MAAM,CAAC,KAAK,YAAY,OAAO,QAAQ,SAAS,aAAa,KAAK,GACrE,WAAW,QAAQ,GAAG,KAAK,OAAO;EAGpC,gBAAgB,KAAK;GACnB,CAAC,aAAa,OAAO,IAAI;SACnB,gBAAgB;SAChB,WAAW;EACnB,CAAC;EAED,iBAAiB,KAAK,WAAW,KAAK;CACxC;CAGA,KAAK,MAAM,gBAAgB,gBAAgB,eAAe;EACxD,MAAM,EAAE,WAAW;EAEnB,IAAI,CAAC,iBAAiB,YAAY,CAAC,CAAC,MAAM,MAAM,EAAE,KAAK,SAAS,KAAK,GACnE;EAGF,MAAM,EAAE,eAAe,aAAa,YAAY;EAEhD,MAAM,kBAAkB,gBAAgB,YAAY;EAEpD,MAAM,aAAa,MAAM,aAAa;GACpC,YAAY;GACZ,MAAM,WAAW,IAAI;GACrB,SAAS;GACT,SAAS,CAAC,YAAY,cAAc,YAAY,CAAC;GACjD,QAAQ;IACN,MAAM;IACN,gBAAgB;IAChB,KAAK,EAAE,MAAM,OAAO;GACtB;GACA,QAAQ;IACN,GAAG,QAAQ;IACX,wBAAwB;GAC1B;GACA,cAAc,EACZ,KAAK,EACH,SAAS,EACP,YAAY,CAAC,MAAM,EACrB,EACF,EACF;GACA,UAAU,SAAS,cAAc,SAAS,SAAS;EACrD,CAAC;EAED,MAAM,MAAM,WAAW,aAAa;EAEpC,MAAM,eAAe,YAAY;GAC/B,IAAI,OAAO,WAAW;GACtB,OAAO,IAAI,OACR,OAA8B,KAAK,SAAS,QAAQ,QAAQ,CAAC,CAAC,CAC9D,MAAM,MAAM,EAAE,OAAO;EAC1B;EAEA,IAAI,WAAW,MAAM,aAAa;EAElC,KAAK,MAAM,CAAC,KAAK,YAAY,OAAO,QAAQ,SAAS,aAAa,KAAK,GACrE,WAAW,QAAQ,GAAG,KAAK,OAAO,SAAS;GAEzC,IADa,IAAI,YAAY,iBAAiB,IAC1C,CAAA,EAAM,MAAM;IACd,MAAM,QAAQ,IAAI;IAClB,MAAM,UAAU,kBAAkB;IAClC,WAAW,MAAM,aAAa;GAChC;EACF,CAAC;EAGH,gBAAgB,KAAK;GACnB,CAAC,aAAa,OAAO,MAAM,aAAa,OAAO,OAAO;SAChD,SAAS,kBAAkB,gBAAgB;SAC3C,SAAS,eAAe;EAChC,CAAC;EAED,iBAAiB,KAAK,WAAW,KAAK;CACxC;;;;;;;;;;;;;;CAeA,MAAM,wBAAwB,CAC5B,cACsC;EACtC,MAAM,CAAC,MAAM,OAAO;;;;;;EAMpB,MAAM,SAAS,KAAK,MAAM,GAAG,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC;EAC/C,OAAO,MAAM,SAAS,IAAI;CAC5B;CAEA,MAAM,WAAW,gBAAgB,MAC9B,GAAG,MAAM,qBAAqB,CAAC,IAAI,qBAAqB,CAAC,CAC5D;CAEA,MAAM,aAAa,KAAK,cAAc,KAAK,QAAQ;EACjD,KAAK,MAAM,GAAG,gBAAgB,mBAAmB,UAAU;GAEzD,MAAM,CAAC,SAAS,WAAW,CAAC,eAAe,GAAG,eAAe,CAAC;GAC9D,IAAI,QAAQ,GAAG,GAAG;IAChB,QAAQ,KAAK,GAAG;IAChB;GACF;EACF;EACA,IAAI,UAAU,KAAK,EAAE,gBAAgB,YAAY,CAAC;EAClD,IAAI,IAAI,yBAAyB;CACnC,CAAC;CAED,WAAW,GAAG,UAAU,UAAU;EAChC,QAAQ,MACN,UAAU,OAAO,sCAAsC,SAAS,CAClE;EACA,QAAQ,MAAM,MAAM,OAAO;EAC3B,QAAQ,KAAK,CAAC;CAChB,CAAC;CAED,WAAW,OAAO,OAAO;CAEzB,iBAAiB,KAAK,YAAY;EAChC,WAAW,MAAM;CACnB,CAAC;CAED,OAAO,YAAY;EACjB,KAAK,MAAM,WAAW,kBACpB,MAAM,QAAQ;EAGhB,MAAM,IAAI,SAAS,YAAY,WAAW,SAAS,GAAG,CAAC;CACzD;AACF;AAEA,IAAM,YACJ,EAAE,MAAM,QACR,SACA,SACG;CACH,OAAO,QAAQ,MAAM,aAAa,KAAK,GAAG,QAAQ,GAAG,MAAM;AAC7D;AAEA,IAAM,oBAAoB,iBAAqD;CAC7E,MAAM,EAAE,aAAa,CAAC,MAAM,aAAa;CAEzC,MAAM,iBAEF,CAAC;CAEL,MAAM,iBAAuC,CAAC;CAE9C,KAAK,MAAM,QAAQ,YACjB,IAAI,KAAK,KAAK,MACZ,eAAe,KAAK,KAAK,QAAQ;MAEjC,eAAe,KAAK,IAAI;CAI5B,OAAO;EAEL,cAAc;EAEd,GAAI,eAAe,MAAM,CAAC,eAAe,GAAG,IAAI,CAAC;EAEjD,GAAI,eAAe,SAAS,eAAe,MACvC,CAAC,eAAe,KAAK,IACrB,CAAC;EAEL,GAAG;EAEH,GAAI,eAAe,MAAM,CAAC,eAAe,GAAG,IAAI,CAAC;EAEjD,GAAI,eAAe,MAAM,CAAC,eAAe,GAAG,IAAI,CAAC;CACnD;AACF;AAEA,IAAM,eAAe,OACnB,iBAGG;CACH,MAAM,EAAE,WAAW,qBAAqB,MAAM,cAC5C,cACA,YACF;CAEA,MAAM,EAAE,eAAe,aAAa,YAAY;CAEhD,MAAM,aAGD,CAAC;CAEN,KAAK,MAAM,QAAQ,iBAAiB,YAAY,GAAG;EACjD,MAAM,UAAU,KAAK,QAAQ,YAAY;EACzC,WAAW,KAAK;GAAE,MAAM,KAAK,KAAK;GAAM;EAAQ,CAAC;CACnD;CAEA,MAAM,iCAAiB,IAAI,IAGzB;CAEF,MAAM,gBAAgB,OAAO,UAAyB;;;;;EAKpD,MAAM,UAAU,MAAM,KAAK,eAAe,OAAO,CAAC;EAElD,KAAK,MAAM,EAAE,MAAM,aAAa,YAC9B,IAAI;GACF,MAAM,QAAQ,QAAQ,SAAS,KAAK;EACtC,SAAS,OAAO;GACd,QAAQ,MACN,UAAU,OAAO,GAAG,aAAa,KAAK,IAAI,KAAK,kBAAkB,CACnE;GACA,IAAI,OACF,QAAQ,MAAM,KAAK;GAErB,QAAQ,MAAM,KAAK;EACrB;CAEJ;CAEA,MAAM,sBAAsB,OAAO,SAAiB;EAClD,MAAM,WAAW,UAAU,IAAI,IAAI;EAEnC,IAAI,CAAC,UACH;EAGF,IAAI;GACF,MAAM,gBAAgB,MAAM,SAAS,QAAQ,IAAI;GACjD,eAAe,IAAI,cAAc,MAAM,cAAc,aAAa;GAClE,OAAO;EACT,SAAS,OAAO;GACd,MAAM,QAAQ,KAAK,QAAQ,GAAG,WAAW,IAAI,EAAE,IAAI,EAAE;GACrD,QAAQ,MACN,UACE,OACA,GAAG,aAAa,KAAK,IAAI,MAAM,yBACjC,CACF;GACA,QAAQ,MAAM,KAAK;GACnB;EACF;CACF;CAEA;EACE,MAAM,UAAU,eAAe,GAAG,aAAa,KAAK,mBAAmB;EACvE,KAAK,MAAM,EAAE,MAAM,aAAa,UAAU,OAAO,GAAG;GAClD,QAAQ,OACN,KAAK,eAAe,OAAO,EAAE,MAAM,UAAU,KAAK,KAAK,MACzD;GACA,MAAM,QAAQ,MAAM,QAAQ;GAC5B,eAAe,IAAI,MAAM,MAAM,cAAc,KAAK;EACpD;EACA,QAAQ,QAAQ,SAAS;CAC3B;CAGA,MAAM,cAAc;CAEpB,OAAO;EACL,MAAM,IAAI,MAAc;GACtB,MAAM,CAAC,YAAY,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO;GAEnD,IAAI,CAAC,UACH;GAGF,UAAU,IAAI,MAAM,QAAQ;GAK5B,IAAI,MAFwB,oBAAoB,IAAI,GAGlD,MAAM,cAAc;IAAE,MAAM;IAAU;GAAK,CAAC;EAEhD;EAEA,MAAM,OAAO,MAAc;GACzB,IAAI,eAAe,IAAI,IAAI,GAEzB,MAAM,oBAAoB,IAAI;QACzB;IAEL,MAAM,gBAAgB,eACnB,OAAO,CAAC,CACR,SAAS,EAAE,MAAM,YAAY;KAC5B,OAAO,SAAS,aACZ,MAAM,gBAAgB,SAAS,IAAI,IACjC,CAAC,KAAK,IACN,CAAC,IACH,CAAC;IACP,CAAC;IAEH,KAAK,MAAM,SAAS,eAClB,MAAM,oBAAoB,MAAM,YAAY;GAEhD;GAEA,MAAM,cAAc;IAAE,MAAM;IAAU;GAAK,CAAC;EAC9C;EAEA,MAAM,OAAO,MAAM;GAEjB,UAAU,OAAO,IAAI;GACrB,eAAe,OAAO,IAAI;GAC1B,MAAM,cAAc;IAAE,MAAM;IAAU;GAAK,CAAC;EAC9C;CACF;AACF;AAEA,IAAM,mBAE4D,EAChE,aACI;CACJ,MAAM,cAAc,IAAI,OAAO,IAAI,OAAO,KAAK,OAAO;CACtD,MAAM,aAAa,IAAI,OAAO,IAAI,KAAK,OAAO,MAAM,OAAO,OAAO,EAAE,OAAO;CAC3E,OAAO;EACL,KAAK,KAAK;GACR,OAAO,WAAW,KAAK,IAAI,GAAa,IACpC,QACA,YAAY,KAAK,IAAI,GAAa;EACxC;EACA,IAAI,KAAK;GACP,OAAO,WAAW,KAAK,IAAI,GAAa;EAC1C;CACF;AACF;AAEA,IAAM,eAAe,OAAO,YAAqC;CAC/D,IAAI,UAAU;CACd,IAAI,UAAU;CAEd,KAAK,MAAM,KAAK;EAAC;EAAG;EAAG;EAAG;CAAE,GAAG;EAC7B,UAAU,OAAO,GAAG,IAAI,SAAS,IAAI;EACrC,UAAU,UAAU;EACpB,IAAI,UAAU,MACZ;CAEJ;CAEA,IAAI,WAAW,MACb,MAAM,IAAI,MAAM,uDAAuD;CAGzE,MAAM,QAAQ,UAAU,UAAU;CAClC,MAAM,cAAc,KAAK,MAAM,KAAK,OAAO,IAAI,KAAK;CAMpD,MAAM,WAAW,MAJH,MAAM,KAAK,EAAE,QAAQ,MAAM,IAAI,GAAG,MAAM;EACpD,OAAO,WAAY,cAAc,KAAK;CACxC,CAEuB,CAAA,CAAM,OAC3B,OAAO,aAAa,SAAS;EAC3B,MAAM,WAAW,MAAM;EACvB,IAAI,UACF,OAAO;EAGT,OAAO,MADc,WAAW,IAAI,IACpB,OAAO,KAAA;CACzB,GACA,QAAQ,QAAQ,KAAA,CAA+B,CACjD;CAEA,IAAI,CAAC,UACH,MAAM,IAAI,MAAM,gCAAgC,QAAQ,GAAG,SAAS;CAGtE,OAAO;AACT;AAEA,IAAM,cAAc,SAAmC;CACrD,OAAO,IAAI,SAAS,YAAY;EAC9B,MAAM,SAAS,IAAI,aAAa;EAEhC,OAAO,KAAK,eAAe,QAAQ,KAAK,CAAC;EAEzC,OAAO,KAAK,mBAAmB;GAC7B,OAAO,MAAM;GACb,QAAQ,IAAI;EACd,CAAC;EAED,OAAO,OAAO,MAAM,WAAW;CACjC,CAAC;AACH"}
1
+ {"version":3,"file":"chassis.js","names":[],"sources":["../src/cache.ts","../src/chassis.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport { dirname, resolve } from \"node:path\";\n\nimport crc from \"crc/crc32\";\n\nimport type {\n RouteResolverCache,\n RouteResolverCacheFactory,\n} from \"@kosmojs/core\";\nimport { pathExists, pathResolver } from \"@kosmojs/lib\";\n\n/**\n * Read the installed package.json at runtime to get the actual version.\n * A static `import ... with { type: \"json\" }` would be inlined by the\n * bundler with the pre-bump version, defeating the point.\n * */\nconst self = JSON.parse(\n readFileSync(\n createRequire(import.meta.url).resolve(\"@kosmojs/dev/package.json\"),\n \"utf-8\",\n ),\n);\n\nexport const cacheFactory: RouteResolverCacheFactory = (\n route,\n sourceFolder,\n extraContext,\n) => {\n const cacheFile = pathResolver(sourceFolder).createPath.libApi(\n dirname(route.file),\n \"cache.json\",\n );\n\n const validateCache = async (cache: RouteResolverCache) => {\n if (!cache?.hash) {\n return;\n }\n\n if (!cache.typeDeclarations || !cache.referencedFiles) {\n // incomplete cache\n return;\n }\n\n const hash = await generateFileHash(route.fileFullpath, {\n ...extraContext,\n });\n\n if (!identicalHashSum(cache.hash, hash)) {\n // route itself updated\n return;\n }\n\n for (const [file, hash] of Object.entries(cache.referencedFiles)) {\n if (\n !identicalHashSum(\n hash,\n await generateFileHash(resolve(sourceFolder.root, file)),\n )\n ) {\n // some referenced file updated\n return;\n }\n }\n\n return cache;\n };\n\n return {\n async get(opt?: { validate?: boolean }) {\n if (await pathExists(cacheFile)) {\n try {\n const cache = JSON.parse(await readFile(cacheFile, \"utf8\"));\n return opt?.validate //\n ? validateCache(cache)\n : cache;\n } catch (_e) {}\n }\n return undefined;\n },\n\n async set(cache) {\n const hash = await generateFileHash(route.fileFullpath, {\n ...extraContext,\n });\n\n const referencedFiles: Record<string, number> = {};\n\n for (const file of cache.referencedFiles) {\n referencedFiles[\n // Strip project root to ensure cached paths are relative\n // and portable across environments (CI, local, etc.)\n file.replace(`${sourceFolder.root}/`, \"\")\n ] = await generateFileHash(file);\n }\n\n const value = { ...cache, hash, referencedFiles };\n\n await mkdir(dirname(cacheFile), { recursive: true });\n await writeFile(cacheFile, JSON.stringify(value, null, 2), \"utf8\");\n\n return value;\n },\n };\n};\n\nconst generateFileHash = async (\n file: string,\n extraContext?: object,\n): Promise<number> => {\n let fileContent: string | undefined;\n try {\n fileContent = await readFile(file, \"utf8\");\n } catch (_e) {\n // file could be deleted since last build\n return 0;\n }\n return fileContent\n ? crc(\n JSON.stringify({\n ...extraContext,\n [self.cacheVersion]: fileContent,\n }),\n )\n : 0;\n};\n\n// return true if sums are identical\nconst identicalHashSum = (a: number, b: number) => {\n return a === b;\n};\n","import http, { type IncomingMessage, type ServerResponse } from \"node:http\";\nimport net from \"node:net\";\nimport { join, resolve } from \"node:path\";\nimport { styleText } from \"node:util\";\n\nimport { build, createServer, type RunnableDevEnvironment } from \"vite\";\n\nimport {\n defaults,\n type GeneratorBase,\n type GeneratorFactoryInstance,\n type GeneratorMeta,\n type ProjectSettings,\n type ResolvedEntry,\n type SourceFolder,\n type WatcherEvent,\n} from \"@kosmojs/core\";\nimport type { DevSetup } from \"@kosmojs/core/api\";\nimport {\n mergeConfigs,\n pathResolver,\n routesFactory,\n spinnerFactory,\n vitePlugins,\n} from \"@kosmojs/lib\";\n\nimport coreGenerator from \"@kosmojs/core-generator\";\n\nimport { cacheFactory } from \"./cache\";\n\nexport default async (\n projectSettings: ProjectSettings,\n): Promise<() => Promise<void>> => {\n const { devPort, command } = projectSettings;\n\n // NOTE: initialize generators before anything else, regardless command\n for (const sourceFolder of projectSettings.sourceFolders) {\n for (const base of folderGenerators(sourceFolder)) {\n if (!base.meta?.name || typeof base.factory !== \"function\") {\n throw new Error(\n `${sourceFolder.name}: Unrecognized generator - must be created via defineGenerator()`,\n );\n }\n\n const factory = base.factory(sourceFolder);\n\n if (!factory.meta?.name) {\n throw new Error(\n `${sourceFolder.name}: ${base.meta.name} generator is missing meta property`,\n );\n }\n\n try {\n await factory.start?.();\n } catch (error) {\n console.error(\n styleText(\n \"red\",\n `${sourceFolder.name}: ${base.meta.name} generator failed to initialize`,\n ),\n );\n throw error;\n }\n }\n }\n\n if (command === \"build\") {\n for (const sourceFolder of projectSettings.sourceFolders) {\n const { createPath } = pathResolver(sourceFolder);\n\n const resolvedRoutes = [];\n\n {\n const { resolvers } = await routesFactory(sourceFolder, cacheFactory);\n\n const spinner = spinnerFactory(\n `${sourceFolder.name}: resolving routes`,\n );\n\n for (const { name, handler } of resolvers.values()) {\n spinner.append(\n `[ ${resolvedRoutes.length + 1} of ${resolvers.size} ] ${name}`,\n );\n resolvedRoutes.push(await handler());\n }\n\n spinner.succeed(\"ready ✨\");\n }\n\n const generators = folderGenerators(sourceFolder);\n\n for (const generator of generators) {\n await generator.factory(sourceFolder).build?.(resolvedRoutes);\n }\n\n const plugins = [\n vitePlugins.tsconfigPaths(sourceFolder),\n vitePlugins.nodePrefix(),\n ];\n\n // INFO: === build client ===\n await build(\n mergeConfigs(\n // user-provided config - lowest priority\n sourceFolder.config,\n // generators configs - higher priority\n ...generators.map(({ factory }) => {\n return factory(sourceFolder).config?.({ kind: \"client\", command });\n }),\n // main config - highest priority\n {\n // base provided by sourceFolder.config\n root: createPath.src(),\n cacheDir: cacheDir(sourceFolder, command, \"client\"),\n plugins,\n build: {\n outDir: createPath.distDir(\"client\"),\n manifest: true,\n emptyOutDir: true,\n },\n },\n ),\n );\n\n const apiGenerator = generators.find((e) => e.meta.slot === \"api\");\n\n // INFO: === build backend ===\n if (apiGenerator) {\n const dir = createPath.distDir(\"api\");\n\n // NOTE: sourceFolder.config is client-specific config - not using for backend!\n // To provide backend-specific config pass it as api generator options.\n await build(\n mergeConfigs(\n // user-provided config - lowest priority\n apiGenerator.options,\n // generator config - higher priority\n apiGenerator\n .factory(sourceFolder)\n .config?.({ kind: \"backend\", command }),\n // main config - highest priority\n {\n base: \"./\",\n root: createPath.src(),\n appType: \"custom\",\n plugins,\n resolve: {\n conditions: [\"node\"],\n },\n build: {\n ssr: true,\n target: \"esnext\",\n sourcemap: true,\n emptyOutDir: true,\n rolldownOptions: {\n input: [\n createPath.api(\"app.ts\"),\n createPath.api(\"server.ts\"),\n ],\n output: {\n dir,\n format: \"esm\",\n },\n },\n },\n cacheDir: cacheDir(sourceFolder, command, \"backend\"),\n },\n ),\n );\n }\n\n for (const generator of generators) {\n await generator.factory(sourceFolder).postBuild?.(resolvedRoutes);\n }\n }\n\n return async () => {};\n }\n\n type RequestMatcher = (req: IncomingMessage) => boolean;\n type RequestHandler = (req: IncomingMessage, res: ServerResponse) => void;\n\n const requestHandlers: Array<\n [\n segments: [base: string, api?: string],\n matcherFactory: () => RequestMatcher,\n handlerFactory: () => RequestHandler,\n ]\n > = [];\n\n const teardownHandlers: Array<() => Promise<unknown>> = [];\n\n const eventMap: Record<string, Awaited<ReturnType<typeof eventFactory>>> = {};\n\n // WARN: call this before starting any server!\n for (const sourceFolder of projectSettings.sourceFolders) {\n eventMap[sourceFolder.name] = await eventFactory(sourceFolder);\n }\n\n let port = await findFreePort(devPort);\n\n for (const sourceFolder of projectSettings.sourceFolders) {\n const { createPath } = pathResolver(sourceFolder);\n\n const requestMatchers = matchersFactory(sourceFolder);\n\n const generators = folderGenerators(sourceFolder);\n\n const plugins = [\n vitePlugins.tsconfigPaths(sourceFolder),\n vitePlugins.nodePrefix(),\n ];\n\n // INFO: === start client server ===\n {\n const viteServer = await createServer(\n mergeConfigs(\n // user-provided config - lowest priority\n sourceFolder.config,\n // generators configs - higher priority\n ...generators.map(({ factory }) => {\n return factory(sourceFolder).config?.({ kind: \"client\", command });\n }),\n // main config - highest priority\n {\n // base provided by sourceFolder.config\n root: createPath.src(),\n cacheDir: cacheDir(sourceFolder, command, \"client\"),\n plugins,\n server: {\n port: port++,\n middlewareMode: true,\n hmr: { port: port++ },\n },\n },\n ),\n );\n\n for (const [evt, handler] of Object.entries(\n eventMap[sourceFolder.name],\n )) {\n viteServer.watcher.on(evt, handler);\n }\n\n requestHandlers.push([\n [sourceFolder.config.base],\n () => requestMatchers.base,\n () => viteServer.middlewares,\n ]);\n\n teardownHandlers.push(viteServer.close);\n }\n\n const apiGenerator = generators.find((e) => e.meta.slot === \"api\");\n\n // INFO: === start backend server ===\n if (apiGenerator) {\n // NOTE: sourceFolder.config is client-specific config - not using for backend!\n // To provide backend-specific config pass it as api generator options.\n const viteServer = await createServer(\n mergeConfigs(\n // user-provided config - lowest priority\n apiGenerator.options,\n // generator config - higher priority\n apiGenerator\n .factory(sourceFolder)\n .config?.({ kind: \"backend\", command }),\n // main config - highest priority\n {\n root: createPath.src(),\n appType: \"custom\",\n cacheDir: cacheDir(sourceFolder, command, \"backend\"),\n plugins,\n server: {\n port: port++,\n middlewareMode: true,\n hmr: { port: port++ },\n },\n resolve: {\n conditions: [\"node\"],\n },\n environments: {\n api: {\n resolve: {\n conditions: [\"node\"],\n },\n },\n },\n },\n ),\n );\n\n const env = viteServer.environments.api as RunnableDevEnvironment;\n\n const loadDevSetup = async () => {\n env.runner.clearCache();\n return env.runner\n .import<{ default: DevSetup }>(join(defaults.apiDir, \"dev.ts\"))\n .then((e) => e.default);\n };\n\n let devSetup = await loadDevSetup();\n\n for (const [evt, handler] of Object.entries(\n eventMap[sourceFolder.name],\n )) {\n viteServer.watcher.on(evt, async (file) => {\n const mods = env.moduleGraph.getModulesByFile(file);\n if (mods?.size) {\n await handler(file);\n await devSetup?.teardownHandler?.();\n devSetup = await loadDevSetup();\n }\n });\n }\n\n requestHandlers.push([\n [sourceFolder.config.base, sourceFolder.config.apiBase],\n () => devSetup.requestMatcher || requestMatchers.api,\n () => devSetup.requestHandler(),\n ]);\n\n teardownHandlers.push(viteServer.close);\n }\n }\n\n /**\n * Sorting is essential to ensure more specific paths are matched before broader ones.\n *\n * Given source folders:\n * - main app: baseurl=/ apiurl=/api\n * - admin app: baseurl=/admin apiurl=/admin/api\n *\n * Correct sort order:\n * 1. /admin/api — most specific\n * 2. /api\n * 3. /admin\n * 4. /\n * */\n const requestHandlerWeight = ([\n segments,\n ]: (typeof requestHandlers)[number]) => {\n const [base, api] = segments;\n /**\n * set weight to number of non-empty segments:\n * \"/\" weight is 0\n * \"/admin\" weight is 1\n * */\n const weight = base.split(\"/\").filter(Boolean).length;\n return api ? weight + 5 : weight;\n };\n\n const handlers = requestHandlers.sort(\n (a, b) => requestHandlerWeight(b) - requestHandlerWeight(a),\n );\n\n const httpServer = http.createServer((req, res) => {\n for (const [, matcherFactory, handlerFactory] of handlers) {\n // should be called on every request\n const [matcher, handler] = [matcherFactory(), handlerFactory()];\n if (matcher(req)) {\n handler(req, res);\n return;\n }\n }\n res.writeHead(404, { \"Content-Type\": \"text/html\" });\n res.end(\"<h1>404: Not Found</h1>\");\n });\n\n httpServer.on(\"error\", (error) => {\n console.error(\n styleText(\"red\", `Failed to start dev server on port ${devPort}`),\n );\n console.error(error.message);\n process.exit(1);\n });\n\n httpServer.listen(devPort);\n\n teardownHandlers.push(async () => {\n httpServer.close();\n });\n\n return async () => {\n for (const handler of teardownHandlers) {\n await handler();\n }\n // Let chokidar fully release file handles\n await new Promise((resolve) => setTimeout(resolve, 100));\n };\n};\n\nconst cacheDir = (\n { root, name }: SourceFolder,\n command: ProjectSettings[\"command\"],\n mode: \"client\" | \"backend\",\n) => {\n return resolve(root, `var/.vite/${name}/${command}/${mode}`);\n};\n\nconst folderGenerators = (sourceFolder: SourceFolder): Array<GeneratorBase> => {\n const { generators = [] } = sourceFolder.config;\n\n const coreGenerators: Partial<\n Record<NonNullable<GeneratorMeta[\"slot\"]>, GeneratorBase>\n > = {};\n\n const userGenerators: Array<GeneratorBase> = [];\n\n for (const base of generators) {\n if (base.meta.slot) {\n coreGenerators[base.meta.slot] = base;\n } else {\n userGenerators.push(base);\n }\n }\n\n return [\n // core generator should run first\n coreGenerator(),\n // then api generator\n ...(coreGenerators.api ? [coreGenerators.api] : []),\n // then fetch generator, only if api generator also enabled\n ...(coreGenerators.fetch && coreGenerators.api\n ? [coreGenerators.fetch]\n : []),\n // then user generators in the order they were added\n ...userGenerators,\n // then ssr generator should run after user generators\n ...(coreGenerators.ssr ? [coreGenerators.ssr] : []),\n // and ssg generator should run last\n ...(coreGenerators.ssg ? [coreGenerators.ssg] : []),\n ];\n};\n\nconst eventFactory = async (\n sourceFolder: SourceFolder,\n): Promise<\n Record<\"add\" | \"change\" | \"unlink\", (f: string) => Promise<void>>\n> => {\n const { resolvers, resolversFactory } = await routesFactory(\n sourceFolder,\n cacheFactory,\n );\n\n const { createPath } = pathResolver(sourceFolder);\n\n const generators: Array<{\n name: string | undefined;\n factory: GeneratorFactoryInstance;\n }> = [];\n\n for (const base of folderGenerators(sourceFolder)) {\n const factory = base.factory(sourceFolder);\n generators.push({ name: base.meta.name, factory });\n }\n\n const resolvedRoutes = new Map<\n string, // fileFullpath\n ResolvedEntry\n >();\n\n const runGenerators = async (event?: WatcherEvent) => {\n /**\n * Watch handlers receive the full list of entries\n * and should process only those whose source file or dependencies were updated.\n * */\n const entries = Array.from(resolvedRoutes.values());\n\n for (const { name, factory } of generators) {\n try {\n await factory.watch?.(entries, event);\n } catch (error) {\n console.error(\n styleText(\"red\", `${sourceFolder.name}: ${name} generator failed`),\n );\n if (event) {\n console.error(event);\n }\n console.error(error);\n }\n }\n };\n\n const updateResolvedEntry = async (file: string) => {\n const resolver = resolvers.get(file);\n\n if (!resolver) {\n return;\n }\n\n try {\n const resolvedEntry = await resolver.handler(file);\n resolvedRoutes.set(resolvedEntry.entry.fileFullpath, resolvedEntry);\n return resolvedEntry;\n } catch (error) {\n const route = file.replace(`${createPath.api()}/`, \"\");\n console.error(\n styleText(\n \"red\",\n `${sourceFolder.name}: ${route} route resolution failed`,\n ),\n );\n console.error(error);\n return;\n }\n };\n\n {\n const spinner = spinnerFactory(`${sourceFolder.name}: resolving routes`);\n for (const { name, handler } of resolvers.values()) {\n spinner.append(\n `[ ${resolvedRoutes.size + 1} of ${resolvers.size} ] ${name}`,\n );\n const route = await handler();\n resolvedRoutes.set(route.entry.fileFullpath, route);\n }\n spinner.succeed(\"ready ✨\");\n }\n\n // NOTE: call only after routes resolved\n await runGenerators();\n\n return {\n async add(file: string) {\n const [resolver] = resolversFactory([file]).values();\n\n if (!resolver) {\n return;\n }\n\n resolvers.set(file, resolver);\n\n // call only after `resolvers.set(file)`\n const resolvedEntry = await updateResolvedEntry(file);\n\n if (resolvedEntry) {\n await runGenerators({ kind: \"create\", file });\n }\n },\n\n async change(file: string) {\n if (resolvedRoutes.has(file)) {\n // route updated\n await updateResolvedEntry(file);\n } else {\n // updating entries that are referencing updated file\n const relatedRoutes = resolvedRoutes\n .values()\n .flatMap(({ kind, entry }) => {\n return kind === \"apiRoute\"\n ? entry.referencedFiles.includes(file)\n ? [entry]\n : []\n : [];\n });\n\n for (const route of relatedRoutes) {\n await updateResolvedEntry(route.fileFullpath);\n }\n }\n\n await runGenerators({ kind: \"update\", file });\n },\n\n async unlink(file) {\n // route deleted\n resolvers.delete(file);\n resolvedRoutes.delete(file);\n await runGenerators({ kind: \"delete\", file });\n },\n };\n};\n\nconst matchersFactory: (\n sourceFolder: SourceFolder,\n) => Record<\"base\" | \"api\", (req: IncomingMessage) => boolean> = ({\n config,\n}) => {\n const basePattern = new RegExp(`^${config.base}($|/*)`);\n const apiPattern = new RegExp(`^${join(config.base, config.apiBase)}($|/*)`);\n return {\n base(req) {\n return apiPattern.test(req.url as string)\n ? false\n : basePattern.test(req.url as string);\n },\n api(req) {\n return apiPattern.test(req.url as string);\n },\n };\n};\n\nconst findFreePort = async (devPort: number): Promise<number> => {\n let minPort = 0;\n let maxPort = 0;\n\n for (const n of [3, 2, 1, \"\"]) {\n minPort = Number(`${n}${devPort}`) + 100;\n maxPort = minPort + 100;\n if (maxPort < 65000) {\n break;\n }\n }\n\n if (maxPort >= 65000) {\n throw new Error(\"the devPort in package.json should be less than 64000\");\n }\n\n const range = maxPort - minPort + 1;\n const startOffset = Math.floor(Math.random() * range);\n\n const ports = Array.from({ length: range }, (_, i) => {\n return minPort + ((startOffset + i) % range);\n });\n\n const freePort = await ports.reduce(\n async (prevPromise, port) => {\n const freePort = await prevPromise;\n if (freePort) {\n return freePort;\n }\n const isFree = await isPortFree(port);\n return isFree ? port : undefined;\n },\n Promise.resolve(undefined as number | undefined),\n );\n\n if (!freePort) {\n throw new Error(`No free ports found in range ${minPort}-${maxPort}`);\n }\n\n return freePort;\n};\n\nconst isPortFree = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", () => resolve(false));\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port, \"127.0.0.1\");\n });\n};\n"],"mappings":"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"}
package/pkg/index.d.ts CHANGED
@@ -8,6 +8,7 @@ export { default as reactGenerator } from "@kosmojs/react-generator";
8
8
  export { default as solidGenerator } from "@kosmojs/solid-generator";
9
9
  export { default as ssgGenerator } from "@kosmojs/ssg-generator";
10
10
  export { default as ssrGenerator } from "@kosmojs/ssr-generator";
11
+ export { default as svelteGenerator } from "@kosmojs/svelte-generator";
11
12
  export { default as typeboxGenerator } from "@kosmojs/typebox-generator";
12
13
  export { default as vueGenerator } from "@kosmojs/vue-generator";
13
14
  export declare const defineConfig: (config: FolderConfig) => SourceFolder["config"];
package/pkg/index.js CHANGED
@@ -10,6 +10,7 @@ import reactGenerator from "@kosmojs/react-generator";
10
10
  import solidGenerator from "@kosmojs/solid-generator";
11
11
  import ssgGenerator from "@kosmojs/ssg-generator";
12
12
  import ssrGenerator from "@kosmojs/ssr-generator";
13
+ import svelteGenerator from "@kosmojs/svelte-generator";
13
14
  import typeboxGenerator from "@kosmojs/typebox-generator";
14
15
  import vueGenerator from "@kosmojs/vue-generator";
15
16
  //#region src/index.ts
@@ -24,6 +25,6 @@ var defineConfig = (config) => {
24
25
  };
25
26
  };
26
27
  //#endregion
27
- export { defineConfig, fetchGenerator, honoGenerator, koaGenerator, mdxGenerator, openapiGenerator, reactGenerator, solidGenerator, ssgGenerator, ssrGenerator, typeboxGenerator, vueGenerator };
28
+ export { defineConfig, fetchGenerator, honoGenerator, koaGenerator, mdxGenerator, openapiGenerator, reactGenerator, solidGenerator, ssgGenerator, ssrGenerator, svelteGenerator, typeboxGenerator, vueGenerator };
28
29
 
29
30
  //# sourceMappingURL=index.js.map
package/pkg/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import { join } from \"node:path\";\nimport { styleText } from \"node:util\";\n\nimport {\n DEFAULT_APIBASE,\n type FolderConfig,\n type SourceFolder,\n} from \"@kosmojs/core\";\n\nexport { default as fetchGenerator } from \"@kosmojs/fetch-generator\";\nexport { default as honoGenerator } from \"@kosmojs/hono-generator\";\nexport { default as koaGenerator } from \"@kosmojs/koa-generator\";\nexport { default as mdxGenerator } from \"@kosmojs/mdx-generator\";\nexport { default as openapiGenerator } from \"@kosmojs/openapi-generator\";\nexport { default as reactGenerator } from \"@kosmojs/react-generator\";\nexport { default as solidGenerator } from \"@kosmojs/solid-generator\";\nexport { default as ssgGenerator } from \"@kosmojs/ssg-generator\";\nexport { default as ssrGenerator } from \"@kosmojs/ssr-generator\";\nexport { default as typeboxGenerator } from \"@kosmojs/typebox-generator\";\nexport { default as vueGenerator } from \"@kosmojs/vue-generator\";\n\nexport const defineConfig: (config: FolderConfig) => SourceFolder[\"config\"] = (\n config,\n) => {\n const env = process.env.NODE_ENV || \"development\";\n const base = typeof config.base === \"string\" ? config.base : config.base[env];\n if (!base?.trim()) {\n throw new Error(\n styleText([\"red\"], \"ERROR: Invalid Config - no base provided\"),\n );\n }\n return {\n ...config,\n base: join(\"/\", base),\n apiBase: join(\"/\", config.apiBase || DEFAULT_APIBASE),\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;AAqBA,IAAa,gBACX,WACG;CACH,MAAM,MAAA,QAAA,IAAA,YAA8B;CACpC,MAAM,OAAO,OAAO,OAAO,SAAS,WAAW,OAAO,OAAO,OAAO,KAAK;CACzE,IAAI,CAAC,MAAM,KAAK,GACd,MAAM,IAAI,MACR,UAAU,CAAC,KAAK,GAAG,0CAA0C,CAC/D;CAEF,OAAO;EACL,GAAG;EACH,MAAM,KAAK,KAAK,IAAI;EACpB,SAAS,KAAK,KAAK,OAAO,WAAW,eAAe;CACtD;AACF"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import { join } from \"node:path\";\nimport { styleText } from \"node:util\";\n\nimport {\n DEFAULT_APIBASE,\n type FolderConfig,\n type SourceFolder,\n} from \"@kosmojs/core\";\n\nexport { default as fetchGenerator } from \"@kosmojs/fetch-generator\";\nexport { default as honoGenerator } from \"@kosmojs/hono-generator\";\nexport { default as koaGenerator } from \"@kosmojs/koa-generator\";\nexport { default as mdxGenerator } from \"@kosmojs/mdx-generator\";\nexport { default as openapiGenerator } from \"@kosmojs/openapi-generator\";\nexport { default as reactGenerator } from \"@kosmojs/react-generator\";\nexport { default as solidGenerator } from \"@kosmojs/solid-generator\";\nexport { default as ssgGenerator } from \"@kosmojs/ssg-generator\";\nexport { default as ssrGenerator } from \"@kosmojs/ssr-generator\";\nexport { default as svelteGenerator } from \"@kosmojs/svelte-generator\";\nexport { default as typeboxGenerator } from \"@kosmojs/typebox-generator\";\nexport { default as vueGenerator } from \"@kosmojs/vue-generator\";\n\nexport const defineConfig: (config: FolderConfig) => SourceFolder[\"config\"] = (\n config,\n) => {\n const env = process.env.NODE_ENV || \"development\";\n const base = typeof config.base === \"string\" ? config.base : config.base[env];\n if (!base?.trim()) {\n throw new Error(\n styleText([\"red\"], \"ERROR: Invalid Config - no base provided\"),\n );\n }\n return {\n ...config,\n base: join(\"/\", base),\n apiBase: join(\"/\", config.apiBase || DEFAULT_APIBASE),\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAsBA,IAAa,gBACX,WACG;CACH,MAAM,MAAA,QAAA,IAAA,YAA8B;CACpC,MAAM,OAAO,OAAO,OAAO,SAAS,WAAW,OAAO,OAAO,OAAO,KAAK;CACzE,IAAI,CAAC,MAAM,KAAK,GACd,MAAM,IAAI,MACR,UAAU,CAAC,KAAK,GAAG,0CAA0C,CAC/D;CAEF,OAAO;EACL,GAAG;EACH,MAAM,KAAK,KAAK,IAAI;EACpB,SAAS,KAAK,KAAK,OAAO,WAAW,eAAe;CACtD;AACF"}