@kosmojs/dev 0.4.3 → 0.4.4

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/pkg/index.js CHANGED
@@ -1,6 +1,588 @@
1
- import{t as e}from"./assets/pkg-dTglxmYm.js";import{join as t,resolve as n}from"node:path";import{styleText as r}from"node:util";import{DEFAULT_APIBASE as i,RequestBodyTargets as a,RequestValidationTargets as o,createRouteResolver as s,createTemplateResolver as c,defaults as l}from"@kosmojs/core";import{createH3Pattern as u,createHonoPattern as d,createPathPattern as f,createWatchedApiRouteEntriesFilter as p,createWatchedPageRouteEntriesFilter as m,defineGenerator as h,defineGeneratorFactory as g,mergeConfigs as _,nestedRoutesFactory as v,pathResolver as y,pathTokensFactory as b,renderFactory as x,renderToFile as ee,sortRoutes as S,spinnerFactory as te,vitePlugins as C}from"@kosmojs/lib";import{routeRenderHelpers as w}from"@kosmojs/core/generators";import{HTTPMethods as ne}from"@kosmojs/core/fetch";import T from"crc/crc32";import re from"@mdx-js/rollup";import{build as E,createFilter as ie}from"vite";import ae from"yaml";import{parse as oe}from"path-to-regexp";import se from"typebox";import ce from"@vitejs/plugin-react";import D from"vite-plugin-solid";import{access as le,constants as ue,cp as O,mkdir as de,rm as k,writeFile as fe}from"node:fs/promises";import{svelte as pe}from"@sveltejs/vite-plugin-svelte";import A from"@vitejs/plugin-vue";var j=`export * from "./transport";
2
- `,M=`export const transport = undefined;
3
- `,N=`{{#each routes}}
1
+ import{dirname as e,join as t,posix as n,resolve as r}from"node:path";import{styleText as i}from"node:util";import{DEFAULT_APIBASE as a,RequestBodyTargets as o,RequestValidationTargets as s,createRouteResolver as c,createTemplateResolver as l,defaults as u}from"@kosmojs/core";import{collectVirtualModules as d,createH3Pattern as f,createHonoPattern as p,createPathPattern as m,createWatchedApiRouteEntriesFilter as h,createWatchedPageRouteEntriesFilter as g,defineGenerator as _,defineGeneratorFactory as v,mergeConfigs as y,nestedRoutesFactory as b,pathExists as x,pathResolver as S,pathTokensFactory as C,renderFactory as w,renderToFile as T,sortRoutes as E,sortRoutesForResolution as D,spinnerFactory as ee,vitePlugins as O}from"@kosmojs/lib";import k from"semver";import{routeRenderHelpers as A}from"@kosmojs/core/generators";import{HTTPMethods as te}from"@kosmojs/core/fetch";import j from"crc/crc32";import ne from"@mdx-js/rollup";import{build as M,createFilter as re}from"vite";import ie from"yaml";import{parse as ae}from"path-to-regexp";import oe from"typebox";import se from"@vitejs/plugin-react";import N from"vite-plugin-solid";import{access as ce,constants as le,cp as P,mkdir as ue,rm as F,writeFile as de}from"node:fs/promises";import{svelte as fe}from"@sveltejs/vite-plugin-svelte";import pe from"@vitejs/plugin-vue";var me={type:`module`,private:!0,name:`@kosmojs/core-generator`,version:`0.3.0`,author:`Slee Woo`,license:`MIT`,files:[`pkg/*`],exports:{".":{types:`./pkg/index.d.ts`,default:`./pkg/index.js`}},scripts:{build:`wsbuild src/index.ts`},dependencies:{"@kosmojs/core":`workspace:^`,"@kosmojs/lib":`workspace:^`,semver:`^7.8.5`},devDependencies:{"@types/semver":`^7.8.0`,"path-to-regexp":`^8.4.2`}},he=`export const base = "{{config.base}}";
2
+ export const apiBase = "{{config.apiBase}}";
3
+ `,I=`import type { StaticParams } from "./types";
4
+
5
+ export * from "./config";
6
+ export * from "./routes";
7
+ export * from "./types";
8
+
9
+ export const defineStaticParams = <T extends keyof StaticParams>(
10
+ variants: Array<StaticParams[T]>,
11
+ ) => {
12
+ return variants
13
+ };
14
+ `,L=`{{> routeMapperPartial}}
15
+
16
+ import { base, apiBase } from "./config";
17
+
18
+ // used by backend generators and fetch clients
19
+ export const apiRouteMap = {
20
+ {{#each apiRoutes}}
21
+ "{{name}}": apiRouteMapper<[{{serializeParamsTupleElements .}}]>(
22
+ join(base, apiBase),
23
+ {{serializeApiRoute .}},
24
+ ),
25
+ {{/each}}
26
+ };
27
+
28
+ // used by frontend generators on Link component
29
+ export const pageRouteMap = {
30
+ {{#each pageRoutes}}
31
+ "{{name}}": pageRouteMapper<[{{serializeParamsTupleElements .}}]>(
32
+ base,
33
+ {{serializePageRoute .}},
34
+ ),
35
+ {{/each}}
36
+ };
37
+ `,R=`import { compile, match } from "path-to-regexp";
38
+
39
+ import {
40
+ type ApiRouteSerialized,
41
+ type PageRouteSerialized,
42
+ stringifySearchParams,
43
+ type ValidationTarget,
44
+ } from "@kosmojs/core";
45
+ import { createHost, join } from "@kosmojs/core/fetch";
46
+ import type { RoutePathMethods } from "@kosmojs/core/generators";
47
+
48
+ type NormalizeParams = (path: string) => Record<string, unknown>;
49
+
50
+ type NormalizeSearchParams = (
51
+ searchParams: Record<string, unknown>,
52
+ method: string,
53
+ ) => Record<string, unknown>;
54
+
55
+ type PayloadResolver = <T>(
56
+ payload: Record<ValidationTarget, T> | undefined,
57
+ target: ValidationTarget,
58
+ method: string,
59
+ ) => T | Record<string, unknown> | undefined;
60
+
61
+ export const apiRouteMapper = <ParamsT extends readonly unknown[]>(
62
+ base: string,
63
+ {
64
+ name,
65
+ pathPattern,
66
+ params,
67
+ numericProperties,
68
+ booleanProperties,
69
+ }: ApiRouteSerialized,
70
+ ): RoutePathMethods<ParamsT> & {
71
+ normalizeParams: NormalizeParams;
72
+ normalizeSearchParams: NormalizeSearchParams;
73
+ payloadResolver: PayloadResolver;
74
+ } => {
75
+ const toPath = compile(pathPattern);
76
+ const pathMatcher = match(join(base, pathPattern));
77
+
78
+ const maybeNumber = (val: unknown) => {
79
+ if (val === undefined || val === null) {
80
+ return val;
81
+ }
82
+ const n = Number(val);
83
+ return Number.isFinite(n) ? n : val;
84
+ };
85
+
86
+ const maybeBoolean = (val: unknown) => {
87
+ return [true, false, "true", "false"].includes(val as never) //
88
+ ? JSON.parse(val as never)
89
+ : val;
90
+ };
91
+
92
+ const resolveParam = (path: string, param: (typeof params)[number]) => {
93
+ try {
94
+ const match = pathMatcher(path);
95
+ return match ? match.params[param] : undefined;
96
+ } catch (e) {
97
+ return undefined;
98
+ }
99
+ };
100
+
101
+ const normalizeSearchParams: NormalizeSearchParams = (
102
+ searchParams,
103
+ method,
104
+ ) => {
105
+ return Object.fromEntries(
106
+ Object.entries(searchParams).map(([k, v]) => {
107
+ if (numericProperties.query?.[method]?.includes(k)) {
108
+ return [
109
+ k,
110
+ Array.isArray(v) ? v.map((e) => maybeNumber(e)) : maybeNumber(v),
111
+ ];
112
+ }
113
+ if (booleanProperties.query?.[method]?.includes(k)) {
114
+ return [
115
+ k,
116
+ Array.isArray(v) ? v.map((e) => maybeBoolean(e)) : maybeBoolean(v),
117
+ ];
118
+ }
119
+ return [k, v];
120
+ }),
121
+ );
122
+ };
123
+
124
+ const normalizeParams: NormalizeParams = (path) => {
125
+ return params.reduce((map: Record<string, unknown>, param) => {
126
+ const value = resolveParam(path, param);
127
+ if (Array.isArray(value)) {
128
+ map[param] = numericProperties.params.includes(param)
129
+ ? value.map((e) => maybeNumber(e))
130
+ : value;
131
+ } else if (value) {
132
+ map[param] = numericProperties.params.includes(param)
133
+ ? maybeNumber(value)
134
+ : value;
135
+ }
136
+ return map;
137
+ }, {});
138
+ };
139
+
140
+ const paramsMapper: RoutePathMethods<ParamsT>["paramsMapper"] = (
141
+ input,
142
+ opt,
143
+ ) => {
144
+ return params.reduce<Record<string, unknown>>((map, name, i) => {
145
+ const coerceNumbers = opt?.coerceNumbers
146
+ ? numericProperties.params.includes(name)
147
+ : false;
148
+ if (Array.isArray(input[i])) {
149
+ map[name] = coerceNumbers
150
+ ? input[i].map((v) => maybeNumber(v))
151
+ : input[i].map(String);
152
+ } else if (input[i] !== undefined) {
153
+ map[name] = coerceNumbers ? maybeNumber(input[i]) : String(input[i]);
154
+ }
155
+ return map;
156
+ }, {});
157
+ };
158
+
159
+ const parametrize: RoutePathMethods<ParamsT>["parametrize"] = (params) => {
160
+ try {
161
+ return toPath(paramsMapper(params) as never);
162
+ } catch (error) {
163
+ console.error(\`❗ERROR: Failed building path for \${name}\`);
164
+ throw error;
165
+ }
166
+ };
167
+
168
+ const path: RoutePathMethods<ParamsT>["path"] = (params, query, opt) => {
169
+ const path = join(
170
+ opt?.prefix === false
171
+ ? "/"
172
+ : typeof opt?.prefix === "string"
173
+ ? opt.prefix
174
+ : base,
175
+ parametrize(params),
176
+ );
177
+ return query //
178
+ ? [path, stringifySearchParams(query)].join("?")
179
+ : path;
180
+ };
181
+
182
+ const href: RoutePathMethods<ParamsT>["href"] = (
183
+ host,
184
+ params,
185
+ query,
186
+ opt,
187
+ ) => {
188
+ return createHost(host) + path(params, query, opt);
189
+ };
190
+
191
+ const payloadResolver: PayloadResolver = (payload, target, method) => {
192
+ const data = payload?.[target];
193
+
194
+ if (target === "query") {
195
+ return Object.fromEntries(
196
+ Object.entries({ ...data }).map(([k, v]) => {
197
+ return [
198
+ k,
199
+ numericProperties.query[method]?.includes(k)
200
+ ? Array.isArray(v)
201
+ ? v.map((v) => maybeNumber(v))
202
+ : maybeNumber(v)
203
+ : v,
204
+ ];
205
+ }),
206
+ );
207
+ }
208
+
209
+ if (data instanceof FormData) {
210
+ return [...data].reduce<
211
+ Record<string, FormDataEntryValue | Array<FormDataEntryValue>>
212
+ >((map, [key, val]) => {
213
+ if (key in map) {
214
+ map[key] = [map[key]].flat().concat(val);
215
+ } else {
216
+ map[key] = val;
217
+ }
218
+ return map;
219
+ }, {});
220
+ }
221
+
222
+ return data;
223
+ };
224
+
225
+ return {
226
+ normalizeParams,
227
+ normalizeSearchParams,
228
+ payloadResolver,
229
+ paramsMapper,
230
+ parametrize,
231
+ path,
232
+ href,
233
+ };
234
+ };
235
+
236
+ export const pageRouteMapper = <ParamsT extends readonly unknown[]>(
237
+ base: string,
238
+ route: PageRouteSerialized,
239
+ ): RoutePathMethods<ParamsT> => {
240
+ const toPath = compile(route.pathPattern);
241
+
242
+ const paramsMapper: RoutePathMethods<ParamsT>["paramsMapper"] = (params) => {
243
+ return route.params.reduce<Record<string, unknown>>((map, name, i) => {
244
+ if (Array.isArray(params[i])) {
245
+ map[name] = params[i].map(String);
246
+ } else if (params[i] !== undefined) {
247
+ map[name] = String(params[i]);
248
+ }
249
+ return map;
250
+ }, {});
251
+ };
252
+
253
+ const parametrize: RoutePathMethods<ParamsT>["parametrize"] = (params) => {
254
+ try {
255
+ return toPath(paramsMapper(params) as never);
256
+ } catch (error) {
257
+ console.error(\`❗ERROR: Failed building path for \${route.name}\`);
258
+ throw error;
259
+ }
260
+ };
261
+
262
+ const path: RoutePathMethods<ParamsT>["path"] = (params, query, opt) => {
263
+ const path = join(
264
+ opt?.prefix === false
265
+ ? "/"
266
+ : typeof opt?.prefix === "string"
267
+ ? opt.prefix
268
+ : base,
269
+ parametrize(params),
270
+ );
271
+ return query //
272
+ ? [path, stringifySearchParams(query)].join("?")
273
+ : path;
274
+ };
275
+
276
+ const href: RoutePathMethods<ParamsT>["href"] = (
277
+ host,
278
+ params,
279
+ query,
280
+ opt,
281
+ ) => {
282
+ return createHost(host) + path(params, query, opt);
283
+ };
284
+
285
+ return {
286
+ paramsMapper,
287
+ parametrize,
288
+ path,
289
+ href,
290
+ };
291
+ };
292
+ `,ge=`import { AsyncLocalStorage } from "node:async_hooks";
293
+
294
+ export type RequestContext = {
295
+ headers?: HeadersInit;
296
+ tsqClient?: unknown;
297
+ error?: unknown;
298
+ };
299
+
300
+ /**
301
+ * Request-scoped context store.
302
+ * */
303
+ export const store = new AsyncLocalStorage<RequestContext>();
304
+
305
+ /**
306
+ * Origin used to absolutize the relative URLs the client produces.
307
+ * */
308
+ export const ssrOrigin = "http://ssr.local";
309
+
310
+ export const redirectCodes = [
311
+ // Moved Permanently
312
+ 301,
313
+ // Found (temporary)
314
+ 302,
315
+ // See Other (redirect after POST)
316
+ 303,
317
+ // Temporary Redirect (preserves method)
318
+ 307,
319
+ // Permanent Redirect (preserves method)
320
+ 308,
321
+ ];
322
+ `,_e=`export type Override<A, B> = Omit<A, keyof B> & B;
323
+
324
+ export type StaticParams = {
325
+ {{#each pageRoutes}}
326
+ "{{name}}": [ {{serializeParamsTupleElements .}} ];
327
+ {{/each}}
328
+ };
329
+
330
+ {{#if pageRoutes.length}}
331
+ export type LinkProps =
332
+ {{#each pageRoutes}}
333
+ | [ "{{name}}", {{serializeParamsTupleElements .}} ]
334
+ {{/each}};
335
+ {{else}}
336
+ export type LinkProps = never;
337
+ {{/if}}
338
+ `,ve=`declare module "virtual:kosmo/env" {
339
+ export const command: "serve" | "build";
340
+ }
341
+
342
+ declare module "virtual:kosmo/backend-app" {
343
+ import type { FetchApp, NodeApp } from "@kosmojs/core";
344
+ const backend: FetchApp | NodeApp | undefined;
345
+ export default backend;
346
+ }
347
+
348
+ declare module "virtual:kosmo/fetch-transport" {
349
+ import type { Transport } from "@kosmojs/core/fetch";
350
+ /**
351
+ * Undefined on the client, where fetch clients fall back to global fetch.
352
+ * On the SSR bundle it dispatches straight into the backend app, in process.
353
+ * Supplied by the \`kosmo:virtualModules\` Vite plugin - there is no file.
354
+ * */
355
+ export const transport: Transport | undefined;
356
+ }
357
+
358
+ /**
359
+ * Enhances base TypeScript types with JSON Schema validation constraints.
360
+ * Allows declaring refined types that carry validation metadata for runtime
361
+ * schema validation while maintaining full TypeScript type safety.
362
+ *
363
+ * Useful for generating validation schemas and ensuring
364
+ * data conforms to specific business rules beyond basic type checking.
365
+ * */
366
+ declare type VRefine<
367
+ T extends unknown[] | number | string | object,
368
+ _ extends T extends unknown[]
369
+ ? TArrayOptions
370
+ : T extends number
371
+ ? TNumberOptions
372
+ : T extends string
373
+ ? TStringOptions
374
+ : TObjectOptions,
375
+ > = T;
376
+
377
+ /**
378
+ * Type definitions inspired by and gently adapted from TypeBox.
379
+ * Original TypeBox created by sinclairzx81: https://github.com/sinclairzx81/typebox
380
+ * TypeBox is licensed under MIT: https://github.com/sinclairzx81/typebox/blob/main/license
381
+ *
382
+ * These types provide JSON Schema compatible type refinements for TypeScript.
383
+ * */
384
+ interface TSchema {}
385
+
386
+ // ------------------------------------------------------------------
387
+ // ObjectOptions
388
+ // ------------------------------------------------------------------
389
+ interface TObjectOptions {
390
+ /**
391
+ * Defines whether additional properties are allowed beyond those explicitly defined in \`properties\`.
392
+ */
393
+ additionalProperties?: TSchema | boolean;
394
+ /**
395
+ * The minimum number of properties required in the object.
396
+ */
397
+ minProperties?: number;
398
+ /**
399
+ * The maximum number of properties allowed in the object.
400
+ */
401
+ maxProperties?: number;
402
+ /**
403
+ * Defines conditional requirements for properties.
404
+ */
405
+ dependencies?: Record<string, boolean | TSchema | string[]>;
406
+ /**
407
+ * Specifies properties that *must* be present if a given property is present.
408
+ */
409
+ dependentRequired?: Record<string, string[]>;
410
+ /**
411
+ * Defines schemas that apply if a specific property is present.
412
+ */
413
+ dependentSchemas?: Record<string, TSchema>;
414
+ /**
415
+ * Maps regular expressions to schemas properties matching a pattern must validate against the schema.
416
+ */
417
+ patternProperties?: Record<string, TSchema>;
418
+ /**
419
+ * A schema that all property names within the object must validate against.
420
+ */
421
+ propertyNames?: TSchema;
422
+ }
423
+
424
+ // ------------------------------------------------------------------
425
+ // ArrayOptions
426
+ // ------------------------------------------------------------------
427
+ interface TArrayOptions {
428
+ /**
429
+ * The minimum number of items allowed in the array.
430
+ */
431
+ minItems?: number;
432
+ /**
433
+ * The maximum number of items allowed in the array.
434
+ */
435
+ maxItems?: number;
436
+ /**
437
+ * A schema that at least one item in the array must validate against.
438
+ */
439
+ contains?: TSchema;
440
+ /**
441
+ * The minimum number of array items that must validate against the \`contains\` schema.
442
+ */
443
+ minContains?: number;
444
+ /**
445
+ * The maximum number of array items that may validate against the \`contains\` schema.
446
+ */
447
+ maxContains?: number;
448
+ /**
449
+ * An array of schemas, where each schema in \`prefixItems\` validates against items at corresponding positions from the beginning of the array.
450
+ */
451
+ prefixItems?: TSchema[];
452
+ /**
453
+ * If \`true\`, all items in the array must be unique.
454
+ */
455
+ uniqueItems?: boolean;
456
+ }
457
+
458
+ // ------------------------------------------------------------------
459
+ // NumberOptions
460
+ // ------------------------------------------------------------------
461
+ interface TNumberOptions {
462
+ /**
463
+ * Specifies an exclusive upper limit for the number (number must be less than this value).
464
+ */
465
+ exclusiveMaximum?: number | bigint;
466
+ /**
467
+ * Specifies an exclusive lower limit for the number (number must be greater than this value).
468
+ */
469
+ exclusiveMinimum?: number | bigint;
470
+ /**
471
+ * Specifies an inclusive upper limit for the number (number must be less than or equal to this value).
472
+ */
473
+ maximum?: number | bigint;
474
+ /**
475
+ * Specifies an inclusive lower limit for the number (number must be greater than or equal to this value).
476
+ */
477
+ minimum?: number | bigint;
478
+ /**
479
+ * Specifies that the number must be a multiple of this value.
480
+ */
481
+ multipleOf?: number | bigint;
482
+ }
483
+
484
+ // ------------------------------------------------------------------
485
+ // StringOptions
486
+ // ------------------------------------------------------------------
487
+ type TFormat =
488
+ | "date-time"
489
+ | "date"
490
+ | "duration"
491
+ | "email"
492
+ | "hostname"
493
+ | "idn-email"
494
+ | "idn-hostname"
495
+ | "ipv4"
496
+ | "ipv6"
497
+ | "iri-reference"
498
+ | "iri"
499
+ | "json-pointer-uri-fragment"
500
+ | "json-pointer"
501
+ | "json-string"
502
+ | "regex"
503
+ | "relative-json-pointer"
504
+ | "time"
505
+ | "uri-reference"
506
+ | "uri-template"
507
+ | "url"
508
+ | "uuid";
509
+
510
+ interface TStringOptions {
511
+ /**
512
+ * Specifies the expected string format.
513
+ *
514
+ * Common values include:
515
+ * - \`base64\` – Base64-encoded string.
516
+ * - \`date-time\` – [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) date-time format.
517
+ * - \`date\` – [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) date (YYYY-MM-DD).
518
+ * - \`duration\` – [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) duration format.
519
+ * - \`email\` – RFC 5321/5322 compliant email address.
520
+ * - \`hostname\` – RFC 1034/1035 compliant host name.
521
+ * - \`idn-email\` – Internationalized email address.
522
+ * - \`idn-hostname\` – Internationalized host name.
523
+ * - \`ipv4\` – IPv4 address.
524
+ * - \`ipv6\` – IPv6 address.
525
+ * - \`iri\` / \`iri-reference\` – Internationalized Resource Identifier.
526
+ * - \`json-pointer\` / \`json-pointer-uri-fragment\` – JSON Pointer format.
527
+ * - \`json-string\` – String containing valid JSON.
528
+ * - \`regex\` – Regular expression syntax.
529
+ * - \`relative-json-pointer\` – Relative JSON Pointer format.
530
+ * - \`time\` – [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) time (HH:MM:SS).
531
+ * - \`uri-reference\` / \`uri-template\` – URI reference or template.
532
+ * - \`url\` – Web URL format.
533
+ * - \`uuid\` – RFC 4122 UUID string.
534
+ *
535
+ * May also be a custom format string.
536
+ */
537
+ format?: TFormat;
538
+ /**
539
+ * Specifies the minimum number of characters allowed in the string.
540
+ * Must be a non-negative integer.
541
+ */
542
+ minLength?: number;
543
+ /**
544
+ * Specifies the maximum number of characters allowed in the string.
545
+ * Must be a non-negative integer.
546
+ */
547
+ maxLength?: number;
548
+ /**
549
+ * Specifies a regular expression pattern that the string value must match.
550
+ * Can be provided as a string (ECMA-262 regex syntax) or a \`RegExp\` object.
551
+ */
552
+ pattern?: string | RegExp;
553
+ }
554
+ `,ye=`# Ignore all files
555
+ *
556
+
557
+ # But don't ignore directories (so Git can traverse them)
558
+ !*/
559
+
560
+ # And don't ignore these files at any depth
561
+ !cache.json
562
+ !types.ts
563
+ `,be=`export declare global {
564
+ interface Window {
565
+ __KOSMO_HYDRATION_BOOL__: boolean;
566
+ __KOSMO_HYDRATION_DATA__: Record<string, unknown> | undefined;
567
+ }
568
+ }
569
+ `,xe=`<!doctype html>
570
+ <html lang="en">
571
+ <head>
572
+ <meta charset="UTF-8" />
573
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
574
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
575
+ </head>
576
+ <body>
577
+ <div id="app"><!--app-html--></div>
578
+ <script type="module" src="/{{ entryDir }}/client.ts"><\/script>
579
+ </body>
580
+ </html>
581
+ `,Se=`// stub schemas, specialized generators supposed to overwrite this file
582
+ import type { ValidationSchemas } from "@kosmojs/core";
583
+ export type { ValidationSchemas };
584
+ export const validationSchemas: ValidationSchemas = {};
585
+ `,z=({dependencies:e,devDependencies:t},n)=>{let r="${configDir}",i=Object.keys({...e,...t}),a={types:[`vite/client`,...[`node`,`deno`,`bun`].flatMap(e=>i.includes(`@types/${e}`)?[`@types/${e}`]:[])],moduleResolution:`bundler`,module:`ESNext`,target:`ESNext`,strict:!0,exactOptionalPropertyTypes:!0,noImplicitAny:!0,noImplicitThis:!0,noImplicitOverride:!0,noImplicitReturns:!0,noUnusedLocals:!1,noUnusedParameters:!1,allowArbitraryExtensions:!0,allowImportingTsExtensions:!0,allowUnreachableCode:!1,allowUnusedLabels:!1,useUnknownInCatchVariables:!0,noFallthroughCasesInSwitch:!0,noUncheckedSideEffectImports:!0,resolveJsonModule:!0,esModuleInterop:!0,verbatimModuleSyntax:!0,skipLibCheck:!0,noEmit:!0};return n?{include:[`${r}/`,`${r}/../../${u.libDir}/${n}/`,`${r}/../../**/*.d.ts`],compilerOptions:{...a,types:[...a.types],paths:{[`${u.appPrefix}/*`]:[`${r}/../../*`],[`${u.srcPrefix}/*`]:[`${r}/*`],[`${u.libPrefix}/*`]:[`${r}/../../${u.libDir}/${n}/*`]}}}:{include:[`${r}/`],exclude:[`${r}/${u.srcDir}/`],compilerOptions:{...a,paths:{[`${u.appPrefix}/*`]:[`${r}/*`]}}}},Ce=v(t=>{let{createPath:n,createImportHelpers:a}=S(t),{generators:o}=t.config,s=async()=>{let{dependencies:e={},devDependencies:a={}}=await import(r(t.root,`package.json`),{with:{type:`json`}}).then(e=>e.default);{let t=[],n=[],r=o.flatMap(e=>[`dependencies`,`devDependencies`].flatMap(t=>e[t]?Object.entries(typeof e[t]==`function`?e[t](e.options):e[t]).flatMap(([e,n])=>{let r=k.minVersion(n)?.version;return r?[[e,r,t]]:[]}):[]));for(let[i,o,s]of r){let r=e[i]||a[i],c=r?k.minVersion(r)?.version:void 0;!r||!c?t.push([i,o,s]):k.lt(c,o)&&n.push([i,o,s])}if(t.length){console.error(i([`red`,`italic`],`There are ${t.length} missing dependencies, please consider installing them.`));for(let e of[`dependencies`,`devDependencies`]){let n=t.filter(t=>t[2]===e);n.length&&console.error(`${e}: ${i([`blue`],n.map(([e])=>e).join(` `))}`)}}n.length&&(console.error(i([`yellow`,`italic`],`There are ${n.length} outdated dependencies, please consider updating them:`)),console.error(n.map(([e])=>e).join(` `)),console.error())}{await T(r(t.root,`tsconfig.json`),JSON.stringify({extends:`./${u.libDir}/tsconfig.json`},void 0,2),{},{overwrite:!1}),await T(n.lib(`../tsconfig.json`),JSON.stringify(z({dependencies:e,devDependencies:a}),void 0,2),{}),await T(n.src(`tsconfig.json`),JSON.stringify({extends:`../../${u.libDir}/${t.name}/tsconfig.json`},void 0,2),{},{overwrite:!1});let i=z({dependencies:e,devDependencies:a},t.name),s={},c=new Set(i.compilerOptions.types||[]);for(let{meta:e}of o){e.jsx&&(s.jsx=e.jsx),e.jsxImportSource&&(s.jsxImportSource=e.jsxImportSource);for(let t of e.types||[])c.add(t)}await T(n.lib(`tsconfig.json`),JSON.stringify({...i,compilerOptions:{...i.compilerOptions,...s,types:[...c.values()]}},void 0,2),{})}for(let[e,t]of[[`env.d.ts`,ve],[`global.d.ts`,be]])await T(n.lib(`../${e}`),t,{});await T(n.lib(`../.gitignore`),ye,{},{overwrite:!1}),o.some(e=>e.meta.slot===`frontend`)&&await T(n.src(`index.html`),xe,{entryDir:u.entryDir},{overwrite:e=>!e?.trim()})},c=async r=>{let{renderToFile:i}=w({helpers:{...a({origin:`lib`}),...A()},partials:{routeMapperPartial:R}}),o=r.flatMap(({kind:e,entry:t})=>e===`apiRoute`?[t]:[]),s=r.flatMap(({kind:e,entry:t})=>e===`pageRoute`?[t]:[]);await i(n.libCore(`routes.ts`),L,{apiRoutes:o,pageRoutes:s});for(let[e,r]of[[`config.ts`,he],[`types.ts`,_e],[`ssr.ts`,ge],[`index.ts`,I]])await i(n.libCore(e),r,{...t,apiRoutes:o,pageRoutes:s});for(let{kind:t,entry:a}of r)t===`apiRoute`&&await i(n.libApi(e(a.file),`schemas.ts`),Se,{route:a},{overwrite:!1})};return{start:s,watch:c,build:c,virtualModules(){let{createImport:e}=S(t);return[{specifier:`virtual:kosmo/backend-app`,csr:`export default undefined;`,ssr:o.some(e=>e.meta.slot===`backend`)?`export { default } from "${e.api([`app`],{origin:`lib`})}";`:`export default undefined;`}]}}}),B=_({meta:{name:`Core`},dependencies:{"path-to-regexp":me.devDependencies[`path-to-regexp`]},factory:Ce}),we={type:`module`,private:!0,name:`@kosmojs/fetch-generator`,version:`0.3.0`,author:`Slee Woo`,license:`MIT`,files:[`pkg/*`],exports:{".":{types:`./pkg/index.d.ts`,default:`./pkg/index.js`}},scripts:{build:`wsbuild src/index.ts`,test:`vitest --root ../.. --project generators/fetch-generator`},dependencies:{"@kosmojs/core":`workspace:^`,"@kosmojs/lib":`workspace:^`},devDependencies:{"light-my-request":`^6.6.0`}},Te=`{{#each routes}}
4
586
  import {{id}} from "{{ createImport 'libApi' name 'fetch' }}";
5
587
  {{/each}}
6
588
 
@@ -18,10 +600,10 @@ export default {
18
600
  {{/each}}
19
601
  {{/each}}
20
602
  }
21
- `,P=`import fetchFactory, { join } from "@kosmojs/core/fetch";
603
+ `,Ee=`import fetchFactory, { join } from "@kosmojs/core/fetch";
22
604
 
23
605
  import { base, apiBase, apiRouteMap } from "{{ createImport 'libCore' }}";
24
- import { transport } from "{{ createImport 'lib' '@fetch' }}";
606
+ import { transport } from "virtual:kosmo/fetch-transport";
25
607
 
26
608
  import {
27
609
  type MaybeWrapped,
@@ -73,9 +655,7 @@ export const {{method}} = (
73
655
  _params{{#if ../route.optionalParams}}?{{/if}}: MaybeWrapped<ParamsT>,
74
656
  _payload?: {
75
657
  {{#each payloadTypes}}
76
- {{target}}: {{id}} extends { {{method}}: unknown }
77
- ? MaybeWrapped<{{id}}["{{method}}"]>
78
- : unknown,
658
+ {{target}}: MaybeWrapped<{{id}}>,
79
659
  {{/each}}
80
660
  },
81
661
  opt?: {
@@ -118,13 +698,215 @@ export default {
118
698
  href,
119
699
  validationSchemas,
120
700
  };
121
- `,F=`export type MaybeWrapped<T> = T;
701
+ `,De=`import backend from "virtual:kosmo/backend-app";
702
+
703
+ import {
704
+ redirectCodes,
705
+ ssrOrigin,
706
+ store,
707
+ } from "{{ createImport 'libCore' 'ssr' }}";
708
+
709
+ /**
710
+ * Maximum redirect hops, mirroring the fetch spec limit.
711
+ * */
712
+ export const maxRedirects = 5;
713
+
714
+ /**
715
+ * HeadersProvider for createTransport.
716
+ * */
717
+ const headersProvider = () => {
718
+ return store.getStore()?.headers;
719
+ };
720
+
721
+ const createDispatch = (app) => {
722
+ return typeof app.fetch === "function"
723
+ ? app.fetch
724
+ : async (request) => {
725
+ const { inject } = await import("light-my-request");
726
+
727
+ /**
728
+ * Node dispatch: serializes the web Request into light-my-request's
729
+ * injection format and lifts the injected response back into a web Response.
730
+ * */
731
+ const url = new URL(request.url);
732
+
733
+ const payload = ["GET", "HEAD"].includes(request.method)
734
+ ? undefined
735
+ : Buffer.from(await request.arrayBuffer());
736
+
737
+ const result = await inject(app.callback(), {
738
+ method: request.method,
739
+ url: url.pathname + url.search,
740
+ headers: Object.fromEntries(request.headers),
741
+ ...(payload?.length ? { payload } : {}),
742
+ });
743
+
744
+ const headers = new Headers();
745
+
746
+ for (const [key, value] of Object.entries(result.headers)) {
747
+ for (const entry of Array.isArray(value) ? value : [value]) {
748
+ if (entry !== undefined) {
749
+ headers.append(key, String(entry));
750
+ }
751
+ }
752
+ }
753
+
754
+ /**
755
+ * 204/304 responses must not carry a body per the Response
756
+ * constructor contract.
757
+ * */
758
+ const body = [204, 304].includes(result.statusCode)
759
+ ? null
760
+ : new Uint8Array(result.rawPayload);
761
+
762
+ return new Response(body, {
763
+ status: result.statusCode,
764
+ statusText: result.statusMessage,
765
+ headers,
766
+ });
767
+ };
768
+ };
769
+
770
+ const createTransport = (app) => {
771
+ const dispatch = createDispatch(app);
772
+
773
+ /**
774
+ * Build a fetch-compatible transport that dispatches requests
775
+ * directly into the given app - no sockets, no interception.
776
+ * Redirects are followed in-process, including the 303 and 301/302 method rewrite to GET.
777
+ * */
778
+ return async (input, init) => {
779
+ /**
780
+ * Request-scoped headers act as defaults: anything set explicitly
781
+ * on the call itself wins over forwarded values.
782
+ * */
783
+ const headers = new Headers(init?.headers);
784
+
785
+ // When the body is FormData, the Request constructor sets a multipart
786
+ // Content-Type with a fresh boundary. A forwarded Content-Type default would
787
+ // override that boundary and desync it from the serialized body, so never
788
+ // forward Content-Type for FormData bodies.
789
+ const isFormBody = init?.body instanceof FormData;
790
+
791
+ for (const [key, value] of new Headers(headersProvider() || undefined)) {
792
+ if (isFormBody && key.toLowerCase() === "content-type") {
793
+ continue;
794
+ }
795
+ if (!headers.has(key)) {
796
+ headers.set(key, value);
797
+ }
798
+ }
799
+
800
+ let request = new Request(new URL(String(input), ssrOrigin), {
801
+ ...init,
802
+ headers,
803
+ });
804
+
805
+ /**
806
+ * Bodies are buffered once so they can be replayed across
807
+ * 307/308 hops; the client only ever sends strings, FormData
808
+ * and buffer-ish payloads, so this is safe and cheap.
809
+ * */
810
+ const body = ["GET", "HEAD"].includes(request.method)
811
+ ? undefined
812
+ : await request.arrayBuffer();
813
+
814
+ for (let hop = 0; ; hop++) {
815
+ if (hop === maxRedirects) {
816
+ throw new TypeError("Failed to fetch: too many redirects");
817
+ }
818
+
819
+ const response = await dispatch(
820
+ body === undefined || request.method === "GET"
821
+ ? new Request(request, { body: null })
822
+ : new Request(request, { body }),
823
+ );
824
+
825
+ const location = response.headers.get("location");
826
+
827
+ if (!location || !redirectCodes.includes(response.status)) {
828
+ return response;
829
+ }
830
+
831
+ const method =
832
+ response.status === 303 ||
833
+ ([301, 302].includes(response.status) && request.method === "POST")
834
+ ? "GET"
835
+ : request.method;
836
+
837
+ request = new Request(new URL(location, request.url), {
838
+ method,
839
+ headers: request.headers,
840
+ });
841
+ }
842
+ };
843
+ };
844
+
845
+ const ssrTransport = backend ? createTransport(backend) : undefined;
846
+
847
+ export const transport = ssrTransport
848
+ ? async (input, init) => {
849
+ try {
850
+ const response = await ssrTransport(input, init);
851
+ if (response?.ok) {
852
+ return response;
853
+ }
854
+ // the rethrow here needed cause ssrTransport does not throw on non-2xx responses
855
+ throw new SSRFetchError([
856
+ input,
857
+ response,
858
+ typeof response?.text === "function"
859
+ ? await response.text()
860
+ : response?.statusText,
861
+ ]);
862
+ } catch (error) {
863
+ /**
864
+ * Capture the fetch error at the transport level and stash it on the request store.
865
+ * Some frameworks - Solid notably - swallow a rejecting loader and still emit a partial render tree.
866
+ * Storing the error here keeps it observable regardless of how the framework handles the loader rejection.
867
+ * */
868
+ const storage = store.getStore();
869
+ if (storage) {
870
+ storage.error = error;
871
+ }
872
+ throw error;
873
+ }
874
+ }
875
+ : undefined; // let fetch clients pick the transport
876
+
877
+ class SSRFetchError extends Error {
878
+ constructor([input, response, message]) {
879
+ const pathname = pathnameOf(input);
880
+ const status = response.status ?? "unknown";
881
+ super(\`\${pathname}: \${status} [ \${message} ]\`.trim());
882
+ this.name = "SSRFetchError";
883
+ }
884
+ }
885
+
886
+ const pathnameOf = (input) => {
887
+ try {
888
+ if (typeof input === "string") {
889
+ return new URL(input, "http://x").pathname;
890
+ }
891
+ if (input instanceof URL) {
892
+ return input.pathname;
893
+ }
894
+ if (input instanceof Request) {
895
+ return new URL(input.url).pathname;
896
+ }
897
+ } catch {}
898
+ return String(input);
899
+ };
900
+ `,Oe=`export type MaybeWrapped<T> = T;
122
901
  export const unwrap = <T>(data: T) => data;
123
- `,I=g(e=>{let{createPath:t,createImportHelpers:n}=y(e),{renderToFile:r}=x({helpers:{...n({origin:`lib`}),...w()}}),i=async(e,n)=>{let i=e.flatMap(({kind:e,entry:t})=>e===`apiRoute`?[t]:[]).sort(S);await r(t.lib(`fetch.ts`),N,{routes:i});for(let{kind:e,entry:i}of n)if(e===`apiRoute`){let e=[];for(let t of i.validationDefinitions)if(t.target===`response`)for(let{id:n,status:r,body:i,resolvedType:a}of t.variants)!i||Math.floor(r/100)!==2||e.push({id:n,target:t.target,method:t.method,resolvedType:a});else{let{id:n,resolvedType:r}=t.schema;e.push({id:n,target:t.target,method:t.method,resolvedType:r})}let n=Object.keys(ne),a=i.methods.flatMap(t=>n.includes(t)?[{method:t,payloadTypes:e.filter(e=>e.method===t&&![`headers`,`cookies`,`response`].includes(e.target)),responseType:e.find(e=>e.target===`response`&&e.method===t)}]:[]),o=Object.values(e.reduce((e,{id:t,target:n,method:r,resolvedType:i})=>(n===`response`&&(e[r]||(e[r]={method:r,types:[]}),e[r].types.push({id:t,target:n,method:r,resolvedType:i})),e),{}));await r(t.libApi(i.name,`fetch.ts`),P,{route:i,validationTypes:e,routeMethods:a,responseTypes:o})}};return{async start(){for(let[e,n]of[[`unwrap.ts`,F],[`@fetch/transport.ts`,M],[`@fetch/index.ts`,j]])await r(t.lib(e),n,{})},async watch(e,t){await i(e,e.filter(p(t,[`create`,`update`])))},async build(e){await i(e,e)},async ssrBuild(){for(let[e,n]of[[`@fetch/transport.ts`,`export { transport } from "${l.libPrefix}/@ssr/fetch";`]])await r(t.lib(e),n,{})}}}),L=h({meta:{name:`Fetch`,slot:`fetch`},factory:I}),R={type:`module`,private:!0,name:`@kosmojs/h3-generator`,version:`0.3.0`,author:`Slee Woo`,license:`MIT`,files:[`pkg/*`],exports:{".":{types:`./pkg/index.d.ts`,default:`./pkg/index.js`}},scripts:{build:`wsbuild src/index.ts`,test:`vitest --root ../.. --project generators/h3-generator`},dependencies:{"@kosmojs/core":`workspace:^`,"@kosmojs/lib":`workspace:^`,crc:`^4.3.2`},devDependencies:{h3:`2.0.1-rc.29`,vite:`^8.2.2`}},z=`import { H3, type Middleware } from "h3";
902
+ `,ke=v(e=>{let{createPath:t,createImportHelpers:n}=S(e),{render:r,renderToFile:i}=w({helpers:{...n({origin:`lib`}),...A()}}),a=async(e,n)=>{let r=e.flatMap(({kind:e,entry:t})=>e===`apiRoute`?[t]:[]).sort(E);await i(t.lib(`fetch.ts`),Te,{routes:r});for(let{kind:e,entry:r}of n)if(e===`apiRoute`){let e=[];for(let t of r.validationDefinitions)if(t.target===`response`)for(let{id:n,status:r,body:i,resolvedType:a}of t.variants)!i||Math.floor(r/100)!==2||e.push({id:n,target:t.target,method:t.method,resolvedType:a});else{let{id:n,resolvedType:r}=t.schema;e.push({id:n,target:t.target,method:t.method,resolvedType:r})}let n=Object.keys(te),a=r.methods.flatMap(t=>n.includes(t)?[{method:t,payloadTypes:e.filter(e=>e.method===t&&![`headers`,`cookies`,`response`].includes(e.target)),responseType:e.find(e=>e.target===`response`&&e.method===t)}]:[]),o=Object.values(e.reduce((e,{id:t,target:n,method:r,resolvedType:i})=>(n===`response`&&(e[r]||(e[r]={method:r,types:[]}),e[r].types.push({id:t,target:n,method:r,resolvedType:i})),e),{}));await i(t.libApi(r.name,`fetch.ts`),Ee,{route:r,validationTypes:e,routeMethods:a,responseTypes:o})}};return{async start(){for(let[e,n]of[[`unwrap.ts`,Oe]])await i(t.lib(e),n,{})},async watch(e,t){await a(e,e.filter(h(t,[`create`,`update`])))},async build(e){await a(e,e)},virtualModules(){return[{specifier:`virtual:kosmo/fetch-transport`,csr:`export const transport = undefined;`,ssr:r(De,{})}]}}}),Ae=_({meta:{name:`Fetch`,slot:`fetch`},dependencies:{"light-my-request":we.devDependencies[`light-my-request`]},factory:ke}),je={type:`module`,private:!0,name:`@kosmojs/h3-generator`,version:`0.3.0`,author:`Slee Woo`,license:`MIT`,files:[`pkg/*`],exports:{".":{types:`./pkg/index.d.ts`,default:`./pkg/index.js`}},scripts:{build:`wsbuild src/index.ts`,test:`vitest --root ../.. --project generators/h3-generator`},dependencies:{"@kosmojs/core":`workspace:^`,"@kosmojs/lib":`workspace:^`,crc:`^4.3.2`},devDependencies:{h3:`2.0.1-rc.29`,vite:`^8.2.2`}},Me=`import { H3, type Middleware } from "h3";
124
903
 
125
904
  import type { Route, RouteDebugOption } from "@kosmojs/core/api";
126
905
 
127
- export type App = H3;
906
+ /**
907
+ * The interface is a nameable symbol of this module, emit stops here and never chases through to the class.
908
+ * */
909
+ export interface App extends H3 {}
128
910
 
129
911
  export type AppOptions = ConstructorParameters<typeof H3>[0] & {
130
912
  debug?: RouteDebugOption;
@@ -223,10 +1005,10 @@ export function appFactory(
223
1005
 
224
1006
  return app;
225
1007
  }
226
- `,B=`import type { DevSetup } from "@kosmojs/core/api";
1008
+ `,Ne=`import type { DevSetup } from "@kosmojs/core/api";
227
1009
 
228
1010
  export const devSetup = (setup: DevSetup) => setup;
229
- `,me=`import { type H3Event, HTTPError } from "h3";
1011
+ `,Pe=`import { type H3Event, HTTPError } from "h3";
230
1012
 
231
1013
  import { ValidationError } from "@kosmojs/core/errors";
232
1014
 
@@ -250,7 +1032,17 @@ export const errorHandlerFactory: ErrorHandlerFactory = (handler) => {
250
1032
  );
251
1033
  };
252
1034
  };
253
- `,he=`import { type H3Event, readBody } from "h3";
1035
+ `,Fe=`import { createListener } from "./server";
1036
+
1037
+ import app from "{{ createImport 'api' 'app' }}";
1038
+
1039
+ /**
1040
+ * Entry for the \`dist/<folder>/api/listener.js\` bundle.
1041
+ * Exposes this folder's API as a plain node:http listener, mounted by \`dist/run.js\`
1042
+ * next to the other folders. Nothing here listens on a port - \`server.ts\` does that.
1043
+ * */
1044
+ export default createListener(app);
1045
+ `,Ie=`import { type H3Event, readBody } from "h3";
254
1046
 
255
1047
  import {
256
1048
  parseCookies,
@@ -290,7 +1082,8 @@ export const bodyparsers: {
290
1082
  return event.req.text();
291
1083
  },
292
1084
  };
293
- `,ge=`import type { Middleware } from "h3";
1085
+ `,Le=`import { command } from "virtual:kosmo/env";
1086
+ import type { Middleware } from "h3";
294
1087
 
295
1088
  import type {
296
1089
  RequestBodyTarget,
@@ -467,13 +1260,13 @@ export const createRouteMiddleware: CreateRouteMiddleware<
467
1260
  // options are same for all variants
468
1261
  const { runtimeValidation, customErrors } = variants[0];
469
1262
 
470
- if (KOSMO_PRODUCTION_BUILD) {
471
- // skip if undefined or explicitly set to false
1263
+ if (command === "build") {
1264
+ // production build - skip if undefined or explicitly set to false
472
1265
  if (runtimeValidation === undefined || runtimeValidation === false) {
473
1266
  return next();
474
1267
  }
475
1268
  } else {
476
- // skip only if explicitly set to false
1269
+ // dev mode - skip only if explicitly set to false
477
1270
  if (runtimeValidation === false) {
478
1271
  return next();
479
1272
  }
@@ -682,7 +1475,7 @@ export const routes = createRoutes<ParameterizedMiddleware, Middleware>(
682
1475
  createRouteMiddleware,
683
1476
  },
684
1477
  );
685
- `,_e=`import { join } from "node:path";
1478
+ `,Re=`import { join } from "node:path";
686
1479
 
687
1480
  import type { RouteSource } from "@kosmojs/core/api";
688
1481
 
@@ -734,12 +1527,25 @@ export const routeSources: Array<RouteSource<never>> = [
734
1527
  },
735
1528
  {{/each}}
736
1529
  ];
737
- `,ve=`import { parseArgs, styleText } from "node:util";
1530
+ `,ze=`import type { IncomingMessage, ServerResponse } from "node:http";
1531
+ import { parseArgs, styleText } from "node:util";
738
1532
 
739
1533
  import { serve as h3serve } from "h3";
1534
+ import { toNodeHandler } from "h3/node";
740
1535
 
741
1536
  import type { App } from "./app";
742
1537
 
1538
+ export type NodeListener = (req: IncomingMessage, res: ServerResponse) => void;
1539
+
1540
+ /**
1541
+ * Wrap the app into a node:http request listener.
1542
+ * Used by dist/run.js to mount this folder's API next to other folders;
1543
+ * the standalone server (\`serve\`) binds the app through h3's own adapter instead.
1544
+ * */
1545
+ export const createListener = <T extends App>(app: T): NodeListener => {
1546
+ return toNodeHandler(app);
1547
+ };
1548
+
743
1549
  type Handles = {
744
1550
  port?: number | undefined;
745
1551
  onListen?: () => Promise<void>;
@@ -782,7 +1588,7 @@ export const serve = async <T extends App>(app: T, opt?: Handles) => {
782
1588
 
783
1589
  return server as never;
784
1590
  };
785
- `,ye=`import type { H3Event, H3EventContext } from "h3";
1591
+ `,Be=`import type { H3Event, H3EventContext } from "h3";
786
1592
 
787
1593
  import type { ValidationDefmap, ValidationOptmap } from "@kosmojs/core";
788
1594
  import {
@@ -929,22 +1735,22 @@ export const defineRoute: <
929
1735
  use: use as never,
930
1736
  });
931
1737
  };
932
- `,be=`export * from "./@api/app";
1738
+ `,Ve=`export * from "./@api/app";
933
1739
  export { appFactory as default } from "./@api/app";
934
1740
  export * from "./@api/dev";
935
1741
  export * from "./@api/errors";
936
1742
  export * from "./@api/router";
937
1743
  export * from "./@api/routes";
938
1744
  export * from "./@api/server";
939
- `,xe=`import { onError } from "h3";
1745
+ `,He=`import { onError } from "h3";
940
1746
 
941
- import appFactory, { routes, type App } from "{{ createImport 'lib' 'api:factory' }}";
1747
+ import appFactory, { routes } from "{{ createImport 'lib' 'api:factory' }}";
942
1748
  import defaultErrorHandler from "./errors";
943
1749
 
944
1750
  export default appFactory(routes, ({ app }) => {
945
1751
  app.use(onError(defaultErrorHandler));
946
- }) as App;
947
- `,Se=`import { toNodeHandler } from "h3/node";
1752
+ });
1753
+ `,Ue=`import { toNodeHandler } from "h3/node";
948
1754
 
949
1755
  import app from "./app";
950
1756
 
@@ -964,10 +1770,10 @@ process.on("unhandledRejection", (reason) => {
964
1770
  console.error("Reason:", reason);
965
1771
  process.exit(1);
966
1772
  });
967
- `,Ce=`export declare module "{{ createImport 'libApi' }}" {
1773
+ `,We=`export declare module "{{ createImport 'libApi' }}" {
968
1774
  interface DefaultContext {}
969
1775
  }
970
- `,we=`import { ValidationError } from "@kosmojs/core/errors";
1776
+ `,Ge=`import { ValidationError } from "@kosmojs/core/errors";
971
1777
  import { HTTPError } from "h3";
972
1778
 
973
1779
  import { errorHandlerFactory } from "{{ createImport 'lib' 'api:factory' }}";
@@ -993,14 +1799,14 @@ export default errorHandlerFactory(async (error, event) => {
993
1799
  headers: { "Content-Type": "text/plain" },
994
1800
  });
995
1801
  });
996
- `,Te=`import { defineRoute } from "{{ createImport 'libApi' }}";
1802
+ `,Ke=`import { defineRoute } from "{{ createImport 'libApi' }}";
997
1803
 
998
1804
  export default defineRoute<"{{route.name}}">(({ GET }) => [
999
1805
  GET(async (event) => {
1000
1806
  return "Automatically generated route";
1001
1807
  }),
1002
1808
  ]);
1003
- `,Ee=`import { use } from "{{ createImport 'libApi' }}";
1809
+ `,qe=`import { use } from "{{ createImport 'libApi' }}";
1004
1810
 
1005
1811
  export type UseT = {};
1006
1812
 
@@ -1009,11 +1815,11 @@ export default [
1009
1815
  return next();
1010
1816
  }),
1011
1817
  ];
1012
- `,De=`import { serve } from "{{ createImport 'lib' 'api:factory' }}";
1818
+ `,Je=`import { serve } from "{{ createImport 'lib' 'api:factory' }}";
1013
1819
  import app from "./app";
1014
1820
 
1015
1821
  await serve(app);
1016
- `,Oe=`import { use } from "{{ createImport 'libApi' }}";
1822
+ `,Ye=`import { use } from "{{ createImport 'libApi' }}";
1017
1823
 
1018
1824
  /**
1019
1825
  * Define global middleware applied to all routes.
@@ -1024,7 +1830,7 @@ export default [
1024
1830
  return next();
1025
1831
  }),
1026
1832
  ];
1027
- `,ke=g((e,n)=>{let{createPath:r,createImportHelpers:i}=y(e),a=e=>e.length===0?`{}`:e.length===1?e[0]:`Override<${e[0]}, ${a(e.slice(1))}>`,{renderToFile:o}=x({helpers:{...i({origin:`lib`}),...w(),paramsDefaults({params:e}){return`[${e.schema.map(()=>`unknown?`).join(`, `)}]`},paramsMappings({params:e}){return`[${e.schema.map(({name:e,kind:t})=>`["${e}", unknown, ${t===`required`?`true`:`false`}]`).join(`, `)}]`},cascadingState({cascadingMiddleware:e}){return a(e.map(({id:e})=>`UseT${e}`))}}}),{renderToFile:s}=x({helpers:i({origin:`src`})}),l=e=>e?.trim().length===0,d=c(n?.templates,Te),f=async e=>{for(let{kind:t,entry:n}of e)t===`apiRoute`?await s(r.api(n.file),d(n.name,n),{route:n},{overwrite:l}):t===`apiUse`&&await s(r.api(n.file),Ee,{},{overwrite:l})},m=async e=>{let i=e.flatMap(({kind:e,entry:t})=>e===`apiUse`?[t]:[]),a=e.flatMap(({kind:e,entry:r})=>{if(e!==`apiRoute`)return[];let a=r.name.split(`/`).reduce((e,n)=>{let r=e[e.length-1];return e.push(r?t(r,n):n),e},[]),o={...r,path:r.h3Pattern,basename:r.name,cascadingMiddleware:i.flatMap(e=>a.some(t=>e.name===t)?[e]:[])};return[o,...Object.entries({...n?.alias}).flatMap(([e,t])=>{let n=b(e);return t===r.name?[{...o,name:e,basename:r.name,id:`${o.id}_${T(e)}`,alias:u(n),pathTokens:n}]:[]})]}).sort(S);for(let[e,t]of[[`@api/routes.ts`,_e]])await o(r.lib(e),t,{routes:a,cascadingMiddleware:i})};return{config({command:e}){return{define:{KOSMO_PRODUCTION_BUILD:e===`build`?`true`:`false`}}},async start(){for(let[e,t]of[[`api.ts`,ye],[`api:factory.ts`,be],[`@api/app.ts`,z],[`@api/parsers.ts`,he],[`@api/dev.ts`,B],[`@api/errors.ts`,me],[`@api/router.ts`,ge],[`@api/server.ts`,ve]])await o(r.lib(e),t,{});for(let[e,t]of[[`app.ts`,xe],[`dev.ts`,Se],[`errors.ts`,we],[`server.ts`,De],[`use.ts`,Oe],[`env.d.ts`,Ce]])await s(r.api(e),t,{},{overwrite:l})},async watch(e,t){await f(e.filter(p(t,[`create`]))),await m(e)},async build(e){await f(e),await m(e)}}}),Ae=h({meta:{name:`H3`,slot:`backend`},dependencies:{h3:R.devDependencies.h3},factory:ke}),V={type:`module`,private:!0,name:`@kosmojs/hono-generator`,version:`0.3.0`,author:`Slee Woo`,license:`MIT`,files:[`pkg/*`],exports:{".":{types:`./pkg/index.d.ts`,default:`./pkg/index.js`}},scripts:{build:`wsbuild src/index.ts`,test:`vitest --root ../.. --project generators/hono-generator`},dependencies:{"@kosmojs/core":`workspace:^`,"@kosmojs/lib":`workspace:^`,crc:`^4.3.2`},devDependencies:{"@hono/node-server":`^2.1.1`,hono:`^4.13.3`,vite:`^8.2.2`}},je=`import { Hono, type MiddlewareHandler } from "hono";
1833
+ `,Xe=v((e,n)=>{let{createPath:r,createImportHelpers:i}=S(e),a=e=>e.length===0?`{}`:e.length===1?e[0]:`Override<${e[0]}, ${a(e.slice(1))}>`,{renderToFile:o}=w({helpers:{...i({origin:`lib`}),...A(),paramsDefaults({params:e}){return`[${e.schema.map(()=>`unknown?`).join(`, `)}]`},paramsMappings({params:e}){return`[${e.schema.map(({name:e,kind:t})=>`["${e}", unknown, ${t===`required`?`true`:`false`}]`).join(`, `)}]`},cascadingState({cascadingMiddleware:e}){return a(e.map(({id:e})=>`UseT${e}`))}}}),{renderToFile:s}=w({helpers:i({origin:`src`})}),c=e=>e?.trim().length===0,u=l(n?.templates,Ke),d=async e=>{for(let{kind:t,entry:n}of e)t===`apiRoute`?await s(r.api(n.file),u(n.name,n),{route:n},{overwrite:c}):t===`apiUse`&&await s(r.api(n.file),qe,{},{overwrite:c})},p=async e=>{let i=e.flatMap(({kind:e,entry:t})=>e===`apiUse`?[t]:[]),a=e.flatMap(({kind:e,entry:r})=>{if(e!==`apiRoute`)return[];let a=r.name.split(`/`).reduce((e,n)=>{let r=e[e.length-1];return e.push(r?t(r,n):n),e},[]),o={...r,path:r.h3Pattern,basename:r.name,cascadingMiddleware:i.flatMap(e=>a.some(t=>e.name===t)?[e]:[])};return[o,...Object.entries({...n?.alias}).flatMap(([e,t])=>{let n=C(e);return t===r.name?[{...o,name:e,basename:r.name,id:`${o.id}_${j(e)}`,alias:f(n),pathTokens:n}]:[]})]}).sort(E);for(let[e,t]of[[`@api/routes.ts`,Re]])await o(r.lib(e),t,{routes:a,cascadingMiddleware:i})};return{async start(){for(let[e,t]of[[`api.ts`,Be],[`api:factory.ts`,Ve],[`@api/app.ts`,Me],[`@api/parsers.ts`,Ie],[`@api/dev.ts`,Ne],[`@api/errors.ts`,Pe],[`@api/listener.ts`,Fe],[`@api/router.ts`,Le],[`@api/server.ts`,ze]])await o(r.lib(e),t,{});for(let[e,t]of[[`app.ts`,He],[`dev.ts`,Ue],[`errors.ts`,Ge],[`server.ts`,Je],[`use.ts`,Ye],[`env.d.ts`,We]])await s(r.api(e),t,{},{overwrite:c})},async watch(e,t){await d(e.filter(h(t,[`create`]))),await p(e)},async build(e){await d(e),await p(e)}}}),Ze=_({meta:{name:`H3`,slot:`backend`},dependencies:{h3:je.devDependencies.h3},factory:Xe}),V={type:`module`,private:!0,name:`@kosmojs/hono-generator`,version:`0.3.0`,author:`Slee Woo`,license:`MIT`,files:[`pkg/*`],exports:{".":{types:`./pkg/index.d.ts`,default:`./pkg/index.js`}},scripts:{build:`wsbuild src/index.ts`,test:`vitest --root ../.. --project generators/hono-generator`},dependencies:{"@kosmojs/core":`workspace:^`,"@kosmojs/lib":`workspace:^`,crc:`^4.3.2`},devDependencies:{"@hono/node-server":`^2.1.1`,hono:`^4.13.3`,vite:`^8.2.2`}},Qe=`import { Hono, type MiddlewareHandler } from "hono";
1028
1834
  import type { Router } from "hono/router";
1029
1835
  import { RegExpRouter } from "hono/router/reg-exp-router";
1030
1836
  import { SmartRouter } from "hono/router/smart-router";
@@ -1126,10 +1932,10 @@ export function appFactory(
1126
1932
 
1127
1933
  return app as never;
1128
1934
  }
1129
- `,Me=`import type { DevSetup } from "@kosmojs/core/api";
1935
+ `,$e=`import type { DevSetup } from "@kosmojs/core/api";
1130
1936
 
1131
1937
  export const devSetup = (setup: DevSetup) => setup;
1132
- `,Ne=`import type { Context } from "hono";
1938
+ `,et=`import type { Context } from "hono";
1133
1939
 
1134
1940
  import type { AppEnv } from "./app";
1135
1941
 
@@ -1143,7 +1949,17 @@ export type ErrorHandlerFactory = (handler: ErrorHandler) => ErrorHandler;
1143
1949
  export const errorHandlerFactory: ErrorHandlerFactory = (handler) => {
1144
1950
  return handler;
1145
1951
  };
1146
- `,Pe=`import type { Context } from "hono";
1952
+ `,tt=`import { createListener } from "./server";
1953
+
1954
+ import app from "{{ createImport 'api' 'app' }}";
1955
+
1956
+ /**
1957
+ * Entry for the \`dist/<folder>/api/listener.js\` bundle.
1958
+ * Exposes this folder's API as a plain node:http listener, mounted by \`dist/run.js\`
1959
+ * next to the other folders. Nothing here listens on a port - \`server.ts\` does that.
1960
+ * */
1961
+ export default createListener(app);
1962
+ `,nt=`import type { Context } from "hono";
1147
1963
 
1148
1964
  import {
1149
1965
  parseCookies,
@@ -1192,7 +2008,8 @@ export const bodyparsers: {
1192
2008
  return ctx.req[as]();
1193
2009
  },
1194
2010
  };
1195
- `,Fe=`import type { MiddlewareHandler } from "hono";
2011
+ `,rt=`import { command } from "virtual:kosmo/env";
2012
+ import type { MiddlewareHandler } from "hono";
1196
2013
 
1197
2014
  import type {
1198
2015
  RequestBodyTarget,
@@ -1370,13 +2187,13 @@ export const createRouteMiddleware: CreateRouteMiddleware<
1370
2187
  // options are same for all variants
1371
2188
  const { runtimeValidation, customErrors } = variants[0];
1372
2189
 
1373
- if (KOSMO_PRODUCTION_BUILD) {
1374
- // skip if undefined or explicitly set to false
2190
+ if (command === "build") {
2191
+ // production build - skip if undefined or explicitly set to false
1375
2192
  if (runtimeValidation === undefined || runtimeValidation === false) {
1376
2193
  return next();
1377
2194
  }
1378
2195
  } else {
1379
- // skip only if explicitly set to false
2196
+ // dev mode - skip only if explicitly set to false
1380
2197
  if (runtimeValidation === false) {
1381
2198
  return next();
1382
2199
  }
@@ -1571,7 +2388,7 @@ export const routes = createRoutes<ParameterizedMiddleware, MiddlewareHandler>(
1571
2388
  createRouteMiddleware,
1572
2389
  },
1573
2390
  );
1574
- `,Ie=`import { join } from "node:path";
2391
+ `,it=`import { join } from "node:path";
1575
2392
 
1576
2393
  import type { RouteSource } from "@kosmojs/core/api";
1577
2394
 
@@ -1623,13 +2440,25 @@ export const routeSources: Array<RouteSource<never>> = [
1623
2440
  },
1624
2441
  {{/each}}
1625
2442
  ];
1626
- `,Le=`import { chmod, unlink } from "node:fs/promises";
2443
+ `,at=`import { chmod, unlink } from "node:fs/promises";
2444
+ import type { IncomingMessage, ServerResponse } from "node:http";
1627
2445
  import { parseArgs, styleText } from "node:util";
1628
2446
 
1629
- import { createAdaptorServer } from "@hono/node-server";
2447
+ import { createAdaptorServer, getRequestListener } from "@hono/node-server";
1630
2448
 
1631
2449
  import type { App } from "./app";
1632
2450
 
2451
+ export type NodeListener = (req: IncomingMessage, res: ServerResponse) => void;
2452
+
2453
+ /**
2454
+ * Wrap the app into a node:http request listener.
2455
+ * Used by dist/run.js to mount this folder's API next to other folders;
2456
+ * the standalone server (\`serve\`) binds the app through the runtime's native adapter instead.
2457
+ * */
2458
+ export const createListener = <T extends App>(app: T): NodeListener => {
2459
+ return getRequestListener(app.fetch);
2460
+ };
2461
+
1633
2462
  type Handles = {
1634
2463
  port?: number | undefined;
1635
2464
  sock?: string | undefined;
@@ -1708,7 +2537,7 @@ export const serve = async <T extends App>(app: T, opt?: Handles) => {
1708
2537
 
1709
2538
  return server as never;
1710
2539
  };
1711
- `,Re=`import type { Context, Next } from "hono";
2540
+ `,ot=`import type { Context, Next } from "hono";
1712
2541
 
1713
2542
  import type { ValidationDefmap, ValidationOptmap } from "@kosmojs/core";
1714
2543
  import {
@@ -1891,20 +2720,20 @@ export const defineRoute: <
1891
2720
  use: use as never,
1892
2721
  });
1893
2722
  };
1894
- `,ze=`export * from "./@api/app";
2723
+ `,st=`export * from "./@api/app";
1895
2724
  export { appFactory as default } from "./@api/app";
1896
2725
  export * from "./@api/dev";
1897
2726
  export * from "./@api/errors";
1898
2727
  export * from "./@api/router";
1899
2728
  export * from "./@api/routes";
1900
2729
  export * from "./@api/server";
1901
- `,Be=`import appFactory, { routes } from "{{ createImport 'lib' 'api:factory' }}";
2730
+ `,ct=`import appFactory, { routes } from "{{ createImport 'lib' 'api:factory' }}";
1902
2731
  import defaultErrorHandler from "./errors";
1903
2732
 
1904
2733
  export default appFactory(routes, ({ app }) => {
1905
2734
  app.onError(defaultErrorHandler);
1906
2735
  })
1907
- `,Ve=`import { getRequestListener } from "@hono/node-server";
2736
+ `,lt=`import { getRequestListener } from "@hono/node-server";
1908
2737
 
1909
2738
  import app from "./app";
1910
2739
 
@@ -1925,11 +2754,11 @@ process.on("unhandledRejection", (reason) => {
1925
2754
  process.exit(1);
1926
2755
  });
1927
2756
 
1928
- `,He=`export declare module "{{ createImport 'libApi' }}" {
2757
+ `,ut=`export declare module "{{ createImport 'libApi' }}" {
1929
2758
  interface DefaultVariables {}
1930
2759
  interface DefaultBindings {}
1931
2760
  }
1932
- `,Ue=`import { accepts } from "hono/accepts";
2761
+ `,dt=`import { accepts } from "hono/accepts";
1933
2762
  import { HTTPException } from "hono/http-exception";
1934
2763
 
1935
2764
  import { ValidationError, HTTPError } from "@kosmojs/core/errors";
@@ -1961,7 +2790,7 @@ export default errorHandlerFactory(async (error, ctx) => {
1961
2790
  ? ctx.json({ error: message }, status)
1962
2791
  : ctx.text(message, status);
1963
2792
  });
1964
- `,We=`import { defineRoute } from "{{ createImport 'libApi' }}";
2793
+ `,ft=`import { defineRoute } from "{{ createImport 'libApi' }}";
1965
2794
 
1966
2795
  export default defineRoute<"{{route.name}}">(({ GET }) => [
1967
2796
  GET(async (ctx) => {
@@ -1970,7 +2799,7 @@ export default defineRoute<"{{route.name}}">(({ GET }) => [
1970
2799
  return ctx.text("Automatically generated route");
1971
2800
  }),
1972
2801
  ]);
1973
- `,Ge=`import { use } from "{{ createImport 'libApi' }}";
2802
+ `,pt=`import { use } from "{{ createImport 'libApi' }}";
1974
2803
 
1975
2804
  export type UseT = {};
1976
2805
 
@@ -1981,11 +2810,11 @@ export default [
1981
2810
  return next();
1982
2811
  }),
1983
2812
  ];
1984
- `,Ke=`import { serve } from "{{ createImport 'lib' 'api:factory' }}";
2813
+ `,mt=`import { serve } from "{{ createImport 'lib' 'api:factory' }}";
1985
2814
  import app from "./app";
1986
2815
 
1987
2816
  await serve(app);
1988
- `,qe=`import { use } from "{{ createImport 'libApi' }}";
2817
+ `,ht=`import { use } from "{{ createImport 'libApi' }}";
1989
2818
 
1990
2819
  /**
1991
2820
  * Define global middleware applied to all routes.
@@ -1996,7 +2825,7 @@ export default [
1996
2825
  return next();
1997
2826
  }),
1998
2827
  ];
1999
- `,Je=g((e,n)=>{let{createPath:r,createImportHelpers:i}=y(e),a=e=>e.length===0?`{}`:e.length===1?e[0]:`Override<${e[0]}, ${a(e.slice(1))}>`,{renderToFile:o}=x({helpers:{...i({origin:`lib`}),...w(),paramsDefaults({params:e}){return`[${e.schema.map(()=>`unknown?`).join(`, `)}]`},paramsMappings({params:e}){return`[${e.schema.map(({name:e,kind:t})=>`["${e}", unknown, ${t===`required`?`true`:`false`}]`).join(`, `)}]`},cascadingState({cascadingMiddleware:e}){return a(e.map(({id:e})=>`UseT${e}`))}}}),{renderToFile:s}=x({helpers:i({origin:`src`})}),l=e=>e?.trim().length===0,u=c(n?.templates,We),f=async e=>{for(let{kind:t,entry:n}of e)t===`apiRoute`?await s(r.api(n.file),u(n.name,n),{route:n},{overwrite:l}):t===`apiUse`&&await s(r.api(n.file),Ge,{},{overwrite:l})},m=async e=>{let i=e.flatMap(({kind:e,entry:t})=>e===`apiUse`?[t]:[]),a=e.flatMap(({kind:e,entry:r})=>{if(e!==`apiRoute`)return[];let a=r.name.split(`/`).reduce((e,n)=>{let r=e[e.length-1];return e.push(r?t(r,n):n),e},[]),o={...r,path:r.honoPattern,basename:r.name,cascadingMiddleware:i.flatMap(e=>a.some(t=>e.name===t)?[e]:[])};return[o,...Object.entries({...n?.alias}).flatMap(([e,t])=>{let n=b(e);return t===r.name?[{...o,name:e,basename:r.name,id:`${o.id}_${T(e)}`,alias:d(n),pathTokens:n}]:[]})]}).sort(S);for(let[e,t]of[[`@api/routes.ts`,Ie]])await o(r.lib(e),t,{routes:a,cascadingMiddleware:i})};return{config({command:e}){return{define:{KOSMO_PRODUCTION_BUILD:e===`build`?`true`:`false`}}},async start(){for(let[e,t]of[[`api.ts`,Re],[`api:factory.ts`,ze],[`@api/app.ts`,je],[`@api/parsers.ts`,Pe],[`@api/dev.ts`,Me],[`@api/errors.ts`,Ne],[`@api/router.ts`,Fe],[`@api/server.ts`,Le]])await o(r.lib(e),t,{});for(let[e,t]of[[`app.ts`,Be],[`dev.ts`,Ve],[`errors.ts`,Ue],[`server.ts`,Ke],[`use.ts`,qe],[`env.d.ts`,He]])await s(r.api(e),t,{},{overwrite:l})},async watch(e,t){await f(e.filter(p(t,[`create`]))),await m(e)},async build(e){await f(e),await m(e)}}}),Ye=h({meta:{name:`Hono`,slot:`backend`},dependencies:{hono:V.devDependencies.hono,"@hono/node-server":V.devDependencies[`@hono/node-server`]},factory:Je}),H={type:`module`,private:!0,name:`@kosmojs/koa-generator`,version:`0.3.0`,author:`Slee Woo`,license:`MIT`,files:[`pkg/*`],exports:{".":{types:`./pkg/index.d.ts`,default:`./pkg/index.js`},"./lib":{types:`./pkg/lib.d.ts`,default:`./pkg/lib.js`}},scripts:{build:`wsbuild src/index.ts src/lib.ts`,test:`vitest --root ../.. --project generators/koa-generator`},dependencies:{"@kosmojs/core":`workspace:^`,"@kosmojs/lib":`workspace:^`,crc:`^4.3.2`},devDependencies:{"@koa/router":`^15.7.0`,"@types/formidable":`^3.5.1`,"@types/koa":`^3.0.3`,"@types/koa-compose":`^3.2.9`,formidable:`^3.5.4`,koa:`^3.2.1`,"koa-compose":`^4.1.0`,"light-my-request":`^6.6.0`,"raw-body":`^4.0.0`,vite:`^8.2.2`}},Xe=`import { styleText } from "node:util";
2828
+ `,gt=v((e,n)=>{let{createPath:r,createImportHelpers:i}=S(e),a=e=>e.length===0?`{}`:e.length===1?e[0]:`Override<${e[0]}, ${a(e.slice(1))}>`,{renderToFile:o}=w({helpers:{...i({origin:`lib`}),...A(),paramsDefaults({params:e}){return`[${e.schema.map(()=>`unknown?`).join(`, `)}]`},paramsMappings({params:e}){return`[${e.schema.map(({name:e,kind:t})=>`["${e}", unknown, ${t===`required`?`true`:`false`}]`).join(`, `)}]`},cascadingState({cascadingMiddleware:e}){return a(e.map(({id:e})=>`UseT${e}`))}}}),{renderToFile:s}=w({helpers:i({origin:`src`})}),c=e=>e?.trim().length===0,u=l(n?.templates,ft),d=async e=>{for(let{kind:t,entry:n}of e)t===`apiRoute`?await s(r.api(n.file),u(n.name,n),{route:n},{overwrite:c}):t===`apiUse`&&await s(r.api(n.file),pt,{},{overwrite:c})},f=async e=>{let i=e.flatMap(({kind:e,entry:t})=>e===`apiUse`?[t]:[]),a=e.flatMap(({kind:e,entry:r})=>{if(e!==`apiRoute`)return[];let a=r.name.split(`/`).reduce((e,n)=>{let r=e[e.length-1];return e.push(r?t(r,n):n),e},[]),o={...r,path:r.honoPattern,basename:r.name,cascadingMiddleware:i.flatMap(e=>a.some(t=>e.name===t)?[e]:[])};return[o,...Object.entries({...n?.alias}).flatMap(([e,t])=>{let n=C(e);return t===r.name?[{...o,name:e,basename:r.name,id:`${o.id}_${j(e)}`,alias:p(n),pathTokens:n}]:[]})]}).sort(E);for(let[e,t]of[[`@api/routes.ts`,it]])await o(r.lib(e),t,{routes:a,cascadingMiddleware:i})};return{async start(){for(let[e,t]of[[`api.ts`,ot],[`api:factory.ts`,st],[`@api/app.ts`,Qe],[`@api/parsers.ts`,nt],[`@api/dev.ts`,$e],[`@api/errors.ts`,et],[`@api/listener.ts`,tt],[`@api/router.ts`,rt],[`@api/server.ts`,at]])await o(r.lib(e),t,{});for(let[e,t]of[[`app.ts`,ct],[`dev.ts`,lt],[`errors.ts`,dt],[`server.ts`,mt],[`use.ts`,ht],[`env.d.ts`,ut]])await s(r.api(e),t,{},{overwrite:c})},async watch(e,t){await d(e.filter(h(t,[`create`]))),await f(e)},async build(e){await d(e),await f(e)}}}),_t=_({meta:{name:`Hono`,slot:`backend`},dependencies:{hono:V.devDependencies.hono,"@hono/node-server":V.devDependencies[`@hono/node-server`]},factory:gt}),H={type:`module`,private:!0,name:`@kosmojs/koa-generator`,version:`0.3.0`,author:`Slee Woo`,license:`MIT`,files:[`pkg/*`],exports:{".":{types:`./pkg/index.d.ts`,default:`./pkg/index.js`},"./lib":{types:`./pkg/lib.d.ts`,default:`./pkg/lib.js`}},scripts:{build:`wsbuild src/index.ts src/lib.ts`,test:`vitest --root ../.. --project generators/koa-generator`},dependencies:{"@kosmojs/core":`workspace:^`,"@kosmojs/lib":`workspace:^`,crc:`^4.3.2`},devDependencies:{"@koa/router":`^15.7.0`,"@types/formidable":`^3.5.1`,"@types/koa":`^3.0.3`,"@types/koa-compose":`^3.2.9`,formidable:`^3.5.4`,koa:`^3.2.1`,"koa-compose":`^4.1.0`,"light-my-request":`^6.6.0`,"raw-body":`^4.0.0`,vite:`^8.2.2`}},vt=`import { styleText } from "node:util";
2000
2829
 
2001
2830
  import Router, { type RouterMiddleware } from "@koa/router";
2002
2831
  import Koa from "koa";
@@ -2095,10 +2924,10 @@ export function appFactory(
2095
2924
 
2096
2925
  return app;
2097
2926
  }
2098
- `,Ze=`import type { DevSetup } from "@kosmojs/core/api";
2927
+ `,yt=`import type { DevSetup } from "@kosmojs/core/api";
2099
2928
 
2100
2929
  export const devSetup = (setup: DevSetup) => setup;
2101
- `,Qe=`import type {
2930
+ `,bt=`import type {
2102
2931
  DefaultContext,
2103
2932
  DefaultState,
2104
2933
  ParameterizedContext,
@@ -2114,7 +2943,17 @@ export type ErrorHandlerFactory = (handler: ErrorHandler) => ErrorHandler;
2114
2943
  export const errorHandlerFactory: ErrorHandlerFactory = (handler) => {
2115
2944
  return handler;
2116
2945
  };
2117
- `,$e=`import zlib from "node:zlib";
2946
+ `,xt=`import { createListener } from "./server";
2947
+
2948
+ import app from "{{ createImport 'api' 'app' }}";
2949
+
2950
+ /**
2951
+ * Entry for the \`dist/<folder>/api/listener.js\` bundle.
2952
+ * Exposes this folder's API as a plain node:http listener, mounted by \`dist/run.js\`
2953
+ * next to the other folders. Nothing here listens on a port - \`server.ts\` does that.
2954
+ * */
2955
+ export default createListener(app);
2956
+ `,St=`import zlib from "node:zlib";
2118
2957
 
2119
2958
  import type { RouterContext } from "@koa/router";
2120
2959
  import Formidable, { type Options as FormidableOptions } from "formidable";
@@ -2327,7 +3166,8 @@ export const bodyparsers: {
2327
3166
  return rawParser(stream, rawParserOptions);
2328
3167
  },
2329
3168
  };
2330
- `,et=`import type { RouterMiddleware } from "@koa/router";
3169
+ `,Ct=`import { command } from "virtual:kosmo/env";
3170
+ import type { RouterMiddleware } from "@koa/router";
2331
3171
 
2332
3172
  import type {
2333
3173
  RequestBodyTarget,
@@ -2505,13 +3345,13 @@ export const createRouteMiddleware: CreateRouteMiddleware<
2505
3345
  // options are same for all variants
2506
3346
  const { runtimeValidation, customErrors } = variants[0];
2507
3347
 
2508
- if (KOSMO_PRODUCTION_BUILD) {
2509
- // skip if undefined or explicitly set to false
3348
+ if (command === "build") {
3349
+ // production build - skip if undefined or explicitly set to false
2510
3350
  if (runtimeValidation === undefined || runtimeValidation === false) {
2511
3351
  return next();
2512
3352
  }
2513
3353
  } else {
2514
- // skip only if explicitly set to false
3354
+ // dev mode - skip only if explicitly set to false
2515
3355
  if (runtimeValidation === false) {
2516
3356
  return next();
2517
3357
  }
@@ -2705,7 +3545,7 @@ export const routes = createRoutes<ParameterizedMiddleware, RouterMiddleware>(
2705
3545
  createRouteMiddleware,
2706
3546
  },
2707
3547
  );
2708
- `,tt=`import { join } from "node:path";
3548
+ `,wt=`import { join } from "node:path";
2709
3549
 
2710
3550
  import type { RouteSource } from "@kosmojs/core/api";
2711
3551
 
@@ -2757,11 +3597,23 @@ export const routeSources: Array<RouteSource<never>> = [
2757
3597
  },
2758
3598
  {{/each}}
2759
3599
  ];
2760
- `,nt=`import { chmod, unlink } from "node:fs/promises";
3600
+ `,Tt=`import { chmod, unlink } from "node:fs/promises";
3601
+ import type { IncomingMessage, ServerResponse } from "node:http";
2761
3602
  import { parseArgs, styleText } from "node:util";
2762
3603
 
2763
3604
  import type { App } from "./app";
2764
3605
 
3606
+ export type NodeListener = (req: IncomingMessage, res: ServerResponse) => void;
3607
+
3608
+ /**
3609
+ * Wrap the app into a node:http request listener.
3610
+ * Used by dist/run.js to mount this folder's API next to other folders;
3611
+ * the standalone server (\`serve\`) calls app.listen() directly instead.
3612
+ * */
3613
+ export const createListener = <T extends App>(app: T): NodeListener => {
3614
+ return app.callback();
3615
+ };
3616
+
2765
3617
  type Handles = {
2766
3618
  port?: number | undefined;
2767
3619
  sock?: string | undefined;
@@ -2820,7 +3672,7 @@ export const serve = async <T extends App>(app: T, opt?: Handles) => {
2820
3672
  const server = app.listen(port || sock, onListen);
2821
3673
  return server as never;
2822
3674
  };
2823
- `,rt=`import type { RouterContext } from "@koa/router";
3675
+ `,Et=`import type { RouterContext } from "@koa/router";
2824
3676
  import type { Next } from "koa";
2825
3677
 
2826
3678
  import type { ValidationDefmap, ValidationOptmap } from "@kosmojs/core";
@@ -2982,20 +3834,20 @@ export const defineRoute: <
2982
3834
  use: use as never,
2983
3835
  });
2984
3836
  };
2985
- `,it=`export * from "./@api/app";
3837
+ `,Dt=`export * from "./@api/app";
2986
3838
  export { appFactory as default } from "./@api/app";
2987
3839
  export * from "./@api/dev";
2988
3840
  export * from "./@api/errors";
2989
3841
  export * from "./@api/router";
2990
3842
  export * from "./@api/routes";
2991
3843
  export * from "./@api/server";
2992
- `,at=`import appFactory, { routes } from "{{ createImport 'lib' 'api:factory' }}";
3844
+ `,Ot=`import appFactory, { routes } from "{{ createImport 'lib' 'api:factory' }}";
2993
3845
  import defaultErrorHandler from "./errors";
2994
3846
 
2995
3847
  export default appFactory(routes, ({ app }) => {
2996
3848
  app.use(defaultErrorHandler);
2997
3849
  })
2998
- `,ot=`import app from "./app";
3850
+ `,kt=`import app from "./app";
2999
3851
 
3000
3852
  import { devSetup } from "{{ createImport 'lib' 'api:factory' }}";
3001
3853
 
@@ -3013,11 +3865,11 @@ process.on("unhandledRejection", (reason) => {
3013
3865
  console.error("Reason:", reason);
3014
3866
  process.exit(1);
3015
3867
  });
3016
- `,st=`export declare module "{{ createImport 'libApi' }}" {
3868
+ `,At=`export declare module "{{ createImport 'libApi' }}" {
3017
3869
  interface DefaultState {}
3018
3870
  interface DefaultContext {}
3019
3871
  }
3020
- `,ct=`import { HTTPError, ValidationError } from "@kosmojs/core/errors";
3872
+ `,jt=`import { HTTPError, ValidationError } from "@kosmojs/core/errors";
3021
3873
 
3022
3874
  import { errorHandlerFactory } from "{{ createImport 'lib' 'api:factory' }}";
3023
3875
 
@@ -3042,14 +3894,14 @@ export default errorHandlerFactory(async (ctx, next) => {
3042
3894
  }
3043
3895
  }
3044
3896
  });
3045
- `,lt=`import { defineRoute } from "{{ createImport 'libApi' }}";
3897
+ `,Mt=`import { defineRoute } from "{{ createImport 'libApi' }}";
3046
3898
 
3047
3899
  export default defineRoute<"{{route.name}}">(({ GET }) => [
3048
3900
  GET(async (ctx) => {
3049
3901
  ctx.body = "Automatically generated route";
3050
3902
  }),
3051
3903
  ]);
3052
- `,ut=`import { use } from "{{ createImport 'libApi' }}";
3904
+ `,Nt=`import { use } from "{{ createImport 'libApi' }}";
3053
3905
 
3054
3906
  export type UseT = {};
3055
3907
 
@@ -3060,11 +3912,11 @@ export default [
3060
3912
  return next();
3061
3913
  }),
3062
3914
  ];
3063
- `,dt=`import { serve } from "{{ createImport 'lib' 'api:factory' }}";
3915
+ `,Pt=`import { serve } from "{{ createImport 'lib' 'api:factory' }}";
3064
3916
  import app from "./app";
3065
3917
 
3066
3918
  await serve(app);
3067
- `,ft=`import { use } from "{{ createImport 'libApi' }}";
3919
+ `,Ft=`import { use } from "{{ createImport 'libApi' }}";
3068
3920
 
3069
3921
  /**
3070
3922
  * Define global middleware applied to all routes.
@@ -3075,17 +3927,17 @@ export default [
3075
3927
  return next();
3076
3928
  }),
3077
3929
  ];
3078
- `,pt=g((e,n)=>{let{createPath:r,createImportHelpers:i}=y(e),a=e=>e.length===0?`{}`:e.length===1?e[0]:`Override<${e[0]}, ${a(e.slice(1))}>`,{renderToFile:o}=x({helpers:{...i({origin:`lib`}),...w(),paramsDefaults({params:e}){return`[${e.schema.map(()=>`unknown?`).join(`, `)}]`},paramsMappings({params:e}){return`[${e.schema.map(({name:e,kind:t})=>`["${e}", unknown, ${t===`required`?`true`:`false`}]`).join(`, `)}]`},cascadingState({cascadingMiddleware:e}){return a(e.map(({id:e})=>`UseT${e}`))}}}),{renderToFile:s}=x({helpers:i({origin:`src`})}),l=e=>e?.trim().length===0,u=c(n?.templates,lt),d=async e=>{for(let{kind:t,entry:n}of e)t===`apiRoute`?await s(r.api(n.file),u(n.name,n),{route:n},{overwrite:l}):t===`apiUse`&&await s(r.api(n.file),ut,{},{overwrite:l})},m=async e=>{let i=e.flatMap(({kind:e,entry:t})=>e===`apiUse`?[t]:[]),a=e.flatMap(({kind:e,entry:r})=>{if(e!==`apiRoute`)return[];let a=r.name.split(`/`).reduce((e,n)=>{let r=e[e.length-1];return e.push(r?t(r,n):n),e},[]),o={...r,basename:r.name,path:r.pathPattern,cascadingMiddleware:i.flatMap(e=>a.some(t=>e.name===t)?[e]:[])};return[o,...Object.entries({...n?.alias}).flatMap(([e,t])=>{let n=b(e);return t===r.name?[{...o,name:e,basename:r.name,id:`${o.id}_${T(e)}`,alias:f(n),pathTokens:n}]:[]})]}).sort(S);for(let[e,t]of[[`@api/routes.ts`,tt]])await o(r.lib(e),t,{routes:a,cascadingMiddleware:i})};return{config({command:e}){return{define:{KOSMO_PRODUCTION_BUILD:e===`build`?`true`:`false`}}},async start(){for(let[e,t]of[[`api.ts`,rt],[`api:factory.ts`,it],[`@api/app.ts`,Xe],[`@api/dev.ts`,Ze],[`@api/errors.ts`,Qe],[`@api/parsers.ts`,$e],[`@api/router.ts`,et],[`@api/server.ts`,nt]])await o(r.lib(e),t,{});for(let[e,t]of[[`app.ts`,at],[`dev.ts`,ot],[`errors.ts`,ct],[`server.ts`,dt],[`use.ts`,ft],[`env.d.ts`,st]])await s(r.api(e),t,{},{overwrite:l})},async watch(e,t){await d(e.filter(p(t,[`create`]))),await m(e)},async build(e){await d(e),await m(e)}}}),mt=h({meta:{name:`Koa`,slot:`backend`,types:[`@types/koa`]},dependencies:{koa:H.devDependencies.koa,"@koa/router":H.devDependencies[`@koa/router`],formidable:H.devDependencies.formidable,"raw-body":H.devDependencies[`raw-body`]},devDependencies:{"@types/koa":H.devDependencies[`@types/koa`],"@types/formidable":H.devDependencies[`@types/formidable`]},factory:pt}),U={type:`module`,private:!0,name:`@kosmojs/mdx-generator`,version:`0.3.0`,author:`Slee Woo`,license:`MIT`,files:[`pkg/*`],exports:{".":{types:`./pkg/index.d.ts`,default:`./pkg/index.js`}},scripts:{build:`wsbuild src/index.ts`},dependencies:{"@kosmojs/core":`workspace:^`,"@kosmojs/lib":`workspace:^`,"@mdx-js/rollup":`^3.1.1`,vite:`^8.2.2`},devDependencies:{"@mdx-js/mdx":`^3.1.1`,"@mdx-js/preact":`^3.1.1`,"path-to-regexp":`^8.4.2`,preact:`^10.29.8`,"preact-render-to-string":`^6.7.0`,"remark-frontmatter":`^5.0.0`,"remark-mdx-frontmatter":`^5.2.0`}},ht=()=>{let e=[`🎉 Well done! You just created a new MDX page.`,`🚀 Success! A fresh MDX page is ready to roll.`,`🌟 Nice work! Another MDX page added to your site.`,`🧩 All set! A new MDX page has been scaffolded.`,`🔧 Scaffold complete! Your new MDX page is in place.`,`✅ Built! Your MDX page is scaffolded and ready.`,`✨ Fantastic! Your new MDX page is good to go.`,`🎯 Nailed it! A brand new MDX page just landed.`,`💫 Awesome! Another MDX page joins the party.`,`⚡ Lightning fast! A new MDX page created successfully.`];return e[Math.floor(Math.random()*e.length)]},gt=(e,t,n)=>{let{remarkPlugins:r=[],rehypePlugins:i=[]}={...n},a=()=>{let t=[`${l.srcDir}/${e.name}/${l.entryDir}/client.ts`].map(e=>ie(e)),n=e=>t.some(t=>t(e));return{name:`kosmo:mdx[hmr]`,enforce:`post`,transform(e,t){if(!(!n(t)||e.includes(`import.meta.hot.accept`)))return{code:[e,`
3930
+ `,It=v((e,n)=>{let{createPath:r,createImportHelpers:i}=S(e),a=e=>e.length===0?`{}`:e.length===1?e[0]:`Override<${e[0]}, ${a(e.slice(1))}>`,{renderToFile:o}=w({helpers:{...i({origin:`lib`}),...A(),paramsDefaults({params:e}){return`[${e.schema.map(()=>`unknown?`).join(`, `)}]`},paramsMappings({params:e}){return`[${e.schema.map(({name:e,kind:t})=>`["${e}", unknown, ${t===`required`?`true`:`false`}]`).join(`, `)}]`},cascadingState({cascadingMiddleware:e}){return a(e.map(({id:e})=>`UseT${e}`))}}}),{renderToFile:s}=w({helpers:i({origin:`src`})}),c=e=>e?.trim().length===0,u=l(n?.templates,Mt),d=async e=>{for(let{kind:t,entry:n}of e)t===`apiRoute`?await s(r.api(n.file),u(n.name,n),{route:n},{overwrite:c}):t===`apiUse`&&await s(r.api(n.file),Nt,{},{overwrite:c})},f=async e=>{let i=e.flatMap(({kind:e,entry:t})=>e===`apiUse`?[t]:[]),a=e.flatMap(({kind:e,entry:r})=>{if(e!==`apiRoute`)return[];let a=r.name.split(`/`).reduce((e,n)=>{let r=e[e.length-1];return e.push(r?t(r,n):n),e},[]),o={...r,basename:r.name,path:r.pathPattern,cascadingMiddleware:i.flatMap(e=>a.some(t=>e.name===t)?[e]:[])};return[o,...Object.entries({...n?.alias}).flatMap(([e,t])=>{let n=C(e);return t===r.name?[{...o,name:e,basename:r.name,id:`${o.id}_${j(e)}`,alias:m(n),pathTokens:n}]:[]})]}).sort(E);for(let[e,t]of[[`@api/routes.ts`,wt]])await o(r.lib(e),t,{routes:a,cascadingMiddleware:i})};return{async start(){for(let[e,t]of[[`api.ts`,Et],[`api:factory.ts`,Dt],[`@api/app.ts`,vt],[`@api/dev.ts`,yt],[`@api/errors.ts`,bt],[`@api/listener.ts`,xt],[`@api/parsers.ts`,St],[`@api/router.ts`,Ct],[`@api/server.ts`,Tt]])await o(r.lib(e),t,{});for(let[e,t]of[[`app.ts`,Ot],[`dev.ts`,kt],[`errors.ts`,jt],[`server.ts`,Pt],[`use.ts`,Ft],[`env.d.ts`,At]])await s(r.api(e),t,{},{overwrite:c})},async watch(e,t){await d(e.filter(h(t,[`create`]))),await f(e)},async build(e){await d(e),await f(e)}}}),Lt=_({meta:{name:`Koa`,slot:`backend`,types:[`@types/koa`]},dependencies:{koa:H.devDependencies.koa,"@koa/router":H.devDependencies[`@koa/router`],formidable:H.devDependencies.formidable,"raw-body":H.devDependencies[`raw-body`]},devDependencies:{"@types/koa":H.devDependencies[`@types/koa`],"@types/formidable":H.devDependencies[`@types/formidable`]},factory:It}),U={type:`module`,private:!0,name:`@kosmojs/mdx-generator`,version:`0.3.0`,author:`Slee Woo`,license:`MIT`,files:[`pkg/*`],exports:{".":{types:`./pkg/index.d.ts`,default:`./pkg/index.js`}},scripts:{build:`wsbuild src/index.ts`},dependencies:{"@kosmojs/core":`workspace:^`,"@kosmojs/lib":`workspace:^`,"@mdx-js/rollup":`^3.1.1`,vite:`^8.2.2`},devDependencies:{"@mdx-js/mdx":`^3.1.1`,"@mdx-js/preact":`^3.1.1`,"path-to-regexp":`^8.4.2`,preact:`^10.29.8`,"preact-render-to-string":`^6.7.0`,"remark-frontmatter":`^5.0.0`,"remark-mdx-frontmatter":`^5.2.0`}},Rt=()=>{let e=[`🎉 Well done! You just created a new MDX page.`,`🚀 Success! A fresh MDX page is ready to roll.`,`🌟 Nice work! Another MDX page added to your site.`,`🧩 All set! A new MDX page has been scaffolded.`,`🔧 Scaffold complete! Your new MDX page is in place.`,`✅ Built! Your MDX page is scaffolded and ready.`,`✨ Fantastic! Your new MDX page is good to go.`,`🎯 Nailed it! A brand new MDX page just landed.`,`💫 Awesome! Another MDX page joins the party.`,`⚡ Lightning fast! A new MDX page created successfully.`];return e[Math.floor(Math.random()*e.length)]},zt=(e,t,n)=>{let{remarkPlugins:r=[],rehypePlugins:i=[]}={...n},a=()=>{let t=[`${u.srcDir}/${e.name}/${u.entryDir}/client.ts`].map(e=>re(e)),n=e=>t.some(t=>t(e));return{name:`kosmo:mdx[hmr]`,enforce:`post`,transform(e,t){if(!(!n(t)||e.includes(`import.meta.hot.accept`)))return{code:[e,`
3079
3931
  if (import.meta.hot) {
3080
3932
  import.meta.hot.accept(() => {});
3081
3933
  }
3082
3934
  `].join(`
3083
- `)}}}},o=[re({jsxImportSource:`preact`,providerImportSource:`@mdx-js/preact`,remarkPlugins:r,rehypePlugins:i})];return t===`serve`&&o.push(a()),o},_t=`import type { FunctionComponent } from "preact";
3935
+ `)}}}},o=[ne({jsxImportSource:`preact`,providerImportSource:`@mdx-js/preact`,remarkPlugins:r,rehypePlugins:i})];return t===`serve`&&o.push(a()),o},Bt=`import type { FunctionComponent } from "preact";
3084
3936
 
3085
3937
  export const AppProvider: FunctionComponent = (props) => {
3086
3938
  return props.children;
3087
3939
  };
3088
- `,vt=`import { render, hydrate as hydrateOrig } from "preact";
3940
+ `,Vt=`import { render, hydrate as hydrateOrig } from "preact";
3089
3941
  import type { RouterFactoryReturn } from "@kosmojs/core";
3090
3942
  import { clientRenderFactory } from "@kosmojs/core/generators";
3091
3943
 
@@ -3126,7 +3978,7 @@ export const mount = async (
3126
3978
  }
3127
3979
 
3128
3980
  export default clientRenderFactory();
3129
- `,yt=`import { renderToString as renderToStringOrig } from "preact-render-to-string";
3981
+ `,Ht=`import { renderToString as renderToStringOrig } from "preact-render-to-string";
3130
3982
 
3131
3983
  import type {
3132
3984
  RenderToStringWrapper,
@@ -3200,7 +4052,7 @@ export const renderToString: RenderToStringWrapper<
3200
4052
  }
3201
4053
 
3202
4054
  export default serverRenderFactory<false>();
3203
- `,bt=`declare module "*.mdx" {
4055
+ `,Ut=`declare module "*.mdx" {
3204
4056
  import type { ComponentType } from "preact";
3205
4057
  export const frontmatter: Record<string, unknown>;
3206
4058
  const component: ComponentType;
@@ -3213,7 +4065,7 @@ declare module "*.md" {
3213
4065
  const component: ComponentType;
3214
4066
  export default component;
3215
4067
  }
3216
- `,xt=`import { MDXProvider } from "@mdx-js/preact";
4068
+ `,Wt=`import { MDXProvider } from "@mdx-js/preact";
3217
4069
  import { match, pathToRegexp } from "path-to-regexp";
3218
4070
  import { type ComponentType, createContext, h, type VNode } from "preact";
3219
4071
 
@@ -3224,7 +4076,6 @@ import { base } from "{{ createImport 'libCore' }}";
3224
4076
 
3225
4077
  export type RawRoute = {
3226
4078
  name: string;
3227
- pathSegments: number | undefined;
3228
4079
  regexp: RegExp;
3229
4080
  extractParams: (path: string) => Route["params"];
3230
4081
  loader: () => Promise<RouteModule>;
@@ -3292,23 +4143,20 @@ export const createRouter = (
3292
4143
  return {
3293
4144
  async resolve(url: URL = new URL(window.location.href)) {
3294
4145
  const searchParams = parseSearchParams(url);
3295
- const urlSegments = url.pathname.split("/").filter(Boolean).length;
3296
-
3297
- // 1: use lightweight \`RegExp.test()\` on linear scan - no capture allocation
3298
- const matchedRoutes = routes.filter(({ regexp }) => {
3299
- return regexp.test(url.pathname);
3300
- });
3301
4146
 
4147
+ // The routes array is generated pre-sorted by specificity
4148
+ // (static beats required beats optional beats splat, token by token),
4149
+ // the same ordering the SSR server registers routes in -
4150
+ // so the first pattern that matches IS the most specific one,
4151
+ // and CSR resolution stays consistent with SSR.
4152
+ // A route with optional parameters matches a range of segment counts,
4153
+ // which is why no segment-count heuristic can disambiguate here.
4154
+ // Lightweight \`RegExp.test()\` on linear scan - no capture allocation.
3302
4155
  const matchedRoute =
3303
- matchedRoutes.length > 1
3304
- ? matchedRoutes.find(({ pathSegments }) => {
3305
- return pathSegments === undefined || pathSegments === urlSegments;
3306
- }) || catchallRoute
3307
- : matchedRoutes.length === 1
3308
- ? matchedRoutes[0]
3309
- : catchallRoute;
3310
-
3311
- // 2: capture params only on matched route
4156
+ routes.find(({ regexp }) => {
4157
+ return regexp.test(url.pathname);
4158
+ }) || catchallRoute;
4159
+
3312
4160
  const params = matchedRoute
3313
4161
  ? matchedRoute.extractParams(url.pathname)
3314
4162
  : {};
@@ -3402,11 +4250,6 @@ export const createRoute = (
3402
4250
  return {
3403
4251
  name,
3404
4252
  regexp,
3405
- // count segments of the same base-joined path the regexp matches against;
3406
- // resolve() compares this against the full url pathname's segment count
3407
- pathSegments: name.includes("...")
3408
- ? undefined
3409
- : path.split("/").filter(Boolean).length,
3410
4253
  extractParams: (path) => {
3411
4254
  const match = matcher(path);
3412
4255
  return match ? match.params : {};
@@ -3415,7 +4258,7 @@ export const createRoute = (
3415
4258
  layouts,
3416
4259
  };
3417
4260
  };
3418
- `,St=`/* @jsxImportSource preact */
4261
+ `,Gt=`/* @jsxImportSource preact */
3419
4262
 
3420
4263
  import styles from "./styles.module.css";
3421
4264
 
@@ -3456,7 +4299,7 @@ export default function PageSample(props: {
3456
4299
  </div>
3457
4300
  );
3458
4301
  }
3459
- `,Ct=`/* @jsxImportSource preact */
4302
+ `,Kt=`/* @jsxImportSource preact */
3460
4303
 
3461
4304
  import styles from "./styles.module.css";
3462
4305
 
@@ -3508,7 +4351,7 @@ export default function PageSample(props: {
3508
4351
  </div>
3509
4352
  );
3510
4353
  }
3511
- `,wt=`* {
4354
+ `,qt=`* {
3512
4355
  margin: 0;
3513
4356
  padding: 0;
3514
4357
  box-sizing: border-box;
@@ -3643,7 +4486,7 @@ export default function PageSample(props: {
3643
4486
  align-items: center;
3644
4487
  gap: 0.25rem;
3645
4488
  }
3646
- `,Tt=`/* @jsxImportSource preact */
4489
+ `,Jt=`/* @jsxImportSource preact */
3647
4490
 
3648
4491
  import styles from "./styles.module.css";
3649
4492
 
@@ -3709,7 +4552,7 @@ export default function WelcomePage() {
3709
4552
  </div>
3710
4553
  );
3711
4554
  }
3712
- `,Et=`export type ParamsMap = {
4555
+ `,Yt=`export type ParamsMap = {
3713
4556
  {{#each pageRoutes}}"{{name}}": {{serializeParamsLiteral .}};
3714
4557
  {{/each}}
3715
4558
  };
@@ -3718,7 +4561,7 @@ export const paramNames = {
3718
4561
  {{#each pageRoutes}}"{{name}}": [ {{#each params.schema}}"{{name}}", {{/each}}],
3719
4562
  {{/each}}
3720
4563
  } as const;
3721
- `,Dt=`import type { ComponentType } from "preact";
4564
+ `,Xt=`import type { ComponentType } from "preact";
3722
4565
 
3723
4566
  import type { RouterFactoryReturn } from "@kosmojs/core";
3724
4567
  import { createRouterFactory } from "@kosmojs/core/generators";
@@ -3762,77 +4605,7 @@ export default createRouterFactory<
3762
4605
  Promise<RouteComponent>,
3763
4606
  { server: { route: Route } }
3764
4607
  >();
3765
- `,Ot=`import { join } from "node:path";
3766
-
3767
- import { compile } from "path-to-regexp";
3768
-
3769
- import type { PageRoute } from "@kosmojs/core";
3770
-
3771
- import routes from "{{ createImport 'lib' 'ssg:routes' }}";
3772
- import { base } from "{{ createImport 'libCore' }}";
3773
-
3774
- const paramsMapper = (params: PageRoute["params"], value: Array<unknown>) => {
3775
- return params.schema.reduce<Record<string, unknown>>(
3776
- (map, { name, kind }, i) => {
3777
- if (kind === "splat") {
3778
- if (Array.isArray(value[i]) && value[i].length) {
3779
- map[name] = value[i].map(String);
3780
- }
3781
- } else if (value[i] !== undefined) {
3782
- map[name] = String(value[i]);
3783
- }
3784
- return map;
3785
- },
3786
- {},
3787
- );
3788
- };
3789
-
3790
- export default Object.entries(routes)
3791
- .flatMap(([name, { pathPattern, params, frontmatter }]) => {
3792
- if (!params.schema.length || Array.isArray(frontmatter?.staticParams)) {
3793
- if (params.schema.length) {
3794
- const toPath = compile(pathPattern);
3795
- return Array.from(frontmatter?.staticParams || []).flatMap((entry) => {
3796
- try {
3797
- return [toPath(paramsMapper(params, entry) as never)];
3798
- } catch (error: any) {
3799
- console.error(\`❗SSG: Failed building path for \${name}\`);
3800
- console.error(error);
3801
- return [];
3802
- }
3803
- });
3804
- }
3805
- // static route
3806
- return [pathPattern.replace(/^index\\/?/, "")];
3807
- }
3808
- return [];
3809
- })
3810
- .map((path) => join(base, path));
3811
- `,kt=`import type { PageRoute } from "@kosmojs/core";
3812
-
3813
- {{#each pageRoutes}}
3814
- import * as {{id}} from "{{ createImport 'pages' file }}";
3815
- {{/each}}
3816
-
3817
- const routeMap: Record<
3818
- string,
3819
- {
3820
- frontmatter?: { staticParams?: Array<Array<string | Array<string>>> };
3821
- pathPattern: string;
3822
- params: PageRoute["params"];
3823
- }
3824
- > = {
3825
- {{#each pageRoutes}}
3826
- "{{name}}": {
3827
- frontmatter: {{id}}.frontmatter,
3828
- pathPattern: "{{pathPattern}}",
3829
- params: {{serializeParams .}},
3830
- },
3831
- {{/each}}
3832
- }
3833
-
3834
- export default routeMap;
3835
- `,At=`import { useContext } from "preact/hooks";
4608
+ `,Zt=`import { useContext } from "preact/hooks";
3836
4609
 
3837
4610
  import { RouterContext } from "./mdx";
3838
4611
 
@@ -3878,10 +4651,10 @@ export const useFrontmatter = <
3878
4651
  >(): T => {
3879
4652
  return useRoute().frontmatter as T;
3880
4653
  };
3881
- `,jt=`import { AppProvider } from "{{ createImport 'lib' 'app' }}";
4654
+ `,Qt=`import { AppProvider } from "{{ createImport 'lib' 'app' }}";
3882
4655
 
3883
4656
  <AppProvider>{props.children}</AppProvider>
3884
- `,Mt=`import { h, type JSX } from "preact";
4657
+ `,$t=`import { h, type JSX } from "preact";
3885
4658
 
3886
4659
  import { pageRouteMap, type LinkProps } from "{{ createImport 'libCore' }}";
3887
4660
 
@@ -3898,7 +4671,7 @@ export default function Link(
3898
4671
 
3899
4672
  return h("a", { ...restProps, href }, children);
3900
4673
  }
3901
- `,Nt=`/**
4674
+ `,en=`/**
3902
4675
  * MDX component overrides.
3903
4676
  *
3904
4677
  * Every standard markdown element (headings, links, code blocks, etc.)
@@ -3921,7 +4694,7 @@ export const components = {
3921
4694
  declare global {
3922
4695
  type MDXProvidedComponents = typeof components;
3923
4696
  }
3924
- `,Pt=`import renderFactory, {
4697
+ `,tn=`import renderFactory, {
3925
4698
  createRoutes,
3926
4699
  hydrate,
3927
4700
  mount,
@@ -3948,7 +4721,7 @@ if (root) {
3948
4721
  } else {
3949
4722
  console.error("❌ Root element not found!");
3950
4723
  }
3951
- `,Ft=`import renderFactory, {
4724
+ `,nn=`import renderFactory, {
3952
4725
  createRoutes,
3953
4726
  renderToString,
3954
4727
  // no renderToStream on MDX folders
@@ -3969,13 +4742,13 @@ export default renderFactory(() => {
3969
4742
  },
3970
4743
  };
3971
4744
  });
3972
- `,It=`import PageSample from "{{ createImport 'lib' 'pageSamples/404.tsx' }}";
4745
+ `,rn=`import PageSample from "{{ createImport 'lib' 'pageSamples/404.tsx' }}";
3973
4746
 
3974
4747
  export default function Page() {
3975
4748
  return <PageSample />;
3976
4749
  }
3977
- `,Lt=`{props.children}
3978
- `,Rt=`---
4750
+ `,an=`{props.children}
4751
+ `,on=`---
3979
4752
  title: "{{title}}"
3980
4753
  ---
3981
4754
 
@@ -3992,7 +4765,7 @@ export const pathMap = {
3992
4765
  routeName="{{route.name}}"
3993
4766
  pathMap={pathMap}
3994
4767
  />
3995
- `,zt=`---
4768
+ `,sn=`---
3996
4769
  title: Welcome to KosmoJS
3997
4770
  description: Content-first development with MDX and Vite
3998
4771
  ---
@@ -4000,7 +4773,7 @@ description: Content-first development with MDX and Vite
4000
4773
  import WelcomePage from "{{ createImport 'lib' 'pageSamples/welcome.tsx' }}"
4001
4774
 
4002
4775
  <WelcomePage />
4003
- `,Bt=`import routerFactory, { createRouters } from "{{ createImport 'lib' 'router' }}";
4776
+ `,cn=`import routerFactory, { createRouters } from "{{ createImport 'lib' 'router' }}";
4004
4777
 
4005
4778
  import app from "./app.mdx";
4006
4779
  import { components } from "./components/mdx"
@@ -4016,12 +4789,12 @@ export default routerFactory((routes) => {
4016
4789
  },
4017
4790
  };
4018
4791
  });
4019
- `,Vt=g((e,t)=>{let{createPath:n,createImportHelpers:r}=y(e),{renderToFile:i}=x({helpers:{...r({origin:`lib`}),...w(),serializeParams(e){return JSON.stringify(e.params)}}}),{renderToFile:a}=x({helpers:r({origin:`src`})}),o=e=>!e?.trim().length,s=c(t?.templates,Rt),u=async e=>{for(let{kind:t,entry:r}of e)t===`pageRoute`?await a(n.pages(r.file),r.name===`index`?zt:s(r.name,r),{route:r,title:r.name.replace(/\{([^}]+)\}/g,`$1`),message:ht()},{overwrite:o}):t===`pageLayout`&&await a(n.pages(r.file),Lt,{route:r},{overwrite:o})},d=async e=>{let t=e.flatMap(({kind:e,entry:t})=>e===`pageLayout`?[t]:[]),r=e.flatMap(({kind:e,entry:n})=>{if(e===`pageRoute`){let{name:e,file:r}=n;return[{...n,layouts:t.flatMap(t=>t.name===e||r.startsWith(`${t.name}/`)?[t]:[]).sort(S)}]}return[]}).sort(S);for(let[e,a]of[[`client.ts`,vt],[`server.ts`,yt]])await i(n.libEntry(e),a,{pageRoutes:r,layouts:t});for(let[e,t]of[[`params.ts`,Et],[`router.ts`,Dt],[`ssg:routes.ts`,kt]])await i(n.lib(e),t,{pageRoutes:r})};return{config({command:n}){return{oxc:{jsx:{runtime:`automatic`,importSource:`preact`}},plugins:gt(e,n,t)}},async start(){for(let[e,t]of[[`env.d.ts`,bt],[`app.ts`,_t],[`mdx.ts`,xt],[`use.ts`,At],[`ssg.ts`,Ot],[`pageSamples/styles.module.css`,wt],[`pageSamples/welcome.tsx`,Tt],[`pageSamples/page.tsx`,Ct],[`pageSamples/404.tsx`,St]])await i(n.lib(e),t,{});for(let[e,t]of[[`pages/404.mdx`,It],[`components/Link.tsx`,Mt],[`components/mdx.ts`,Nt],[`app.mdx`,jt],[`router.ts`,Bt]])await a(n.src(e),t,{entryDir:l.entryDir},{overwrite:o});for(let[e,t]of[[`client.ts`,Pt],[`server.ts`,Ft]])await a(n.entry(e),t,{},{overwrite:o})},async watch(e,t){await u(e.filter(m(t,[`create`]))),await d(e)},async build(e){await u(e),await d(e)}}}),Ht=h({meta:{name:`MDX`,slot:`frontend`,jsx:`react-jsx`,jsxImportSource:`preact`},dependencies:{"path-to-regexp":U.devDependencies[`path-to-regexp`]},devDependencies:{preact:U.devDependencies.preact,"preact-render-to-string":U.devDependencies[`preact-render-to-string`],"@mdx-js/preact":U.devDependencies[`@mdx-js/preact`],"remark-frontmatter":U.devDependencies[`remark-frontmatter`],"remark-mdx-frontmatter":U.devDependencies[`remark-mdx-frontmatter`]},factory:Vt}),Ut={json:`application/json`,form:[`application/x-www-form-urlencoded`,`multipart/form-data`],raw:void 0},Wt=()=>{let e=e=>[`Buffer`,`ArrayBuffer`,`Blob`].includes(e)?{type:`string`,format:`binary`}:se.Script(e),n=(e,t,n)=>{let r=n?`${t}_${n.replace(/[^\w.-]/g,`_`)}${T(n)}`:t;return`${e.id}_${r}`},r=(e,t,r,i)=>[`#`,`components`,e,n(t,r,i)].join(`/`),i=e=>e.split(`/`).reduce((e,t)=>e+ +!t.includes(`{`),0),o=e=>{if(e.name===`index`)return[`/`];let{tokens:n}=oe(e.pathPattern),r=e=>e.flatMap(e=>{switch(e.type){case`param`:return[e.name];case`wildcard`:return[e.name];case`group`:return r(e.tokens);default:return[]}}),a=(e,t)=>{if(!e.length)return[t];let[n,...i]=e;switch(n.type){case`text`:return a(i,{path:`${t.path}${n.value}`,params:t.params});case`param`:return a(i,{path:`${t.path}{${n.name}}`,params:[...t.params,n.name]});case`wildcard`:return a(i,{path:`${t.path}{${n.name}*}`,params:[...t.params,n.name]});case`group`:{let e=a(i,t),o=a([...n.tokens,...i],t),s=r(n.tokens),c=o.filter(e=>s.some(t=>e.params.includes(t)));return[...e,...c]}}},o=a(n,{path:``,params:[]}),s=e.params.schema.reduce((e,{name:t},n)=>(e[n]=t,e),{});return o.reduce((e,n)=>{let r=t(`/`,n.path);return e.includes(r)||n.params.every((e,t)=>e===s[t])&&e.push(r),e},[]).sort((e,t)=>i(t)-i(e))},s=(e,t)=>{let n=e.params.resolvedType?.properties?.flatMap(n=>RegExp(`\\{${n.name}\\*?\\}`).test(t)?[{$ref:r(`parameters`,e,e.params.id,n.name)}]:[]);return n?.length?n:void 0},c=(e,t)=>{let n=e.validationDefinitions.find(e=>e.method===t&&e.target===`response`);return Array.isArray(n?.variants)?n.variants.reduce((t,{id:n,status:i,contentType:a,body:o})=>(t[i]=Gt(i,a)||{description:`Success`,content:{[a||`application/json`]:{schema:o?{$ref:r(`schemas`,e,n)}:{type:`object`}}}},t),{}):{200:{description:`Success - TODO: Add response schema`,content:{"text/plain":{schema:{type:`string`}}}}}},l=t=>{let{parameters:r,schemas:i}={parameters:{},schemas:{}};for(let r of t.validationDefinitions)if(r.target===`response`)for(let{id:a,resolvedType:o}of r.variants)o?.typeboxSchema&&(i[n(t,a)]=e(o.typeboxSchema));else if(r.target===`query`){let{id:a,resolvedType:o}=r.schema;for(let r of o?.properties||[])if(r?.typeboxSchema){let o=n(t,a,r.name);i[o]=e(r.typeboxSchema)}}else{let{id:a,resolvedType:o}=r.schema;o?.typeboxSchema&&(i[n(t,a)]=e(o.typeboxSchema))}if(t.params.resolvedType)for(let i of t.params.resolvedType.properties||[])i?.typeboxSchema&&(r[n(t,t.params.id,i.name)]={name:i.name,in:`path`,required:!0,schema:e(i.typeboxSchema)});return{parameters:r,schemas:i}},u=e=>{let t={},n=e.validationDefinitions.flatMap(e=>e.target===`response`?[]:e.schema.resolvedType?[e]:[]);for(let i of o(e))for(let o of e.methods){let l={responses:c(e,o)},u=s(e,i);u&&(l.parameters=u);let d=n.find(e=>e.method===o&&e.target===`query`);if(d?.schema)for(let t of d.schema.resolvedType?.properties||[])l.parameters||=[],l.parameters.push({name:t.name,in:`query`,required:!t.optional,schema:{$ref:r(`schemas`,e,d.schema.id,t.name)}});let f=n.filter(e=>e.method===o&&Object.keys(a).includes(e.target));f.length&&(l.requestBody={required:!0,content:f.reduce((t,n)=>{let{contentType:i=Ut[n.target]}=n;if(i){let a={$ref:r(`schemas`,e,n.schema.id)};for(let e of[i].flat())t[e]={schema:a}}return t},{})}),t[i]||(t[i]={}),t[i][o.toLowerCase()]=l}return t};return{generateComponentId:n,generateComponentPath:r,generatePathVariations:o,generateOpenAPISchema:e=>{let t=new Map;for(let n of e)t.set(n.name,o(n));let{components:n,paths:r}=e.sort(S).flatMap(n=>{let r=t.get(n.name)??[];return r.length>0&&e.some(e=>{if(e.name===n.name)return!1;let i=t.get(e.name)??[],a=new Set(i);return r.every(e=>a.has(e))})?[]:[n]}).reduce((e,t)=>{let n=u(t),{parameters:r,schemas:i}=l(t);return{paths:{...e.paths,...n},components:{parameters:{...e.components.parameters,...r},schemas:{...e.components.schemas,...i}}}},{paths:{},components:{parameters:{},schemas:{}}});return{paths:r,components:n}}}},Gt=(e,t)=>{let n={type:`string`,format:`uri`,...t?{enum:[t]}:{}};return{301:{description:`Moved Permanently`,headers:{Location:{description:`New permanent location`,schema:n}}},302:{description:`Found`,headers:{Location:{description:`Temporary location`,schema:n}}},303:{description:`See Other`,headers:{Location:{description:`Location to GET after POST/PUT/DELETE`,schema:n}}},307:{description:`Temporary Redirect`,headers:{Location:{description:`Temporary location (preserves request method)`,schema:n}}},308:{description:`Permanent Redirect`,headers:{Location:{description:`New permanent location (preserves request method)`,schema:n}}}}[e]},Kt=g((e,t)=>{let{outfile:n=``,...r}={...t},{createPath:i}=y(e),{generateOpenAPISchema:a}=Wt(),o=async e=>{let t=e.flatMap(({kind:e,entry:t})=>e===`apiRoute`?[t]:[]),{paths:o,components:s}=a(t),c={...JSON.parse(JSON.stringify(r)),paths:o,components:s},l=/ya?ml/.test(n)?ae.stringify(c):JSON.stringify(c,null,2);await ee(i.src(n),l,{})};return{async watch(e){await o(e)},async build(e){await o(e)}}}),qt=h({meta:{name:`OpenAPI`,resolveTypes:!0},factory:Kt}),W={type:`module`,private:!0,name:`@kosmojs/react-generator`,version:`0.3.0`,author:`Slee Woo`,license:`MIT`,files:[`pkg/*`],exports:{".":{types:`./pkg/index.d.ts`,default:`./pkg/index.js`}},scripts:{build:`wsbuild src/index.ts`,test:`vitest --root ../.. --project generators/react-generator`},dependencies:{"@kosmojs/core":`workspace:^`,"@kosmojs/lib":`workspace:^`,"@vitejs/plugin-react":`^6.1.0`},devDependencies:{"@tanstack/react-query":`^5.102.2`,"@types/react":`^19.2.18`,"@types/react-dom":`^19.2.5`,"path-to-regexp":`^8.4.2`,react:`^19.2.8`,"react-dom":`^19.2.8`,"react-router":`^8.3.0`}},Jt=e=>{let t=e.map(e=>e.orig).join(`/`),n=e=>e.kind===`splat`?`*`:e.kind===`optional`?`:${e.name}?`:`:${e.name}`;return e.flatMap(e=>e.kind===`static`?[e.parts[0].value]:e.kind===`param`?[n(e.parts[0])]:(/\.\w+$/.test(e.orig)||(console.warn(`❗${r([`red`,`bold`],`WARN`)}: React Router v7 only supports dot-suffix mixed segments (e.g. :param.html).`),console.warn(` ${r([`magenta`],e.orig)} in ${r([`blue`],t)} route won't match as expected.`),console.warn()),[e.parts.map(e=>e.type===`static`?e.value:n(e)).join(``)])).join(`/`)},Yt=()=>{let e=e=>e?.kind===`param`&&e.parts[0]?.kind===`splat`,t=n=>n.flatMap(({index:n,layout:r,children:i})=>{let{name:a,pathTokens:o}={...n,...r};if(!o)return[];let s=`${a}:layout`,c=Jt(o),l=o.at(-1);return e(l)?n&&r?[{name:s,path:c,component:r.id,children:[{name:a,path:`*`,component:n.id}]}]:n?[{path:c,children:[{name:a,path:`*`,component:n.id},...t(i)]}]:r?[{name:s,path:c,component:r.id,children:t(i)}]:[]:n&&r?[{name:s,path:c,component:r.id,children:[{name:a,index:!0,component:n.id},...t(i)]}]:n?[{path:c,children:[{name:a,index:!0,component:n.id},...t(i)]}]:r?[{name:s,path:c,component:r.id,children:t(i)}]:[]});return t},Xt=()=>{let e=[`🎉 Well done! You just created a new React route.`,`🚀 Success! A fresh React route is ready to roll.`,`🌟 Nice work! Another React route added to your app.`,`⚡ Quick and easy! Your new React route is good to go.`,`🥳 Congrats! Your app just leveled up with a new React route.`,`🧩 All set! A new React route has been scaffolded.`,`🔧 Scaffold complete! Your new React route is in place.`,`✨ Fantastic! Your new React route is ready.`,`🎯 Nailed it! A brand new React route just landed.`,`💫 Awesome! Another React route joins the lineup.`];return e[Math.floor(Math.random()*e.length)]},Zt=`import type { ReactNode } from "react";
4792
+ `,ln=v((e,t)=>{let{createPath:n,createImportHelpers:r}=S(e),{renderToFile:i}=w({helpers:{...r({origin:`lib`}),...A(),serializeParams(e){return JSON.stringify(e.params)}}}),{renderToFile:a}=w({helpers:r({origin:`src`})}),o=e=>!e?.trim().length,s=l(t?.templates,on),c=async e=>{for(let{kind:t,entry:r}of e)t===`pageRoute`?await a(n.pages(r.file),r.name===`index`?sn:s(r.name,r),{route:r,title:r.name.replace(/\{([^}]+)\}/g,`$1`),message:Rt()},{overwrite:o}):t===`pageLayout`&&await a(n.pages(r.file),an,{route:r},{overwrite:o})},d=async e=>{let t=e.flatMap(({kind:e,entry:t})=>e===`pageLayout`?[t]:[]),r=e.flatMap(({kind:e,entry:n})=>{if(e===`pageRoute`){let{name:e,file:r}=n;return[{...n,layouts:t.flatMap(t=>t.name===e||r.startsWith(`${t.name}/`)?[t]:[]).sort(E)}]}return[]}).sort(D);for(let[e,a]of[[`client.ts`,Vt],[`server.ts`,Ht]])await i(n.libEntry(e),a,{pageRoutes:r,layouts:t});for(let[e,t]of[[`params.ts`,Yt],[`router.ts`,Xt]])await i(n.lib(e),t,{pageRoutes:r})};return{config({command:n}){return{oxc:{jsx:{runtime:`automatic`,importSource:`preact`}},plugins:zt(e,n,t)}},async start(){for(let[e,t]of[[`env.d.ts`,Ut],[`app.ts`,Bt],[`mdx.ts`,Wt],[`use.ts`,Zt],[`pageSamples/styles.module.css`,qt],[`pageSamples/welcome.tsx`,Jt],[`pageSamples/page.tsx`,Kt],[`pageSamples/404.tsx`,Gt]])await i(n.lib(e),t,{});for(let[e,t]of[[`pages/404.mdx`,rn],[`components/Link.tsx`,$t],[`components/mdx.ts`,en],[`app.mdx`,Qt],[`router.ts`,cn]])await a(n.src(e),t,{entryDir:u.entryDir},{overwrite:o});for(let[e,t]of[[`client.ts`,tn],[`server.ts`,nn]])await a(n.entry(e),t,{},{overwrite:o})},async watch(e,t){await c(e.filter(g(t,[`create`]))),await d(e)},async build(e){await c(e),await d(e)}}}),un=_({meta:{name:`MDX`,slot:`frontend`,jsx:`react-jsx`,jsxImportSource:`preact`},dependencies:{"path-to-regexp":U.devDependencies[`path-to-regexp`]},devDependencies:{preact:U.devDependencies.preact,"preact-render-to-string":U.devDependencies[`preact-render-to-string`],"@mdx-js/preact":U.devDependencies[`@mdx-js/preact`],"remark-frontmatter":U.devDependencies[`remark-frontmatter`],"remark-mdx-frontmatter":U.devDependencies[`remark-mdx-frontmatter`]},factory:ln}),dn={json:`application/json`,form:[`application/x-www-form-urlencoded`,`multipart/form-data`],raw:void 0},fn=()=>{let e=e=>[`Buffer`,`ArrayBuffer`,`Blob`].includes(e)?{type:`string`,format:`binary`}:oe.Script(e),n=(e,t,n)=>{let r=n?`${t}_${n.replace(/[^\w.-]/g,`_`)}${j(n)}`:t;return`${e.id}_${r}`},r=(e,t,r,i)=>[`#`,`components`,e,n(t,r,i)].join(`/`),i=e=>e.split(`/`).reduce((e,t)=>e+ +!t.includes(`{`),0),a=e=>{if(e.name===`index`)return[`/`];let{tokens:n}=ae(e.pathPattern),r=e=>e.flatMap(e=>{switch(e.type){case`param`:return[e.name];case`wildcard`:return[e.name];case`group`:return r(e.tokens);default:return[]}}),a=(e,t)=>{if(!e.length)return[t];let[n,...i]=e;switch(n.type){case`text`:return a(i,{path:`${t.path}${n.value}`,params:t.params});case`param`:return a(i,{path:`${t.path}{${n.name}}`,params:[...t.params,n.name]});case`wildcard`:return a(i,{path:`${t.path}{${n.name}*}`,params:[...t.params,n.name]});case`group`:{let e=a(i,t),o=a([...n.tokens,...i],t),s=r(n.tokens),c=o.filter(e=>s.some(t=>e.params.includes(t)));return[...e,...c]}}},o=a(n,{path:``,params:[]}),s=e.params.schema.reduce((e,{name:t},n)=>(e[n]=t,e),{});return o.reduce((e,n)=>{let r=t(`/`,n.path);return e.includes(r)||n.params.every((e,t)=>e===s[t])&&e.push(r),e},[]).sort((e,t)=>i(t)-i(e))},s=(e,t)=>{let n=e.params.resolvedType?.properties?.flatMap(n=>RegExp(`\\{${n.name}\\*?\\}`).test(t)?[{$ref:r(`parameters`,e,e.params.id,n.name)}]:[]);return n?.length?n:void 0},c=(e,t)=>{let n=e.validationDefinitions.find(e=>e.method===t&&e.target===`response`);return Array.isArray(n?.variants)?n.variants.reduce((t,{id:n,status:i,contentType:a,body:o})=>(t[i]=pn(i,a)||{description:`Success`,content:{[a||`application/json`]:{schema:o?{$ref:r(`schemas`,e,n)}:{type:`object`}}}},t),{}):{200:{description:`Success - TODO: Add response schema`,content:{"text/plain":{schema:{type:`string`}}}}}},l=t=>{let{parameters:r,schemas:i}={parameters:{},schemas:{}};for(let r of t.validationDefinitions)if(r.target===`response`)for(let{id:a,resolvedType:o}of r.variants)o?.typeboxSchema&&(i[n(t,a)]=e(o.typeboxSchema));else if(r.target===`query`){let{id:a,resolvedType:o}=r.schema;for(let r of o?.properties||[])if(r?.typeboxSchema){let o=n(t,a,r.name);i[o]=e(r.typeboxSchema)}}else{let{id:a,resolvedType:o}=r.schema;o?.typeboxSchema&&(i[n(t,a)]=e(o.typeboxSchema))}if(t.params.resolvedType)for(let i of t.params.resolvedType.properties||[])i?.typeboxSchema&&(r[n(t,t.params.id,i.name)]={name:i.name,in:`path`,required:!0,schema:e(i.typeboxSchema)});return{parameters:r,schemas:i}},u=e=>{let t={},n=e.validationDefinitions.flatMap(e=>e.target===`response`?[]:e.schema.resolvedType?[e]:[]);for(let i of a(e))for(let a of e.methods){let l={responses:c(e,a)},u=s(e,i);u&&(l.parameters=u);let d=n.find(e=>e.method===a&&e.target===`query`);if(d?.schema)for(let t of d.schema.resolvedType?.properties||[])l.parameters||=[],l.parameters.push({name:t.name,in:`query`,required:!t.optional,schema:{$ref:r(`schemas`,e,d.schema.id,t.name)}});let f=n.filter(e=>e.method===a&&Object.keys(o).includes(e.target));f.length&&(l.requestBody={required:!0,content:f.reduce((t,n)=>{let{contentType:i=dn[n.target]}=n;if(i){let a={$ref:r(`schemas`,e,n.schema.id)};for(let e of[i].flat())t[e]={schema:a}}return t},{})}),t[i]||(t[i]={}),t[i][a.toLowerCase()]=l}return t};return{generateComponentId:n,generateComponentPath:r,generatePathVariations:a,generateOpenAPISchema:e=>{let t=new Map;for(let n of e)t.set(n.name,a(n));let{components:n,paths:r}=e.sort(E).flatMap(n=>{let r=t.get(n.name)??[];return r.length>0&&e.some(e=>{if(e.name===n.name)return!1;let i=t.get(e.name)??[],a=new Set(i);return r.every(e=>a.has(e))})?[]:[n]}).reduce((e,t)=>{let n=u(t),{parameters:r,schemas:i}=l(t);return{paths:{...e.paths,...n},components:{parameters:{...e.components.parameters,...r},schemas:{...e.components.schemas,...i}}}},{paths:{},components:{parameters:{},schemas:{}}});return{paths:r,components:n}}}},pn=(e,t)=>{let n={type:`string`,format:`uri`,...t?{enum:[t]}:{}};return{301:{description:`Moved Permanently`,headers:{Location:{description:`New permanent location`,schema:n}}},302:{description:`Found`,headers:{Location:{description:`Temporary location`,schema:n}}},303:{description:`See Other`,headers:{Location:{description:`Location to GET after POST/PUT/DELETE`,schema:n}}},307:{description:`Temporary Redirect`,headers:{Location:{description:`Temporary location (preserves request method)`,schema:n}}},308:{description:`Permanent Redirect`,headers:{Location:{description:`New permanent location (preserves request method)`,schema:n}}}}[e]},mn=v((e,t)=>{let{outfile:n=``,...r}={...t},{createPath:i}=S(e),{generateOpenAPISchema:a}=fn(),o=async e=>{let t=e.flatMap(({kind:e,entry:t})=>e===`apiRoute`?[t]:[]),{paths:o,components:s}=a(t),c={...JSON.parse(JSON.stringify(r)),paths:o,components:s},l=/ya?ml/.test(n)?ie.stringify(c):JSON.stringify(c,null,2);await T(i.src(n),l,{})};return{async watch(e){await o(e)},async build(e){await o(e)}}}),hn=_({meta:{name:`OpenAPI`,resolveTypes:!0},factory:mn}),W={type:`module`,private:!0,name:`@kosmojs/react-generator`,version:`0.3.0`,author:`Slee Woo`,license:`MIT`,files:[`pkg/*`],exports:{".":{types:`./pkg/index.d.ts`,default:`./pkg/index.js`}},scripts:{build:`wsbuild src/index.ts`,test:`vitest --root ../.. --project generators/react-generator`},dependencies:{"@kosmojs/core":`workspace:^`,"@kosmojs/lib":`workspace:^`,"@vitejs/plugin-react":`^6.1.0`},devDependencies:{"@tanstack/react-query":`^5.102.2`,"@types/react":`^19.2.18`,"@types/react-dom":`^19.2.5`,react:`^19.2.8`,"react-dom":`^19.2.8`,"react-router":`^8.3.0`}},gn=e=>{let t=e.map(e=>e.orig).join(`/`),n=e=>e.kind===`splat`?`*`:e.kind===`optional`?`:${e.name}?`:`:${e.name}`;return e.flatMap(e=>e.kind===`static`?[e.parts[0].value]:e.kind===`param`?[n(e.parts[0])]:(/\.\w+$/.test(e.orig)||(console.warn(`❗${i([`red`,`bold`],`WARN`)}: React Router v7 only supports dot-suffix mixed segments (e.g. :param.html).`),console.warn(` ${i([`magenta`],e.orig)} in ${i([`blue`],t)} route won't match as expected.`),console.warn()),[e.parts.map(e=>e.type===`static`?e.value:n(e)).join(``)])).join(`/`)},_n=()=>{let e=e=>e?.kind===`param`&&e.parts[0]?.kind===`splat`,t=n=>n.flatMap(({index:n,layout:r,children:i})=>{let{name:a,pathTokens:o}={...n,...r};if(!o)return[];let s=`${a}:layout`,c=gn(o),l=o.at(-1);return e(l)?n&&r?[{name:s,path:c,component:r.id,children:[{name:a,path:`*`,component:n.id}]}]:n?[{path:c,children:[{name:a,path:`*`,component:n.id},...t(i)]}]:r?[{name:s,path:c,component:r.id,children:t(i)}]:[]:n&&r?[{name:s,path:c,component:r.id,children:[{name:a,index:!0,component:n.id},...t(i)]}]:n?[{path:c,children:[{name:a,index:!0,component:n.id},...t(i)]}]:r?[{name:s,path:c,component:r.id,children:t(i)}]:[]});return t},vn=()=>{let e=[`🎉 Well done! You just created a new React route.`,`🚀 Success! A fresh React route is ready to roll.`,`🌟 Nice work! Another React route added to your app.`,`⚡ Quick and easy! Your new React route is good to go.`,`🥳 Congrats! Your app just leveled up with a new React route.`,`🧩 All set! A new React route has been scaffolded.`,`🔧 Scaffold complete! Your new React route is in place.`,`✨ Fantastic! Your new React route is ready.`,`🎯 Nailed it! A brand new React route just landed.`,`💫 Awesome! Another React route joins the lineup.`];return e[Math.floor(Math.random()*e.length)]},yn=`import type { ReactNode } from "react";
4020
4793
 
4021
4794
  export const AppProvider = ({ children }: { children: ReactNode }) => {
4022
4795
  return children;
4023
4796
  }
4024
- `,Qt=`import { type QueryClient, QueryClientProvider } from "@tanstack/react-query";
4797
+ `,bn=`import { type QueryClient, QueryClientProvider } from "@tanstack/react-query";
4025
4798
  import type { ReactNode } from "react";
4026
4799
 
4027
4800
  import { getQueryClient } from "./query";
@@ -4040,7 +4813,7 @@ export const AppProvider = ({
4040
4813
  </QueryClientProvider>
4041
4814
  );
4042
4815
  }
4043
- `,$t=`import { lazy, type JSX } from "react";
4816
+ `,xn=`import { lazy, type JSX } from "react";
4044
4817
 
4045
4818
  import {
4046
4819
  createRoot,
@@ -4094,7 +4867,7 @@ export const mount = async (
4094
4867
  }
4095
4868
 
4096
4869
  export default clientRenderFactory();
4097
- `,en=`{
4870
+ `,Sn=`{
4098
4871
  {{#if name}}
4099
4872
  id: "{{name}}",
4100
4873
  {{/if}}
@@ -4112,7 +4885,7 @@ export default clientRenderFactory();
4112
4885
  children: [ {{#each children}}{{> routePartial}}, {{/each}}],
4113
4886
  {{/if}}
4114
4887
  }
4115
- `,tn=`import type { JSX } from "react";
4888
+ `,Cn=`import type { JSX } from "react";
4116
4889
 
4117
4890
  import {
4118
4891
  renderToString as renderToStringOrig,
@@ -4178,7 +4951,12 @@ export const renderToStream: RenderToStreamWrapper<
4178
4951
  };
4179
4952
 
4180
4953
  export default serverRenderFactory();
4181
- `,nn=`/* @jsxImportSource react */
4954
+ `,wn=`declare module "virtual:kosmo/tsq-client" {
4955
+ import type { QueryClient, QueryClientConfig } from "@tanstack/react-query";
4956
+ export const createQueryClient: (options?: QueryClientConfig) => QueryClient;
4957
+ export const getQueryClient: () => QueryClient;
4958
+ }
4959
+ `,Tn=`/* @jsxImportSource react */
4182
4960
 
4183
4961
  import styles from "./styles.module.css";
4184
4962
 
@@ -4219,7 +4997,7 @@ export default function PageSample(props: {
4219
4997
  </div>
4220
4998
  );
4221
4999
  }
4222
- `,rn=`/* @jsxImportSource react */
5000
+ `,En=`/* @jsxImportSource react */
4223
5001
 
4224
5002
  import styles from "./styles.module.css";
4225
5003
 
@@ -4271,7 +5049,7 @@ export default function PageSample(props: {
4271
5049
  </div>
4272
5050
  );
4273
5051
  }
4274
- `,an=`* {
5052
+ `,Dn=`* {
4275
5053
  margin: 0;
4276
5054
  padding: 0;
4277
5055
  box-sizing: border-box;
@@ -4406,7 +5184,7 @@ export default function PageSample(props: {
4406
5184
  align-items: center;
4407
5185
  gap: 0.25rem;
4408
5186
  }
4409
- `,on=`/* @jsxImportSource react */
5187
+ `,On=`/* @jsxImportSource react */
4410
5188
 
4411
5189
  import styles from "./styles.module.css";
4412
5190
 
@@ -4472,26 +5250,27 @@ export default function WelcomePage() {
4472
5250
  </div>
4473
5251
  );
4474
5252
  }
4475
- `,sn=`import { QueryClient, type QueryClientConfig } from "@tanstack/react-query";
5253
+ `,kn=`export * from "virtual:kosmo/tsq-client";
5254
+ `,An=`import { QueryClient } from "@tanstack/react-query";
4476
5255
 
4477
- let client: QueryClient | undefined;
5256
+ let client = undefined;
4478
5257
 
4479
- export const createQueryClient = (options?: QueryClientConfig): QueryClient => {
5258
+ export const createQueryClient = (options) => {
4480
5259
  client = new QueryClient(options);
4481
5260
  return client;
4482
5261
  };
4483
5262
 
4484
- export const getQueryClient = (): QueryClient => {
5263
+ export const getQueryClient = () => {
4485
5264
  if (!client) {
4486
5265
  client = new QueryClient();
4487
5266
  }
4488
5267
  return client;
4489
5268
  };
4490
- `,cn=`import { QueryClient, type QueryClientConfig } from "@tanstack/react-query";
5269
+ `,jn=`import { QueryClient } from "@tanstack/react-query";
4491
5270
 
4492
- import { store } from "{{ createImport 'lib' '@ssr/base' }}";
5271
+ import { store } from "{{ createImport 'libCore' 'ssr' }}";
4493
5272
 
4494
- export const createQueryClient = (options?: QueryClientConfig): QueryClient => {
5273
+ export const createQueryClient = (options) => {
4495
5274
  const client = new QueryClient(options);
4496
5275
  const ctx = store?.getStore();
4497
5276
  if (ctx) {
@@ -4500,7 +5279,7 @@ export const createQueryClient = (options?: QueryClientConfig): QueryClient => {
4500
5279
  return client;
4501
5280
  };
4502
5281
 
4503
- export const getQueryClient = (): QueryClient => {
5282
+ export const getQueryClient = () => {
4504
5283
  const ctx = store?.getStore();
4505
5284
  if (!ctx) {
4506
5285
  throw new Error("getQueryClient(): called outside an SSR request scope");
@@ -4508,9 +5287,9 @@ export const getQueryClient = (): QueryClient => {
4508
5287
  if (!ctx.tsqClient) {
4509
5288
  ctx.tsqClient = new QueryClient();
4510
5289
  }
4511
- return ctx.tsqClient as QueryClient;
5290
+ return ctx.tsqClient;
4512
5291
  };
4513
- `,ln=`export type ComponentLoader = () => Promise<{
5292
+ `,Mn=`export type ComponentLoader = () => Promise<{
4514
5293
  loader?: (arg: unknown) => Promise<unknown>;
4515
5294
  }>;
4516
5295
 
@@ -4530,7 +5309,7 @@ export const loaderFactory = (opt?: { withPreload?: boolean }) => {
4530
5309
  return opt?.withPreload ? { loader } : {};
4531
5310
  };
4532
5311
  };
4533
- `,un=`import type { JSX, ComponentType } from "react";
5312
+ `,Nn=`import type { JSX, ComponentType } from "react";
4534
5313
 
4535
5314
  import {
4536
5315
  type RouteObject,
@@ -4588,7 +5367,7 @@ export const createRouters = (
4588
5367
  }
4589
5368
 
4590
5369
  export default createRouterFactory<RouteObject, Promise<JSX.Element>>();
4591
- `,dn=`import { Outlet } from "react-router";
5370
+ `,Pn=`import { Outlet } from "react-router";
4592
5371
  import { AppProvider } from "{{ createImport 'lib' 'app' }}";
4593
5372
 
4594
5373
  export default function App() {
@@ -4598,7 +5377,7 @@ export default function App() {
4598
5377
  </AppProvider>
4599
5378
  );
4600
5379
  }
4601
- `,fn=`import {
5380
+ `,Fn=`import {
4602
5381
  type LinkProps as RouterLinkProps,
4603
5382
  Link as RouterLink,
4604
5383
  } from "react-router";
@@ -4626,7 +5405,7 @@ export default function Link(
4626
5405
  </RouterLink>
4627
5406
  );
4628
5407
  }
4629
- `,pn=`import renderFactory, {
5408
+ `,In=`import renderFactory, {
4630
5409
  createRoutes,
4631
5410
  hydrate,
4632
5411
  mount,
@@ -4653,7 +5432,7 @@ if (root) {
4653
5432
  } else {
4654
5433
  console.error("❌ Root element not found!");
4655
5434
  }
4656
- `,mn=`import renderFactory, {
5435
+ `,Ln=`import renderFactory, {
4657
5436
  createRoutes,
4658
5437
  renderToStream,
4659
5438
  renderToString,
@@ -4680,17 +5459,17 @@ export default renderFactory(() => {
4680
5459
  },
4681
5460
  };
4682
5461
  });
4683
- `,hn=`import PageSample from "{{ createImport 'lib' 'pageSamples/404.tsx' }}";
5462
+ `,Rn=`import PageSample from "{{ createImport 'lib' 'pageSamples/404.tsx' }}";
4684
5463
 
4685
5464
  export default function Page() {
4686
5465
  return <PageSample />;
4687
5466
  }
4688
- `,gn=`import { Outlet } from "react-router";
5467
+ `,zn=`import { Outlet } from "react-router";
4689
5468
 
4690
5469
  export default function Layout() {
4691
5470
  return <Outlet />;
4692
5471
  }
4693
- `,_n=`import PageSample from "{{ createImport 'lib' 'pageSamples/page.tsx' }}";
5472
+ `,Bn=`import PageSample from "{{ createImport 'lib' 'pageSamples/page.tsx' }}";
4694
5473
 
4695
5474
  export default function Page() {
4696
5475
  return PageSample({
@@ -4703,8 +5482,8 @@ export default function Page() {
4703
5482
  },
4704
5483
  });
4705
5484
  }
4706
- `,vn=`export { default } from "{{ createImport 'lib' 'pageSamples/welcome.tsx' }}";
4707
- `,yn=`import routerFactory, { createRouters } from "{{ createImport 'lib' 'router' }}";
5485
+ `,Vn=`export { default } from "{{ createImport 'lib' 'pageSamples/welcome.tsx' }}";
5486
+ `,Hn=`import routerFactory, { createRouters } from "{{ createImport 'lib' 'router' }}";
4708
5487
 
4709
5488
  import app from "./app";
4710
5489
 
@@ -4719,12 +5498,12 @@ export default routerFactory((routes) => {
4719
5498
  },
4720
5499
  };
4721
5500
  });
4722
- `,bn=g((e,t)=>{let{createPath:n,createImportHelpers:r}=y(e),{renderToFile:i}=x({helpers:{...r({origin:`lib`}),...w()},partials:{routePartial:en}}),{renderToFile:a}=x({helpers:r({origin:`src`})}),o=Yt(),s=e=>!e?.trim().length,u=c(t?.templates,_n),d=async e=>{for(let{kind:t,entry:r}of e)t===`pageRoute`?await a(n.pages(r.file),r.name===`index`?vn:u(r.name,r),{route:r,message:Xt()},{overwrite:s}):t===`pageLayout`&&await a(n.pages(r.file),gn,{route:r},{overwrite:s})},f=async e=>{let t=e.flatMap(({kind:e,entry:t})=>e===`pageRoute`?[t]:[]).sort(S),r=e.flatMap(({kind:e,entry:t})=>e===`pageRoute`||e===`pageLayout`?[t]:[]),a=o(v(r));for(let[e,t]of[[`client.ts`,$t],[`server.ts`,tn]])await i(n.libEntry(e),t,{pageEntries:r,nestedRoutes:a});await i(n.lib(`router.tsx`),un,{entries:e,indexRoutes:t})};return{config(){let{templates:e,...n}={...t};return{plugins:[ce(n)]}},async start(){for(let[e,r]of[[`env.d.ts`,``],[`react.ts`,ln],[`pageSamples/styles.module.css`,an],[`pageSamples/welcome.tsx`,on],[`pageSamples/page.tsx`,rn],[`pageSamples/404.tsx`,nn],...t?.tanstack?.query?[[`app.tsx`,Qt],[`query.ts`,sn]]:[[`app.tsx`,Zt],[`query.ts`,`/** tanstack query disabled */`]]])await i(n.lib(e),r,{});for(let[e,t]of[[`pages/404.tsx`,hn],[`components/Link.tsx`,fn],[`app.tsx`,dn],[`router.ts`,yn]])await a(n.src(e),t,{entryDir:l.entryDir},{overwrite:s});for(let[e,t]of[[`client.ts`,pn],[`server.ts`,mn]])await a(n.entry(e),t,{},{overwrite:s})},async watch(e,t){await d(e.filter(m(t,[`create`]))),await f(e)},async build(e){await d(e),await f(e)},async ssrBuild(){await i(n.lib(`query.ts`),t?.tanstack?.query?cn:`/** tanstack query disabled */`,{ssrBundle:!0})}}}),xn=h({meta:{name:`React`,slot:`frontend`,jsx:`preserve`,jsxImportSource:`react`},dependencies(e){return{react:W.devDependencies.react,"react-router":W.devDependencies[`react-router`],"path-to-regexp":W.devDependencies[`path-to-regexp`],...e?.tanstack?.query?{"@tanstack/react-query":W.devDependencies[`@tanstack/react-query`]}:{}}},devDependencies:{"@types/react":W.devDependencies[`@types/react`],"@types/react-dom":W.devDependencies[`@types/react-dom`],"react-dom":W.devDependencies[`react-dom`]},factory:bn}),G={type:`module`,private:!0,name:`@kosmojs/solid-generator`,version:`0.3.0`,author:`Slee Woo`,license:`MIT`,files:[`pkg/*`],exports:{".":{types:`./pkg/index.d.ts`,default:`./pkg/index.js`}},scripts:{build:`wsbuild src/index.ts`,test:`vitest --root ../.. --project generators/solid-generator`},dependencies:{"@kosmojs/core":`workspace:^`,"@kosmojs/lib":`workspace:^`,"vite-plugin-solid":`^2.11.14`},devDependencies:{"@solidjs/router":`^1.0.0`,"@tanstack/solid-query":`^5.102.2`,"path-to-regexp":`^8.4.2`,"solid-js":`^1.9.15`}},Sn=()=>{let e=e=>e?.kind===`param`&&e.parts[0]?.kind===`splat`,t=t=>t?.kind===`param`?t.parts[0]?.kind===`optional`||e(t):!1,n=r=>r.flatMap(({index:r,layout:i,children:a})=>{let{pathTokens:o}={...r,...i},s=K(o.map((e,n)=>e.kind===`param`&&(t(o[n+1])||a.some(e=>e.index?.pathTokens.some(t)))?{...e,parts:[{...e.parts[0],kind:`required`}]}:e)),c=o.at(-1);if(e(c)){let e=K([c]);return r&&i?[{path:s,component:i.id,children:[{path:e,component:r.id}]}]:r?[{path:s,children:[{path:e,component:r.id},...n(a)]}]:i?[{path:s,component:i.id,children:n(a)}]:[]}return r&&i?[{path:s,component:i.id,children:[{path:`/`,component:r.id},...n(a)]}]:r?[{path:s,children:[{path:`/`,component:r.id},...n(a)]}]:i?[{path:s,component:i.id,children:n(a)}]:[]});return n},K=e=>{let t=e.map(e=>e.orig).join(`/`),n=e=>e.kind===`splat`?`*${e.name}`:e.kind===`optional`?`:${e.name}?`:`:${e.name}`;return e.flatMap(e=>e.kind===`static`?[e.parts[0].value]:e.kind===`param`?[n(e.parts[0])]:(e.parts.length&&(console.warn(`❗${r([`red`,`bold`],`WARN`)}: At the moment Solid Router does not support mixed path segments.`),console.warn(` ${r([`magenta`],e.orig)} segment in ${r([`blue`],t)} route won't match as expected.`),console.warn()),[e.parts.map(e=>e.type===`static`?e.value:n(e)).join(``)])).join(`/`)},Cn=()=>{let e=[`🎉 Well done! You just created a new Solid route.`,`🚀 Success! A fresh Solid route is ready to roll.`,`🌟 Nice work! Another Solid route added to your app.`,`🧩 All set! A new Solid route has been scaffolded.`,`🔧 Scaffold complete! Your new Solid route is in place.`,`✅ Built! Your Solid route is scaffolded and ready.`,`✨ Fantastic! Your new Solid route is good to go.`,`🎯 Nailed it! A brand new Solid route just landed.`,`💫 Awesome! Another Solid route joins the party.`,`⚡ Lightning fast! A new Solid route created successfully.`];return e[Math.floor(Math.random()*e.length)]},wn=`import type { ParentComponent } from "solid-js";
5501
+ `,Un=v((e,t)=>{let{createPath:n,createImportHelpers:r}=S(e),{render:i,renderToFile:a}=w({helpers:{...r({origin:`lib`}),...A()},partials:{routePartial:Sn}}),{renderToFile:o}=w({helpers:r({origin:`src`})}),s=_n(),c=e=>!e?.trim().length,d=l(t?.templates,Bn),f=async e=>{for(let{kind:t,entry:r}of e)t===`pageRoute`?await o(n.pages(r.file),r.name===`index`?Vn:d(r.name,r),{route:r,message:vn()},{overwrite:c}):t===`pageLayout`&&await o(n.pages(r.file),zn,{route:r},{overwrite:c})},p=async e=>{let t=e.flatMap(({kind:e,entry:t})=>e===`pageRoute`?[t]:[]).sort(E),r=e.flatMap(({kind:e,entry:t})=>e===`pageRoute`||e===`pageLayout`?[t]:[]),i=s(b(r));for(let[e,t]of[[`client.ts`,xn],[`server.ts`,Cn]])await a(n.libEntry(e),t,{pageEntries:r,nestedRoutes:i});await a(n.lib(`router.tsx`),Nn,{entries:e,indexRoutes:t})};return{config(){let{templates:e,...n}={...t};return{plugins:[se(n)]}},async start(){for(let[e,r]of[[`env.d.ts`,wn],[`react.ts`,Mn],[`pageSamples/styles.module.css`,Dn],[`pageSamples/welcome.tsx`,On],[`pageSamples/page.tsx`,En],[`pageSamples/404.tsx`,Tn],...t?.tanstack?.query?[[`app.tsx`,bn],[`query.ts`,kn]]:[[`app.tsx`,yn],[`query.ts`,`/** tanstack query disabled */`]]])await a(n.lib(e),r,{});for(let[e,t]of[[`pages/404.tsx`,Rn],[`components/Link.tsx`,Fn],[`app.tsx`,Pn],[`router.ts`,Hn]])await o(n.src(e),t,{entryDir:u.entryDir},{overwrite:c});for(let[e,t]of[[`client.ts`,In],[`server.ts`,Ln]])await o(n.entry(e),t,{},{overwrite:c})},async watch(e,t){await f(e.filter(g(t,[`create`]))),await p(e)},async build(e){await f(e),await p(e)},virtualModules(){return t?.tanstack?.query?[{specifier:`virtual:kosmo/tsq-client`,csr:i(An,{}),ssr:i(jn,{})}]:[]}}}),Wn=_({meta:{name:`React`,slot:`frontend`,jsx:`preserve`,jsxImportSource:`react`},dependencies(e){return{react:W.devDependencies.react,"react-router":W.devDependencies[`react-router`],...e?.tanstack?.query?{"@tanstack/react-query":W.devDependencies[`@tanstack/react-query`]}:{}}},devDependencies:{"@types/react":W.devDependencies[`@types/react`],"@types/react-dom":W.devDependencies[`@types/react-dom`],"react-dom":W.devDependencies[`react-dom`]},factory:Un}),G={type:`module`,private:!0,name:`@kosmojs/solid-generator`,version:`0.3.0`,author:`Slee Woo`,license:`MIT`,files:[`pkg/*`],exports:{".":{types:`./pkg/index.d.ts`,default:`./pkg/index.js`}},scripts:{build:`wsbuild src/index.ts`,test:`vitest --root ../.. --project generators/solid-generator`},dependencies:{"@kosmojs/core":`workspace:^`,"@kosmojs/lib":`workspace:^`,"vite-plugin-solid":`^2.11.14`},devDependencies:{"@solidjs/router":`^1.0.0`,"@tanstack/solid-query":`^5.102.2`,"solid-js":`^1.9.15`}},Gn=()=>{let e=e=>e?.kind===`param`&&e.parts[0]?.kind===`splat`,t=t=>t?.kind===`param`?t.parts[0]?.kind===`optional`||e(t):!1,n=r=>r.flatMap(({index:r,layout:i,children:a})=>{let{pathTokens:o}={...r,...i},s=K(o.map(e=>e.kind===`param`&&a.some(e=>e.index?.pathTokens.some(t))?{...e,parts:[{...e.parts[0],kind:`required`}]}:e)),c=o.at(-1);if(e(c)){let e=K([c]);return r&&i?[{path:s,component:i.id,children:[{path:e,component:r.id}]}]:r?[{path:s,children:[{path:e,component:r.id},...n(a)]}]:i?[{path:s,component:i.id,children:n(a)}]:[]}return r&&i?[{path:s,component:i.id,children:[{path:`/`,component:r.id},...n(a)]}]:r?[{path:s,children:[{path:`/`,component:r.id},...n(a)]}]:i?[{path:s,component:i.id,children:n(a)}]:[]});return n},K=e=>{let t=e.map(e=>e.orig).join(`/`),n=e=>e.kind===`splat`?`*${e.name}`:e.kind===`optional`?`:${e.name}?`:`:${e.name}`;return e.flatMap(e=>e.kind===`static`?[e.parts[0].value]:e.kind===`param`?[n(e.parts[0])]:(e.parts.length&&(console.warn(`❗${i([`red`,`bold`],`WARN`)}: At the moment Solid Router does not support mixed path segments.`),console.warn(` ${i([`magenta`],e.orig)} segment in ${i([`blue`],t)} route won't match as expected.`),console.warn()),[e.parts.map(e=>e.type===`static`?e.value:n(e)).join(``)])).join(`/`)},Kn=()=>{let e=[`🎉 Well done! You just created a new Solid route.`,`🚀 Success! A fresh Solid route is ready to roll.`,`🌟 Nice work! Another Solid route added to your app.`,`🧩 All set! A new Solid route has been scaffolded.`,`🔧 Scaffold complete! Your new Solid route is in place.`,`✅ Built! Your Solid route is scaffolded and ready.`,`✨ Fantastic! Your new Solid route is good to go.`,`🎯 Nailed it! A brand new Solid route just landed.`,`💫 Awesome! Another Solid route joins the party.`,`⚡ Lightning fast! A new Solid route created successfully.`];return e[Math.floor(Math.random()*e.length)]},qn=`import type { ParentComponent } from "solid-js";
4723
5502
 
4724
5503
  export const AppProvider: ParentComponent = (props) => {
4725
5504
  return props.children;
4726
5505
  };
4727
- `,Tn=`import type { ParentComponent } from "solid-js";
5506
+ `,Jn=`import type { ParentComponent } from "solid-js";
4728
5507
  import { type QueryClient, QueryClientProvider } from "@tanstack/solid-query";
4729
5508
 
4730
5509
  import { getQueryClient } from "./query";
@@ -4736,7 +5515,7 @@ export const AppProvider: ParentComponent<{ client?: QueryClient }> = (props) =>
4736
5515
  </QueryClientProvider>
4737
5516
  );
4738
5517
  };
4739
- `,En=`import { lazy, type JSX } from "solid-js";
5518
+ `,Yn=`import { lazy, type JSX } from "solid-js";
4740
5519
  import { hydrate as hydrateOrig, render } from "solid-js/web";
4741
5520
  import type { RouterFactoryReturn } from "@kosmojs/core";
4742
5521
  import { clientRenderFactory } from "@kosmojs/core/generators";
@@ -4781,7 +5560,7 @@ export const mount = async (
4781
5560
  }
4782
5561
 
4783
5562
  export default clientRenderFactory();
4784
- `,Dn=`{
5563
+ `,Xn=`{
4785
5564
  path: "{{path}}",
4786
5565
  {{#if component}}
4787
5566
  component: {{component}}_component,
@@ -4791,7 +5570,7 @@ export default clientRenderFactory();
4791
5570
  children: [ {{#each children}}{{> routePartial}}, {{/each}}],
4792
5571
  {{/if}}
4793
5572
  }
4794
- `,On=`import type { JSX } from "solid-js";
5573
+ `,Zn=`import type { JSX } from "solid-js";
4795
5574
 
4796
5575
  import {
4797
5576
  generateHydrationScript,
@@ -4846,11 +5625,44 @@ export const renderWrapper: SSRRenderWrapper = (context, render) => {
4846
5625
  export const renderToString: RenderToStringWrapper<
4847
5626
  () => RouterFactoryReturn<JSX.Element>,
4848
5627
  Parameters<typeof renderToStringAsync>[1]
4849
- > = async (resolver, { headerTags = [], ...options } = {}) => {
4850
- return {
4851
- head: [...headerTags, generateHydrationScript()].join("\\n"),
4852
- html: await renderToStringAsync(() => resolver().component, options),
4853
- };
5628
+ > = async (resolver, { headerTags = [], timeoutMs = 30_000, ...options } = {}) => {
5629
+ /**
5630
+ * renderToStringAsync adaptation.
5631
+ * Solid arms its internal timeout before invoking the component,
5632
+ * so a component throwing synchronously leaves that timeout promise orphaned -
5633
+ * its rejection, 30s later, is unhandled and fatal to the process.
5634
+ * renderToStream's thenable resolves with the same html;
5635
+ * deferring the call turns a sync throw into an immediate, catchable rejection carrying the real error,
5636
+ * and the replacement timeout below is pre-observed, so it can never reject unhandled.
5637
+ * */
5638
+ let timeoutHandle: ReturnType<typeof setTimeout> | undefined;
5639
+
5640
+ const timeout = new Promise<never>((_, reject) => {
5641
+ timeoutHandle = setTimeout(() => {
5642
+ reject(new Error("SSR: solid render timed out"));
5643
+ }, timeoutMs);
5644
+ });
5645
+
5646
+ timeout.catch(() => {});
5647
+
5648
+ try {
5649
+ return {
5650
+ head: [...headerTags, generateHydrationScript()].join("\\n"),
5651
+ html: await Promise.race([
5652
+ Promise.resolve().then(() => {
5653
+ // typed as a stream handle, but resolving to the full html at runtime.
5654
+ // renderToStringAsync itself races it the same way.
5655
+ return renderToStreamOrig(
5656
+ () => resolver().component,
5657
+ options,
5658
+ ) as unknown as Promise<string>;
5659
+ }),
5660
+ timeout,
5661
+ ]),
5662
+ };
5663
+ } finally {
5664
+ clearTimeout(timeoutHandle);
5665
+ }
4854
5666
  };
4855
5667
 
4856
5668
  export const renderToStream: RenderToStreamWrapper<
@@ -4872,7 +5684,12 @@ export const renderToStream: RenderToStreamWrapper<
4872
5684
  };
4873
5685
 
4874
5686
  export default serverRenderFactory<true>();
4875
- `,kn=`/* @jsxImportSource solid-js */
5687
+ `,Qn=`declare module "virtual:kosmo/tsq-client" {
5688
+ import type { QueryClient, QueryClientConfig } from "@tanstack/solid-query";
5689
+ export const createQueryClient: (options?: QueryClientConfig) => QueryClient;
5690
+ export const getQueryClient: () => QueryClient;
5691
+ }
5692
+ `,$n=`/* @jsxImportSource solid-js */
4876
5693
 
4877
5694
  import styles from "./styles.module.css";
4878
5695
 
@@ -4913,7 +5730,7 @@ export default function PageSample(props: {
4913
5730
  </div>
4914
5731
  );
4915
5732
  }
4916
- `,An=`/* @jsxImportSource solid-js */
5733
+ `,er=`/* @jsxImportSource solid-js */
4917
5734
 
4918
5735
  import styles from "./styles.module.css";
4919
5736
 
@@ -4965,7 +5782,7 @@ export default function PageSample(props: {
4965
5782
  </div>
4966
5783
  );
4967
5784
  }
4968
- `,jn=`* {
5785
+ `,tr=`* {
4969
5786
  margin: 0;
4970
5787
  padding: 0;
4971
5788
  box-sizing: border-box;
@@ -5100,7 +5917,7 @@ export default function PageSample(props: {
5100
5917
  align-items: center;
5101
5918
  gap: 0.25rem;
5102
5919
  }
5103
- `,Mn=`/* @jsxImportSource solid-js */
5920
+ `,nr=`/* @jsxImportSource solid-js */
5104
5921
 
5105
5922
  import styles from "./styles.module.css";
5106
5923
 
@@ -5166,26 +5983,27 @@ export default function WelcomePage() {
5166
5983
  </div>
5167
5984
  );
5168
5985
  }
5169
- `,Nn=`import { QueryClient, type QueryClientConfig } from "@tanstack/solid-query";
5986
+ `,rr=`export * from "virtual:kosmo/tsq-client";
5987
+ `,ir=`import { QueryClient } from "@tanstack/solid-query";
5170
5988
 
5171
- let client: QueryClient | undefined;
5989
+ let client = undefined;
5172
5990
 
5173
- export const createQueryClient = (options?: QueryClientConfig): QueryClient => {
5991
+ export const createQueryClient = (options) => {
5174
5992
  client = new QueryClient(options);
5175
5993
  return client;
5176
5994
  };
5177
5995
 
5178
- export const getQueryClient = (): QueryClient => {
5996
+ export const getQueryClient = () => {
5179
5997
  if (!client) {
5180
5998
  client = new QueryClient();
5181
5999
  }
5182
6000
  return client;
5183
6001
  };
5184
- `,Pn=`import { QueryClient, type QueryClientConfig } from "@tanstack/solid-query";
6002
+ `,ar=`import { QueryClient } from "@tanstack/solid-query";
5185
6003
 
5186
- import { store } from "{{ createImport 'lib' '@ssr/base' }}";
6004
+ import { store } from "{{ createImport 'libCore' 'ssr' }}";
5187
6005
 
5188
- export const createQueryClient = (options?: QueryClientConfig): QueryClient => {
6006
+ export const createQueryClient = (options) => {
5189
6007
  const client = new QueryClient(options);
5190
6008
  const ctx = store?.getStore();
5191
6009
  if (ctx) {
@@ -5194,7 +6012,7 @@ export const createQueryClient = (options?: QueryClientConfig): QueryClient => {
5194
6012
  return client;
5195
6013
  };
5196
6014
 
5197
- export const getQueryClient = (): QueryClient => {
6015
+ export const getQueryClient = () => {
5198
6016
  const ctx = store?.getStore();
5199
6017
  if (!ctx) {
5200
6018
  throw new Error("getQueryClient(): called outside an SSR request scope");
@@ -5202,9 +6020,9 @@ export const getQueryClient = (): QueryClient => {
5202
6020
  if (!ctx.tsqClient) {
5203
6021
  ctx.tsqClient = new QueryClient();
5204
6022
  }
5205
- return ctx.tsqClient as QueryClient;
6023
+ return ctx.tsqClient;
5206
6024
  };
5207
- `,Fn=`import type { JSX, ParentComponent } from "solid-js";
6025
+ `,or=`import type { JSX, ParentComponent } from "solid-js";
5208
6026
  import { Router, type RouteDefinition } from "@solidjs/router";
5209
6027
  import type { RouterFactoryReturn } from "@kosmojs/core";
5210
6028
  import { createRouterFactory } from "@kosmojs/core/generators";
@@ -5240,7 +6058,7 @@ export const createRouters = (
5240
6058
  }
5241
6059
 
5242
6060
  export default createRouterFactory<RouteDefinition, JSX.Element>();
5243
- `,In=`export type ComponentLoader = () => Promise<{
6061
+ `,sr=`export type ComponentLoader = () => Promise<{
5244
6062
  preload?: () => Promise<unknown>;
5245
6063
  }>;
5246
6064
 
@@ -5255,10 +6073,10 @@ export const loaderFactory = (opt?: { withPreload?: boolean }) => {
5255
6073
  return opt?.withPreload ? { preload } : {};
5256
6074
  };
5257
6075
  };
5258
- `,Ln=`export type MaybeWrapped<T> = import("solid-js/store").Store<T> | T;
6076
+ `,cr=`export type MaybeWrapped<T> = import("solid-js/store").Store<T> | T;
5259
6077
 
5260
6078
  export { unwrap } from "solid-js/store";
5261
- `,Rn=`import type { ParentComponent } from "solid-js";
6079
+ `,lr=`import type { ParentComponent } from "solid-js";
5262
6080
  import { AppProvider } from "{{ createImport 'lib' 'app' }}";
5263
6081
 
5264
6082
  const App: ParentComponent = (props) => {
@@ -5266,7 +6084,7 @@ const App: ParentComponent = (props) => {
5266
6084
  };
5267
6085
 
5268
6086
  export default App;
5269
- `,zn=`import { A, type AnchorProps } from "@solidjs/router";
6087
+ `,ur=`import { A, type AnchorProps } from "@solidjs/router";
5270
6088
  import { type JSXElement, splitProps } from "solid-js";
5271
6089
 
5272
6090
  import { pageRouteMap, type LinkProps } from "{{ createImport 'libCore' }}";
@@ -5291,7 +6109,7 @@ export default function Link(
5291
6109
 
5292
6110
  return <A {...{ ...restProps, href: href() }}>{knownProps.children}</A>;
5293
6111
  }
5294
- `,Bn=`import renderFactory, {
6112
+ `,dr=`import renderFactory, {
5295
6113
  createRoutes,
5296
6114
  hydrate,
5297
6115
  mount,
@@ -5318,7 +6136,7 @@ if (root) {
5318
6136
  } else {
5319
6137
  console.error("❌ Root element not found!");
5320
6138
  }
5321
- `,Vn=`import renderFactory, {
6139
+ `,fr=`import renderFactory, {
5322
6140
  createRoutes,
5323
6141
  renderToStream,
5324
6142
  renderToString,
@@ -5345,19 +6163,19 @@ export default renderFactory(() => {
5345
6163
  },
5346
6164
  };
5347
6165
  });
5348
- `,Hn=`import PageSample from "{{ createImport 'lib' 'pageSamples/404.tsx' }}";
6166
+ `,pr=`import PageSample from "{{ createImport 'lib' 'pageSamples/404.tsx' }}";
5349
6167
 
5350
6168
  export default function Page() {
5351
6169
  return <PageSample />;
5352
6170
  }
5353
- `,Un=`import type { ParentComponent } from "solid-js";
6171
+ `,mr=`import type { ParentComponent } from "solid-js";
5354
6172
 
5355
6173
  const Layout: ParentComponent = (props) => {
5356
6174
  return props.children;
5357
6175
  };
5358
6176
 
5359
6177
  export default Layout;
5360
- `,Wn=`import PageSample from "{{ createImport 'lib' 'pageSamples/page.tsx' }}";
6178
+ `,hr=`import PageSample from "{{ createImport 'lib' 'pageSamples/page.tsx' }}";
5361
6179
 
5362
6180
  export default function Page() {
5363
6181
  return PageSample({
@@ -5370,302 +6188,146 @@ export default function Page() {
5370
6188
  },
5371
6189
  });
5372
6190
  }
5373
- `,Gn=`export { default } from "{{ createImport 'lib' 'pageSamples/welcome.tsx' }}";
5374
- `,Kn=`import routerFactory, { createRouters } from "{{ createImport 'lib' 'router' }}";
6191
+ `,gr=`export { default } from "{{ createImport 'lib' 'pageSamples/welcome.tsx' }}";
6192
+ `,_r=`import routerFactory, { createRouters } from "{{ createImport 'lib' 'router' }}";
5375
6193
 
5376
6194
  import app from "./app";
5377
6195
 
5378
- export default routerFactory((routes) => {
5379
- const { clientRouter, serverRouter } = createRouters(routes, { app });
5380
- return {
5381
- clientRouter() {
5382
- return clientRouter()
5383
- },
5384
- serverRouter(url) {
5385
- return serverRouter(url)
5386
- },
5387
- };
5388
- });
5389
- `,qn=g((e,t)=>{let{generators:n=[]}=e.config,{createPath:r,createImportHelpers:i}=y(e),{renderToFile:a}=x({helpers:{...i({origin:`lib`}),...w()},partials:{routePartial:Dn}}),{renderToFile:o}=x({helpers:i({origin:`src`})}),s=Sn(),u=e=>!e?.trim().length,d=c(t?.templates,Wn),f=async e=>{for(let{kind:t,entry:n}of e)t===`pageRoute`?await o(r.pages(n.file),n.name===`index`?Gn:d(n.name,n),{route:n,message:Cn()},{overwrite:u}):t===`pageLayout`&&await o(r.pages(n.file),Un,{route:n},{overwrite:u})},p=async e=>{let t=e.flatMap(({kind:e,entry:t})=>e===`pageRoute`?[t]:[]).sort(S),n=e.flatMap(({kind:e,entry:t})=>e===`pageRoute`||e===`pageLayout`?[t]:[]),i=s(v(n));for(let[e,t]of[[`client.ts`,En],[`server.ts`,On]])await a(r.libEntry(e),t,{pageEntries:n,nestedRoutes:i});await a(r.lib(`router.tsx`),Fn,{entries:e,indexRoutes:t})};return{config({command:e}){let{templates:r,...i}={...t};return{oxc:{jsx:{importSource:`solid-js`}},plugins:e===`build`?[D({...i,...n.some(e=>e.meta.slot===`ssr`)?{ssr:!0,solid:{...i?.solid,hydratable:!0}}:{}})]:[D({...i,dev:!0,hot:!0})]}},async start(){for(let[e,n]of[[`env.d.ts`,``],[`solid.ts`,In],[`unwrap.ts`,Ln],[`pageSamples/styles.module.css`,jn],[`pageSamples/welcome.tsx`,Mn],[`pageSamples/page.tsx`,An],[`pageSamples/404.tsx`,kn],...t?.tanstack?.query?[[`app.tsx`,Tn],[`query.ts`,Nn]]:[[`app.tsx`,wn],[`query.ts`,`/** tanstack query disabled */`]]])await a(r.lib(e),n,{});for(let[e,t]of[[`pages/404.tsx`,Hn],[`components/Link.tsx`,zn],[`app.tsx`,Rn],[`router.ts`,Kn]])await o(r.src(e),t,{entryDir:l.entryDir},{overwrite:u});for(let[e,t]of[[`client.ts`,Bn],[`server.ts`,Vn]])await o(r.entry(e),t,{},{overwrite:u})},async watch(e,t){await f(e.filter(m(t,[`create`]))),await p(e)},async build(e){await f(e),await p(e)},async ssrBuild(){await a(r.lib(`query.ts`),t?.tanstack?.query?Pn:`/** tanstack query disabled */`,{ssrBundle:!0})}}}),Jn=h({meta:{name:`SolidJS`,slot:`frontend`,jsx:`preserve`,jsxImportSource:`solid-js`},dependencies(e){return{"solid-js":G.devDependencies[`solid-js`],"@solidjs/router":G.devDependencies[`@solidjs/router`],"path-to-regexp":G.devDependencies[`path-to-regexp`],...e?.tanstack?.query?{"@tanstack/solid-query":G.devDependencies[`@tanstack/solid-query`]}:{}}},factory:qn}),Yn=g(e=>{let{generators:i=[],refineTypeName:a,...o}={...e.config},{createPath:s}=y(e);return{async postBuild(){let a=s.distDir(`ssg`),c=n(a,`../ssr/server.js`);if(!await le(c,ue.F_OK).then(()=>!0,()=>!1)){console.error(),console.error(r(`red`,`❗Please enable ssrGenerator in ${e.name}/kosmo.config.ts`)),console.error(` SSG generator can not run without SSR server`),console.error();return}let l=te(`${e.name}: SSG`);l.append(`preparing...`);let{createDisposableServer:u}=await import(c);await O(n(a,`../client/assets`),t(a,`assets`),{recursive:!0}),l.append(`bundling routes...`),await E(_(o,...i.map(({factory:t})=>t(e).config?.({kind:`client`,command:`build`})),{root:s.lib(),appType:`custom`,plugins:[C.tsconfigPaths(e),C.nodePrefix()],resolve:{conditions:[`node`]},build:{ssr:s.lib(`ssg.ts`),target:`esnext`,sourcemap:!1,emptyOutDir:!0,rolldownOptions:{output:{dir:a,entryFileNames:`routes.js`,format:`esm`}}}}));try{let e=await import(t(a,`routes.js`)).then(e=>e.default);u(async n=>{for(let[r,i]of e.entries()){l.append(`[ ${r+1} of ${e.length} ] ${i}`);let o=await Xn(n,i);o!==void 0&&(await de(t(a,i),{recursive:!0}),await fe(t(a,t(i,`index.html`)),o,`utf8`))}l.succeed(`done ✨`)})}finally{await k(`${a}/routes.js`)}}}}),Xn=async(e,t)=>{try{let n=`http://localhost:${e}${t}`;return await(await fetch(n)).text()}catch(e){console.error(r(`red`,`✗ SSG: Failed generating ${t} route: ${e.message}`));return}},Zn=h({meta:{name:`SSG`,slot:`ssg`},factory:Yn}),q={type:`module`,private:!0,name:`@kosmojs/ssr-generator`,version:`0.3.0`,author:`Slee Woo`,license:`MIT`,files:[`pkg/*`],exports:{".":{types:`./pkg/index.d.ts`,default:`./pkg/index.js`}},scripts:{build:`wsbuild src/index.ts`},dependencies:{"@kosmojs/core":`workspace:^`,"@kosmojs/lib":`workspace:^`,vite:`^8.2.2`},devDependencies:{"@hono/node-server":`^2.1.1`,hono:`^4.13.3`,"light-my-request":`^6.6.0`,tinyglobby:`^0.2.17`}},Qn=`{{#if apiGenerator}}
5390
- export { default as apiApp } from "{{ createImport 'api' 'app' }}";
5391
- {{else}}
5392
- export const apiApp = undefined;
5393
- {{/if}}
5394
- `,$n=`import { AsyncLocalStorage } from "node:async_hooks";
5395
-
5396
- import type { FetchApp, NodeApp } from "@kosmojs/core";
5397
-
5398
- export type RequestContext = {
5399
- headers?: HeadersInit;
5400
- tsqClient?: unknown;
5401
- error?: unknown;
5402
- };
5403
-
5404
- export const redirectCodes = [
5405
- // Moved Permanently
5406
- 301,
5407
- // Found (temporary)
5408
- 302,
5409
- // See Other (redirect after POST)
5410
- 303,
5411
- // Temporary Redirect (preserves method)
5412
- 307,
5413
- // Permanent Redirect (preserves method)
5414
- 308,
5415
- ];
5416
-
5417
- /**
5418
- * Origin used to absolutize the relative URLs the client produces.
5419
- * Never resolved over the network; the host part is irrelevant to
5420
- * route matching in both Hono and Koa.
5421
- * */
5422
- export const ssrOrigin = "http://ssr.local";
5423
-
5424
- /**
5425
- * Maximum redirect hops, mirroring the fetch spec limit.
5426
- * */
5427
- export const maxRedirects = 5;
5428
-
5429
- /**
5430
- * Request-scoped context store.
5431
- * Server-only module - never reaches browser bundles.
5432
- * */
5433
- export const store = new AsyncLocalStorage<RequestContext>();
5434
-
5435
- export const isFetchApp = (app: FetchApp | NodeApp): app is FetchApp => {
5436
- return typeof (app as FetchApp).fetch === "function";
5437
- };
5438
- `,er=`import { type RequestContext, store } from "./base";
5439
-
5440
- import { renderWrapper } from "{{ createImport 'libEntry' 'server' }}";
5441
-
5442
- export { default as ssrApp } from "{{ createImport 'entry' 'server' }}";
5443
- export { apiApp } from "{{ createImport 'lib' '@ssr/api' }}";
5444
-
5445
- /**
5446
- * Wraps a render call, making the given context visible to every
5447
- * fetch dispatch that happens during it - across await points,
5448
- * stream chunks and parallel component data loads.
5449
- * */
5450
- export const withSsrContext = <T>(
5451
- context: RequestContext,
5452
- render: () => T,
5453
- ): T => {
5454
- return store.run(context, () => renderWrapper(context, render));
5455
- };
5456
-
5457
- export const errorProvider = () => {
5458
- return store.getStore()?.error;
5459
- };
5460
- `,tr=`import type { FetchApp, NodeApp } from "@kosmojs/core";
5461
- import type { Transport } from "@kosmojs/core/fetch";
5462
-
5463
- import {
5464
- isFetchApp,
5465
- maxRedirects,
5466
- redirectCodes,
5467
- ssrOrigin,
5468
- store,
5469
- } from "./base";
5470
-
5471
- import { apiApp } from "{{ createImport 'lib' '@ssr/api' }}";
5472
-
5473
- /**
5474
- * HeadersProvider for createTransport.
5475
- * */
5476
- const headersProvider = (): HeadersInit | undefined => {
5477
- return store.getStore()?.headers;
5478
- };
5479
-
5480
- const createDispatch = (app: FetchApp | NodeApp) => {
5481
- return isFetchApp(app)
5482
- ? app.fetch
5483
- : async (request: Request): Promise<Response> => {
5484
- const { inject } = await import("light-my-request");
5485
-
5486
- /**
5487
- * Node dispatch: serializes the web Request into light-my-request's
5488
- * injection format and lifts the injected response back into a web Response.
5489
- * */
5490
- const url = new URL(request.url);
5491
-
5492
- const payload = ["GET", "HEAD"].includes(request.method)
5493
- ? undefined
5494
- : Buffer.from(await request.arrayBuffer());
5495
-
5496
- const result = await inject(app.callback() as never, {
5497
- method: request.method as never,
5498
- url: url.pathname + url.search,
5499
- headers: Object.fromEntries(request.headers),
5500
- ...(payload?.length ? { payload } : {}),
5501
- });
5502
-
5503
- const headers = new Headers();
5504
-
5505
- for (const [key, value] of Object.entries(result.headers)) {
5506
- for (const entry of Array.isArray(value) ? value : [value]) {
5507
- if (entry !== undefined) {
5508
- headers.append(key, String(entry));
5509
- }
5510
- }
5511
- }
5512
-
5513
- /**
5514
- * 204/304 responses must not carry a body per the Response
5515
- * constructor contract.
5516
- * */
5517
- const body = [204, 304].includes(result.statusCode)
5518
- ? null
5519
- : new Uint8Array(result.rawPayload);
5520
-
5521
- return new Response(body, {
5522
- status: result.statusCode,
5523
- statusText: result.statusMessage,
5524
- headers,
5525
- });
5526
- };
5527
- };
5528
-
5529
- const createTransport = (app: FetchApp | NodeApp): Transport => {
5530
- const dispatch = createDispatch(app);
5531
-
5532
- /**
5533
- * Build a fetch-compatible transport that dispatches requests
5534
- * directly into the given app - no sockets, no interception.
5535
- * Redirects are followed in-process, including the 303 and 301/302 method rewrite to GET.
5536
- * */
5537
- return async (input, init) => {
5538
- /**
5539
- * Request-scoped headers act as defaults: anything set explicitly
5540
- * on the call itself wins over forwarded values.
5541
- * */
5542
- const headers = new Headers(init?.headers);
5543
-
5544
- // When the body is FormData, the Request constructor sets a multipart
5545
- // Content-Type with a fresh boundary. A forwarded Content-Type default would
5546
- // override that boundary and desync it from the serialized body, so never
5547
- // forward Content-Type for FormData bodies.
5548
- const isFormBody = init?.body instanceof FormData;
5549
-
5550
- for (const [key, value] of new Headers(headersProvider() || undefined)) {
5551
- if (isFormBody && key.toLowerCase() === "content-type") {
5552
- continue;
5553
- }
5554
- if (!headers.has(key)) {
5555
- headers.set(key, value);
5556
- }
5557
- }
5558
-
5559
- let request = new Request(new URL(String(input), ssrOrigin), {
5560
- ...init,
5561
- headers,
5562
- });
6196
+ export default routerFactory((routes) => {
6197
+ const { clientRouter, serverRouter } = createRouters(routes, { app });
6198
+ return {
6199
+ clientRouter() {
6200
+ return clientRouter()
6201
+ },
6202
+ serverRouter(url) {
6203
+ return serverRouter(url)
6204
+ },
6205
+ };
6206
+ });
6207
+ `,vr=v((e,t)=>{let{generators:n=[]}=e.config,{createPath:r,createImportHelpers:i}=S(e),{render:a,renderToFile:o}=w({helpers:{...i({origin:`lib`}),...A()},partials:{routePartial:Xn}}),{renderToFile:s}=w({helpers:i({origin:`src`})}),c=Gn(),d=e=>!e?.trim().length,f=l(t?.templates,hr),p=async e=>{for(let{kind:t,entry:n}of e)t===`pageRoute`?await s(r.pages(n.file),n.name===`index`?gr:f(n.name,n),{route:n,message:Kn()},{overwrite:d}):t===`pageLayout`&&await s(r.pages(n.file),mr,{route:n},{overwrite:d})},m=async e=>{let t=e.flatMap(({kind:e,entry:t})=>e===`pageRoute`?[t]:[]).sort(E),n=e.flatMap(({kind:e,entry:t})=>e===`pageRoute`||e===`pageLayout`?[t]:[]),i=c(b(n));for(let[e,t]of[[`client.ts`,Yn],[`server.ts`,Zn]])await o(r.libEntry(e),t,{pageEntries:n,nestedRoutes:i});await o(r.lib(`router.tsx`),or,{entries:e,indexRoutes:t})};return{config({command:e}){let{templates:r,...i}={...t};return{oxc:{jsx:{importSource:`solid-js`}},plugins:e===`build`?[N({...i,...n.some(e=>e.meta.slot===`ssr`)?{ssr:!0,solid:{...i?.solid,hydratable:!0}}:{}})]:[N({...i,dev:!0,hot:!0})]}},async start(){for(let[e,n]of[[`env.d.ts`,Qn],[`solid.ts`,sr],[`unwrap.ts`,cr],[`pageSamples/styles.module.css`,tr],[`pageSamples/welcome.tsx`,nr],[`pageSamples/page.tsx`,er],[`pageSamples/404.tsx`,$n],...t?.tanstack?.query?[[`app.tsx`,Jn],[`query.ts`,rr]]:[[`app.tsx`,qn],[`query.ts`,`/** tanstack query disabled */`]]])await o(r.lib(e),n,{});for(let[e,t]of[[`pages/404.tsx`,pr],[`components/Link.tsx`,ur],[`app.tsx`,lr],[`router.ts`,_r]])await s(r.src(e),t,{entryDir:u.entryDir},{overwrite:d});for(let[e,t]of[[`client.ts`,dr],[`server.ts`,fr]])await s(r.entry(e),t,{},{overwrite:d})},async watch(e,t){await p(e.filter(g(t,[`create`]))),await m(e)},async build(e){await p(e),await m(e)},virtualModules(){return t?.tanstack?.query?[{specifier:`virtual:kosmo/tsq-client`,csr:a(ir,{}),ssr:a(ar,{})}]:[]}}}),yr=_({meta:{name:`SolidJS`,slot:`frontend`,jsx:`preserve`,jsxImportSource:`solid-js`},dependencies(e){return{"solid-js":G.devDependencies[`solid-js`],"@solidjs/router":G.devDependencies[`@solidjs/router`],...e?.tanstack?.query?{"@tanstack/solid-query":G.devDependencies[`@tanstack/solid-query`]}:{}}},factory:vr}),br=`import { join } from "node:path";
5563
6208
 
5564
- /**
5565
- * Bodies are buffered once so they can be replayed across
5566
- * 307/308 hops; the client only ever sends strings, FormData
5567
- * and buffer-ish payloads, so this is safe and cheap.
5568
- * */
5569
- const body = ["GET", "HEAD"].includes(request.method)
5570
- ? undefined
5571
- : await request.arrayBuffer();
6209
+ import { compile } from "path-to-regexp";
5572
6210
 
5573
- for (let hop = 0; ; hop++) {
5574
- if (hop === maxRedirects) {
5575
- throw new TypeError("Failed to fetch: too many redirects");
5576
- }
6211
+ import type { PageRoute } from "@kosmojs/core";
5577
6212
 
5578
- const response = await dispatch(
5579
- body === undefined || request.method === "GET"
5580
- ? new Request(request, { body: null })
5581
- : new Request(request, { body }),
5582
- );
6213
+ import routes from "{{ createImport 'lib' 'ssg:routes' }}";
6214
+ import { base } from "{{ createImport 'libCore' }}";
5583
6215
 
5584
- const location = response.headers.get("location");
6216
+ type StaticParams = Array<Array<string | number | Array<string | number>>>;
5585
6217
 
5586
- if (!location || !redirectCodes.includes(response.status)) {
5587
- return response;
6218
+ /**
6219
+ * Where a page declares the parameter sets to pre-render:
6220
+ * - a \`staticParams\` named export - React/Solid page modules,
6221
+ * a plain \`<script>\` block in Vue, a \`<script module>\` block in Svelte
6222
+ * - \`staticParams\` in MDX frontmatter
6223
+ * Each entry is positional, in the route's parameter order.
6224
+ * */
6225
+ const staticParamsOf = (module: unknown): StaticParams | undefined => {
6226
+ const { staticParams, frontmatter } = (module ?? {}) as {
6227
+ staticParams?: unknown;
6228
+ frontmatter?: { staticParams?: unknown };
6229
+ };
6230
+ const value = staticParams ?? frontmatter?.staticParams;
6231
+ return Array.isArray(value) ? (value as StaticParams) : undefined;
6232
+ };
6233
+
6234
+ const paramsMapper = (
6235
+ params: PageRoute["params"],
6236
+ value: StaticParams[number],
6237
+ ) => {
6238
+ return params.schema.reduce<Record<string, unknown>>(
6239
+ (map, { name, kind }, i) => {
6240
+ if (kind === "splat") {
6241
+ if (Array.isArray(value[i]) && value[i].length) {
6242
+ map[name] = value[i].map(String);
6243
+ }
6244
+ } else if (value[i] !== undefined) {
6245
+ map[name] = String(value[i]);
5588
6246
  }
6247
+ return map;
6248
+ },
6249
+ {},
6250
+ );
6251
+ };
5589
6252
 
5590
- const method =
5591
- response.status === 303 ||
5592
- ([301, 302].includes(response.status) && request.method === "POST")
5593
- ? "GET"
5594
- : request.method;
6253
+ export default Object.entries(routes)
6254
+ .flatMap(([name, { module, pathPattern, params }]) => {
6255
+ if (!params.schema.length) {
6256
+ // static route
6257
+ return [pathPattern.replace(/^index\\/?/, "")];
6258
+ }
5595
6259
 
5596
- request = new Request(new URL(location, request.url), {
5597
- method,
5598
- headers: request.headers,
5599
- });
6260
+ const staticParams = staticParamsOf(module);
6261
+
6262
+ // a dynamic route without staticParams has nothing to pre-render
6263
+ if (!staticParams) {
6264
+ return [];
5600
6265
  }
5601
- };
5602
- };
5603
6266
 
5604
- const ssrTransport = apiApp ? createTransport(apiApp as never) : undefined;
6267
+ const toPath = compile(pathPattern);
5605
6268
 
5606
- export const transport = ssrTransport
5607
- ? async (input: RequestInfo | URL, init?: RequestInit) => {
6269
+ return staticParams.flatMap((entry) => {
5608
6270
  try {
5609
- const response = await ssrTransport(input, init);
5610
- if (response?.ok) {
5611
- return response;
5612
- }
5613
- // the rethrow here needed cause ssrTransport does not throw on non-2xx responses
5614
- throw new SSRFetchError([
5615
- input,
5616
- response,
5617
- typeof response?.text === "function"
5618
- ? await response.text()
5619
- : response?.statusText,
5620
- ]);
6271
+ return [toPath(paramsMapper(params, entry) as never)];
5621
6272
  } catch (error) {
5622
- /**
5623
- * Capture the fetch error at the transport level and stash it on the request store.
5624
- * Some frameworks - Solid notably - swallow a rejecting loader and still emit a partial render tree.
5625
- * Storing the error here keeps it observable regardless of how the framework handles the loader rejection.
5626
- * */
5627
- const storage = store.getStore();
5628
- if (storage) {
5629
- storage.error = error;
5630
- }
5631
- throw error;
6273
+ console.error(\`❗SSG: Failed building path for \${name}\`);
6274
+ console.error(error);
6275
+ return [];
5632
6276
  }
5633
- }
5634
- : undefined; // let fetch clients pick the transport
6277
+ });
6278
+ })
6279
+ .map((path) => join(base, path));
6280
+ `,xr=`import type { PageRoute } from "@kosmojs/core";
5635
6281
 
5636
- class SSRFetchError extends Error {
5637
- constructor([input, response, message]: [
5638
- input: RequestInfo | URL,
5639
- response: Response,
5640
- message: string | undefined,
5641
- ]) {
5642
- const pathname = pathnameOf(input);
5643
- const status = response.status ?? "unknown";
5644
- super(\`\${pathname}: \${status} [ \${message} ]\`.trim());
5645
- this.name = "SSRFetchError";
5646
- }
5647
- }
6282
+ {{#each pageRoutes}}
6283
+ import * as {{id}} from "{{ createImport 'pages' file }}";
6284
+ {{/each}}
5648
6285
 
5649
- const pathnameOf = (input: RequestInfo | URL): string => {
5650
- try {
5651
- if (typeof input === "string") {
5652
- return new URL(input, "http://x").pathname;
5653
- }
5654
- if (input instanceof URL) {
5655
- return input.pathname;
5656
- }
5657
- if (input instanceof Request) {
5658
- return new URL(input.url).pathname;
5659
- }
5660
- } catch {}
5661
- return String(input);
6286
+ type SSGRoute = {
6287
+ // the page module as imported; the shape differs per framework
6288
+ module: unknown;
6289
+ pathPattern: string;
6290
+ params: PageRoute["params"];
6291
+ };
6292
+
6293
+ const routeMap: Record<string, SSGRoute> = {
6294
+ {{#each pageRoutes}}
6295
+ "{{name}}": {
6296
+ module: {{id}},
6297
+ pathPattern: "{{pathPattern}}",
6298
+ params: {{serializeParams .}},
6299
+ },
6300
+ {{/each}}
6301
+ };
6302
+
6303
+ export default routeMap;
6304
+ `,Sr=v(a=>{let{generators:o=[],refineTypeName:s,...c}={...a.config},{base:l}=c,{createPath:u,createImportHelpers:f}=S(a),{renderToFile:p}=w({helpers:{...f({origin:`lib`}),...A(),serializeParams(e){return JSON.stringify(e.params)}}}),m=async e=>{let t=e.flatMap(({kind:e,entry:t})=>e===`pageRoute`?[t]:[]).sort(E);await p(u.lib(`ssg:routes.ts`),xr,{pageRoutes:t})};return{async start(){await p(u.lib(`ssg.ts`),br,{})},async watch(e){await m(e)},async build(e){await m(e)},async postBuild(){let s=u.distDir(`ssg`),f=r(s,`../ssr/server.js`);if(!await ce(f,le.F_OK).then(()=>!0,()=>!1)){console.error(),console.error(i(`red`,`❗Please enable ssrGenerator in ${a.name}/kosmo.config.ts`)),console.error(` SSG generator can not run without SSR server`),console.error();return}let p=ee(`${a.name}: SSG`);p.append(`preparing...`);let{createApp:m}=await import(f);p.append(`bundling routes...`),await M(y(c,...o.map(({factory:e})=>e(a).config?.({kind:`client`,command:`build`})),{root:u.lib(),appType:`custom`,plugins:[O.tsconfigPaths(a),O.nodePrefix(),O.virtualModules(d(a,o),{kind:`csr`,command:`build`})],resolve:{conditions:[`node`]},build:{ssr:u.lib(`ssg.ts`),target:`esnext`,sourcemap:!1,emptyOutDir:!0,rolldownOptions:{output:{dir:s,entryFileNames:`routes.js`,format:`esm`}}}}));try{let i=await import(t(s,`routes.js`)).then(e=>e.default),a=new Map,o=await m(e=>{a.set(new URL(e.url).pathname,{error:e.message})});for(let[e,t]of i.entries()){p.append(`[ ${e+1} of ${i.length} ] ${t}`);try{let e=await Cr(o,t);a.has(t)||a.set(t,{html:e})}catch(e){a.has(t)||a.set(t,{error:String(e)})}}let c=[...a.entries()].flatMap(([e,t])=>`error`in t?[[e,t.error]]:[]);if(c.length)throw p.failed(`failed ❗`),Error([`SSG: failed rendering ${c.length} route(s):`,...c.map(([e,t])=>` ${e} - ${t}`)].join(`
6305
+ `));await P(r(s,`../ssr/assets`),t(s,`assets`),{recursive:!0});let u=r(s,`../ssr/public`);await x(u)&&await P(u,s,{recursive:!0});for(let[r,i]of a)if(`html`in i){let a=t(s,n.relative(l,r),`index.html`);await ue(e(a),{recursive:!0}),await de(a,i.html,`utf8`)}p.succeed(`done ✨`)}finally{await F(`${s}/routes.js`)}}}}),Cr=async(e,t)=>{let n=await e.fetch(new Request(`http://localhost${t}`));if(!n.ok)throw Error(`app responded with ${n.status}`);return n.text()},wr=_({meta:{name:`SSG`,slot:`ssg`},factory:Sr}),q={type:`module`,private:!0,name:`@kosmojs/ssr-generator`,version:`0.3.0`,author:`Slee Woo`,license:`MIT`,files:[`pkg/*`],exports:{".":{types:`./pkg/index.d.ts`,default:`./pkg/index.js`}},scripts:{build:`wsbuild src/index.ts`},dependencies:{"@kosmojs/core":`workspace:^`,"@kosmojs/lib":`workspace:^`,vite:`^8.2.2`},devDependencies:{"@hono/node-server":`^2.1.1`,hono:`^4.13.3`,tinyglobby:`^0.2.17`}},Tr=`import { type RequestContext, store } from "{{ createImport 'libCore' 'ssr' }}";
6306
+ import { renderWrapper } from "{{ createImport 'libEntry' 'server' }}";
6307
+
6308
+ export { default as backendApp } from "virtual:kosmo/backend-app";
6309
+
6310
+ export { default as ssrApp } from "{{ createImport 'entry' 'server' }}";
6311
+
6312
+ /**
6313
+ * Wrap a render call, making the given context visible to every component
6314
+ * */
6315
+ export const withSsrContext = <T>(
6316
+ context: RequestContext,
6317
+ render: () => T,
6318
+ ): T => {
6319
+ return store.run(context, () => renderWrapper(context, render));
6320
+ };
6321
+
6322
+ export const errorProvider = () => {
6323
+ return store.getStore()?.error;
5662
6324
  };
5663
- `,nr=`export const routeMap = [
6325
+ `,Er=`export const routeMap = [
5664
6326
  {{#each pageRoutes}}
5665
6327
  { pathPattern: "{{honoPattern}}", renderMode: "{{renderMode}}" },
5666
6328
  {{/each}}
5667
6329
  ];
5668
- `,rr=`import { access, chmod, constants, readFile, unlink } from "node:fs/promises";
6330
+ `,Dr=`import { access, chmod, constants, readFile, unlink } from "node:fs/promises";
5669
6331
  import {
5670
6332
  createServer,
5671
6333
  type IncomingMessage,
@@ -5675,18 +6337,22 @@ import { extname, join, resolve } from "node:path";
5675
6337
  import { fileURLToPath } from "node:url";
5676
6338
  import { parseArgs, styleText } from "node:util";
5677
6339
 
5678
- import { createAdaptorServer, getRequestListener } from "@hono/node-server";
6340
+ import { getRequestListener } from "@hono/node-server";
5679
6341
  import { type Context, Hono } from "hono";
5680
6342
  import { HTTPException } from "hono/http-exception";
5681
6343
  import { stream } from "hono/streaming";
5682
6344
  import { glob } from "tinyglobby";
5683
6345
 
5684
- import type { FetchApp, NodeApp, SSRSetup } from "@kosmojs/core";
5685
-
5686
- import { isFetchApp, redirectCodes, ssrOrigin } from "./@ssr/base";
6346
+ import {
6347
+ type FetchApp,
6348
+ MIME_TYPES,
6349
+ type NodeApp,
6350
+ type SSRSetup,
6351
+ } from "@kosmojs/core";
5687
6352
 
5688
6353
  import { routeMap } from "{{ createImport 'lib' '@ssr/routes' }}";
5689
6354
  import { apiBase, base } from "{{ createImport 'libCore' }}";
6355
+ import { redirectCodes, ssrOrigin } from "{{ createImport 'libCore' 'ssr' }}";
5690
6356
 
5691
6357
  const ROOT = import.meta.dirname;
5692
6358
  const HEAD_CLOSE_PATTERN = /<\\/head\\s*>/i;
@@ -5699,9 +6365,13 @@ type AssetInfo = {
5699
6365
  contentType: string;
5700
6366
  // Cached size to set Content-Length without re-measuring the buffer.
5701
6367
  size: number;
6368
+ // Cache-Control header - hashed assets are immutable, public/ files are not.
6369
+ cacheControl: string;
5702
6370
  };
5703
6371
 
5704
- export const createApp = async () => {
6372
+ export const createApp = async (
6373
+ errorHandler?: (error: Error & { url: string }) => void | undefined,
6374
+ ) => {
5705
6375
  // Import the SSR entry produced by Vite's ssr build.
5706
6376
  const {
5707
6377
  ssrApp,
@@ -5724,7 +6394,7 @@ export const createApp = async () => {
5724
6394
  with: { type: "json" },
5725
6395
  }).then((e) => e.default);
5726
6396
 
5727
- const { renderToString, renderToStream } = ssrApp;
6397
+ const { renderToString, renderToStream, onError } = ssrApp;
5728
6398
 
5729
6399
  const [htmlStart, htmlEnd = ""] = template.split(/<!--\\s*app-html\\s*-->/);
5730
6400
 
@@ -5772,6 +6442,18 @@ export const createApp = async () => {
5772
6442
  };
5773
6443
  };
5774
6444
 
6445
+ const handleError = (url: string, error: Error, fallback: Function) => {
6446
+ // assign, not spread: message and stack are non-enumerable on Error,
6447
+ // a spread silently drops them
6448
+ Object.assign(error, { url });
6449
+ if (onError) {
6450
+ onError(error as never);
6451
+ } else {
6452
+ fallback();
6453
+ }
6454
+ errorHandler?.(error as never);
6455
+ };
6456
+
5775
6457
  const injectHead = (html: string, head: string) => {
5776
6458
  const error = "WARN: missing </head> - required for SSR head injection";
5777
6459
  if (HEAD_CLOSE_PATTERN.test(html)) {
@@ -5814,9 +6496,11 @@ export const createApp = async () => {
5814
6496
 
5815
6497
  if (error) {
5816
6498
  const errorMessage = "WARN: SSR failed, fallback to CSR";
5817
- console.error(errorMessage);
5818
- console.error(error);
5819
- console.error();
6499
+ handleError(ctx.req.url, error as never, () => {
6500
+ console.error(errorMessage);
6501
+ console.error(error);
6502
+ console.error();
6503
+ });
5820
6504
  return [
5821
6505
  injectHead(
5822
6506
  htmlStart,
@@ -5831,6 +6515,31 @@ export const createApp = async () => {
5831
6515
 
5832
6516
  const app = new Hono({ strict: false });
5833
6517
 
6518
+ // Static files win over routes, as they do in vite dev and behind a reverse proxy.
6519
+ // This covers hashed assets/ (JS, CSS, images, fonts, .map siblings) and public/ files.
6520
+ app.use(async (ctx, next) => {
6521
+ if (!["GET", "HEAD"].includes(ctx.req.method)) {
6522
+ return next();
6523
+ }
6524
+
6525
+ const asset = assets.get(ctx.req.path);
6526
+
6527
+ if (!asset) {
6528
+ return next();
6529
+ }
6530
+
6531
+ return new Response(
6532
+ ctx.req.method === "HEAD" ? null : (asset.buffer as never),
6533
+ {
6534
+ headers: {
6535
+ "Content-Type": asset.contentType,
6536
+ "Content-Length": String(asset.size),
6537
+ "Cache-Control": asset.cacheControl,
6538
+ },
6539
+ },
6540
+ );
6541
+ });
6542
+
5834
6543
  for (const { pathPattern, renderMode } of routeMap) {
5835
6544
  app.get(join(base, pathPattern), async (ctx) => {
5836
6545
  try {
@@ -5844,16 +6553,37 @@ export const createApp = async () => {
5844
6553
  if (renderMode === "stream" && typeof renderToStream === "function") {
5845
6554
  ctx.header("Content-Type", "text/html");
5846
6555
  return stream(ctx, async (stream) => {
5847
- const { head = "", html } = await withSsrContext(
5848
- {
5849
- headers: Object.fromEntries(ctx.req.raw.headers),
5850
- url: ctx.req.url,
5851
- },
5852
- () => renderToStream(url, ssrOptions(), stream as never),
5853
- );
5854
- await stream.write(injectHead(htmlStart, head));
5855
- await stream.pipe(html);
5856
- await stream.write(htmlEnd);
6556
+ let error: Error | undefined;
6557
+
6558
+ /**
6559
+ * Stream failures surface here, not in a catch upstream:
6560
+ * on solid and vue pipe rejects; react shell errors reject the render promise itself.
6561
+ * The shell may already be on the wire -
6562
+ * reporting is all that is left to do, the response cannot be replaced.
6563
+ * */
6564
+ try {
6565
+ const { head = "", html } = await withSsrContext(
6566
+ {
6567
+ headers: Object.fromEntries(ctx.req.raw.headers),
6568
+ url: ctx.req.url,
6569
+ },
6570
+ () => renderToStream(url, ssrOptions(), stream as never),
6571
+ );
6572
+ await stream.write(injectHead(htmlStart, head));
6573
+ await stream.pipe(html);
6574
+ error = errorProvider();
6575
+ await stream.write(htmlEnd);
6576
+ } catch (e: any) {
6577
+ error = e;
6578
+ }
6579
+
6580
+ if (error) {
6581
+ handleError(ctx.req.url, error, () => {
6582
+ console.error("ERROR: SSR stream render failed");
6583
+ console.error(error);
6584
+ console.error();
6585
+ });
6586
+ }
5857
6587
  });
5858
6588
  }
5859
6589
 
@@ -5878,21 +6608,6 @@ export const createApp = async () => {
5878
6608
  }
5879
6609
 
5880
6610
  app.get("/*", async (ctx) => {
5881
- const { path } = ctx.req;
5882
-
5883
- // If incoming request path matches something cached at startup, serve it directly.
5884
- // This covers JS, CSS, images, fonts, etc., including their .map siblings.
5885
- const asset = assets.get(path);
5886
-
5887
- if (asset) {
5888
- return new Response(asset.buffer as never, {
5889
- headers: {
5890
- "Content-Type": asset.contentType,
5891
- "Content-Length": String(asset.size),
5892
- },
5893
- });
5894
- }
5895
-
5896
6611
  // render 404 page
5897
6612
  if (typeof renderToString === "function") {
5898
6613
  const url = new URL(ctx.req.url);
@@ -5911,47 +6626,47 @@ export const createApp = async () => {
5911
6626
  * Build an in-memory asset graph, loading asset content into memory.
5912
6627
  * The asset graph always includes every built asset URL so the SSR server
5913
6628
  * can correctly recognize static asset requests.
6629
+ *
6630
+ * Two roots, each directory being its own allowlist - nothing else in the bundle root is served:
6631
+ * - assets/ - emitted by vite with content hashes, served at base/assets/, cacheable forever
6632
+ * - public/ - copied verbatim from the folder's public dir, served at base/, names are stable so clients must revalidate
5914
6633
  * */
5915
- const loadAssets = async (
5916
- root: string,
5917
- patterns: string | Array<string> = "**",
5918
- ) => {
5919
- const mimeTypeMap: Record<string, string> = {
5920
- ".js": "application/javascript",
5921
- ".mjs": "application/javascript",
5922
- ".css": "text/css",
5923
- ".json": "application/json",
5924
- ".png": "image/png",
5925
- ".apng": "image/png",
5926
- ".jpg": "image/jpeg",
5927
- ".jpeg": "image/jpeg",
5928
- ".gif": "image/gif",
5929
- ".svg": "image/svg+xml",
5930
- ".ico": "image/x-icon",
5931
- ".woff": "font/woff",
5932
- ".woff2": "font/woff2",
5933
- ".ttf": "font/ttf",
5934
- ".webp": "image/webp",
5935
- };
5936
-
6634
+ const loadAssets = async (root: string) => {
5937
6635
  // Resolve HTTP Content-Type from the asset's file extension.
5938
6636
  const contentTypeResolver = (filePath: string) => {
5939
6637
  const ext = extname(filePath).toLowerCase();
5940
- return mimeTypeMap[ext] || "application/octet-stream";
6638
+ return MIME_TYPES[ext] || "application/octet-stream";
5941
6639
  };
5942
6640
 
5943
6641
  // Map from URL path (as used in requests) to asset metadata.
5944
6642
  const assetCache = new Map<string, AssetInfo>();
5945
6643
 
5946
- const folder = "assets";
5947
- const cwd = resolve(root, folder);
6644
+ const roots = [
6645
+ {
6646
+ folder: "assets",
6647
+ prefix: join(base, "assets"),
6648
+ cacheControl: "public, max-age=31536000, immutable",
6649
+ },
6650
+ {
6651
+ folder: "public",
6652
+ prefix: base,
6653
+ cacheControl: "no-cache",
6654
+ },
6655
+ ];
6656
+
6657
+ for (const { folder, prefix, cacheControl } of roots) {
6658
+ const cwd = resolve(root, folder);
6659
+
6660
+ const readable = await access(cwd, constants.F_OK).then(
6661
+ () => true,
6662
+ () => false,
6663
+ );
5948
6664
 
5949
- if (
5950
- await access(cwd, constants.R_OK)
5951
- .then(() => true)
5952
- .catch(() => false)
5953
- ) {
5954
- const files = await glob(patterns, {
6665
+ if (!readable) {
6666
+ continue;
6667
+ }
6668
+
6669
+ const files = await glob("**", {
5955
6670
  cwd,
5956
6671
  onlyFiles: true,
5957
6672
  absolute: false,
@@ -5959,11 +6674,12 @@ const loadAssets = async (
5959
6674
 
5960
6675
  for (const file of files) {
5961
6676
  const buffer = new Uint8Array(await readFile(resolve(cwd, file)));
5962
- assetCache.set(join(base, folder, file), {
6677
+ assetCache.set(join(prefix, file), {
5963
6678
  file,
5964
6679
  buffer,
5965
6680
  contentType: contentTypeResolver(file),
5966
- size: buffer?.length,
6681
+ size: buffer.length,
6682
+ cacheControl,
5967
6683
  });
5968
6684
  }
5969
6685
  }
@@ -5974,11 +6690,40 @@ const loadAssets = async (
5974
6690
  type NodeListener = (req: IncomingMessage, res: ServerResponse) => void;
5975
6691
 
5976
6692
  const createNodeListener = (app: FetchApp | NodeApp): NodeListener => {
5977
- return isFetchApp(app)
6693
+ return typeof (app as FetchApp).fetch === "function"
5978
6694
  ? getRequestListener((app as FetchApp).fetch)
5979
6695
  : (app as NodeApp).callback();
5980
6696
  };
5981
6697
 
6698
+ /**
6699
+ * The folder's complete request surface as a single node:http listener:
6700
+ * API requests under \`apiBase\` go to the bundled backend, everything else to the SSR app.
6701
+ * \`startServer\` binds it to a port/socket; \`dist/run.js\` mounts it next to other folders.
6702
+ * */
6703
+ export const createListener = async (): Promise<NodeListener> => {
6704
+ const {
6705
+ backendApp,
6706
+ }: {
6707
+ backendApp: FetchApp | NodeApp;
6708
+ } = await import(\`\${ROOT}/app.js\`);
6709
+
6710
+ const ssrApp = await createApp();
6711
+ const apiPrefix = join(base, apiBase);
6712
+
6713
+ const ssrListener = createNodeListener(ssrApp as never);
6714
+
6715
+ const apiListener = backendApp
6716
+ ? createNodeListener(backendApp as never)
6717
+ : async () => {};
6718
+
6719
+ return (req, res) => {
6720
+ const { pathname } = new URL(req.url ?? "/", ssrOrigin);
6721
+ return pathname === apiPrefix || pathname.startsWith(\`\${apiPrefix}/\`)
6722
+ ? apiListener(req, res)
6723
+ : ssrListener(req, res);
6724
+ };
6725
+ };
6726
+
5982
6727
  export const startServer = async ({
5983
6728
  sock,
5984
6729
  port,
@@ -5990,12 +6735,6 @@ export const startServer = async ({
5990
6735
  throw new Error("Please provide either -p/--port or -s/--sock");
5991
6736
  }
5992
6737
 
5993
- const {
5994
- apiApp,
5995
- }: {
5996
- apiApp: FetchApp | NodeApp;
5997
- } = await import(\`\${ROOT}/app.js\`);
5998
-
5999
6738
  if (sock) {
6000
6739
  // Clean up any stale socket file before binding.
6001
6740
  await unlink(sock).catch((error) => {
@@ -6012,23 +6751,7 @@ export const startServer = async ({
6012
6751
  sock ? \`sock: \${sock}\` : \`port: \${port}\`,
6013
6752
  );
6014
6753
 
6015
- const ssrApp = await createApp();
6016
- const apiPrefix = join(base, apiBase);
6017
-
6018
- const ssrListener = createNodeListener(ssrApp as never);
6019
-
6020
- const apiListener = apiApp
6021
- ? createNodeListener(apiApp as never)
6022
- : async () => {};
6023
-
6024
- const gatewayListener: NodeListener = (req, res) => {
6025
- const { pathname } = new URL(req.url ?? "/", ssrOrigin);
6026
- return pathname === apiPrefix || pathname.startsWith(\`\${apiPrefix}/\`)
6027
- ? apiListener(req, res)
6028
- : ssrListener(req, res);
6029
- };
6030
-
6031
- const server = createServer(gatewayListener);
6754
+ const server = createServer(await createListener());
6032
6755
 
6033
6756
  server.listen(sock || port, async () => {
6034
6757
  if (sock) {
@@ -6042,24 +6765,6 @@ export const startServer = async ({
6042
6765
  return server;
6043
6766
  };
6044
6767
 
6045
- export const createDisposableServer = async (
6046
- callback: (port: number) => Promise<void>,
6047
- ) => {
6048
- const app = await createApp();
6049
- const server = createAdaptorServer(app).listen(0); // OS picks a free port
6050
- const address = server.address();
6051
-
6052
- if (!address || typeof address === "string") {
6053
- throw new Error("SSR: Failed starting disposable server on a free port");
6054
- }
6055
-
6056
- try {
6057
- await callback(address.port);
6058
- } finally {
6059
- server.close();
6060
- }
6061
- };
6062
-
6063
6768
  const isMain = fileURLToPath(import.meta.url) === resolve(process.argv[1]);
6064
6769
 
6065
6770
  if (isMain) {
@@ -6090,14 +6795,14 @@ if (isMain) {
6090
6795
  process.exit(1);
6091
6796
  }
6092
6797
  }
6093
- `,ir=`string`,ar=g((e,r)=>{let{generators:i=[],refineTypeName:a,...o}=e.config,{createPath:c,createImportHelpers:l}=y(e),{renderToFile:u}=x({helpers:{...l({origin:`lib`})}});return{async build(e){let t=r?.renderMode?typeof r.renderMode==`string`?()=>r.renderMode:s(r?.renderMode,`string`):()=>ir,n={renderMode:JSON.stringify(r?.renderMode||null),pageRoutes:e.flatMap(e=>e.kind===`pageRoute`?[{...e.entry,renderMode:t(e.entry.name)}]:[]).sort(S),apiGenerator:i.some(e=>e.meta.slot===`backend`)};for(let[e,t]of[[`ssr.ts`,rr],[`@ssr/api.ts`,Qn],[`@ssr/__kosmo_ssr_bundle.ts`,er],[`@ssr/base.ts`,$n],[`@ssr/fetch.ts`,tr],[`@ssr/routes.ts`,nr]])await u(c.lib(e),t,n)},async postBuild(){if(!i.some(e=>e.meta.slot===`frontend`))return;let r=c.distDir(`ssr`),a=[C.tsconfigPaths(e),C.nodePrefix()];for(let t of i)await t.factory(e).ssrBuild?.();await E(_(o,...i.map(({factory:t})=>t(e).config?.({kind:`client`,command:`build`})),{root:c.src(),plugins:a,define:{KOSMO_PRODUCTION_BUILD:`true`},build:{ssr:c.lib(`@ssr/__kosmo_ssr_bundle`),ssrEmitAssets:!0,sourcemap:!0,emptyOutDir:!0,minify:!1,rolldownOptions:{output:{dir:r,entryFileNames:`app.js`,format:`esm`}}}})),await E({root:c.lib(),configFile:!1,appType:`custom`,plugins:a,resolve:{conditions:[`node`]},build:{ssr:c.lib(`ssr.ts`),target:`esnext`,sourcemap:!0,emptyOutDir:!0,rolldownOptions:{output:{dir:t(r,`server`),entryFileNames:`server.js`,format:`esm`}}}}),await O(n(r,`../client`),r,{recursive:!0});for(let e of[`server.js`,`server.js.map`])await O(`${r}/server/${e}`,`${r}/${e}`);await k(`${r}/server`,{recursive:!0,force:!0})}}}),or=h({meta:{name:`SSR`,slot:`ssr`},dependencies:{tinyglobby:q.devDependencies.tinyglobby,hono:q.devDependencies.hono,"@hono/node-server":q.devDependencies[`@hono/node-server`],"light-my-request":q.devDependencies[`light-my-request`]},factory:ar}),J={type:`module`,private:!0,name:`@kosmojs/svelte-generator`,version:`0.3.0`,author:`Slee Woo`,license:`MIT`,files:[`pkg/*`],exports:{".":{types:`./pkg/index.d.ts`,default:`./pkg/index.js`}},scripts:{build:`wsbuild src/index.ts`},dependencies:{"@kosmojs/core":`workspace:^`,"@kosmojs/lib":`workspace:^`,"@sveltejs/vite-plugin-svelte":`^7.3.0`,vite:`^8.2.2`},devDependencies:{"@tanstack/svelte-query":`^6.1.41`,"path-to-regexp":`^8.4.2`,svelte:`^5.56.10`}},sr=()=>{let e=[`🎉 Well done! You just created a new Svelte page.`,`🚀 Success! A fresh Svelte page is ready to roll.`,`🌟 Nice work! Another Svelte page added to your app.`,`🧩 All set! A new Svelte page has been scaffolded.`,`🔧 Scaffold complete! Your new Svelte page is in place.`,`✅ Built! Your Svelte page is scaffolded and ready.`,`✨ Fantastic! Your new Svelte page is good to go.`,`🎯 Nailed it! A brand new Svelte page just landed.`,`💫 Awesome! Another Svelte page joins the party.`,`⚡ Lightning fast! A new Svelte page created successfully.`];return e[Math.floor(Math.random()*e.length)]},Y=`<script lang="ts">
6798
+ `,Or=`string`,kr=v((e,n)=>{let{createPath:i,createImportHelpers:a}=S(e),{generators:o,refineTypeName:s,...l}=e.config,{renderToFile:u}=w({helpers:{...a({origin:`lib`})}});return{async build(e){let t=n?.renderMode?typeof n.renderMode==`string`?()=>n.renderMode:c(n?.renderMode,`string`):()=>Or,r={renderMode:JSON.stringify(n?.renderMode||null),pageRoutes:e.flatMap(e=>e.kind===`pageRoute`?[{...e.entry,renderMode:t(e.entry.name)}]:[]).sort(E),apiGenerator:o.some(e=>e.meta.slot===`backend`)};for(let[e,t]of[[`ssr.ts`,Dr],[`@ssr/__kosmo_ssr_bundle.ts`,Tr],[`@ssr/routes.ts`,Er]])await u(i.lib(e),t,r)},async postBuild(){if(!o.some(e=>e.meta.slot===`frontend`))return;let n=i.distDir(`ssr`),a=[O.tsconfigPaths(e),O.nodePrefix(),O.virtualModules(d(e,o),{kind:`ssr`,command:`build`})];await M(y(l,...o.map(({factory:t})=>t(e).config?.({kind:`client`,command:`build`})),{root:i.src(),plugins:a,build:{ssr:i.lib(`@ssr/__kosmo_ssr_bundle`),ssrEmitAssets:!0,sourcemap:!0,emptyOutDir:!0,minify:!1,copyPublicDir:!1,rolldownOptions:{output:{dir:n,entryFileNames:`app.js`,format:`esm`}}}})),await M({root:i.lib(),configFile:!1,appType:`custom`,plugins:a,resolve:{conditions:[`node`]},build:{ssr:i.lib(`ssr.ts`),target:`esnext`,sourcemap:!0,emptyOutDir:!0,rolldownOptions:{output:{dir:t(n,`server`),entryFileNames:`server.js`,format:`esm`}}}});for(let e of[`.vite`,`assets`,`index.html`])await P(r(n,`../client`,e),t(n,e),{recursive:!0});if(![!1,``].includes(l.publicDir)){let e=r(i.src(),l.publicDir||`public`);await x(e)&&await P(e,t(n,`public`),{recursive:!0})}for(let e of[`server.js`,`server.js.map`])await P(`${n}/server/${e}`,`${n}/${e}`);await F(`${n}/server`,{recursive:!0,force:!0})}}}),Ar=_({meta:{name:`SSR`,slot:`ssr`},dependencies:{tinyglobby:q.devDependencies.tinyglobby,hono:q.devDependencies.hono,"@hono/node-server":q.devDependencies[`@hono/node-server`]},factory:kr}),J={type:`module`,private:!0,name:`@kosmojs/svelte-generator`,version:`0.3.0`,author:`Slee Woo`,license:`MIT`,files:[`pkg/*`],exports:{".":{types:`./pkg/index.d.ts`,default:`./pkg/index.js`}},scripts:{build:`wsbuild src/index.ts`},dependencies:{"@kosmojs/core":`workspace:^`,"@kosmojs/lib":`workspace:^`,"@sveltejs/vite-plugin-svelte":`^7.3.0`,vite:`^8.2.2`},devDependencies:{"@tanstack/svelte-query":`^6.1.41`,"path-to-regexp":`^8.4.2`,svelte:`^5.56.10`}},jr=()=>{let e=[`🎉 Well done! You just created a new Svelte page.`,`🚀 Success! A fresh Svelte page is ready to roll.`,`🌟 Nice work! Another Svelte page added to your app.`,`🧩 All set! A new Svelte page has been scaffolded.`,`🔧 Scaffold complete! Your new Svelte page is in place.`,`✅ Built! Your Svelte page is scaffolded and ready.`,`✨ Fantastic! Your new Svelte page is good to go.`,`🎯 Nailed it! A brand new Svelte page just landed.`,`💫 Awesome! Another Svelte page joins the party.`,`⚡ Lightning fast! A new Svelte page created successfully.`];return e[Math.floor(Math.random()*e.length)]},Y=`<script lang="ts">
6094
6799
  import type { Snippet } from "svelte";
6095
6800
 
6096
6801
  let { children }: { children: Snippet } = $props();
6097
6802
  <\/script>
6098
6803
 
6099
6804
  {@render children()}
6100
- `,cr=`<script lang="ts">
6805
+ `,Mr=`<script lang="ts">
6101
6806
  import { type QueryClient, QueryClientProvider } from "@tanstack/svelte-query";
6102
6807
  import type { Snippet } from "svelte";
6103
6808
 
@@ -6114,7 +6819,7 @@ if (isMain) {
6114
6819
  <QueryClientProvider client={queryClient}>
6115
6820
  {@render children()}
6116
6821
  </QueryClientProvider>
6117
- `,lr=`import { hydrate as hydrateOrig, mount as mountOrig } from "svelte";
6822
+ `,Nr=`import { hydrate as hydrateOrig, mount as mountOrig } from "svelte";
6118
6823
  import type { RouterFactoryReturn } from "@kosmojs/core";
6119
6824
  import { clientRenderFactory } from "@kosmojs/core/generators";
6120
6825
 
@@ -6155,7 +6860,7 @@ export const mount = async (
6155
6860
  }
6156
6861
 
6157
6862
  export default clientRenderFactory();
6158
- `,ur=`import { render as renderOrig } from "svelte/server";
6863
+ `,Pr=`import { render as renderOrig } from "svelte/server";
6159
6864
 
6160
6865
  import type {
6161
6866
  RenderToStringWrapper,
@@ -6221,12 +6926,18 @@ export const renderToString: RenderToStringWrapper<
6221
6926
  // svelte/server exposes only render() - no web-stream renderer -
6222
6927
  // so this folder is string-only SSR.
6223
6928
  export default serverRenderFactory<false>();
6224
- `,dr=`declare module "*.svelte" {
6929
+ `,Fr=`declare module "*.svelte" {
6225
6930
  import type { Component } from "svelte";
6226
6931
  const component: Component;
6227
6932
  export default component;
6228
6933
  }
6229
- `,fr=`<script lang="ts">
6934
+
6935
+ declare module "virtual:kosmo/tsq-client" {
6936
+ import type { QueryClient, QueryClientConfig } from "@tanstack/svelte-query";
6937
+ export const createQueryClient: (options?: QueryClientConfig) => QueryClient;
6938
+ export const getQueryClient: () => QueryClient;
6939
+ }
6940
+ `,Ir=`<script lang="ts">
6230
6941
  /**
6231
6942
  * Folds [app, ...layouts] around the page component.
6232
6943
  *
@@ -6260,7 +6971,7 @@ export default serverRenderFactory<false>();
6260
6971
  {/snippet}
6261
6972
 
6262
6973
  {@render layer(0)}
6263
- `,pr=`<script lang="ts">
6974
+ `,Lr=`<script lang="ts">
6264
6975
  import styles from "./styles.module.css";
6265
6976
 
6266
6977
  let { headline }: { headline?: string } = $props();
@@ -6292,7 +7003,7 @@ export default serverRenderFactory<false>();
6292
7003
  </div>
6293
7004
  </div>
6294
7005
  </div>
6295
- `,mr=`<script lang="ts">
7006
+ `,Rr=`<script lang="ts">
6296
7007
  import styles from "./styles.module.css";
6297
7008
 
6298
7009
  let {
@@ -6337,7 +7048,7 @@ export default serverRenderFactory<false>();
6337
7048
  </div>
6338
7049
  </div>
6339
7050
  </div>
6340
- `,hr=`* {
7051
+ `,zr=`* {
6341
7052
  margin: 0;
6342
7053
  padding: 0;
6343
7054
  box-sizing: border-box;
@@ -6472,7 +7183,7 @@ export default serverRenderFactory<false>();
6472
7183
  align-items: center;
6473
7184
  gap: 0.25rem;
6474
7185
  }
6475
- `,gr=`<script lang="ts">
7186
+ `,Br=`<script lang="ts">
6476
7187
  import styles from "./styles.module.css";
6477
7188
  <\/script>
6478
7189
 
@@ -6530,7 +7241,7 @@ export default serverRenderFactory<false>();
6530
7241
  </div>
6531
7242
  </div>
6532
7243
  </div>
6533
- `,_r=`export type ParamsMap = {
7244
+ `,Vr=`export type ParamsMap = {
6534
7245
  {{#each pageRoutes}}"{{name}}": {{serializeParamsLiteral .}};
6535
7246
  {{/each}}
6536
7247
  };
@@ -6539,26 +7250,27 @@ export const paramNames = {
6539
7250
  {{#each pageRoutes}}"{{name}}": [ {{#each params.schema}}"{{name}}", {{/each}}],
6540
7251
  {{/each}}
6541
7252
  } as const;
6542
- `,vr=`import { QueryClient, type QueryClientConfig } from "@tanstack/svelte-query";
7253
+ `,Hr=`export * from "virtual:kosmo/tsq-client";
7254
+ `,Ur=`import { QueryClient } from "@tanstack/svelte-query";
6543
7255
 
6544
- let client: QueryClient | undefined;
7256
+ let client = undefined;
6545
7257
 
6546
- export const createQueryClient = (options?: QueryClientConfig): QueryClient => {
7258
+ export const createQueryClient = (options) => {
6547
7259
  client = new QueryClient(options);
6548
7260
  return client;
6549
7261
  };
6550
7262
 
6551
- export const getQueryClient = (): QueryClient => {
7263
+ export const getQueryClient = () => {
6552
7264
  if (!client) {
6553
7265
  client = new QueryClient();
6554
7266
  }
6555
7267
  return client;
6556
7268
  };
6557
- `,yr=`import { QueryClient, type QueryClientConfig } from "@tanstack/svelte-query";
7269
+ `,Wr=`import { QueryClient } from "@tanstack/svelte-query";
6558
7270
 
6559
- import { store } from "{{ createImport 'lib' '@ssr/base' }}";
7271
+ import { store } from "{{ createImport 'libCore' 'ssr' }}";
6560
7272
 
6561
- export const createQueryClient = (options?: QueryClientConfig): QueryClient => {
7273
+ export const createQueryClient = (options) => {
6562
7274
  const client = new QueryClient(options);
6563
7275
  const ctx = store?.getStore();
6564
7276
  if (ctx) {
@@ -6567,7 +7279,7 @@ export const createQueryClient = (options?: QueryClientConfig): QueryClient => {
6567
7279
  return client;
6568
7280
  };
6569
7281
 
6570
- export const getQueryClient = (): QueryClient => {
7282
+ export const getQueryClient = () => {
6571
7283
  const ctx = store?.getStore();
6572
7284
  if (!ctx) {
6573
7285
  throw new Error("getQueryClient(): called outside an SSR request scope");
@@ -6575,9 +7287,9 @@ export const getQueryClient = (): QueryClient => {
6575
7287
  if (!ctx.tsqClient) {
6576
7288
  ctx.tsqClient = new QueryClient();
6577
7289
  }
6578
- return ctx.tsqClient as QueryClient;
7290
+ return ctx.tsqClient;
6579
7291
  };
6580
- `,br=`import type { RouterFactoryReturn } from "@kosmojs/core";
7292
+ `,Gr=`import type { RouterFactoryReturn } from "@kosmojs/core";
6581
7293
  import { createRouterFactory } from "@kosmojs/core/generators";
6582
7294
 
6583
7295
  import Layouts from "./Layouts.svelte";
@@ -6617,7 +7329,7 @@ export default createRouterFactory<
6617
7329
  Promise<RouteComponent>,
6618
7330
  { server: { route: Route } }
6619
7331
  >();
6620
- `,xr=`import { match, pathToRegexp } from "path-to-regexp";
7332
+ `,Kr=`import { match, pathToRegexp } from "path-to-regexp";
6621
7333
  import { type Component, createContext } from "svelte";
6622
7334
 
6623
7335
  import { parseSearchParams } from "@kosmojs/core";
@@ -6637,7 +7349,6 @@ export type AnyComponent = Component<any, any, any>;
6637
7349
 
6638
7350
  export type RawRoute = {
6639
7351
  name: string;
6640
- pathSegments: number | undefined;
6641
7352
  regexp: RegExp;
6642
7353
  extractParams: (path: string) => Route["params"];
6643
7354
  loader: () => Promise<RouteModule>;
@@ -6728,23 +7439,19 @@ export const createRouter = (
6728
7439
  return {
6729
7440
  async resolve(url: URL = new URL(window.location.href)) {
6730
7441
  const searchParams = parseSearchParams(url);
6731
- const urlSegments = url.pathname.split("/").filter(Boolean).length;
6732
-
6733
- // 1: use lightweight \`RegExp.test()\` on linear scan - no capture allocation
6734
- const matchedRoutes = routes.filter(({ regexp }) => {
6735
- return regexp.test(url.pathname);
6736
- });
6737
7442
 
7443
+ // The routes array is generated pre-sorted by specificity
7444
+ // (static beats required beats optional beats splat, token by token),
7445
+ // the same ordering the SSR server registers routes in -
7446
+ // so the first pattern that matches IS the most specific one, and CSR resolution stays consistent with SSR.
7447
+ // A route with optional parameters matches a range of segment counts,
7448
+ // which is why no segment-count heuristic can disambiguate here.
7449
+ // Lightweight \`RegExp.test()\` on linear scan - no capture allocation.
6738
7450
  const matchedRoute =
6739
- matchedRoutes.length > 1
6740
- ? matchedRoutes.find(({ pathSegments }) => {
6741
- return pathSegments === undefined || pathSegments === urlSegments;
6742
- }) || catchallRoute
6743
- : matchedRoutes.length === 1
6744
- ? matchedRoutes[0]
6745
- : catchallRoute;
6746
-
6747
- // 2: capture params only on matched route
7451
+ routes.find(({ regexp }) => {
7452
+ return regexp.test(url.pathname);
7453
+ }) || catchallRoute;
7454
+
6748
7455
  const params = matchedRoute
6749
7456
  ? matchedRoute.extractParams(url.pathname)
6750
7457
  : {};
@@ -6831,11 +7538,6 @@ export const createRoute = (
6831
7538
  return {
6832
7539
  name,
6833
7540
  regexp,
6834
- // count segments of the same base-joined path the regexp matches against;
6835
- // resolve() compares this against the full url pathname's segment count
6836
- pathSegments: name.includes("...")
6837
- ? undefined
6838
- : path.split("/").filter(Boolean).length,
6839
7541
  extractParams: (path) => {
6840
7542
  const match = matcher(path);
6841
7543
  return match ? match.params : {};
@@ -6844,7 +7546,7 @@ export const createRoute = (
6844
7546
  layouts,
6845
7547
  };
6846
7548
  };
6847
- `,Sr=`import { getRouteContext } from "./svelte";
7549
+ `,qr=`import { getRouteContext } from "./svelte";
6848
7550
 
6849
7551
  import type { ParamsMap, paramNames } from "{{ createImport 'lib' 'params' }}";
6850
7552
 
@@ -6884,7 +7586,7 @@ export const useLoaderData = <T>(key?: string): T | undefined => {
6884
7586
  const route = useRoute();
6885
7587
  return route.loaderData?.[key || route.name] as T;
6886
7588
  };
6887
- `,Cr=`<script lang="ts">
7589
+ `,Jr=`<script lang="ts">
6888
7590
  import { AppProvider } from "{{ createImport 'lib' 'app' }}";
6889
7591
  import type { Snippet } from "svelte";
6890
7592
 
@@ -6894,7 +7596,7 @@ export const useLoaderData = <T>(key?: string): T | undefined => {
6894
7596
  <AppProvider>
6895
7597
  {@render children()}
6896
7598
  </AppProvider>
6897
- `,wr=`<script lang="ts">
7599
+ `,Yr=`<script lang="ts">
6898
7600
  import type { Snippet } from "svelte";
6899
7601
  import type { HTMLAnchorAttributes } from "svelte/elements";
6900
7602
 
@@ -6918,7 +7620,7 @@ export const useLoaderData = <T>(key?: string): T | undefined => {
6918
7620
  <\/script>
6919
7621
 
6920
7622
  <a {href} {...rest}>{@render children?.()}</a>
6921
- `,Tr=`import renderFactory, {
7623
+ `,Xr=`import renderFactory, {
6922
7624
  createRoutes,
6923
7625
  hydrate,
6924
7626
  mount,
@@ -6945,7 +7647,7 @@ if (root) {
6945
7647
  } else {
6946
7648
  console.error("❌ Root element not found!");
6947
7649
  }
6948
- `,Er=`import renderFactory, {
7650
+ `,Zr=`import renderFactory, {
6949
7651
  createRoutes,
6950
7652
  renderToString,
6951
7653
  // no renderToStream on Svelte folders
@@ -6966,19 +7668,19 @@ export default renderFactory(() => {
6966
7668
  },
6967
7669
  };
6968
7670
  });
6969
- `,Dr=`<script lang="ts">
7671
+ `,Qr=`<script lang="ts">
6970
7672
  import PageSample from "{{ createImport 'lib' 'pageSamples/404.svelte' }}";
6971
7673
  <\/script>
6972
7674
 
6973
7675
  <PageSample />
6974
- `,Or=`<script lang="ts">
7676
+ `,$r=`<script lang="ts">
6975
7677
  import type { Snippet } from "svelte";
6976
7678
 
6977
7679
  let { children }: { children: Snippet } = $props();
6978
7680
  <\/script>
6979
7681
 
6980
7682
  {@render children()}
6981
- `,kr=`<script lang="ts">
7683
+ `,ei=`<script lang="ts">
6982
7684
  import PageSample from "{{ createImport 'lib' 'pageSamples/page.svelte' }}";
6983
7685
 
6984
7686
  const pathMap = {
@@ -6997,7 +7699,7 @@ export default renderFactory(() => {
6997
7699
  routeName={"{{route.name}}"}
6998
7700
  {pathMap}
6999
7701
  />
7000
- `,Ar=`<script lang="ts">
7702
+ `,ti=`<script lang="ts">
7001
7703
  import WelcomePage from "{{ createImport 'lib' 'pageSamples/welcome.svelte' }}";
7002
7704
  <\/script>
7003
7705
 
@@ -7010,7 +7712,7 @@ export default renderFactory(() => {
7010
7712
  </svelte:head>
7011
7713
 
7012
7714
  <WelcomePage />
7013
- `,jr=`import routerFactory, { createRouters } from "{{ createImport 'lib' 'router' }}";
7715
+ `,ni=`import routerFactory, { createRouters } from "{{ createImport 'lib' 'router' }}";
7014
7716
 
7015
7717
  import app from "./app.svelte";
7016
7718
 
@@ -7025,7 +7727,7 @@ export default routerFactory((routes) => {
7025
7727
  },
7026
7728
  };
7027
7729
  });
7028
- `,Mr=g((e,t)=>{let{createPath:n,createImportHelpers:r}=y(e),{renderToFile:i}=x({helpers:{...r({origin:`lib`}),...w()}}),{renderToFile:a}=x({helpers:r({origin:`src`})}),o=e=>!e?.trim().length,s=c(t?.templates,kr),u=async e=>{for(let{kind:t,entry:r}of e)t===`pageRoute`?await a(n.pages(r.file),r.name===`index`?Ar:s(r.name,r),{route:r,title:r.name.replace(/\{([^}]+)\}/g,`$1`),message:sr()},{overwrite:o}):t===`pageLayout`&&await a(n.pages(r.file),Or,{route:r},{overwrite:o})},d=async e=>{let t=e.flatMap(({kind:e,entry:t})=>e===`pageLayout`?[t]:[]),r=e.flatMap(({kind:e,entry:n})=>{if(e===`pageRoute`){let{name:e,file:r}=n;return[{...n,layouts:t.flatMap(t=>t.name===e||r.startsWith(`${t.name}/`)?[t]:[]).sort(S)}]}return[]}).sort(S);for(let[e,a]of[[`client.ts`,lr],[`server.ts`,ur]])await i(n.libEntry(e),a,{pageRoutes:r,layouts:t});for(let[e,t]of[[`params.ts`,_r],[`router.ts`,br]])await i(n.lib(e),t,{pageRoutes:r})};return{config(){let{templates:e,...n}={...t};return{plugins:pe(n)}},async start(){for(let[e,r]of[[`env.d.ts`,dr],[`svelte.ts`,xr],[`Layouts.svelte`,fr],[`use.ts`,Sr],[`pageSamples/styles.module.css`,hr],[`pageSamples/welcome.svelte`,gr],[`pageSamples/page.svelte`,mr],[`pageSamples/404.svelte`,pr],...t?.tanstack?.query?[[`app/app.svelte`,Y],[`app/app-tsq.svelte`,cr],[`app/index.ts`,`export { default as AppProvider } from "./app-tsq.svelte";`],[`query.ts`,vr]]:[[`app/app.svelte`,Y],[`app/app-tsq.svelte`,`/** tanstack query disabled */`],[`app/index.ts`,`export { default as AppProvider } from "./app.svelte";`],[`query.ts`,`/** tanstack query disabled */`]]])await i(n.lib(e),r,{});for(let[e,t]of[[`pages/404.svelte`,Dr],[`components/Link.svelte`,wr],[`app.svelte`,Cr],[`router.ts`,jr]])await a(n.src(e),t,{entryDir:l.entryDir},{overwrite:o});for(let[e,t]of[[`client.ts`,Tr],[`server.ts`,Er]])await a(n.entry(e),t,{},{overwrite:o})},async watch(e,t){await u(e.filter(m(t,[`create`]))),await d(e)},async build(e){await u(e),await d(e)},async ssrBuild(){await i(n.lib(`query.ts`),t?.tanstack?.query?yr:`/** tanstack query disabled */`,{ssrBundle:!0})}}}),Nr=h({meta:{name:`Svelte`,slot:`frontend`},dependencies(e){return{svelte:J.devDependencies.svelte,"path-to-regexp":J.devDependencies[`path-to-regexp`],...e?.tanstack?.query?{"@tanstack/svelte-query":J.devDependencies[`@tanstack/svelte-query`]}:{}}},factory:Mr}),Pr={type:`module`,private:!0,name:`@kosmojs/typebox-generator`,version:`0.3.0`,cacheVersion:`1`,author:`Slee Woo`,license:`MIT`,files:[`pkg/*`],exports:{".":{types:`./pkg/index.d.ts`,default:`./pkg/index.js`}},scripts:{build:`wsbuild src/index.ts`,test:`vitest --root ../.. --project generators/typebox-generator`},dependencies:{"@kosmojs/core":`workspace:^`,"@kosmojs/lib":`workspace:^`,crc:`^4.3.2`,semver:`^7.8.5`},devDependencies:{"@kosmojs/core-generator":`workspace:^`,"@kosmojs/koa-generator":`workspace:^`,typebox:`^1.3.18`}},Fr=`import Type from "typebox";
7730
+ `,ri=v((e,t)=>{let{createPath:n,createImportHelpers:r}=S(e),{render:i,renderToFile:a}=w({helpers:{...r({origin:`lib`}),...A()}}),{renderToFile:o}=w({helpers:r({origin:`src`})}),s=e=>!e?.trim().length,c=l(t?.templates,ei),d=async e=>{for(let{kind:t,entry:r}of e)t===`pageRoute`?await o(n.pages(r.file),r.name===`index`?ti:c(r.name,r),{route:r,title:r.name.replace(/\{([^}]+)\}/g,`$1`),message:jr()},{overwrite:s}):t===`pageLayout`&&await o(n.pages(r.file),$r,{route:r},{overwrite:s})},f=async e=>{let t=e.flatMap(({kind:e,entry:t})=>e===`pageLayout`?[t]:[]),r=e.flatMap(({kind:e,entry:n})=>{if(e===`pageRoute`){let{name:e,file:r}=n;return[{...n,layouts:t.flatMap(t=>t.name===e||r.startsWith(`${t.name}/`)?[t]:[]).sort(E)}]}return[]}).sort(D);for(let[e,i]of[[`client.ts`,Nr],[`server.ts`,Pr]])await a(n.libEntry(e),i,{pageRoutes:r,layouts:t});for(let[e,t]of[[`params.ts`,Vr],[`router.ts`,Gr]])await a(n.lib(e),t,{pageRoutes:r})};return{config(){let{templates:e,...n}={...t};return{plugins:fe(n)}},async start(){for(let[e,r]of[[`env.d.ts`,Fr],[`svelte.ts`,Kr],[`Layouts.svelte`,Ir],[`use.ts`,qr],[`pageSamples/styles.module.css`,zr],[`pageSamples/welcome.svelte`,Br],[`pageSamples/page.svelte`,Rr],[`pageSamples/404.svelte`,Lr],...t?.tanstack?.query?[[`app/app.svelte`,Y],[`app/app-tsq.svelte`,Mr],[`app/index.ts`,`export { default as AppProvider } from "./app-tsq.svelte";`],[`query.ts`,Hr]]:[[`app/app.svelte`,Y],[`app/app-tsq.svelte`,`/** tanstack query disabled */`],[`app/index.ts`,`export { default as AppProvider } from "./app.svelte";`],[`query.ts`,`/** tanstack query disabled */`]]])await a(n.lib(e),r,{});for(let[e,t]of[[`pages/404.svelte`,Qr],[`components/Link.svelte`,Yr],[`app.svelte`,Jr],[`router.ts`,ni]])await o(n.src(e),t,{entryDir:u.entryDir},{overwrite:s});for(let[e,t]of[[`client.ts`,Xr],[`server.ts`,Zr]])await o(n.entry(e),t,{},{overwrite:s})},async watch(e,t){await d(e.filter(g(t,[`create`]))),await f(e)},async build(e){await d(e),await f(e)},virtualModules(){return t?.tanstack?.query?[{specifier:`virtual:kosmo/tsq-client`,csr:i(Ur,{}),ssr:i(Wr,{})}]:[]}}}),ii=_({meta:{name:`Svelte`,slot:`frontend`},dependencies(e){return{svelte:J.devDependencies.svelte,...e?.tanstack?.query?{"@tanstack/svelte-query":J.devDependencies[`@tanstack/svelte-query`]}:{}}},factory:ri}),ai={type:`module`,private:!0,name:`@kosmojs/typebox-generator`,version:`0.3.0`,cacheVersion:`1`,author:`Slee Woo`,license:`MIT`,files:[`pkg/*`],exports:{".":{types:`./pkg/index.d.ts`,default:`./pkg/index.js`}},scripts:{build:`wsbuild src/index.ts`,test:`vitest --root ../.. --project generators/typebox-generator`},dependencies:{"@kosmojs/core":`workspace:^`,"@kosmojs/lib":`workspace:^`,crc:`^4.3.2`,semver:`^7.8.5`},devDependencies:{"@kosmojs/core-generator":`workspace:^`,"@kosmojs/koa-generator":`workspace:^`,typebox:`^1.3.18`}},oi=`import Type from "typebox";
7029
7731
 
7030
7732
  /**
7031
7733
  * Custom types for JavaScript constructs that have no JSON Schema
@@ -7097,7 +7799,7 @@ export default {
7097
7799
  Buffer: TBuffer(),
7098
7800
  ArrayBuffer: TArrayBuffer(),
7099
7801
  };
7100
- `,Ir=`import type { TValidationError } from "typebox/error";
7802
+ `,si=`import type { TValidationError } from "typebox/error";
7101
7803
 
7102
7804
  import type { ValidationErrorEntry } from "@kosmojs/core";
7103
7805
 
@@ -8319,7 +9021,7 @@ const format = (fmt: string, ...args: unknown[]): string => {
8319
9021
 
8320
9022
  return str;
8321
9023
  };
8322
- `,Lr=`import Type from "typebox";
9024
+ `,ci=`import Type from "typebox";
8323
9025
  import { Compile } from "typebox/compile";
8324
9026
  import Value from "typebox/value";
8325
9027
 
@@ -8371,14 +9073,14 @@ export const validationSchemaFactory = (
8371
9073
  },
8372
9074
  };
8373
9075
  };
8374
- `,Rr=`import { Settings } from "typebox/system";
9076
+ `,li=`import { Settings } from "typebox/system";
8375
9077
 
8376
9078
  Settings.Set({{settings}});
8377
9079
 
8378
9080
  export { default as customTypes } from "{{customTypesImport}}";
8379
9081
 
8380
9082
  export const validationMessages = {{validationMessages}};
8381
- `,zr=`import type { ValidationSchemas } from "@kosmojs/core";
9083
+ `,ui=`import type { ValidationSchemas } from "@kosmojs/core";
8382
9084
 
8383
9085
  import { validationSchemaFactory } from "{{ createImport 'lib' '@typebox' }}";
8384
9086
 
@@ -8439,14 +9141,14 @@ export const validationSchemas: ValidationSchemas = {
8439
9141
  {{/each}}
8440
9142
  },
8441
9143
  };
8442
- `,Br={exactOptionalPropertyTypes:!0},Vr=g((e,t)=>{let{createPath:n,createImport:r,createImportHelpers:i}=y(e),{renderToFile:a}=x({helpers:{...i({origin:`lib`})}}),{validationMessages:s={},customTypesImport:c=r.lib([`@typebox/custom-types`],{origin:`lib`}),settings:l}={...t},u=async e=>{for(let{kind:t,entry:r}of e){if(t!==`apiRoute`)continue;let e=[r.params,...r.validationDefinitions.flatMap(e=>e.target===`response`?e.variants:[e.schema])].flatMap(({resolvedType:e})=>e?[e]:[]),i=[...new Set(r.validationDefinitions.flatMap(({target:e})=>Object.keys(o).includes(e)?[e]:[]))].map(e=>({target:e,methods:r.methods.flatMap(t=>{let n=r.validationDefinitions.find(n=>n.method===t&&n.target===e);return n?[{route:r.name,method:t,target:e,schema:n.schema,...n.runtimeValidation===void 0?{}:{runtimeValidation:JSON.stringify(n.runtimeValidation)},...n.customErrors===void 0?{}:{customErrors:JSON.stringify(n.customErrors)}}]:[]})})),s=r.methods.flatMap(e=>{let t=r.validationDefinitions.find(t=>t.method===e&&t.target===`response`);return t?[{method:e,variants:t.variants.map(e=>({route:r.name,target:`response`,...e,...t.runtimeValidation===void 0?{}:{runtimeValidation:JSON.stringify(t.runtimeValidation)},...t.customErrors===void 0?{}:{customErrors:JSON.stringify(t.customErrors)}}))}]:[]});await a(n.libApi(r.name,`schemas.ts`),zr,{route:r,resolvedTypes:e,requestSchemas:i,responseSchemas:s})}};return{async start(){for(let[e,t]of[[`custom-types.ts`,Fr],[`error-handler.ts`,Ir],[`index.ts`,Lr],[`setup.ts`,Rr]])await a(n.lib(`@typebox`,e),t,{validationMessages:JSON.stringify(s),customTypesImport:c,settings:JSON.stringify({...Br,...l})})},async watch(e,t){await u(e.filter(p(t,[`create`,`update`])))},async build(e){await u(e)}}}),X={PROPERTY:`PROPERTY`,PROPERTIES:`PROPERTIES`,ALLOWED_VALUES:`ALLOWED_VALUES`,FOUND_N_DUPLICATES:`FOUND_N_DUPLICATES`,VALIDATION_PASSED:`VALIDATION_PASSED`,VALIDATION_FAILED_PREFIX:`VALIDATION_FAILED_PREFIX`,ERROR_SUMMARY:`ERROR_SUMMARY`,PLURAL_SUFFIX:`PLURAL_SUFFIX`,FIRST:`FIRST`,SECOND:`SECOND`,THIRD:`THIRD`,FOURTH:`FOURTH`,FIFTH:`FIFTH`,TYPE_INVALID:`TYPE_INVALID`,STRING_MIN_LENGTH:`STRING_MIN_LENGTH`,STRING_MAX_LENGTH:`STRING_MAX_LENGTH`,STRING_PATTERN:`STRING_PATTERN`,STRING_FORMAT:`STRING_FORMAT`,STRING_FORMAT_EMAIL:`STRING_FORMAT_EMAIL`,STRING_FORMAT_DATE:`STRING_FORMAT_DATE`,STRING_FORMAT_DATETIME:`STRING_FORMAT_DATETIME`,STRING_FORMAT_TIME:`STRING_FORMAT_TIME`,STRING_FORMAT_URI:`STRING_FORMAT_URI`,STRING_FORMAT_URL:`STRING_FORMAT_URL`,STRING_FORMAT_UUID:`STRING_FORMAT_UUID`,STRING_FORMAT_IPV4:`STRING_FORMAT_IPV4`,STRING_FORMAT_IPV6:`STRING_FORMAT_IPV6`,STRING_FORMAT_HOSTNAME:`STRING_FORMAT_HOSTNAME`,STRING_FORMAT_JSON_POINTER:`STRING_FORMAT_JSON_POINTER`,STRING_FORMAT_REGEX:`STRING_FORMAT_REGEX`,NUMBER_MINIMUM:`NUMBER_MINIMUM`,NUMBER_MAXIMUM:`NUMBER_MAXIMUM`,NUMBER_EXCLUSIVE_MINIMUM:`NUMBER_EXCLUSIVE_MINIMUM`,NUMBER_EXCLUSIVE_MAXIMUM:`NUMBER_EXCLUSIVE_MAXIMUM`,NUMBER_MULTIPLE_OF:`NUMBER_MULTIPLE_OF`,ARRAY_MIN_ITEMS:`ARRAY_MIN_ITEMS`,ARRAY_MAX_ITEMS:`ARRAY_MAX_ITEMS`,ARRAY_UNIQUE_ITEMS:`ARRAY_UNIQUE_ITEMS`,ARRAY_CONTAINS:`ARRAY_CONTAINS`,ARRAY_MIN_CONTAINS:`ARRAY_MIN_CONTAINS`,ARRAY_MAX_CONTAINS:`ARRAY_MAX_CONTAINS`,ARRAY_PREFIX_ITEMS:`ARRAY_PREFIX_ITEMS`,ARRAY_ITEMS:`ARRAY_ITEMS`,ARRAY_UNEVALUATED_ITEMS:`ARRAY_UNEVALUATED_ITEMS`,TUPLE_MIN_ITEMS:`TUPLE_MIN_ITEMS`,TUPLE_MAX_ITEMS:`TUPLE_MAX_ITEMS`,OBJECT_REQUIRED:`OBJECT_REQUIRED`,OBJECT_ADDITIONAL_PROPERTIES:`OBJECT_ADDITIONAL_PROPERTIES`,OBJECT_MIN_PROPERTIES:`OBJECT_MIN_PROPERTIES`,OBJECT_MAX_PROPERTIES:`OBJECT_MAX_PROPERTIES`,OBJECT_PROPERTY_NAMES:`OBJECT_PROPERTY_NAMES`,OBJECT_DEPENDENCIES:`OBJECT_DEPENDENCIES`,OBJECT_UNEVALUATED_PROPERTIES:`OBJECT_UNEVALUATED_PROPERTIES`,ENUM_MISMATCH:`ENUM_MISMATCH`,CONST_MISMATCH:`CONST_MISMATCH`,CONDITIONAL_IF:`CONDITIONAL_IF`,CONDITIONAL_THEN:`CONDITIONAL_THEN`,CONDITIONAL_ELSE:`CONDITIONAL_ELSE`,COMPOSITION_ONE_OF:`COMPOSITION_ONE_OF`,COMPOSITION_ANY_OF:`COMPOSITION_ANY_OF`,COMPOSITION_ALL_OF:`COMPOSITION_ALL_OF`,COMPOSITION_NOT:`COMPOSITION_NOT`,CONTENT_DISCRIMINATOR:`CONTENT_DISCRIMINATOR`,CONTENT_ENCODING:`CONTENT_ENCODING`,CONTENT_MEDIA_TYPE:`CONTENT_MEDIA_TYPE`,CUSTOM_RANGE:`CUSTOM_RANGE`,CUSTOM_EXCLUSIVE_RANGE:`CUSTOM_EXCLUSIVE_RANGE`,CUSTOM_REGEXP:`CUSTOM_REGEXP`,CUSTOM_DYNAMIC_DEFAULTS:`CUSTOM_DYNAMIC_DEFAULTS`,CUSTOM_SELECT:`CUSTOM_SELECT`,CUSTOM_TRANSFORM:`CUSTOM_TRANSFORM`,CUSTOM_UNIQUE_ITEM_PROPERTIES:`CUSTOM_UNIQUE_ITEM_PROPERTIES`,UNKNOWN:`UNKNOWN`};X.PROPERTY,X.PROPERTIES,X.ALLOWED_VALUES,X.FOUND_N_DUPLICATES,X.VALIDATION_PASSED,X.VALIDATION_FAILED_PREFIX,X.ERROR_SUMMARY,X.PLURAL_SUFFIX,X.FIRST,X.SECOND,X.THIRD,X.FOURTH,X.FIFTH,X.TYPE_INVALID,X.STRING_MIN_LENGTH,X.STRING_MAX_LENGTH,X.STRING_PATTERN,X.STRING_FORMAT,X.STRING_FORMAT_EMAIL,X.STRING_FORMAT_DATE,X.STRING_FORMAT_DATETIME,X.STRING_FORMAT_TIME,X.STRING_FORMAT_URI,X.STRING_FORMAT_URL,X.STRING_FORMAT_UUID,X.STRING_FORMAT_IPV4,X.STRING_FORMAT_IPV6,X.STRING_FORMAT_HOSTNAME,X.STRING_FORMAT_JSON_POINTER,X.STRING_FORMAT_REGEX,X.NUMBER_MINIMUM,X.NUMBER_MAXIMUM,X.NUMBER_EXCLUSIVE_MINIMUM,X.NUMBER_EXCLUSIVE_MAXIMUM,X.NUMBER_MULTIPLE_OF,X.ARRAY_MIN_ITEMS,X.ARRAY_MAX_ITEMS,X.ARRAY_UNIQUE_ITEMS,X.ARRAY_CONTAINS,X.ARRAY_MIN_CONTAINS,X.ARRAY_MAX_CONTAINS,X.ARRAY_PREFIX_ITEMS,X.ARRAY_ITEMS,X.ARRAY_UNEVALUATED_ITEMS,X.TUPLE_MIN_ITEMS,X.TUPLE_MAX_ITEMS,X.OBJECT_REQUIRED,X.OBJECT_ADDITIONAL_PROPERTIES,X.OBJECT_MIN_PROPERTIES,X.OBJECT_MAX_PROPERTIES,X.OBJECT_PROPERTY_NAMES,X.OBJECT_DEPENDENCIES,X.OBJECT_UNEVALUATED_PROPERTIES,X.ENUM_MISMATCH,X.CONST_MISMATCH,X.CONDITIONAL_IF,X.CONDITIONAL_THEN,X.CONDITIONAL_ELSE,X.COMPOSITION_ONE_OF,X.COMPOSITION_ANY_OF,X.COMPOSITION_ALL_OF,X.COMPOSITION_NOT,X.CONTENT_DISCRIMINATOR,X.CONTENT_ENCODING,X.CONTENT_MEDIA_TYPE,X.CUSTOM_RANGE,X.CUSTOM_EXCLUSIVE_RANGE,X.CUSTOM_REGEXP,X.CUSTOM_DYNAMIC_DEFAULTS,X.CUSTOM_SELECT,X.CUSTOM_TRANSFORM,X.CUSTOM_UNIQUE_ITEM_PROPERTIES,X.UNKNOWN;var Hr=h({meta:{name:`TypeBox`,resolveTypes:!0},dependencies:{typebox:Pr.devDependencies.typebox},factory:Vr}),Z={type:`module`,private:!0,name:`@kosmojs/vue-generator`,version:`0.3.0`,author:`Slee Woo`,license:`MIT`,files:[`pkg/*`],exports:{".":{types:`./pkg/index.d.ts`,default:`./pkg/index.js`}},scripts:{build:`wsbuild src/index.ts`,test:`vitest --root ../.. --project generators/vue-generator`},dependencies:{"@kosmojs/core":`workspace:^`,"@kosmojs/lib":`workspace:^`,"@vitejs/plugin-vue":`^6.0.8`},devDependencies:{"@tanstack/vue-query":`^5.102.2`,"path-to-regexp":`^8.4.2`,vue:`^3.5.41`,"vue-router":`^5.2.0`}},Q=e=>{let t=e=>e.kind===`splat`?`:${e.name}(.*)?`:e.kind===`optional`?`:${e.name}?`:`:${e.name}`;return e.flatMap(e=>e.kind===`static`?[e.parts[0].value]:e.kind===`param`?[t(e.parts[0])]:[e.parts.map(e=>e.type===`static`?e.value:t(e)).join(``)]).join(`/`)},Ur=()=>{let e=e=>e?.kind===`param`&&e.parts[0]?.kind===`splat`,n=(r,i)=>r.flatMap(({index:r,layout:a,children:o})=>{let{name:s,pathTokens:c}={...r,...a};if(!c)return[];let l=`${s}/layout`,u=i?Q(c):t(`/`,Q(c)),d=c.at(-1);return e(d)?r&&a?[{name:l,path:u,component:a.id,children:[{name:s,path:``,component:r.id}]}]:r?[{path:u,children:[{name:s,path:``,component:r.id},...n(o,s)]}]:a?[{name:l,path:u,component:a.id,children:n(o,s)}]:[]:r&&a?[{name:l,path:u,component:a.id,children:[{name:s,path:``,component:r.id},...n(o,s)]}]:r?[{path:u,children:[{name:s,path:``,component:r.id},...n(o,s)]}]:a?[{name:l,path:u,component:a.id,children:n(o,s)}]:[]});return n},Wr=()=>{let e=[`🎉 Well done! You just created a new Vue route.`,`🚀 Success! A fresh Vue route is ready to roll.`,`🌟 Nice work! Another Vue route added to your app.`,`🧩 All set! A new Vue route has been scaffolded.`,`🔧 Scaffold complete! Your new Vue route is in place.`,`✅ Built! Your Vue route is scaffolded and ready.`,`✨ Fantastic! Your new Vue route is good to go.`,`🎯 Nailed it! A brand new Vue route just landed.`,`💫 Awesome! Another Vue route joins the party.`,`⚡ Lightning fast! A new Vue route created successfully.`];return e[Math.floor(Math.random()*e.length)]},Gr=`import type { Plugin } from "vue";
9144
+ `,di={exactOptionalPropertyTypes:!0},fi=v((e,t)=>{let{createPath:n,createImport:r,createImportHelpers:i}=S(e),{renderToFile:a}=w({helpers:{...i({origin:`lib`})}}),{validationMessages:o={},customTypesImport:c=r.lib([`@typebox/custom-types`],{origin:`lib`}),settings:l}={...t},u=async e=>{for(let{kind:t,entry:r}of e){if(t!==`apiRoute`)continue;let e=[r.params,...r.validationDefinitions.flatMap(e=>e.target===`response`?e.variants:[e.schema])].flatMap(({resolvedType:e})=>e?[e]:[]),i=[...new Set(r.validationDefinitions.flatMap(({target:e})=>Object.keys(s).includes(e)?[e]:[]))].map(e=>({target:e,methods:r.methods.flatMap(t=>{let n=r.validationDefinitions.find(n=>n.method===t&&n.target===e);return n?[{route:r.name,method:t,target:e,schema:n.schema,...n.runtimeValidation===void 0?{}:{runtimeValidation:JSON.stringify(n.runtimeValidation)},...n.customErrors===void 0?{}:{customErrors:JSON.stringify(n.customErrors)}}]:[]})})),o=r.methods.flatMap(e=>{let t=r.validationDefinitions.find(t=>t.method===e&&t.target===`response`);return t?[{method:e,variants:t.variants.map(e=>({route:r.name,target:`response`,...e,...t.runtimeValidation===void 0?{}:{runtimeValidation:JSON.stringify(t.runtimeValidation)},...t.customErrors===void 0?{}:{customErrors:JSON.stringify(t.customErrors)}}))}]:[]});await a(n.libApi(r.name,`schemas.ts`),ui,{route:r,resolvedTypes:e,requestSchemas:i,responseSchemas:o})}};return{async start(){for(let[e,t]of[[`custom-types.ts`,oi],[`error-handler.ts`,si],[`index.ts`,ci],[`setup.ts`,li]])await a(n.lib(`@typebox`,e),t,{validationMessages:JSON.stringify(o),customTypesImport:c,settings:JSON.stringify({...di,...l})})},async watch(e,t){await u(e.filter(h(t,[`create`,`update`])))},async build(e){await u(e)}}}),X={PROPERTY:`PROPERTY`,PROPERTIES:`PROPERTIES`,ALLOWED_VALUES:`ALLOWED_VALUES`,FOUND_N_DUPLICATES:`FOUND_N_DUPLICATES`,VALIDATION_PASSED:`VALIDATION_PASSED`,VALIDATION_FAILED_PREFIX:`VALIDATION_FAILED_PREFIX`,ERROR_SUMMARY:`ERROR_SUMMARY`,PLURAL_SUFFIX:`PLURAL_SUFFIX`,FIRST:`FIRST`,SECOND:`SECOND`,THIRD:`THIRD`,FOURTH:`FOURTH`,FIFTH:`FIFTH`,TYPE_INVALID:`TYPE_INVALID`,STRING_MIN_LENGTH:`STRING_MIN_LENGTH`,STRING_MAX_LENGTH:`STRING_MAX_LENGTH`,STRING_PATTERN:`STRING_PATTERN`,STRING_FORMAT:`STRING_FORMAT`,STRING_FORMAT_EMAIL:`STRING_FORMAT_EMAIL`,STRING_FORMAT_DATE:`STRING_FORMAT_DATE`,STRING_FORMAT_DATETIME:`STRING_FORMAT_DATETIME`,STRING_FORMAT_TIME:`STRING_FORMAT_TIME`,STRING_FORMAT_URI:`STRING_FORMAT_URI`,STRING_FORMAT_URL:`STRING_FORMAT_URL`,STRING_FORMAT_UUID:`STRING_FORMAT_UUID`,STRING_FORMAT_IPV4:`STRING_FORMAT_IPV4`,STRING_FORMAT_IPV6:`STRING_FORMAT_IPV6`,STRING_FORMAT_HOSTNAME:`STRING_FORMAT_HOSTNAME`,STRING_FORMAT_JSON_POINTER:`STRING_FORMAT_JSON_POINTER`,STRING_FORMAT_REGEX:`STRING_FORMAT_REGEX`,NUMBER_MINIMUM:`NUMBER_MINIMUM`,NUMBER_MAXIMUM:`NUMBER_MAXIMUM`,NUMBER_EXCLUSIVE_MINIMUM:`NUMBER_EXCLUSIVE_MINIMUM`,NUMBER_EXCLUSIVE_MAXIMUM:`NUMBER_EXCLUSIVE_MAXIMUM`,NUMBER_MULTIPLE_OF:`NUMBER_MULTIPLE_OF`,ARRAY_MIN_ITEMS:`ARRAY_MIN_ITEMS`,ARRAY_MAX_ITEMS:`ARRAY_MAX_ITEMS`,ARRAY_UNIQUE_ITEMS:`ARRAY_UNIQUE_ITEMS`,ARRAY_CONTAINS:`ARRAY_CONTAINS`,ARRAY_MIN_CONTAINS:`ARRAY_MIN_CONTAINS`,ARRAY_MAX_CONTAINS:`ARRAY_MAX_CONTAINS`,ARRAY_PREFIX_ITEMS:`ARRAY_PREFIX_ITEMS`,ARRAY_ITEMS:`ARRAY_ITEMS`,ARRAY_UNEVALUATED_ITEMS:`ARRAY_UNEVALUATED_ITEMS`,TUPLE_MIN_ITEMS:`TUPLE_MIN_ITEMS`,TUPLE_MAX_ITEMS:`TUPLE_MAX_ITEMS`,OBJECT_REQUIRED:`OBJECT_REQUIRED`,OBJECT_ADDITIONAL_PROPERTIES:`OBJECT_ADDITIONAL_PROPERTIES`,OBJECT_MIN_PROPERTIES:`OBJECT_MIN_PROPERTIES`,OBJECT_MAX_PROPERTIES:`OBJECT_MAX_PROPERTIES`,OBJECT_PROPERTY_NAMES:`OBJECT_PROPERTY_NAMES`,OBJECT_DEPENDENCIES:`OBJECT_DEPENDENCIES`,OBJECT_UNEVALUATED_PROPERTIES:`OBJECT_UNEVALUATED_PROPERTIES`,ENUM_MISMATCH:`ENUM_MISMATCH`,CONST_MISMATCH:`CONST_MISMATCH`,CONDITIONAL_IF:`CONDITIONAL_IF`,CONDITIONAL_THEN:`CONDITIONAL_THEN`,CONDITIONAL_ELSE:`CONDITIONAL_ELSE`,COMPOSITION_ONE_OF:`COMPOSITION_ONE_OF`,COMPOSITION_ANY_OF:`COMPOSITION_ANY_OF`,COMPOSITION_ALL_OF:`COMPOSITION_ALL_OF`,COMPOSITION_NOT:`COMPOSITION_NOT`,CONTENT_DISCRIMINATOR:`CONTENT_DISCRIMINATOR`,CONTENT_ENCODING:`CONTENT_ENCODING`,CONTENT_MEDIA_TYPE:`CONTENT_MEDIA_TYPE`,CUSTOM_RANGE:`CUSTOM_RANGE`,CUSTOM_EXCLUSIVE_RANGE:`CUSTOM_EXCLUSIVE_RANGE`,CUSTOM_REGEXP:`CUSTOM_REGEXP`,CUSTOM_DYNAMIC_DEFAULTS:`CUSTOM_DYNAMIC_DEFAULTS`,CUSTOM_SELECT:`CUSTOM_SELECT`,CUSTOM_TRANSFORM:`CUSTOM_TRANSFORM`,CUSTOM_UNIQUE_ITEM_PROPERTIES:`CUSTOM_UNIQUE_ITEM_PROPERTIES`,UNKNOWN:`UNKNOWN`};X.PROPERTY,X.PROPERTIES,X.ALLOWED_VALUES,X.FOUND_N_DUPLICATES,X.VALIDATION_PASSED,X.VALIDATION_FAILED_PREFIX,X.ERROR_SUMMARY,X.PLURAL_SUFFIX,X.FIRST,X.SECOND,X.THIRD,X.FOURTH,X.FIFTH,X.TYPE_INVALID,X.STRING_MIN_LENGTH,X.STRING_MAX_LENGTH,X.STRING_PATTERN,X.STRING_FORMAT,X.STRING_FORMAT_EMAIL,X.STRING_FORMAT_DATE,X.STRING_FORMAT_DATETIME,X.STRING_FORMAT_TIME,X.STRING_FORMAT_URI,X.STRING_FORMAT_URL,X.STRING_FORMAT_UUID,X.STRING_FORMAT_IPV4,X.STRING_FORMAT_IPV6,X.STRING_FORMAT_HOSTNAME,X.STRING_FORMAT_JSON_POINTER,X.STRING_FORMAT_REGEX,X.NUMBER_MINIMUM,X.NUMBER_MAXIMUM,X.NUMBER_EXCLUSIVE_MINIMUM,X.NUMBER_EXCLUSIVE_MAXIMUM,X.NUMBER_MULTIPLE_OF,X.ARRAY_MIN_ITEMS,X.ARRAY_MAX_ITEMS,X.ARRAY_UNIQUE_ITEMS,X.ARRAY_CONTAINS,X.ARRAY_MIN_CONTAINS,X.ARRAY_MAX_CONTAINS,X.ARRAY_PREFIX_ITEMS,X.ARRAY_ITEMS,X.ARRAY_UNEVALUATED_ITEMS,X.TUPLE_MIN_ITEMS,X.TUPLE_MAX_ITEMS,X.OBJECT_REQUIRED,X.OBJECT_ADDITIONAL_PROPERTIES,X.OBJECT_MIN_PROPERTIES,X.OBJECT_MAX_PROPERTIES,X.OBJECT_PROPERTY_NAMES,X.OBJECT_DEPENDENCIES,X.OBJECT_UNEVALUATED_PROPERTIES,X.ENUM_MISMATCH,X.CONST_MISMATCH,X.CONDITIONAL_IF,X.CONDITIONAL_THEN,X.CONDITIONAL_ELSE,X.COMPOSITION_ONE_OF,X.COMPOSITION_ANY_OF,X.COMPOSITION_ALL_OF,X.COMPOSITION_NOT,X.CONTENT_DISCRIMINATOR,X.CONTENT_ENCODING,X.CONTENT_MEDIA_TYPE,X.CUSTOM_RANGE,X.CUSTOM_EXCLUSIVE_RANGE,X.CUSTOM_REGEXP,X.CUSTOM_DYNAMIC_DEFAULTS,X.CUSTOM_SELECT,X.CUSTOM_TRANSFORM,X.CUSTOM_UNIQUE_ITEM_PROPERTIES,X.UNKNOWN;var pi=_({meta:{name:`TypeBox`,resolveTypes:!0},dependencies:{typebox:ai.devDependencies.typebox},factory:fi}),Z={type:`module`,private:!0,name:`@kosmojs/vue-generator`,version:`0.3.0`,author:`Slee Woo`,license:`MIT`,files:[`pkg/*`],exports:{".":{types:`./pkg/index.d.ts`,default:`./pkg/index.js`}},scripts:{build:`wsbuild src/index.ts`,test:`vitest --root ../.. --project generators/vue-generator`},dependencies:{"@kosmojs/core":`workspace:^`,"@kosmojs/lib":`workspace:^`,"@vitejs/plugin-vue":`^6.0.8`},devDependencies:{"@tanstack/vue-query":`^5.102.2`,vue:`^3.5.41`,"vue-router":`^5.2.0`}},Q=e=>{let t=e=>e.kind===`splat`?`:${e.name}(.*)?`:e.kind===`optional`?`:${e.name}?`:`:${e.name}`;return e.flatMap(e=>e.kind===`static`?[e.parts[0].value]:e.kind===`param`?[t(e.parts[0])]:[e.parts.map(e=>e.type===`static`?e.value:t(e)).join(``)]).join(`/`)},mi=()=>{let e=e=>e?.kind===`param`&&e.parts[0]?.kind===`splat`,n=(r,i)=>r.flatMap(({index:r,layout:a,children:o})=>{let{name:s,pathTokens:c}={...r,...a};if(!c)return[];let l=`${s}/layout`,u=i?Q(c):t(`/`,Q(c)),d=c.at(-1);return e(d)?r&&a?[{name:l,path:u,component:a.id,children:[{name:s,path:``,component:r.id}]}]:r?[{path:u,children:[{name:s,path:``,component:r.id},...n(o,s)]}]:a?[{name:l,path:u,component:a.id,children:n(o,s)}]:[]:r&&a?[{name:l,path:u,component:a.id,children:[{name:s,path:``,component:r.id},...n(o,s)]}]:r?[{path:u,children:[{name:s,path:``,component:r.id},...n(o,s)]}]:a?[{name:l,path:u,component:a.id,children:n(o,s)}]:[]});return n},hi=()=>{let e=[`🎉 Well done! You just created a new Vue route.`,`🚀 Success! A fresh Vue route is ready to roll.`,`🌟 Nice work! Another Vue route added to your app.`,`🧩 All set! A new Vue route has been scaffolded.`,`🔧 Scaffold complete! Your new Vue route is in place.`,`✅ Built! Your Vue route is scaffolded and ready.`,`✨ Fantastic! Your new Vue route is good to go.`,`🎯 Nailed it! A brand new Vue route just landed.`,`💫 Awesome! Another Vue route joins the party.`,`⚡ Lightning fast! A new Vue route created successfully.`];return e[Math.floor(Math.random()*e.length)]},gi=`import type { Plugin } from "vue";
8443
9145
 
8444
9146
  export { default as AppProvider } from "./provider.vue";
8445
9147
 
8446
9148
  export const appProvider: Plugin = {
8447
9149
  install() {},
8448
9150
  };
8449
- `,Kr=`import { VueQueryPlugin } from "@tanstack/vue-query";
9151
+ `,_i=`import { VueQueryPlugin } from "@tanstack/vue-query";
8450
9152
  import type { Plugin } from "vue";
8451
9153
 
8452
9154
  import { getQueryClient } from "../query";
@@ -8458,10 +9160,10 @@ export const appProvider: Plugin = {
8458
9160
  app.use(VueQueryPlugin, { queryClient: getQueryClient() });
8459
9161
  },
8460
9162
  };
8461
- `,$=`<template>
9163
+ `,vi=`<template>
8462
9164
  <slot />
8463
9165
  </template>
8464
- `,qr=`import type { App } from "vue";
9166
+ `,yi=`import type { App } from "vue";
8465
9167
  import type { RouterFactoryReturn } from "@kosmojs/core";
8466
9168
  import { clientRenderFactory } from "@kosmojs/core/generators";
8467
9169
 
@@ -8501,7 +9203,7 @@ export const mount = async (
8501
9203
  }
8502
9204
 
8503
9205
  export default clientRenderFactory();
8504
- `,Jr=`{
9206
+ `,bi=`{
8505
9207
  path: "{{path}}",
8506
9208
  {{#if name}}
8507
9209
  name: "{{name}}",
@@ -8519,7 +9221,7 @@ export default clientRenderFactory();
8519
9221
  children: [ {{#each children}}{{> routePartial}}, {{/each}}],
8520
9222
  {{/if}}
8521
9223
  }
8522
- `,Yr=`import type { App } from "vue";
9224
+ `,$=`import type { App } from "vue";
8523
9225
 
8524
9226
  import {
8525
9227
  renderToString as renderToStringOrig,
@@ -8610,12 +9312,18 @@ export const renderToStream: RenderToStreamWrapper<
8610
9312
  }
8611
9313
 
8612
9314
  export default serverRenderFactory();
8613
- `,Xr=`declare module "*.vue" {
9315
+ `,xi=`declare module "*.vue" {
8614
9316
  import type { DefineComponent } from "vue";
8615
9317
  const component: DefineComponent<{}, {}, any>;
8616
9318
  export default component;
8617
9319
  }
8618
- `,Zr=`<script setup lang="ts">
9320
+
9321
+ declare module "virtual:kosmo/tsq-client" {
9322
+ import type { QueryClient, QueryClientConfig } from "@tanstack/vue-query";
9323
+ export const createQueryClient: (options?: QueryClientConfig) => QueryClient;
9324
+ export const getQueryClient: () => QueryClient;
9325
+ }
9326
+ `,Si=`<script setup lang="ts">
8619
9327
  import styles from "./styles.module.css";
8620
9328
  defineProps<{
8621
9329
  headline?: string;
@@ -8654,7 +9362,7 @@ defineProps<{
8654
9362
  </div>
8655
9363
  </div>
8656
9364
  </template>
8657
- `,Qr=`<script setup lang="ts">
9365
+ `,Ci=`<script setup lang="ts">
8658
9366
  import styles from "./styles.module.css";
8659
9367
  defineProps<{
8660
9368
  message: string;
@@ -8703,7 +9411,7 @@ defineProps<{
8703
9411
  </div>
8704
9412
  </div>
8705
9413
  </template>
8706
- `,$r=`* {
9414
+ `,wi=`* {
8707
9415
  margin: 0;
8708
9416
  padding: 0;
8709
9417
  box-sizing: border-box;
@@ -8836,7 +9544,7 @@ defineProps<{
8836
9544
  align-items: center;
8837
9545
  gap: 0.25rem;
8838
9546
  }
8839
- `,ei=`<script setup lang="ts">
9547
+ `,Ti=`<script setup lang="ts">
8840
9548
  import styles from "./styles.module.css";
8841
9549
  <\/script>
8842
9550
 
@@ -8900,26 +9608,27 @@ import styles from "./styles.module.css";
8900
9608
  </div>
8901
9609
  </div>
8902
9610
  </template>
8903
- `,ti=`import { QueryClient, type QueryClientConfig } from "@tanstack/vue-query";
9611
+ `,Ei=`export * from "virtual:kosmo/tsq-client";
9612
+ `,Di=`import { QueryClient } from "@tanstack/vue-query";
8904
9613
 
8905
- let client: QueryClient | undefined;
9614
+ let client = undefined
8906
9615
 
8907
- export const createQueryClient = (options?: QueryClientConfig): QueryClient => {
9616
+ export const createQueryClient = (options) => {
8908
9617
  client = new QueryClient(options);
8909
9618
  return client;
8910
9619
  };
8911
9620
 
8912
- export const getQueryClient = (): QueryClient => {
9621
+ export const getQueryClient = () => {
8913
9622
  if (!client) {
8914
9623
  client = new QueryClient();
8915
9624
  }
8916
9625
  return client;
8917
9626
  };
8918
- `,ni=`import { QueryClient, type QueryClientConfig } from "@tanstack/vue-query";
9627
+ `,Oi=`import { QueryClient } from "@tanstack/vue-query";
8919
9628
 
8920
- import { store } from "{{ createImport 'lib' '@ssr/base' }}";
9629
+ import { store } from "{{ createImport 'libCore' 'ssr' }}";
8921
9630
 
8922
- export const createQueryClient = (options?: QueryClientConfig): QueryClient => {
9631
+ export const createQueryClient = (options) => {
8923
9632
  const client = new QueryClient(options);
8924
9633
  const ctx = store?.getStore();
8925
9634
  if (ctx) {
@@ -8928,7 +9637,7 @@ export const createQueryClient = (options?: QueryClientConfig): QueryClient => {
8928
9637
  return client;
8929
9638
  };
8930
9639
 
8931
- export const getQueryClient = (): QueryClient => {
9640
+ export const getQueryClient = () => {
8932
9641
  const ctx = store?.getStore();
8933
9642
  if (!ctx) {
8934
9643
  throw new Error("getQueryClient(): called outside an SSR request scope");
@@ -8936,9 +9645,9 @@ export const getQueryClient = (): QueryClient => {
8936
9645
  if (!ctx.tsqClient) {
8937
9646
  ctx.tsqClient = new QueryClient();
8938
9647
  }
8939
- return ctx.tsqClient as QueryClient;
9648
+ return ctx.tsqClient;
8940
9649
  };
8941
- `,ri=`import {
9650
+ `,ki=`import {
8942
9651
  type App,
8943
9652
  type Component,
8944
9653
  createApp,
@@ -9100,14 +9809,14 @@ export default createRouterFactory<
9100
9809
  Promise<App>,
9101
9810
  { server: { loaderData: Record<string, unknown> } }
9102
9811
  >();
9103
- `,ii=`import { type Ref, unref } from "vue";
9812
+ `,Ai=`import { type Ref, unref } from "vue";
9104
9813
 
9105
9814
  export type MaybeWrapped<T> = Ref<T> | T;
9106
9815
 
9107
9816
  export function unwrap<T>(value: MaybeWrapped<T>): T {
9108
9817
  return unref(value);
9109
9818
  }
9110
- `,ai=`import { useRoute, useRouter } from "vue-router";
9819
+ `,ji=`import { useRoute, useRouter } from "vue-router";
9111
9820
 
9112
9821
  import type { RouterWithLoaderData } from "./router";
9113
9822
 
@@ -9122,7 +9831,7 @@ export const useLoaderData = <T>(key?: string): T | undefined => {
9122
9831
  const route = useRoute();
9123
9832
  return router.__loaderData?.[key || (route.name as string)] as T;
9124
9833
  };
9125
- `,oi=`<script setup lang="ts">
9834
+ `,Mi=`<script setup lang="ts">
9126
9835
  import { AppProvider } from "_/app";
9127
9836
  <\/script>
9128
9837
 
@@ -9131,7 +9840,7 @@ import { AppProvider } from "_/app";
9131
9840
  <RouterView />
9132
9841
  </AppProvider>
9133
9842
  </template>
9134
- `,si=`<script setup lang="ts" generic="T extends LinkProps">
9843
+ `,Ni=`<script setup lang="ts" generic="T extends LinkProps">
9135
9844
  import { computed } from "vue";
9136
9845
  import { RouterLink } from "vue-router";
9137
9846
 
@@ -9164,7 +9873,7 @@ const linkProps = computed(() => ({
9164
9873
  <slot />
9165
9874
  </RouterLink>
9166
9875
  </template>
9167
- `,ci=`import renderFactory, {
9876
+ `,Pi=`import renderFactory, {
9168
9877
  createRoutes,
9169
9878
  hydrate,
9170
9879
  mount,
@@ -9191,7 +9900,7 @@ if (root) {
9191
9900
  } else {
9192
9901
  console.error("❌ Root element not found!");
9193
9902
  }
9194
- `,li=`import renderFactory, {
9903
+ `,Fi=`import renderFactory, {
9195
9904
  createRoutes,
9196
9905
  renderToStream,
9197
9906
  renderToString,
@@ -9218,17 +9927,17 @@ export default renderFactory(() => {
9218
9927
  },
9219
9928
  };
9220
9929
  });
9221
- `,ui=`<script setup lang="ts">
9930
+ `,Ii=`<script setup lang="ts">
9222
9931
  import PageSample from "{{ createImport 'lib' 'pageSamples/404.vue' }}";
9223
9932
  <\/script>
9224
9933
 
9225
9934
  <template>
9226
9935
  <PageSample />
9227
9936
  </template>
9228
- `,di=`<template>
9937
+ `,Li=`<template>
9229
9938
  <router-view />
9230
9939
  </template>
9231
- `,fi=`<script setup lang="ts">
9940
+ `,Ri=`<script setup lang="ts">
9232
9941
  import PageSample from "{{ createImport 'lib' 'pageSamples/page.vue' }}";
9233
9942
  <\/script>
9234
9943
 
@@ -9243,14 +9952,14 @@ import PageSample from "{{ createImport 'lib' 'pageSamples/page.vue' }}";
9243
9952
  }"
9244
9953
  />
9245
9954
  </template>
9246
- `,pi=`<script setup lang="ts">
9955
+ `,zi=`<script setup lang="ts">
9247
9956
  import WelcomePage from "{{ createImport 'lib' 'pageSamples/welcome.vue' }}";
9248
9957
  <\/script>
9249
9958
 
9250
9959
  <template>
9251
9960
  <WelcomePage />
9252
9961
  </template>
9253
- `,mi=`import routerFactory, { createRouters } from "{{ createImport 'lib' 'router' }}";
9962
+ `,Bi=`import routerFactory, { createRouters } from "{{ createImport 'lib' 'router' }}";
9254
9963
  import { appProvider } from "{{ createImport 'lib' 'app' }}";
9255
9964
 
9256
9965
  import app from "./app.vue";
@@ -9269,5 +9978,5 @@ export default routerFactory((routes) => {
9269
9978
  },
9270
9979
  };
9271
9980
  });
9272
- `,hi=g((e,t)=>{let{createPath:n,createImportHelpers:r}=y(e),{renderToFile:i}=x({helpers:{...r({origin:`lib`}),...w()},partials:{routePartial:Jr}}),{renderToFile:a}=x({helpers:r({origin:`src`})}),o=Ur(),s=e=>!e?.trim().length,u=c(t?.templates,fi),d=async e=>{for(let{kind:t,entry:r}of e)t===`pageRoute`?await a(n.pages(r.file),r.name===`index`?pi:u(r.name,r),{route:r,message:Wr()},{overwrite:s}):t===`pageLayout`&&await a(n.pages(r.file),di,{route:r},{overwrite:s})},f=async e=>{let t=e.flatMap(({kind:e,entry:t})=>e===`pageRoute`?[t]:[]).sort(S),r=e.flatMap(({kind:e,entry:t})=>e===`pageRoute`||e===`pageLayout`?[t]:[]),a=o(v(r));for(let[e,t]of[[`client.ts`,qr],[`server.ts`,Yr]])await i(n.libEntry(e),t,{pageEntries:r,nestedRoutes:a,lazyLoad:e===`client.ts`});await i(n.lib(`router.ts`),ri,{entries:e,indexRoutes:t})};return{config(){let{templates:e,...n}={...t};return{plugins:[A(n)]}},async start(){for(let[e,r]of[[`env.d.ts`,Xr],[`unwrap.ts`,ii],[`use.ts`,ai],[`pageSamples/styles.module.css`,$r],[`pageSamples/welcome.vue`,ei],[`pageSamples/page.vue`,Qr],[`pageSamples/404.vue`,Zr],[`app/provider.vue`,$],...t?.tanstack?.query?[[`app/index.ts`,Kr],[`query.ts`,ti]]:[[`app/index.ts`,Gr],[`query.ts`,`/** tanstack query disabled */`]]])await i(n.lib(e),r,{});for(let[e,t]of[[`pages/404.vue`,ui],[`components/Link.vue`,si],[`app.vue`,oi],[`router.ts`,mi]])await a(n.src(e),t,{entryDir:l.entryDir},{overwrite:s});for(let[e,t]of[[`client.ts`,ci],[`server.ts`,li]])await a(n.entry(e),t,{},{overwrite:s})},async watch(e,t){await d(e.filter(m(t,[`create`]))),await f(e)},async build(e){await d(e),await f(e)},async ssrBuild(){await i(n.lib(`query.ts`),t?.tanstack?.query?ni:`/** tanstack query disabled */`,{ssrBundle:!0})}}}),gi=h({meta:{name:`Vue`,slot:`frontend`,jsxImportSource:`vue`},dependencies(e){return{vue:Z.devDependencies.vue,"vue-router":Z.devDependencies[`vue-router`],"path-to-regexp":Z.devDependencies[`path-to-regexp`],...e?.tanstack?.query?{"@tanstack/vue-query":Z.devDependencies[`@tanstack/vue-query`]}:{}}},factory:hi}),_i=e=>{let n=process.env.NODE_ENV||`development`,a=typeof e.base==`string`?e.base:e.base[n];if(!a?.trim())throw Error(r([`red`],`ERROR: Invalid Config - no base provided`));return{...e,base:t(`/`,a),apiBase:t(`/`,e.apiBase||i)}};export{e as coreGenerator,_i as defineConfig,L as fetchGenerator,Ae as h3Generator,Ye as honoGenerator,mt as koaGenerator,Ht as mdxGenerator,qt as openapiGenerator,xn as reactGenerator,Jn as solidGenerator,Zn as ssgGenerator,or as ssrGenerator,Nr as svelteGenerator,Hr as typeboxGenerator,gi as vueGenerator};
9981
+ `,Vi=v((e,t)=>{let{createPath:n,createImportHelpers:r}=S(e),{render:i,renderToFile:a}=w({helpers:{...r({origin:`lib`}),...A()},partials:{routePartial:bi}}),{renderToFile:o}=w({helpers:r({origin:`src`})}),s=mi(),c=e=>!e?.trim().length,d=l(t?.templates,Ri),f=async e=>{for(let{kind:t,entry:r}of e)t===`pageRoute`?await o(n.pages(r.file),r.name===`index`?zi:d(r.name,r),{route:r,message:hi()},{overwrite:c}):t===`pageLayout`&&await o(n.pages(r.file),Li,{route:r},{overwrite:c})},p=async e=>{let t=e.flatMap(({kind:e,entry:t})=>e===`pageRoute`?[t]:[]).sort(E),r=e.flatMap(({kind:e,entry:t})=>e===`pageRoute`||e===`pageLayout`?[t]:[]),i=s(b(r));for(let[e,t]of[[`client.ts`,yi],[`server.ts`,$]])await a(n.libEntry(e),t,{pageEntries:r,nestedRoutes:i,lazyLoad:e===`client.ts`});await a(n.lib(`router.ts`),ki,{entries:e,indexRoutes:t})};return{config(){let{templates:e,...n}={...t};return{plugins:[pe(n)]}},async start(){for(let[e,r]of[[`env.d.ts`,xi],[`unwrap.ts`,Ai],[`use.ts`,ji],[`pageSamples/styles.module.css`,wi],[`pageSamples/welcome.vue`,Ti],[`pageSamples/page.vue`,Ci],[`pageSamples/404.vue`,Si],[`app/provider.vue`,vi],...t?.tanstack?.query?[[`app/index.ts`,_i],[`query.ts`,Ei]]:[[`app/index.ts`,gi],[`query.ts`,`/** tanstack query disabled */`]]])await a(n.lib(e),r,{});for(let[e,t]of[[`pages/404.vue`,Ii],[`components/Link.vue`,Ni],[`app.vue`,Mi],[`router.ts`,Bi]])await o(n.src(e),t,{entryDir:u.entryDir},{overwrite:c});for(let[e,t]of[[`client.ts`,Pi],[`server.ts`,Fi]])await o(n.entry(e),t,{},{overwrite:c})},async watch(e,t){await f(e.filter(g(t,[`create`]))),await p(e)},async build(e){await f(e),await p(e)},virtualModules(){return t?.tanstack?.query?[{specifier:`virtual:kosmo/tsq-client`,csr:i(Di,{}),ssr:i(Oi,{})}]:[]}}}),Hi=_({meta:{name:`Vue`,slot:`frontend`,jsxImportSource:`vue`},dependencies(e){return{vue:Z.devDependencies.vue,"vue-router":Z.devDependencies[`vue-router`],...e?.tanstack?.query?{"@tanstack/vue-query":Z.devDependencies[`@tanstack/vue-query`]}:{}}},factory:Vi}),Ui=e=>{let n=process.env.NODE_ENV||`development`,r=typeof e.base==`string`?e.base:e.base[n];if(!r?.trim())throw Error(i([`red`],`ERROR: Invalid Config - no base provided`));return{...e,base:t(`/`,r),apiBase:t(`/`,e.apiBase||a),generators:Wi(e)}},Wi=e=>{let t=[],n={};for(let r of e.generators||[])r.meta.slot?n[r.meta.slot]=r:t.push(r);return[B(),...n.backend?[n.backend]:[],...n.fetch&&n.backend?[n.fetch]:[],...n.frontend?[n.frontend]:[],...t,...n.ssr?[n.ssr]:[],...n.ssg?[n.ssg]:[]]};export{B as coreGenerator,Ui as defineConfig,Ae as fetchGenerator,Ze as h3Generator,_t as honoGenerator,Lt as koaGenerator,un as mdxGenerator,hn as openapiGenerator,Wn as reactGenerator,yr as solidGenerator,wr as ssgGenerator,Ar as ssrGenerator,ii as svelteGenerator,pi as typeboxGenerator,Hi as vueGenerator};
9273
9982
  //# sourceMappingURL=index.js.map