@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/package.json +4 -3
- package/pkg/chassis.js +308 -1
- package/pkg/chassis.js.map +1 -1
- package/pkg/index.d.ts +2 -1
- package/pkg/index.js +1430 -721
- package/pkg/index.js.map +1 -1
- package/pkg/preview.d.ts +15 -0
- package/pkg/runner.d.ts +22 -0
- package/pkg/templates/run.d.ts +29 -0
- package/pkg/assets/pkg-dTglxmYm.js +0 -523
- package/pkg/assets/pkg-dTglxmYm.js.map +0 -1
package/pkg/index.js
CHANGED
|
@@ -1,6 +1,588 @@
|
|
|
1
|
-
import{
|
|
2
|
-
|
|
3
|
-
`,
|
|
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
|
-
`,
|
|
603
|
+
`,Ee=`import fetchFactory, { join } from "@kosmojs/core/fetch";
|
|
22
604
|
|
|
23
605
|
import { base, apiBase, apiRouteMap } from "{{ createImport 'libCore' }}";
|
|
24
|
-
import { transport } from "
|
|
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}}
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
|
|
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
|
-
`,
|
|
1008
|
+
`,Ne=`import type { DevSetup } from "@kosmojs/core/api";
|
|
227
1009
|
|
|
228
1010
|
export const devSetup = (setup: DevSetup) => setup;
|
|
229
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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 (
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
1745
|
+
`,He=`import { onError } from "h3";
|
|
940
1746
|
|
|
941
|
-
import appFactory, { routes
|
|
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
|
-
})
|
|
947
|
-
`,
|
|
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
|
-
`,
|
|
1773
|
+
`,We=`export declare module "{{ createImport 'libApi' }}" {
|
|
968
1774
|
interface DefaultContext {}
|
|
969
1775
|
}
|
|
970
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
1818
|
+
`,Je=`import { serve } from "{{ createImport 'lib' 'api:factory' }}";
|
|
1013
1819
|
import app from "./app";
|
|
1014
1820
|
|
|
1015
1821
|
await serve(app);
|
|
1016
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
|
|
1935
|
+
`,$e=`import type { DevSetup } from "@kosmojs/core/api";
|
|
1130
1936
|
|
|
1131
1937
|
export const devSetup = (setup: DevSetup) => setup;
|
|
1132
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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 (
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
2757
|
+
`,ut=`export declare module "{{ createImport 'libApi' }}" {
|
|
1929
2758
|
interface DefaultVariables {}
|
|
1930
2759
|
interface DefaultBindings {}
|
|
1931
2760
|
}
|
|
1932
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
2813
|
+
`,mt=`import { serve } from "{{ createImport 'lib' 'api:factory' }}";
|
|
1985
2814
|
import app from "./app";
|
|
1986
2815
|
|
|
1987
2816
|
await serve(app);
|
|
1988
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
2927
|
+
`,yt=`import type { DevSetup } from "@kosmojs/core/api";
|
|
2099
2928
|
|
|
2100
2929
|
export const devSetup = (setup: DevSetup) => setup;
|
|
2101
|
-
`,
|
|
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
|
-
|
|
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
|
-
`,
|
|
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 (
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
3868
|
+
`,At=`export declare module "{{ createImport 'libApi' }}" {
|
|
3017
3869
|
interface DefaultState {}
|
|
3018
3870
|
interface DefaultContext {}
|
|
3019
3871
|
}
|
|
3020
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
3915
|
+
`,Pt=`import { serve } from "{{ createImport 'lib' 'api:factory' }}";
|
|
3064
3916
|
import app from "./app";
|
|
3065
3917
|
|
|
3066
3918
|
await serve(app);
|
|
3067
|
-
`,
|
|
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
|
-
`,
|
|
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=[
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
4654
|
+
`,Qt=`import { AppProvider } from "{{ createImport 'lib' 'app' }}";
|
|
3882
4655
|
|
|
3883
4656
|
<AppProvider>{props.children}</AppProvider>
|
|
3884
|
-
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
3978
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
5253
|
+
`,kn=`export * from "virtual:kosmo/tsq-client";
|
|
5254
|
+
`,An=`import { QueryClient } from "@tanstack/react-query";
|
|
4476
5255
|
|
|
4477
|
-
let client
|
|
5256
|
+
let client = undefined;
|
|
4478
5257
|
|
|
4479
|
-
export const createQueryClient = (options
|
|
5258
|
+
export const createQueryClient = (options) => {
|
|
4480
5259
|
client = new QueryClient(options);
|
|
4481
5260
|
return client;
|
|
4482
5261
|
};
|
|
4483
5262
|
|
|
4484
|
-
export const getQueryClient = ()
|
|
5263
|
+
export const getQueryClient = () => {
|
|
4485
5264
|
if (!client) {
|
|
4486
5265
|
client = new QueryClient();
|
|
4487
5266
|
}
|
|
4488
5267
|
return client;
|
|
4489
5268
|
};
|
|
4490
|
-
`,
|
|
5269
|
+
`,jn=`import { QueryClient } from "@tanstack/react-query";
|
|
4491
5270
|
|
|
4492
|
-
import { store } from "{{ createImport '
|
|
5271
|
+
import { store } from "{{ createImport 'libCore' 'ssr' }}";
|
|
4493
5272
|
|
|
4494
|
-
export const createQueryClient = (options
|
|
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 = ()
|
|
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
|
|
5290
|
+
return ctx.tsqClient;
|
|
4512
5291
|
};
|
|
4513
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
5467
|
+
`,zn=`import { Outlet } from "react-router";
|
|
4689
5468
|
|
|
4690
5469
|
export default function Layout() {
|
|
4691
5470
|
return <Outlet />;
|
|
4692
5471
|
}
|
|
4693
|
-
`,
|
|
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
|
-
`,
|
|
4707
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
5986
|
+
`,rr=`export * from "virtual:kosmo/tsq-client";
|
|
5987
|
+
`,ir=`import { QueryClient } from "@tanstack/solid-query";
|
|
5170
5988
|
|
|
5171
|
-
let client
|
|
5989
|
+
let client = undefined;
|
|
5172
5990
|
|
|
5173
|
-
export const createQueryClient = (options
|
|
5991
|
+
export const createQueryClient = (options) => {
|
|
5174
5992
|
client = new QueryClient(options);
|
|
5175
5993
|
return client;
|
|
5176
5994
|
};
|
|
5177
5995
|
|
|
5178
|
-
export const getQueryClient = ()
|
|
5996
|
+
export const getQueryClient = () => {
|
|
5179
5997
|
if (!client) {
|
|
5180
5998
|
client = new QueryClient();
|
|
5181
5999
|
}
|
|
5182
6000
|
return client;
|
|
5183
6001
|
};
|
|
5184
|
-
`,
|
|
6002
|
+
`,ar=`import { QueryClient } from "@tanstack/solid-query";
|
|
5185
6003
|
|
|
5186
|
-
import { store } from "{{ createImport '
|
|
6004
|
+
import { store } from "{{ createImport 'libCore' 'ssr' }}";
|
|
5187
6005
|
|
|
5188
|
-
export const createQueryClient = (options
|
|
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 = ()
|
|
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
|
|
6023
|
+
return ctx.tsqClient;
|
|
5206
6024
|
};
|
|
5207
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
6076
|
+
`,cr=`export type MaybeWrapped<T> = import("solid-js/store").Store<T> | T;
|
|
5259
6077
|
|
|
5260
6078
|
export { unwrap } from "solid-js/store";
|
|
5261
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
5374
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
|
|
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
|
-
|
|
5579
|
-
|
|
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
|
-
|
|
6216
|
+
type StaticParams = Array<Array<string | number | Array<string | number>>>;
|
|
5585
6217
|
|
|
5586
|
-
|
|
5587
|
-
|
|
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
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
|
|
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
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
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
|
|
6267
|
+
const toPath = compile(pathPattern);
|
|
5605
6268
|
|
|
5606
|
-
|
|
5607
|
-
? async (input: RequestInfo | URL, init?: RequestInit) => {
|
|
6269
|
+
return staticParams.flatMap((entry) => {
|
|
5608
6270
|
try {
|
|
5609
|
-
|
|
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
|
-
|
|
5624
|
-
|
|
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
|
-
|
|
6277
|
+
});
|
|
6278
|
+
})
|
|
6279
|
+
.map((path) => join(base, path));
|
|
6280
|
+
`,xr=`import type { PageRoute } from "@kosmojs/core";
|
|
5635
6281
|
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
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
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
}
|
|
5660
|
-
|
|
5661
|
-
|
|
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
|
-
`,
|
|
6325
|
+
`,Er=`export const routeMap = [
|
|
5664
6326
|
{{#each pageRoutes}}
|
|
5665
6327
|
{ pathPattern: "{{honoPattern}}", renderMode: "{{renderMode}}" },
|
|
5666
6328
|
{{/each}}
|
|
5667
6329
|
];
|
|
5668
|
-
`,
|
|
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 {
|
|
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
|
|
5685
|
-
|
|
5686
|
-
|
|
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
|
-
|
|
5818
|
-
|
|
5819
|
-
|
|
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
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
5850
|
-
|
|
5851
|
-
|
|
5852
|
-
|
|
5853
|
-
|
|
5854
|
-
|
|
5855
|
-
|
|
5856
|
-
|
|
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
|
|
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
|
|
5947
|
-
|
|
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
|
-
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
|
|
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(
|
|
6677
|
+
assetCache.set(join(prefix, file), {
|
|
5963
6678
|
file,
|
|
5964
6679
|
buffer,
|
|
5965
6680
|
contentType: contentTypeResolver(file),
|
|
5966
|
-
size: buffer
|
|
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
|
|
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
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
7253
|
+
`,Hr=`export * from "virtual:kosmo/tsq-client";
|
|
7254
|
+
`,Ur=`import { QueryClient } from "@tanstack/svelte-query";
|
|
6543
7255
|
|
|
6544
|
-
let client
|
|
7256
|
+
let client = undefined;
|
|
6545
7257
|
|
|
6546
|
-
export const createQueryClient = (options
|
|
7258
|
+
export const createQueryClient = (options) => {
|
|
6547
7259
|
client = new QueryClient(options);
|
|
6548
7260
|
return client;
|
|
6549
7261
|
};
|
|
6550
7262
|
|
|
6551
|
-
export const getQueryClient = ()
|
|
7263
|
+
export const getQueryClient = () => {
|
|
6552
7264
|
if (!client) {
|
|
6553
7265
|
client = new QueryClient();
|
|
6554
7266
|
}
|
|
6555
7267
|
return client;
|
|
6556
7268
|
};
|
|
6557
|
-
`,
|
|
7269
|
+
`,Wr=`import { QueryClient } from "@tanstack/svelte-query";
|
|
6558
7270
|
|
|
6559
|
-
import { store } from "{{ createImport '
|
|
7271
|
+
import { store } from "{{ createImport 'libCore' 'ssr' }}";
|
|
6560
7272
|
|
|
6561
|
-
export const createQueryClient = (options
|
|
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 = ()
|
|
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
|
|
7290
|
+
return ctx.tsqClient;
|
|
6579
7291
|
};
|
|
6580
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
|
|
6740
|
-
|
|
6741
|
-
|
|
6742
|
-
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
7671
|
+
`,Qr=`<script lang="ts">
|
|
6970
7672
|
import PageSample from "{{ createImport 'lib' 'pageSamples/404.svelte' }}";
|
|
6971
7673
|
<\/script>
|
|
6972
7674
|
|
|
6973
7675
|
<PageSample />
|
|
6974
|
-
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
|
|
9163
|
+
`,vi=`<template>
|
|
8462
9164
|
<slot />
|
|
8463
9165
|
</template>
|
|
8464
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
|
|
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
|
-
`,
|
|
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
|
-
|
|
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
|
-
`,
|
|
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
|
-
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
9611
|
+
`,Ei=`export * from "virtual:kosmo/tsq-client";
|
|
9612
|
+
`,Di=`import { QueryClient } from "@tanstack/vue-query";
|
|
8904
9613
|
|
|
8905
|
-
let client
|
|
9614
|
+
let client = undefined
|
|
8906
9615
|
|
|
8907
|
-
export const createQueryClient = (options
|
|
9616
|
+
export const createQueryClient = (options) => {
|
|
8908
9617
|
client = new QueryClient(options);
|
|
8909
9618
|
return client;
|
|
8910
9619
|
};
|
|
8911
9620
|
|
|
8912
|
-
export const getQueryClient = ()
|
|
9621
|
+
export const getQueryClient = () => {
|
|
8913
9622
|
if (!client) {
|
|
8914
9623
|
client = new QueryClient();
|
|
8915
9624
|
}
|
|
8916
9625
|
return client;
|
|
8917
9626
|
};
|
|
8918
|
-
`,
|
|
9627
|
+
`,Oi=`import { QueryClient } from "@tanstack/vue-query";
|
|
8919
9628
|
|
|
8920
|
-
import { store } from "{{ createImport '
|
|
9629
|
+
import { store } from "{{ createImport 'libCore' 'ssr' }}";
|
|
8921
9630
|
|
|
8922
|
-
export const createQueryClient = (options
|
|
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 = ()
|
|
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
|
|
9648
|
+
return ctx.tsqClient;
|
|
8940
9649
|
};
|
|
8941
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
9937
|
+
`,Li=`<template>
|
|
9229
9938
|
<router-view />
|
|
9230
9939
|
</template>
|
|
9231
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|