@kosmojs/dev 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +11 -10
- package/pkg/assets/pkg-BhfEyKpY.js +490 -0
- package/pkg/assets/pkg-BhfEyKpY.js.map +1 -0
- package/pkg/chassis.js +1 -309
- package/pkg/chassis.js.map +1 -1
- package/pkg/index.d.ts +2 -0
- package/pkg/index.js +1382 -719
- package/pkg/index.js.map +1 -1
package/pkg/index.js
CHANGED
|
@@ -1,120 +1,6 @@
|
|
|
1
|
-
import{join as
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
type ApiRouteSerialized,
|
|
5
|
-
stringifySearchParams,
|
|
6
|
-
type ValidationTarget,
|
|
7
|
-
} from "@kosmojs/core";
|
|
8
|
-
import type { HTTPMethod } from "@kosmojs/core/api";
|
|
9
|
-
import { createHost, type HostOpt, join } from "@kosmojs/core/fetch";
|
|
10
|
-
|
|
11
|
-
export * from "./transport";
|
|
12
|
-
|
|
13
|
-
export const fetchHelpers = <ParamsT extends readonly unknown[]>(
|
|
14
|
-
basePath: string,
|
|
15
|
-
route: ApiRouteSerialized,
|
|
16
|
-
) => {
|
|
17
|
-
const toPath = compile(route.pathPattern);
|
|
18
|
-
|
|
19
|
-
const maybeNumber = (val: unknown) => {
|
|
20
|
-
if (val === undefined || val === null) {
|
|
21
|
-
return val;
|
|
22
|
-
}
|
|
23
|
-
const n = Number(val);
|
|
24
|
-
return Number.isFinite(n) ? n : val;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
const paramsMapper = (params: ParamsT, opt?: { coerceNumbers?: boolean }) => {
|
|
28
|
-
return route.params.reduce<Record<string, unknown>>((map, name, i) => {
|
|
29
|
-
const coerceNumbers = opt?.coerceNumbers
|
|
30
|
-
? route.numericProperties.params.includes(name)
|
|
31
|
-
: false;
|
|
32
|
-
if (Array.isArray(params[i])) {
|
|
33
|
-
map[name] = coerceNumbers
|
|
34
|
-
? params[i].map((v) => maybeNumber(v))
|
|
35
|
-
: params[i].map(String);
|
|
36
|
-
} else if (params[i] !== undefined) {
|
|
37
|
-
map[name] = coerceNumbers ? maybeNumber(params[i]) : String(params[i]);
|
|
38
|
-
}
|
|
39
|
-
return map;
|
|
40
|
-
}, {});
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const parametrize = (params: ParamsT) => {
|
|
44
|
-
try {
|
|
45
|
-
return toPath(paramsMapper(params) as never);
|
|
46
|
-
} catch (error) {
|
|
47
|
-
console.error(\`❗ERROR: Failed building path for \${route.name}\`);
|
|
48
|
-
throw error;
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
const base = (params: ParamsT, query?: Record<string, unknown>) => {
|
|
53
|
-
const path = join("/", parametrize(params));
|
|
54
|
-
return query ? [path, stringifySearchParams(query)].join("?") : path;
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
const path = (params: ParamsT, query?: Record<string, unknown>) => {
|
|
58
|
-
return join(basePath, base(params, query));
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
const href = (
|
|
62
|
-
host: HostOpt,
|
|
63
|
-
params: ParamsT,
|
|
64
|
-
query?: Record<string, unknown>,
|
|
65
|
-
) => {
|
|
66
|
-
return createHost(host) + path(params, query);
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
const payloadResolver = <T>(
|
|
70
|
-
payload: Record<ValidationTarget, T> | undefined,
|
|
71
|
-
target: ValidationTarget,
|
|
72
|
-
method: HTTPMethod,
|
|
73
|
-
) => {
|
|
74
|
-
const data = payload?.[target];
|
|
75
|
-
|
|
76
|
-
if (target === "query") {
|
|
77
|
-
return Object.fromEntries(
|
|
78
|
-
Object.entries({ ...data }).map(([k, v]) => {
|
|
79
|
-
return [
|
|
80
|
-
k,
|
|
81
|
-
route.numericProperties.query[method]?.includes(k)
|
|
82
|
-
? Array.isArray(v)
|
|
83
|
-
? v.map((v) => maybeNumber(v))
|
|
84
|
-
: maybeNumber(v)
|
|
85
|
-
: v,
|
|
86
|
-
];
|
|
87
|
-
}),
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (data instanceof FormData) {
|
|
92
|
-
return [...data].reduce<
|
|
93
|
-
Record<string, FormDataEntryValue | Array<FormDataEntryValue>>
|
|
94
|
-
>((map, [key, val]) => {
|
|
95
|
-
if (key in map) {
|
|
96
|
-
map[key] = [map[key]].flat().concat(val);
|
|
97
|
-
} else {
|
|
98
|
-
map[key] = val;
|
|
99
|
-
}
|
|
100
|
-
return map;
|
|
101
|
-
}, {}) as T;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return data;
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
return {
|
|
108
|
-
paramsMapper,
|
|
109
|
-
parametrize,
|
|
110
|
-
base,
|
|
111
|
-
path,
|
|
112
|
-
href,
|
|
113
|
-
payloadResolver,
|
|
114
|
-
};
|
|
115
|
-
};
|
|
116
|
-
`,k=`export const transport = undefined;
|
|
117
|
-
`,A=`{{#each routes}}
|
|
1
|
+
import{t as e}from"./assets/pkg-BhfEyKpY.js";import{join as t,resolve as n}from"node:path";import{styleText as r}from"node:util";import{DEFAULT_APIBASE as i,RequestBodyTargets as a,RequestValidationTargets as o,createRouteResolver as s,createTemplateResolver as c,defaults as l}from"@kosmojs/core";import{createH3Pattern as u,createHonoPattern as d,createPathPattern as f,createWatchedApiRouteEntriesFilter as p,createWatchedPageRouteEntriesFilter as m,defineGenerator as h,defineGeneratorFactory as g,mergeConfigs as _,nestedRoutesFactory as v,pathResolver as y,pathTokensFactory as b,renderFactory as x,renderToFile as ee,sortRoutes as S,spinnerFactory as te,vitePlugins as C}from"@kosmojs/lib";import{routeRenderHelpers as w}from"@kosmojs/core/generators";import T from"crc/crc32";import ne from"@mdx-js/rollup";import{build as E,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 D from"vite-plugin-solid";import{access as ce,constants as le,cp as O,mkdir as ue,rm as k,writeFile as de}from"node:fs/promises";import{svelte as fe}from"@sveltejs/vite-plugin-svelte";import pe from"@vitejs/plugin-vue";var A=`export * from "./transport";
|
|
2
|
+
`,j=`export const transport = undefined;
|
|
3
|
+
`,M=`{{#each routes}}
|
|
118
4
|
import {{id}} from "{{ createImport 'libApi' name 'fetch' }}";
|
|
119
5
|
{{/each}}
|
|
120
6
|
|
|
@@ -132,10 +18,10 @@ export default {
|
|
|
132
18
|
{{/each}}
|
|
133
19
|
{{/each}}
|
|
134
20
|
}
|
|
135
|
-
`,
|
|
21
|
+
`,N=`import fetchFactory, { join } from "@kosmojs/core/fetch";
|
|
136
22
|
|
|
137
23
|
import { base, apiBase, apiRouteMap } from "{{ createImport 'libCore' }}";
|
|
138
|
-
import { transport
|
|
24
|
+
import { transport } from "{{ createImport 'lib' '@fetch' }}";
|
|
139
25
|
|
|
140
26
|
import {
|
|
141
27
|
type MaybeWrapped,
|
|
@@ -175,10 +61,7 @@ const {
|
|
|
175
61
|
payloadResolver,
|
|
176
62
|
path,
|
|
177
63
|
href,
|
|
178
|
-
} =
|
|
179
|
-
apiBase,
|
|
180
|
-
apiRouteMap["{{route.name}}"],
|
|
181
|
-
);
|
|
64
|
+
} = apiRouteMap["{{route.name}}"];
|
|
182
65
|
|
|
183
66
|
const fetchApi = fetchFactory(
|
|
184
67
|
join(base, apiBase),
|
|
@@ -235,11 +118,858 @@ export default {
|
|
|
235
118
|
href,
|
|
236
119
|
validationSchemas,
|
|
237
120
|
};
|
|
238
|
-
`,
|
|
121
|
+
`,P=`export type MaybeWrapped<T> = T;
|
|
239
122
|
export const unwrap = <T>(data: T) => data;
|
|
240
|
-
`,
|
|
123
|
+
`,F=g(e=>{let{createPath:t,createImportHelpers:n}=y(e),{renderToFile:r}=x({helpers:{...n({origin:`lib`}),...w()}}),i=async(e,n)=>{let i=e.flatMap(({kind:e,entry:t})=>e===`apiRoute`?[t]:[]).sort(S);await r(t.lib(`fetch.ts`),M,{routes:i});for(let{kind:e,entry:i}of n)if(e===`apiRoute`){let e=[];for(let t of i.validationDefinitions)if(t.target===`response`)for(let{id:n,body:r,resolvedType:i}of t.variants)r&&e.push({id:n,target:t.target,method:t.method,resolvedType:i});else{let{id:n,resolvedType:r}=t.schema;e.push({id:n,target:t.target,method:t.method,resolvedType:r})}let n=i.methods.map(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)})),a=Object.values(e.reduce((e,{id:t,target:n,method:r,resolvedType:i})=>(n===`response`&&(e[r]||(e[r]={method:r,types:[]}),e[r].types.push({id:t,target:n,method:r,resolvedType:i})),e),{}));await r(t.libApi(i.name,`fetch.ts`),N,{route:i,validationTypes:e,routeMethods:n,responseTypes:a})}};return{async start(){for(let[e,n]of[[`unwrap.ts`,P],[`@fetch/transport.ts`,j],[`@fetch/index.ts`,A]])await r(t.lib(e),n,{})},async watch(e,t){await i(e,e.filter(p(t,[`create`,`update`])))},async build(e){await i(e,e)},async ssrBuild(){for(let[e,n]of[[`@fetch/transport.ts`,`export { transport } from "${l.libPrefix}/@ssr/fetch";`]])await r(t.lib(e),n,{})}}}),I=h({meta:{name:`Fetch`,slot:`fetch`},factory:F}),L={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`}},R=`import { H3, type Middleware } from "h3";
|
|
124
|
+
|
|
125
|
+
import type { Route, RouteDebugOption } from "@kosmojs/core/api";
|
|
126
|
+
|
|
127
|
+
export type App = H3;
|
|
128
|
+
|
|
129
|
+
export type AppOptions = ConstructorParameters<typeof H3>[0] & {
|
|
130
|
+
debug?: RouteDebugOption;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
export function appFactory(
|
|
134
|
+
routes: Array<Route<Middleware>>,
|
|
135
|
+
options: AppOptions,
|
|
136
|
+
): App;
|
|
137
|
+
|
|
138
|
+
export function appFactory(
|
|
139
|
+
routes: Array<Route<Middleware>>,
|
|
140
|
+
fn: (a: { app: App }) => void,
|
|
141
|
+
): App;
|
|
142
|
+
|
|
143
|
+
export function appFactory(
|
|
144
|
+
routes: Array<Route<Middleware>>,
|
|
145
|
+
options: AppOptions,
|
|
146
|
+
fn: (a: { app: App }) => void,
|
|
147
|
+
): App;
|
|
148
|
+
|
|
149
|
+
export function appFactory(
|
|
150
|
+
routes: Array<Route<Middleware>>,
|
|
151
|
+
...rest: Array<unknown>
|
|
152
|
+
): App {
|
|
153
|
+
const [options, fn] = typeof rest[0] === "function" ? [{}, rest[0]] : rest;
|
|
154
|
+
|
|
155
|
+
const { debug = undefined, ...appOptions } = {
|
|
156
|
+
...(options ? { ...options } : {}),
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const app = new H3(appOptions);
|
|
160
|
+
|
|
161
|
+
if (typeof fn === "function") {
|
|
162
|
+
fn({ app });
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
for (const route of routes) {
|
|
166
|
+
if (typeof debug === "function") {
|
|
167
|
+
(debug as Function)(route.debug, route);
|
|
168
|
+
} else if (debug) {
|
|
169
|
+
console.log(route.debug[typeof debug === "string" ? debug : "full"]);
|
|
170
|
+
}
|
|
171
|
+
for (const method of route.methods) {
|
|
172
|
+
// last middleware is the handler
|
|
173
|
+
const handler = route.middleware.at(-1);
|
|
174
|
+
if (handler) {
|
|
175
|
+
app.on(method, route.path, handler as never, {
|
|
176
|
+
middleware: route.middleware.slice(0, -1),
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return app;
|
|
183
|
+
}
|
|
184
|
+
`,z=`import type { DevSetup } from "@kosmojs/core/api";
|
|
185
|
+
|
|
186
|
+
export const devSetup = (setup: DevSetup) => setup;
|
|
187
|
+
`,B=`import { type H3Event, HTTPError } from "h3";
|
|
188
|
+
|
|
189
|
+
import { ValidationError } from "@kosmojs/core/errors";
|
|
190
|
+
|
|
191
|
+
type ErrorHandler = (
|
|
192
|
+
error: any,
|
|
193
|
+
event: H3Event,
|
|
194
|
+
) => Promise<Response> | Response;
|
|
195
|
+
|
|
196
|
+
export type ErrorHandlerFactory = (handler: ErrorHandler) => ErrorHandler;
|
|
197
|
+
|
|
198
|
+
export const errorHandlerFactory: ErrorHandlerFactory = (handler) => {
|
|
199
|
+
// H3 wraps errors in its own HTTPError with the original error as \`cause\`
|
|
200
|
+
return (error, event) => {
|
|
201
|
+
return handler(
|
|
202
|
+
error instanceof HTTPError
|
|
203
|
+
? error.cause instanceof ValidationError
|
|
204
|
+
? error.cause
|
|
205
|
+
: error
|
|
206
|
+
: error,
|
|
207
|
+
event,
|
|
208
|
+
);
|
|
209
|
+
};
|
|
210
|
+
};
|
|
211
|
+
`,me=`import { type H3Event, readBody } from "h3";
|
|
212
|
+
|
|
213
|
+
import {
|
|
214
|
+
parseCookies,
|
|
215
|
+
parseSearchParams,
|
|
216
|
+
type RequestBodyTarget,
|
|
217
|
+
type RequestMetadataTarget,
|
|
218
|
+
} from "@kosmojs/core";
|
|
219
|
+
|
|
220
|
+
export const metaparsers: {
|
|
221
|
+
[T in RequestMetadataTarget]: (event: H3Event) => unknown;
|
|
222
|
+
} = {
|
|
223
|
+
query(event) {
|
|
224
|
+
return parseSearchParams(event.url);
|
|
225
|
+
},
|
|
226
|
+
|
|
227
|
+
headers(event) {
|
|
228
|
+
return Object.fromEntries(event.req.headers);
|
|
229
|
+
},
|
|
230
|
+
|
|
231
|
+
cookies(event) {
|
|
232
|
+
return parseCookies(Object.fromEntries(event.req.headers));
|
|
233
|
+
},
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
export const bodyparsers: {
|
|
237
|
+
[T in RequestBodyTarget]: (event: H3Event) => Promise<unknown>;
|
|
238
|
+
} = {
|
|
239
|
+
json(event) {
|
|
240
|
+
return event.req.json();
|
|
241
|
+
},
|
|
242
|
+
|
|
243
|
+
form(event) {
|
|
244
|
+
return readBody(event, { type: "formData" });
|
|
245
|
+
},
|
|
246
|
+
|
|
247
|
+
raw(event) {
|
|
248
|
+
return event.req.text();
|
|
249
|
+
},
|
|
250
|
+
};
|
|
251
|
+
`,he=`import type { Middleware } from "h3";
|
|
252
|
+
|
|
253
|
+
import type {
|
|
254
|
+
RequestBodyTarget,
|
|
255
|
+
RequestMetadataTarget,
|
|
256
|
+
RequestValidationTarget,
|
|
257
|
+
ValidationErrorEntry,
|
|
258
|
+
} from "@kosmojs/core";
|
|
259
|
+
import {
|
|
260
|
+
type CreateRouteMiddleware,
|
|
261
|
+
createRoutes,
|
|
262
|
+
type HTTPMethod,
|
|
263
|
+
StateKey,
|
|
264
|
+
} from "@kosmojs/core/api";
|
|
265
|
+
import { ValidationError } from "@kosmojs/core/errors";
|
|
266
|
+
|
|
267
|
+
import {
|
|
268
|
+
type DefaultContext,
|
|
269
|
+
type ParameterizedEvent,
|
|
270
|
+
type ParameterizedMiddleware,
|
|
271
|
+
use,
|
|
272
|
+
} from "../api";
|
|
273
|
+
import { bodyparsers, metaparsers } from "./parsers";
|
|
274
|
+
import { routeSources } from "./routes";
|
|
275
|
+
|
|
276
|
+
import globalMiddleware from "{{ createImport 'api' 'use' }}";
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Create route-level middleware stack that handles:
|
|
280
|
+
* 1. Context extension - adds \`event.bodyparser\` (lazy, cached) and \`event.validated\` accessors
|
|
281
|
+
* 2. Params validation - normalizes and validates URL params (including splat/numeric params)
|
|
282
|
+
* 3. Request validation - validates query, headers, cookies, and body against schemas
|
|
283
|
+
* 4. Response validation - validates outgoing response against defined variants
|
|
284
|
+
*
|
|
285
|
+
* Middleware are assigned named slots (e.g. "validate:params", "validate:json")
|
|
286
|
+
* so they can be replaced by user-defined middleware in the stack.
|
|
287
|
+
*
|
|
288
|
+
* All validation errors are thrown as \`ValidationError\` instances,
|
|
289
|
+
* caught and formatted by the global error handler middleware upstream.
|
|
290
|
+
* */
|
|
291
|
+
export const createRouteMiddleware: CreateRouteMiddleware<
|
|
292
|
+
ParameterizedMiddleware
|
|
293
|
+
> = ({ name, validationSchemas, normalizeParams, normalizeSearchParams }) => {
|
|
294
|
+
const validationMiddleware = [
|
|
295
|
+
/**
|
|
296
|
+
* Extends H3 event with:
|
|
297
|
+
*
|
|
298
|
+
* - \`event.metaparser[target]()\` - lazy, cached meta parsers.
|
|
299
|
+
* Each parser (query, headers, cookies) runs at most once per request;
|
|
300
|
+
* subsequent calls return the cached result.
|
|
301
|
+
*
|
|
302
|
+
* - \`event.bodyparser[target](opts?)\` - lazy, cached body parsers.
|
|
303
|
+
* Each parser (json, form, raw) runs at most once per request;
|
|
304
|
+
* subsequent calls return the cached result.
|
|
305
|
+
* This allows both user middleware/handlers and validators
|
|
306
|
+
* to call the same parser without re-consuming the request stream.
|
|
307
|
+
*
|
|
308
|
+
* - \`event.validated\` - getter that returns all validated data collected so far
|
|
309
|
+
* (params, query, headers, cookies, json etc.) as a plain object.
|
|
310
|
+
*
|
|
311
|
+
* Cache is stored on \`event[StateKey]\` (a Symbol-keyed Map) to keep it
|
|
312
|
+
* hidden from public API surface and serialization.
|
|
313
|
+
* */
|
|
314
|
+
use(
|
|
315
|
+
function useExtendContext(event, next) {
|
|
316
|
+
if (!event[StateKey]) {
|
|
317
|
+
// initialize per-request cache with empty params
|
|
318
|
+
// (later populated by useValidateParams)
|
|
319
|
+
event[StateKey] = new Map([["params", {}]]);
|
|
320
|
+
|
|
321
|
+
Object.defineProperty(event, "metaparser", {
|
|
322
|
+
value: Object.entries(metaparsers).reduce<{
|
|
323
|
+
[T in RequestMetadataTarget]?: () => unknown;
|
|
324
|
+
}>((map, entry) => {
|
|
325
|
+
const [target, parser] = entry as [
|
|
326
|
+
RequestMetadataTarget,
|
|
327
|
+
Function,
|
|
328
|
+
];
|
|
329
|
+
map[target] = () => {
|
|
330
|
+
if (!event[StateKey].has(target)) {
|
|
331
|
+
event[StateKey].set(
|
|
332
|
+
target,
|
|
333
|
+
target === "query"
|
|
334
|
+
? normalizeSearchParams(
|
|
335
|
+
parser(event),
|
|
336
|
+
event.req.method as never,
|
|
337
|
+
)
|
|
338
|
+
: parser(event),
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
return event[StateKey].get(target);
|
|
342
|
+
};
|
|
343
|
+
return map;
|
|
344
|
+
}, {}),
|
|
345
|
+
enumerable: true,
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
Object.defineProperty(event, "bodyparser", {
|
|
349
|
+
value: Object.entries(bodyparsers).reduce<{
|
|
350
|
+
[T in RequestBodyTarget]?: () => Promise<unknown>;
|
|
351
|
+
}>((map, entry) => {
|
|
352
|
+
const [target, parser] = entry as [RequestBodyTarget, Function];
|
|
353
|
+
map[target] = async () => {
|
|
354
|
+
if (!event[StateKey].has(target)) {
|
|
355
|
+
event[StateKey].set(target, await parser(event));
|
|
356
|
+
}
|
|
357
|
+
return event[StateKey].get(target);
|
|
358
|
+
};
|
|
359
|
+
return map;
|
|
360
|
+
}, {}),
|
|
361
|
+
enumerable: true,
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
Object.defineProperty(event, "validated", {
|
|
365
|
+
get() {
|
|
366
|
+
return Object.fromEntries(event[StateKey]);
|
|
367
|
+
},
|
|
368
|
+
enumerable: true,
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
return next();
|
|
372
|
+
},
|
|
373
|
+
{ slot: "@extendContext" },
|
|
374
|
+
) as never,
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Normalize and validate URL params:
|
|
378
|
+
* - Splat params (e.g. \`/files{/*path}\`) are split into arrays by "/"
|
|
379
|
+
* - Numeric params are cast to Number (or array of Numbers for splat params)
|
|
380
|
+
* - Non-splat, non-numeric params pass through as strings
|
|
381
|
+
*
|
|
382
|
+
* Validated params are stored in the cache so \`event.validated.params\`
|
|
383
|
+
* reflects the normalized (and validated) values.
|
|
384
|
+
* */
|
|
385
|
+
use(
|
|
386
|
+
function useValidateParams(event, next) {
|
|
387
|
+
const normalizedParams = normalizeParams(event.url.pathname);
|
|
388
|
+
validationSchemas.params?.validate(normalizedParams);
|
|
389
|
+
event[StateKey].set("params", normalizedParams);
|
|
390
|
+
return next();
|
|
391
|
+
},
|
|
392
|
+
{ slot: "validate:params" },
|
|
393
|
+
) as never,
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Response validation - runs AFTER the handler (post-\`next()\`).
|
|
397
|
+
*
|
|
398
|
+
* Each response schema defines one or more variants, each with:
|
|
399
|
+
* - expected status code
|
|
400
|
+
* - optional content-type
|
|
401
|
+
* - optional body schema
|
|
402
|
+
*
|
|
403
|
+
* All variants are checked; if at least one passes, validation succeeds.
|
|
404
|
+
* If none pass, a ValidationError is thrown with collected errors from all variants.
|
|
405
|
+
*
|
|
406
|
+
* Activation rules:
|
|
407
|
+
* - In dev/test mode: runs unless \`runtimeValidation\` is explicitly \`false\`
|
|
408
|
+
* - In production: runs only if \`runtimeValidation\` is explicitly \`true\`
|
|
409
|
+
*
|
|
410
|
+
* Only attached to HTTP methods that have response schemas defined.
|
|
411
|
+
* */
|
|
412
|
+
use(
|
|
413
|
+
async function useValidateResponse(event, next) {
|
|
414
|
+
const variants = validationSchemas.response?.[event.req.method] || [];
|
|
415
|
+
|
|
416
|
+
if (!Array.isArray(variants) || !variants.length) {
|
|
417
|
+
return next();
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// options are same for all variants
|
|
421
|
+
const { runtimeValidation, customErrors } = variants[0];
|
|
422
|
+
|
|
423
|
+
if (KOSMO_PRODUCTION_BUILD) {
|
|
424
|
+
// skip if undefined or explicitly set to false
|
|
425
|
+
if (runtimeValidation === undefined || runtimeValidation === false) {
|
|
426
|
+
return next();
|
|
427
|
+
}
|
|
428
|
+
} else {
|
|
429
|
+
// skip only if explicitly set to false
|
|
430
|
+
if (runtimeValidation === false) {
|
|
431
|
+
return next();
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// run all downstream middleware (including the route handler)
|
|
436
|
+
const body = await next();
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* H3 builds the actual Response AFTER the middleware chain completes,
|
|
440
|
+
* so at this point event.res only reflects what handlers set explicitly.
|
|
441
|
+
* Reconstruct what will be sent instead: a returned Response is authoritative;
|
|
442
|
+
* otherwise an unset status means 200, and the content type follows H3's
|
|
443
|
+
* serialization rules for the returned value (string -> text, object -> JSON).
|
|
444
|
+
* */
|
|
445
|
+
const rawResponse = body instanceof Response ? body : undefined;
|
|
446
|
+
|
|
447
|
+
const response: {
|
|
448
|
+
status: number;
|
|
449
|
+
contentType: string | null;
|
|
450
|
+
body?: unknown;
|
|
451
|
+
} = {
|
|
452
|
+
status: rawResponse?.status ?? event.res.status ?? 200,
|
|
453
|
+
contentType:
|
|
454
|
+
rawResponse?.headers.get("Content-Type") ??
|
|
455
|
+
event.res.headers.get("Content-Type") ??
|
|
456
|
+
(typeof body === "string"
|
|
457
|
+
? "text/plain"
|
|
458
|
+
: body === undefined || body === null
|
|
459
|
+
? null
|
|
460
|
+
: "application/json"),
|
|
461
|
+
};
|
|
462
|
+
|
|
463
|
+
// Validate body only for JSON variants
|
|
464
|
+
if (variants.some((e) => e.contentType?.includes("json"))) {
|
|
465
|
+
response.body = rawResponse
|
|
466
|
+
? await rawResponse
|
|
467
|
+
.clone()
|
|
468
|
+
.json()
|
|
469
|
+
.catch(() => undefined)
|
|
470
|
+
: body;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Returns an array of validator functions for a single response variant.
|
|
475
|
+
* Each validator checks one aspect (status, content-type, body)
|
|
476
|
+
* and returns an error entry or undefined if the check passes.
|
|
477
|
+
* */
|
|
478
|
+
const variantValidators: (
|
|
479
|
+
v: (typeof variants)[number],
|
|
480
|
+
) => Array<(i: number) => ValidationErrorEntry | undefined> = (
|
|
481
|
+
schema,
|
|
482
|
+
) => {
|
|
483
|
+
return [
|
|
484
|
+
(i) => {
|
|
485
|
+
return schema.status === response.status
|
|
486
|
+
? undefined
|
|
487
|
+
: {
|
|
488
|
+
keyword: "Status",
|
|
489
|
+
path: \`Variant #\${i}\`,
|
|
490
|
+
message: \`expected: \${schema.status}; actual: \${response.status}\`,
|
|
491
|
+
};
|
|
492
|
+
},
|
|
493
|
+
(i) => {
|
|
494
|
+
if (
|
|
495
|
+
!schema.contentType ||
|
|
496
|
+
schema.contentType === response.contentType
|
|
497
|
+
) {
|
|
498
|
+
return undefined;
|
|
499
|
+
}
|
|
500
|
+
return {
|
|
501
|
+
keyword: "ContentType",
|
|
502
|
+
path: \`Variant #\${i}\`,
|
|
503
|
+
message: \`expected: \${schema.contentType}; actual: \${response.contentType}\`,
|
|
504
|
+
};
|
|
505
|
+
},
|
|
506
|
+
(i) => {
|
|
507
|
+
if (!schema.check || "body" in response === false) {
|
|
508
|
+
// no body schema or contentType is not JSON
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
return schema.check(response.body)
|
|
512
|
+
? undefined
|
|
513
|
+
: {
|
|
514
|
+
keyword: "Body",
|
|
515
|
+
path: \`Variant #\${i}\`,
|
|
516
|
+
message: schema.errorMessage(response.body),
|
|
517
|
+
};
|
|
518
|
+
},
|
|
519
|
+
];
|
|
520
|
+
};
|
|
521
|
+
|
|
522
|
+
// collect errors across all variants; exit early if any variant passes
|
|
523
|
+
const errors: Array<ValidationErrorEntry> = [];
|
|
524
|
+
|
|
525
|
+
for (const [i, variant] of variants.entries()) {
|
|
526
|
+
const variantErrors = variantValidators(variant).flatMap(
|
|
527
|
+
(validator) => {
|
|
528
|
+
const error = validator(i);
|
|
529
|
+
return error ? [error] : [];
|
|
530
|
+
},
|
|
531
|
+
);
|
|
532
|
+
if (!variantErrors.length) {
|
|
533
|
+
// variant fully matched - response is valid
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
errors.push(...variantErrors);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
const errorMessage = \`The response did not match any of the expected formats\`;
|
|
540
|
+
const errorSummary = \`\${variants.length} variants checked, none valid\`;
|
|
541
|
+
|
|
542
|
+
// no variant passed validation
|
|
543
|
+
throw new ValidationError([
|
|
544
|
+
"response",
|
|
545
|
+
{
|
|
546
|
+
errors,
|
|
547
|
+
errorMessage: customErrors?.error || errorMessage,
|
|
548
|
+
errorSummary,
|
|
549
|
+
route: name,
|
|
550
|
+
data: response,
|
|
551
|
+
},
|
|
552
|
+
]);
|
|
553
|
+
},
|
|
554
|
+
{
|
|
555
|
+
slot: "validate:response",
|
|
556
|
+
on: Object.keys(validationSchemas.response || {}) as Array<HTTPMethod>,
|
|
557
|
+
},
|
|
558
|
+
) as never,
|
|
559
|
+
];
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* Request validation - dynamically creates one middleware per target
|
|
563
|
+
* (query, headers, cookies, json, form, multipart, raw).
|
|
564
|
+
*
|
|
565
|
+
* Each middleware:
|
|
566
|
+
* 1. Checks if a schema exists for the current HTTP method
|
|
567
|
+
* 2. Skips if \`runtimeValidation\` is explicitly disabled
|
|
568
|
+
* 3. Loads data via the appropriate source (event.query, event.headers, or event.bodyparser)
|
|
569
|
+
* 4. Validates via \`schema.validate()\` which throws on failure
|
|
570
|
+
*
|
|
571
|
+
* Body targets (json, form, raw) go through \`event.bodyparser[target]()\`,
|
|
572
|
+
* benefiting from the lazy parsing and caching set up by slot:extendContext middleware.
|
|
573
|
+
*
|
|
574
|
+
* All request validators are active on any HTTP method that has at least one
|
|
575
|
+
* schema defined across any target - this is intentionally broad to avoid
|
|
576
|
+
* silently skipping validation when methods overlap.
|
|
577
|
+
* */
|
|
578
|
+
const requestTargets: Record<
|
|
579
|
+
RequestValidationTarget,
|
|
580
|
+
(
|
|
581
|
+
event: ParameterizedEvent<Record<string, string>, DefaultContext>,
|
|
582
|
+
) => Promise<unknown>
|
|
583
|
+
> = {
|
|
584
|
+
query: async (event) => event.metaparser.query(),
|
|
585
|
+
headers: async (event) => event.metaparser.headers(),
|
|
586
|
+
cookies: async (event) => event.metaparser.cookies(),
|
|
587
|
+
json: async (event) => event.bodyparser.json(),
|
|
588
|
+
form: async (event) => event.bodyparser.form(),
|
|
589
|
+
raw: async (event) => event.bodyparser.raw(),
|
|
590
|
+
};
|
|
591
|
+
|
|
592
|
+
const requestEntries = Object.entries(requestTargets) as Array<
|
|
593
|
+
[RequestValidationTarget, (typeof requestTargets)[RequestValidationTarget]]
|
|
594
|
+
>;
|
|
595
|
+
|
|
596
|
+
for (const [target, loadData] of requestEntries) {
|
|
597
|
+
validationMiddleware.push(
|
|
598
|
+
use(
|
|
599
|
+
async (event, next) => {
|
|
600
|
+
const schema = {
|
|
601
|
+
...validationSchemas[target]?.[event.req.method],
|
|
602
|
+
};
|
|
603
|
+
if (schema.validate && schema.runtimeValidation !== false) {
|
|
604
|
+
schema.validate(await loadData(event as never));
|
|
605
|
+
}
|
|
606
|
+
return next();
|
|
607
|
+
},
|
|
608
|
+
{
|
|
609
|
+
slot: \`validate:\${target}\`,
|
|
610
|
+
// duplicates not an issue here
|
|
611
|
+
on: requestEntries.flatMap(([target]) => {
|
|
612
|
+
return Object.keys(
|
|
613
|
+
validationSchemas[target] || {},
|
|
614
|
+
) as Array<HTTPMethod>;
|
|
615
|
+
}),
|
|
616
|
+
},
|
|
617
|
+
) as never,
|
|
618
|
+
);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
return validationMiddleware;
|
|
622
|
+
};
|
|
623
|
+
|
|
624
|
+
export const routes = createRoutes<ParameterizedMiddleware, Middleware>(
|
|
625
|
+
routeSources,
|
|
626
|
+
{
|
|
627
|
+
globalMiddleware: globalMiddleware as never,
|
|
628
|
+
createRouteMiddleware,
|
|
629
|
+
},
|
|
630
|
+
);
|
|
631
|
+
`,ge=`import { join } from "node:path";
|
|
632
|
+
|
|
633
|
+
import type { RouteSource } from "@kosmojs/core/api";
|
|
634
|
+
|
|
635
|
+
import { base, apiBase, apiRouteMap, apiRouteMapper } from "{{ createImport 'libCore' }}";
|
|
636
|
+
|
|
637
|
+
{{#each routes}}
|
|
638
|
+
import {{id}} from "{{ createImport 'api' file }}";
|
|
639
|
+
import { validationSchemas as {{id}}_schemas } from "{{ createImport 'libApi' basename 'schemas' }}";
|
|
640
|
+
{{/each}}
|
|
641
|
+
|
|
642
|
+
{{#each cascadingMiddleware}}
|
|
643
|
+
import {{id}}, { type UseT as UseT{{id}} } from "{{ createImport 'api' file }}";
|
|
644
|
+
{{/each}}
|
|
645
|
+
|
|
646
|
+
export type RouteMap = {
|
|
647
|
+
{{#each routes}}
|
|
648
|
+
"{{name}}": {
|
|
649
|
+
paramsDefaults: {{paramsDefaults .}},
|
|
650
|
+
paramsMappings: {{paramsMappings .}},
|
|
651
|
+
cascadingState: {{cascadingState .}},
|
|
652
|
+
},
|
|
653
|
+
{{/each}}
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
export const routeSources: Array<RouteSource<never>> = [
|
|
657
|
+
{{#each routes}}
|
|
658
|
+
{
|
|
659
|
+
{{#if alias}}
|
|
660
|
+
...apiRouteMapper(apiBase, { ...{{serializeApiRoute .}}, pathPattern: "{{alias}}" }),
|
|
661
|
+
path: "{{alias}}",
|
|
662
|
+
pathPattern: "{{alias}}",
|
|
663
|
+
{{else}}
|
|
664
|
+
...apiRouteMap["{{name}}"],
|
|
665
|
+
path: join(base, apiBase, "{{path}}"),
|
|
666
|
+
pathPattern: join(base, apiBase, "{{pathPattern}}"),
|
|
667
|
+
{{/if}}
|
|
668
|
+
name: "{{name}}",
|
|
669
|
+
file: "{{file}}",
|
|
670
|
+
cascadingMiddleware: [ {{#each cascadingMiddleware}}{{id}}, {{/each}}].flat() as Array<never>,
|
|
671
|
+
definitionItems: {{id}} as never,
|
|
672
|
+
validationSchemas: {{id}}_schemas,
|
|
673
|
+
},
|
|
674
|
+
{{/each}}
|
|
675
|
+
];
|
|
676
|
+
`,_e=`import { parseArgs, styleText } from "node:util";
|
|
677
|
+
|
|
678
|
+
import { serve as h3serve } from "h3";
|
|
679
|
+
|
|
680
|
+
import type { App } from "./app";
|
|
681
|
+
|
|
682
|
+
type Handles = {
|
|
683
|
+
port?: number | undefined;
|
|
684
|
+
onListen?: () => Promise<void>;
|
|
685
|
+
};
|
|
686
|
+
|
|
687
|
+
const getListenHandles = async (opt?: Handles) => {
|
|
688
|
+
const { port } = opt
|
|
689
|
+
? opt
|
|
690
|
+
: parseArgs({
|
|
691
|
+
options: {
|
|
692
|
+
port: {
|
|
693
|
+
type: "string",
|
|
694
|
+
short: "p",
|
|
695
|
+
},
|
|
696
|
+
},
|
|
697
|
+
}).values;
|
|
698
|
+
|
|
699
|
+
if (![port].some(Boolean)) {
|
|
700
|
+
throw new Error("Please provide -p/--port number");
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
const onListen = async () => {
|
|
704
|
+
console.log(
|
|
705
|
+
\`\\n ✨ Server Started \${styleText(["dim"], "[ %s ]")}\`,
|
|
706
|
+
\`port: \${port}\`,
|
|
707
|
+
);
|
|
708
|
+
};
|
|
709
|
+
|
|
710
|
+
return {
|
|
711
|
+
port: Number(port),
|
|
712
|
+
onListen: opt?.onListen || onListen,
|
|
713
|
+
};
|
|
714
|
+
};
|
|
715
|
+
|
|
716
|
+
export const serve = async <T extends App>(app: T, opt?: Handles) => {
|
|
717
|
+
const { port, onListen } = await getListenHandles(opt);
|
|
718
|
+
|
|
719
|
+
const server = h3serve(app, { port });
|
|
720
|
+
await server.ready().then(onListen);
|
|
721
|
+
|
|
722
|
+
return server as never;
|
|
723
|
+
};
|
|
724
|
+
`,ve=`import type { H3Event, H3EventContext } from "h3";
|
|
725
|
+
|
|
726
|
+
import type { ValidationDefmap, ValidationOptmap } from "@kosmojs/core";
|
|
727
|
+
import {
|
|
728
|
+
use as createUse,
|
|
729
|
+
type ExtendContext,
|
|
730
|
+
type HandlerDefinition,
|
|
731
|
+
type HTTPMethod,
|
|
732
|
+
type MiddlewareDefinition,
|
|
733
|
+
type RouteDefinitionItem,
|
|
734
|
+
type UseOptions,
|
|
735
|
+
} from "@kosmojs/core/api";
|
|
736
|
+
|
|
737
|
+
import type { RouteMap } from "./@api/routes";
|
|
738
|
+
|
|
739
|
+
export interface DefaultContext extends H3EventContext {}
|
|
740
|
+
|
|
741
|
+
type MaybePromise<T = unknown> = T | Promise<T>;
|
|
742
|
+
|
|
743
|
+
type Next = () => MaybePromise<unknown | undefined>;
|
|
744
|
+
|
|
745
|
+
type ExtractBodies<R> = R extends [number, string, infer Body] ? Body : never;
|
|
746
|
+
|
|
747
|
+
type ValidatedResponseBodies<VDefs extends ValidationDefmap> = [
|
|
748
|
+
ExtractBodies<VDefs["response"]>,
|
|
749
|
+
] extends [never]
|
|
750
|
+
? unknown // No bodies extracted at all - fallback to unknown
|
|
751
|
+
: ExtractBodies<VDefs["response"]>;
|
|
752
|
+
|
|
753
|
+
export type ParameterizedEvent<
|
|
754
|
+
ParamsT,
|
|
755
|
+
ContextT,
|
|
756
|
+
VDefs extends ValidationDefmap = {},
|
|
757
|
+
VOpts extends ValidationOptmap = {},
|
|
758
|
+
> = H3Event & { context: DefaultContext } & ContextT &
|
|
759
|
+
ExtendContext<ParamsT, VDefs, VOpts>;
|
|
760
|
+
|
|
761
|
+
export type ParameterizedMiddleware<
|
|
762
|
+
ParamsT = Record<string, string>,
|
|
763
|
+
ContextT = Record<string, unknown>,
|
|
764
|
+
> = (
|
|
765
|
+
event: ParameterizedEvent<ParamsT, ContextT>,
|
|
766
|
+
next: Next,
|
|
767
|
+
) => MaybePromise<unknown>;
|
|
768
|
+
|
|
769
|
+
export type RouteHandler<
|
|
770
|
+
ParamsT,
|
|
771
|
+
ContextT,
|
|
772
|
+
VDefs extends ValidationDefmap,
|
|
773
|
+
VOpts extends ValidationOptmap = {},
|
|
774
|
+
> = (
|
|
775
|
+
event: ParameterizedEvent<ParamsT, ContextT, VDefs, VOpts>,
|
|
776
|
+
) => MaybePromise<ValidatedResponseBodies<VDefs>>;
|
|
777
|
+
|
|
778
|
+
export type DefineRouteFactory<ParamsT, ContextT> = (
|
|
779
|
+
a: {
|
|
780
|
+
// NOTE: The \`use\` helper intentionally does not accept validation types.
|
|
781
|
+
// Allowing these type parameters on \`use\` would be misleading,
|
|
782
|
+
// since middleware operates across multiple request methods with varying types.
|
|
783
|
+
use: (
|
|
784
|
+
middleware:
|
|
785
|
+
| ParameterizedMiddleware<ParamsT, ContextT>
|
|
786
|
+
| Array<ParameterizedMiddleware<ParamsT, ContextT>>,
|
|
787
|
+
options?: UseOptions,
|
|
788
|
+
) => MiddlewareDefinition<ParameterizedMiddleware<ParamsT, ContextT>>;
|
|
789
|
+
} & {
|
|
790
|
+
[M in HTTPMethod]: <
|
|
791
|
+
VDefs extends ValidationDefmap,
|
|
792
|
+
VOpts extends ValidationOptmap = {},
|
|
793
|
+
>(
|
|
794
|
+
handler:
|
|
795
|
+
| RouteHandler<ParamsT, ContextT, VDefs, VOpts>
|
|
796
|
+
| Array<RouteHandler<ParamsT, ContextT, VDefs, VOpts>>,
|
|
797
|
+
) => HandlerDefinition<ParameterizedMiddleware<ParamsT, ContextT>>;
|
|
798
|
+
},
|
|
799
|
+
) => Array<RouteDefinitionItem<ParameterizedMiddleware<ParamsT, ContextT>>>;
|
|
800
|
+
|
|
801
|
+
type ParamsMap<
|
|
802
|
+
Mappings extends Array<[string, unknown, boolean]>,
|
|
803
|
+
Refinements extends Array<unknown>,
|
|
804
|
+
> = {
|
|
805
|
+
[I in Extract<keyof Mappings, \`\${number}\`> as Mappings[I] extends [
|
|
806
|
+
infer ParamName extends string,
|
|
807
|
+
...Array<unknown>,
|
|
808
|
+
]
|
|
809
|
+
? ParamName
|
|
810
|
+
: never]: Mappings[I] extends [string, infer Default, true]
|
|
811
|
+
? I extends keyof Refinements
|
|
812
|
+
? Refinements[I]
|
|
813
|
+
: Default
|
|
814
|
+
: Mappings[I] extends [string, infer Default, false]
|
|
815
|
+
? I extends keyof Refinements
|
|
816
|
+
? Refinements[I] | undefined
|
|
817
|
+
: Default | undefined
|
|
818
|
+
: never;
|
|
819
|
+
};
|
|
820
|
+
|
|
821
|
+
export const use = <ContextT = DefaultContext>(
|
|
822
|
+
middleware:
|
|
823
|
+
| ParameterizedMiddleware<Record<string, string>, ContextT>
|
|
824
|
+
| Array<ParameterizedMiddleware<Record<string, string>, ContextT>>,
|
|
825
|
+
options?: UseOptions,
|
|
826
|
+
) => {
|
|
827
|
+
return createUse<ParameterizedMiddleware<Record<string, string>, ContextT>>(
|
|
828
|
+
middleware,
|
|
829
|
+
options,
|
|
830
|
+
);
|
|
831
|
+
};
|
|
832
|
+
|
|
833
|
+
export const defineRoute: <
|
|
834
|
+
R extends keyof RouteMap,
|
|
835
|
+
ParamsD extends RouteMap[R]["paramsDefaults"] = RouteMap[R]["paramsDefaults"],
|
|
836
|
+
ContextT extends object = object,
|
|
837
|
+
>(
|
|
838
|
+
factory: DefineRouteFactory<
|
|
839
|
+
ParamsMap<RouteMap[R]["paramsMappings"], ParamsD>,
|
|
840
|
+
ContextT & RouteMap[R]["cascadingState"]
|
|
841
|
+
>,
|
|
842
|
+
) => Array<
|
|
843
|
+
RouteDefinitionItem<
|
|
844
|
+
ParameterizedMiddleware<
|
|
845
|
+
ParamsMap<RouteMap[R]["paramsMappings"], ParamsD>,
|
|
846
|
+
ContextT & RouteMap[R]["cascadingState"]
|
|
847
|
+
>
|
|
848
|
+
>
|
|
849
|
+
> = (factory) => {
|
|
850
|
+
const createHandler = <MiddlewareT>(method: HTTPMethod) => {
|
|
851
|
+
return (middleware: MiddlewareT | Array<MiddlewareT>) => {
|
|
852
|
+
return {
|
|
853
|
+
kind: "handler",
|
|
854
|
+
method,
|
|
855
|
+
middleware: [middleware].flat(),
|
|
856
|
+
};
|
|
857
|
+
};
|
|
858
|
+
};
|
|
859
|
+
return factory({
|
|
860
|
+
HEAD: createHandler("HEAD") as never,
|
|
861
|
+
OPTIONS: createHandler("OPTIONS") as never,
|
|
862
|
+
GET: createHandler("GET") as never,
|
|
863
|
+
POST: createHandler("POST") as never,
|
|
864
|
+
PUT: createHandler("PUT") as never,
|
|
865
|
+
PATCH: createHandler("PATCH") as never,
|
|
866
|
+
DELETE: createHandler("DELETE") as never,
|
|
867
|
+
// route-specific \`use\`, contains types for current route
|
|
868
|
+
use: use as never,
|
|
869
|
+
});
|
|
870
|
+
};
|
|
871
|
+
`,ye=`export * from "./@api/app";
|
|
872
|
+
export { appFactory as default } from "./@api/app";
|
|
873
|
+
export * from "./@api/dev";
|
|
874
|
+
export * from "./@api/errors";
|
|
875
|
+
export * from "./@api/router";
|
|
876
|
+
export * from "./@api/routes";
|
|
877
|
+
export * from "./@api/server";
|
|
878
|
+
`,be=`import { onError } from "h3";
|
|
879
|
+
|
|
880
|
+
import appFactory, { routes, type App } from "{{ createImport 'lib' 'api:factory' }}";
|
|
881
|
+
import defaultErrorHandler from "./errors";
|
|
882
|
+
|
|
883
|
+
export default appFactory(routes, ({ app }) => {
|
|
884
|
+
app.use(onError(defaultErrorHandler));
|
|
885
|
+
}) as App;
|
|
886
|
+
`,xe=`import { toNodeHandler } from "h3/node";
|
|
887
|
+
|
|
888
|
+
import app from "./app";
|
|
889
|
+
|
|
890
|
+
import { devSetup } from "{{ createImport 'lib' 'api:factory' }}";
|
|
891
|
+
|
|
892
|
+
export default devSetup({
|
|
893
|
+
requestHandler() {
|
|
894
|
+
return toNodeHandler(app);
|
|
895
|
+
},
|
|
896
|
+
teardownHandler() {
|
|
897
|
+
// close db connections, server sockets etc.
|
|
898
|
+
},
|
|
899
|
+
});
|
|
900
|
+
|
|
901
|
+
process.on("unhandledRejection", (reason) => {
|
|
902
|
+
console.error("💥 UNHANDLED REJECTION");
|
|
903
|
+
console.error("Reason:", reason);
|
|
904
|
+
process.exit(1);
|
|
905
|
+
});
|
|
906
|
+
`,Se=`export declare module "{{ createImport 'libApi' }}" {
|
|
907
|
+
interface DefaultContext {}
|
|
908
|
+
}
|
|
909
|
+
`,Ce=`import { ValidationError } from "@kosmojs/core/errors";
|
|
910
|
+
import { HTTPError } from "h3";
|
|
911
|
+
|
|
912
|
+
import { errorHandlerFactory } from "{{ createImport 'lib' 'api:factory' }}";
|
|
913
|
+
|
|
914
|
+
export default errorHandlerFactory(async (error, event) => {
|
|
915
|
+
const [status, message = "Unknown error occurred"] = Array.isArray(error)
|
|
916
|
+
? error
|
|
917
|
+
: error instanceof HTTPError
|
|
918
|
+
? [error.status, error.message]
|
|
919
|
+
: error instanceof ValidationError
|
|
920
|
+
? [400, \`\${error.target}: \${error.errorMessage}\`]
|
|
921
|
+
: [error.statusCode || 500, error.message];
|
|
922
|
+
|
|
923
|
+
const accept = event.req.headers.get("accept");
|
|
924
|
+
|
|
925
|
+
return accept?.includes("application/json")
|
|
926
|
+
? new Response(JSON.stringify({ error: message }), {
|
|
927
|
+
status,
|
|
928
|
+
headers: { "Content-Type": "application/json" },
|
|
929
|
+
})
|
|
930
|
+
: new Response(message, {
|
|
931
|
+
status,
|
|
932
|
+
headers: { "Content-Type": "text/plain" },
|
|
933
|
+
});
|
|
934
|
+
});
|
|
935
|
+
`,we=`import { defineRoute } from "{{ createImport 'libApi' }}";
|
|
936
|
+
|
|
937
|
+
export default defineRoute<"{{route.name}}">(({ GET }) => [
|
|
938
|
+
GET(async (event) => {
|
|
939
|
+
return "Automatically generated route";
|
|
940
|
+
}),
|
|
941
|
+
]);
|
|
942
|
+
`,Te=`import { use } from "{{ createImport 'libApi' }}";
|
|
943
|
+
|
|
944
|
+
export type UseT = {};
|
|
945
|
+
|
|
946
|
+
export default [
|
|
947
|
+
use<UseT>(async (event, next) => {
|
|
948
|
+
return next();
|
|
949
|
+
}),
|
|
950
|
+
];
|
|
951
|
+
`,Ee=`import { serve } from "{{ createImport 'lib' 'api:factory' }}";
|
|
952
|
+
import app from "./app";
|
|
953
|
+
|
|
954
|
+
await serve(app);
|
|
955
|
+
`,De=`import { use } from "{{ createImport 'libApi' }}";
|
|
956
|
+
|
|
957
|
+
/**
|
|
958
|
+
* Define global middleware applied to all routes.
|
|
959
|
+
* Can be overridden on a per-route basis using the slot key.
|
|
960
|
+
* */
|
|
961
|
+
export default [
|
|
962
|
+
use(async function useExample(event, next) {
|
|
963
|
+
return next();
|
|
964
|
+
}),
|
|
965
|
+
];
|
|
966
|
+
`,Oe=g((e,n)=>{let{createPath:r,createImportHelpers:i}=y(e),a=e=>e.length===0?`{}`:e.length===1?e[0]:`Override<${e[0]}, ${a(e.slice(1))}>`,{renderToFile:o}=x({helpers:{...i({origin:`lib`}),...w(),paramsDefaults({params:e}){return`[${e.schema.map(()=>`unknown?`).join(`, `)}]`},paramsMappings({params:e}){return`[${e.schema.map(({name:e,kind:t})=>`["${e}", unknown, ${t===`required`?`true`:`false`}]`).join(`, `)}]`},cascadingState({cascadingMiddleware:e}){return a(e.map(({id:e})=>`UseT${e}`))}}}),{renderToFile:s}=x({helpers:i({origin:`src`})}),l=e=>e?.trim().length===0,d=c(n?.templates,we),f=async e=>{for(let{kind:t,entry:n}of e)t===`apiRoute`?await s(r.api(n.file),d(n.name,n),{route:n},{overwrite:l}):t===`apiUse`&&await s(r.api(n.file),Te,{},{overwrite:l})},m=async e=>{let i=e.flatMap(({kind:e,entry:t})=>e===`apiUse`?[t]:[]),a=e.flatMap(({kind:e,entry:r})=>{if(e!==`apiRoute`)return[];let a=r.name.split(`/`).reduce((e,n)=>{let r=e[e.length-1];return e.push(r?t(r,n):n),e},[]),o={...r,path:r.h3Pattern,basename:r.name,cascadingMiddleware:i.flatMap(e=>a.some(t=>e.name===t)?[e]:[])};return[o,...Object.entries({...n?.alias}).flatMap(([e,t])=>{let n=b(e);return t===r.name?[{...o,name:e,basename:r.name,id:`${o.id}_${T(e)}`,alias:u(n),pathTokens:n}]:[]})]}).sort(S);for(let[e,t]of[[`@api/routes.ts`,ge]])await o(r.lib(e),t,{routes:a,cascadingMiddleware:i})};return{config({command:e}){return{define:{KOSMO_PRODUCTION_BUILD:e===`build`?`true`:`false`}}},async start(){for(let[e,t]of[[`api.ts`,ve],[`api:factory.ts`,ye],[`@api/app.ts`,R],[`@api/parsers.ts`,me],[`@api/dev.ts`,z],[`@api/errors.ts`,B],[`@api/router.ts`,he],[`@api/server.ts`,_e]])await o(r.lib(e),t,{});for(let[e,t]of[[`app.ts`,be],[`dev.ts`,xe],[`errors.ts`,Ce],[`server.ts`,Ee],[`use.ts`,De],[`env.d.ts`,Se]])await s(r.api(e),t,{},{overwrite:l})},async watch(e,t){await f(e.filter(p(t,[`create`]))),await m(e)},async build(e){await f(e),await m(e)}}}),ke=h({meta:{name:`H3`,slot:`backend`},dependencies:{h3:L.devDependencies.h3},factory:Oe}),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`}},Ae=`import { Hono, type MiddlewareHandler } from "hono";
|
|
967
|
+
import type { Router } from "hono/router";
|
|
968
|
+
import { RegExpRouter } from "hono/router/reg-exp-router";
|
|
969
|
+
import { SmartRouter } from "hono/router/smart-router";
|
|
970
|
+
import { TrieRouter } from "hono/router/trie-router";
|
|
241
971
|
|
|
242
|
-
import type {
|
|
972
|
+
import type { Route, RouteDebugOption } from "@kosmojs/core/api";
|
|
243
973
|
|
|
244
974
|
import type { DefaultBindings, DefaultVariables } from "../api";
|
|
245
975
|
|
|
@@ -250,18 +980,65 @@ export type AppEnv = {
|
|
|
250
980
|
|
|
251
981
|
export type App = Hono<AppEnv>;
|
|
252
982
|
|
|
253
|
-
export type AppOptions = ConstructorParameters<typeof Hono<AppEnv>>[0]
|
|
983
|
+
export type AppOptions = ConstructorParameters<typeof Hono<AppEnv>>[0] & {
|
|
984
|
+
debug?: RouteDebugOption;
|
|
985
|
+
};
|
|
254
986
|
|
|
255
|
-
export
|
|
256
|
-
|
|
257
|
-
|
|
987
|
+
export function appFactory(
|
|
988
|
+
routes: Array<Route<MiddlewareHandler>>,
|
|
989
|
+
options: AppOptions,
|
|
990
|
+
): App;
|
|
991
|
+
|
|
992
|
+
export function appFactory(
|
|
993
|
+
routes: Array<Route<MiddlewareHandler>>,
|
|
994
|
+
fn: (a: { app: App; router: Router<never> }) => void,
|
|
995
|
+
): App;
|
|
996
|
+
|
|
997
|
+
export function appFactory(
|
|
998
|
+
routes: Array<Route<MiddlewareHandler>>,
|
|
999
|
+
options: AppOptions,
|
|
1000
|
+
fn: (a: { app: App; router: Router<never> }) => void,
|
|
1001
|
+
): App;
|
|
1002
|
+
|
|
1003
|
+
export function appFactory(
|
|
1004
|
+
routes: Array<Route<MiddlewareHandler>>,
|
|
1005
|
+
...rest: Array<unknown>
|
|
1006
|
+
): App {
|
|
1007
|
+
const [options, fn] = typeof rest[0] === "function" ? [{}, rest[0]] : rest;
|
|
1008
|
+
|
|
1009
|
+
const router = new SmartRouter({
|
|
1010
|
+
routers: [new RegExpRouter(), new TrieRouter()],
|
|
1011
|
+
}) as Router<never>;
|
|
1012
|
+
|
|
1013
|
+
const { debug = undefined, ...appOptions } = {
|
|
1014
|
+
...(options ? { ...options } : {}),
|
|
258
1015
|
};
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
1016
|
+
|
|
1017
|
+
const app = new Hono({
|
|
1018
|
+
strict: false,
|
|
1019
|
+
router,
|
|
1020
|
+
...appOptions,
|
|
1021
|
+
});
|
|
1022
|
+
|
|
1023
|
+
if (typeof fn === "function") {
|
|
1024
|
+
fn({ app, router });
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
for (const route of routes) {
|
|
1028
|
+
if (typeof debug === "function") {
|
|
1029
|
+
(debug as Function)(route.debug, route);
|
|
1030
|
+
} else if (debug) {
|
|
1031
|
+
console.log(route.debug[typeof debug === "string" ? debug : "full"]);
|
|
1032
|
+
}
|
|
1033
|
+
app.on(route.methods, [route.path], ...route.middleware);
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
return app as never;
|
|
1037
|
+
}
|
|
1038
|
+
`,je=`import type { DevSetup } from "@kosmojs/core/api";
|
|
262
1039
|
|
|
263
1040
|
export const devSetup = (setup: DevSetup) => setup;
|
|
264
|
-
`,
|
|
1041
|
+
`,Me=`import type { Context } from "hono";
|
|
265
1042
|
|
|
266
1043
|
import type { AppEnv } from "./app";
|
|
267
1044
|
|
|
@@ -275,7 +1052,7 @@ export type ErrorHandlerFactory = (handler: ErrorHandler) => ErrorHandler;
|
|
|
275
1052
|
export const errorHandlerFactory: ErrorHandlerFactory = (handler) => {
|
|
276
1053
|
return handler;
|
|
277
1054
|
};
|
|
278
|
-
`,
|
|
1055
|
+
`,Ne=`import type { Context } from "hono";
|
|
279
1056
|
|
|
280
1057
|
import {
|
|
281
1058
|
parseCookies,
|
|
@@ -324,12 +1101,7 @@ export const bodyparsers: {
|
|
|
324
1101
|
return ctx.req[as]();
|
|
325
1102
|
},
|
|
326
1103
|
};
|
|
327
|
-
`,
|
|
328
|
-
import type { Router } from "hono/router";
|
|
329
|
-
import { RegExpRouter } from "hono/router/reg-exp-router";
|
|
330
|
-
import { SmartRouter } from "hono/router/smart-router";
|
|
331
|
-
import { TrieRouter } from "hono/router/trie-router";
|
|
332
|
-
import { match } from "path-to-regexp";
|
|
1104
|
+
`,Pe=`import type { MiddlewareHandler } from "hono";
|
|
333
1105
|
|
|
334
1106
|
import type {
|
|
335
1107
|
RequestBodyTarget,
|
|
@@ -341,7 +1113,6 @@ import {
|
|
|
341
1113
|
type CreateRouteMiddleware,
|
|
342
1114
|
createRoutes,
|
|
343
1115
|
type HTTPMethod,
|
|
344
|
-
type RouterFactory,
|
|
345
1116
|
StateKey,
|
|
346
1117
|
} from "@kosmojs/core/api";
|
|
347
1118
|
import { ValidationError } from "@kosmojs/core/errors";
|
|
@@ -357,7 +1128,6 @@ import { type BodyparserOptions, bodyparsers, metaparsers } from "./parsers";
|
|
|
357
1128
|
import { routeSources } from "./routes";
|
|
358
1129
|
|
|
359
1130
|
import globalMiddleware from "{{ createImport 'api' 'use' }}";
|
|
360
|
-
import { apiRouteMap } from "{{ createImport 'libCore' }}";
|
|
361
1131
|
|
|
362
1132
|
/**
|
|
363
1133
|
* Create route-level middleware stack that handles:
|
|
@@ -374,33 +1144,7 @@ import { apiRouteMap } from "{{ createImport 'libCore' }}";
|
|
|
374
1144
|
* */
|
|
375
1145
|
export const createRouteMiddleware: CreateRouteMiddleware<
|
|
376
1146
|
ParameterizedMiddleware
|
|
377
|
-
> = ({ name,
|
|
378
|
-
const route = apiRouteMap[name];
|
|
379
|
-
|
|
380
|
-
if (!route) {
|
|
381
|
-
throw new Error(\`createRouteMiddleware: \${name} route does not exists\`);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
const { params, numericProperties } = route;
|
|
385
|
-
|
|
386
|
-
const pathMatcher = match(pathPattern);
|
|
387
|
-
|
|
388
|
-
const matchPath = (path: string) => {
|
|
389
|
-
try {
|
|
390
|
-
return pathMatcher(path);
|
|
391
|
-
} catch (_e) {
|
|
392
|
-
return undefined;
|
|
393
|
-
}
|
|
394
|
-
};
|
|
395
|
-
|
|
396
|
-
const maybeNumber = (val: unknown) => {
|
|
397
|
-
if (val === undefined || val === null) {
|
|
398
|
-
return val;
|
|
399
|
-
}
|
|
400
|
-
const n = Number(val);
|
|
401
|
-
return Number.isFinite(n) ? n : val;
|
|
402
|
-
};
|
|
403
|
-
|
|
1147
|
+
> = ({ name, validationSchemas, normalizeParams, normalizeSearchParams }) => {
|
|
404
1148
|
const validationMiddleware = [
|
|
405
1149
|
/**
|
|
406
1150
|
* Extends Hono context with:
|
|
@@ -441,15 +1185,9 @@ export const createRouteMiddleware: CreateRouteMiddleware<
|
|
|
441
1185
|
ctx[StateKey].set(
|
|
442
1186
|
target,
|
|
443
1187
|
target === "query"
|
|
444
|
-
?
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
numericProperties.query[ctx.req.method]?.includes(k)
|
|
448
|
-
? Array.isArray(v)
|
|
449
|
-
? v.map((e) => maybeNumber(e))
|
|
450
|
-
: maybeNumber(v)
|
|
451
|
-
: v,
|
|
452
|
-
]),
|
|
1188
|
+
? normalizeSearchParams(
|
|
1189
|
+
parser(ctx),
|
|
1190
|
+
ctx.req.method as never,
|
|
453
1191
|
)
|
|
454
1192
|
: parser(ctx),
|
|
455
1193
|
);
|
|
@@ -502,23 +1240,7 @@ export const createRouteMiddleware: CreateRouteMiddleware<
|
|
|
502
1240
|
* */
|
|
503
1241
|
use(
|
|
504
1242
|
function useValidateParams(ctx, next) {
|
|
505
|
-
const
|
|
506
|
-
const normalizedParams = params.reduce(
|
|
507
|
-
(map: Record<string, unknown>, name) => {
|
|
508
|
-
const value = matched ? matched.params[name] : undefined;
|
|
509
|
-
if (Array.isArray(value)) {
|
|
510
|
-
map[name] = numericProperties.params.includes(name)
|
|
511
|
-
? value.map((e) => maybeNumber(e))
|
|
512
|
-
: value;
|
|
513
|
-
} else if (value) {
|
|
514
|
-
map[name] = numericProperties.params.includes(name)
|
|
515
|
-
? maybeNumber(value)
|
|
516
|
-
: value;
|
|
517
|
-
}
|
|
518
|
-
return map;
|
|
519
|
-
},
|
|
520
|
-
{},
|
|
521
|
-
);
|
|
1243
|
+
const normalizedParams = normalizeParams(ctx.req.path);
|
|
522
1244
|
validationSchemas.params?.validate(normalizedParams);
|
|
523
1245
|
ctx[StateKey].set("params", normalizedParams);
|
|
524
1246
|
return next();
|
|
@@ -746,32 +1468,21 @@ export const routes = createRoutes<ParameterizedMiddleware, MiddlewareHandler>(
|
|
|
746
1468
|
createRouteMiddleware,
|
|
747
1469
|
},
|
|
748
1470
|
);
|
|
749
|
-
|
|
750
|
-
export const routerFactory: RouterFactory<Router<never>, never> = (factory) => {
|
|
751
|
-
const createRouter = () => {
|
|
752
|
-
return new SmartRouter({
|
|
753
|
-
routers: [new RegExpRouter(), new TrieRouter()],
|
|
754
|
-
}) as Router<never>;
|
|
755
|
-
};
|
|
756
|
-
return factory({ createRouter });
|
|
757
|
-
};
|
|
758
|
-
`,V=`import { join } from "node:path";
|
|
1471
|
+
`,Fe=`import { join } from "node:path";
|
|
759
1472
|
|
|
760
1473
|
import type { RouteSource } from "@kosmojs/core/api";
|
|
761
1474
|
|
|
762
|
-
import { base, apiBase } from "{{ createImport 'libCore' }}";
|
|
1475
|
+
import { base, apiBase, apiRouteMap, apiRouteMapper } from "{{ createImport 'libCore' }}";
|
|
763
1476
|
|
|
764
1477
|
{{#each routes}}
|
|
765
1478
|
import {{id}} from "{{ createImport 'api' file }}";
|
|
766
|
-
import { validationSchemas as {{id}}_schemas } from "{{ createImport 'libApi'
|
|
1479
|
+
import { validationSchemas as {{id}}_schemas } from "{{ createImport 'libApi' basename 'schemas' }}";
|
|
767
1480
|
{{/each}}
|
|
768
1481
|
|
|
769
1482
|
{{#each cascadingMiddleware}}
|
|
770
1483
|
import {{id}}, { type UseT as UseT{{id}} } from "{{ createImport 'api' file }}";
|
|
771
1484
|
{{/each}}
|
|
772
1485
|
|
|
773
|
-
type Override<A, B> = Omit<A, keyof B> & B;
|
|
774
|
-
|
|
775
1486
|
export type RouteMap = {
|
|
776
1487
|
{{#each routes}}
|
|
777
1488
|
"{{name}}": {
|
|
@@ -785,14 +1496,16 @@ export type RouteMap = {
|
|
|
785
1496
|
export const routeSources: Array<RouteSource<never>> = [
|
|
786
1497
|
{{#each routes}}
|
|
787
1498
|
{
|
|
788
|
-
|
|
789
|
-
{{
|
|
790
|
-
path: "{{
|
|
791
|
-
pathPattern: "{{
|
|
1499
|
+
{{#if alias}}
|
|
1500
|
+
...apiRouteMapper(apiBase, { ...{{serializeApiRoute .}}, pathPattern: "{{alias}}" }),
|
|
1501
|
+
path: "{{alias}}",
|
|
1502
|
+
pathPattern: "{{alias}}",
|
|
792
1503
|
{{else}}
|
|
1504
|
+
...apiRouteMap["{{name}}"],
|
|
793
1505
|
path: join(base, apiBase, "{{path}}"),
|
|
794
1506
|
pathPattern: join(base, apiBase, "{{pathPattern}}"),
|
|
795
1507
|
{{/if}}
|
|
1508
|
+
name: "{{name}}",
|
|
796
1509
|
file: "{{file}}",
|
|
797
1510
|
cascadingMiddleware: [ {{#each cascadingMiddleware}}{{id}}, {{/each}}].flat() as Array<never>,
|
|
798
1511
|
definitionItems: {{id}} as never,
|
|
@@ -800,52 +1513,48 @@ export const routeSources: Array<RouteSource<never>> = [
|
|
|
800
1513
|
},
|
|
801
1514
|
{{/each}}
|
|
802
1515
|
];
|
|
803
|
-
`,
|
|
1516
|
+
`,Ie=`import { chmod, unlink } from "node:fs/promises";
|
|
804
1517
|
import { parseArgs, styleText } from "node:util";
|
|
805
1518
|
|
|
806
1519
|
import { createAdaptorServer } from "@hono/node-server";
|
|
807
1520
|
|
|
808
|
-
import type { ServerFactory } from "@kosmojs/core/api";
|
|
809
|
-
|
|
810
1521
|
import type { App } from "./app";
|
|
811
1522
|
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
short: "p",
|
|
818
|
-
},
|
|
819
|
-
sock: {
|
|
820
|
-
type: "string",
|
|
821
|
-
short: "s",
|
|
822
|
-
},
|
|
823
|
-
},
|
|
824
|
-
});
|
|
825
|
-
|
|
826
|
-
const getListenHandles = async () => {
|
|
827
|
-
const { port, sock } = { ...values };
|
|
1523
|
+
type Handles = {
|
|
1524
|
+
port?: number | undefined;
|
|
1525
|
+
sock?: string | undefined;
|
|
1526
|
+
onListen?: () => Promise<void>;
|
|
1527
|
+
};
|
|
828
1528
|
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
1529
|
+
const getListenHandles = async (opt?: Handles) => {
|
|
1530
|
+
const { port, sock } = opt
|
|
1531
|
+
? opt
|
|
1532
|
+
: parseArgs({
|
|
1533
|
+
options: {
|
|
1534
|
+
port: {
|
|
1535
|
+
type: "string",
|
|
1536
|
+
short: "p",
|
|
1537
|
+
},
|
|
1538
|
+
sock: {
|
|
1539
|
+
type: "string",
|
|
1540
|
+
short: "s",
|
|
1541
|
+
},
|
|
1542
|
+
},
|
|
1543
|
+
}).values;
|
|
833
1544
|
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
return;
|
|
838
|
-
}
|
|
839
|
-
console.error(error.message);
|
|
840
|
-
process.exit(1);
|
|
841
|
-
});
|
|
842
|
-
}
|
|
1545
|
+
if (![port, sock].some(Boolean)) {
|
|
1546
|
+
throw new Error("Please provide either -p/--port number or -s/--sock path");
|
|
1547
|
+
}
|
|
843
1548
|
|
|
844
|
-
|
|
845
|
-
|
|
1549
|
+
if (sock) {
|
|
1550
|
+
await unlink(sock).catch((error) => {
|
|
1551
|
+
if (error.code !== "ENOENT") {
|
|
1552
|
+
throw error;
|
|
1553
|
+
}
|
|
1554
|
+
});
|
|
1555
|
+
}
|
|
846
1556
|
|
|
847
1557
|
const onListen = async () => {
|
|
848
|
-
const { port, sock } = await getListenHandles();
|
|
849
1558
|
if (sock) {
|
|
850
1559
|
// Make Unix socket world-writable so other processes (e.g. a reverse proxy)
|
|
851
1560
|
// can connect without permission issues.
|
|
@@ -857,50 +1566,39 @@ export const serverFactory: ServerFactory<App> = (factory) => {
|
|
|
857
1566
|
);
|
|
858
1567
|
};
|
|
859
1568
|
|
|
860
|
-
return
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
sock
|
|
867
|
-
? { unix: sock, fetch: app.fetch }
|
|
868
|
-
: { port: Number(port), fetch: app.fetch },
|
|
869
|
-
);
|
|
870
|
-
await onListen();
|
|
871
|
-
return server as never;
|
|
872
|
-
}
|
|
873
|
-
|
|
874
|
-
if (typeof Deno !== "undefined") {
|
|
875
|
-
const server = sock
|
|
876
|
-
? Deno.serve({ path: sock, onListen }, app.fetch)
|
|
877
|
-
: Deno.serve({ port: Number(port), onListen }, app.fetch);
|
|
878
|
-
return server as never;
|
|
879
|
-
}
|
|
1569
|
+
return {
|
|
1570
|
+
port: Number(port),
|
|
1571
|
+
sock,
|
|
1572
|
+
onListen: opt?.onListen || onListen,
|
|
1573
|
+
};
|
|
1574
|
+
};
|
|
880
1575
|
|
|
881
|
-
|
|
882
|
-
|
|
1576
|
+
export const serve = async <T extends App>(app: T, opt?: Handles) => {
|
|
1577
|
+
const { port, sock, onListen } = await getListenHandles(opt);
|
|
883
1578
|
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
1579
|
+
if (typeof Bun !== "undefined") {
|
|
1580
|
+
const server = Bun.serve(
|
|
1581
|
+
sock
|
|
1582
|
+
? { unix: sock, fetch: app.fetch }
|
|
1583
|
+
: { port: Number(port), fetch: app.fetch },
|
|
1584
|
+
);
|
|
1585
|
+
await onListen();
|
|
1586
|
+
return server as never;
|
|
1587
|
+
}
|
|
890
1588
|
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
console.error("Reason:", reason);
|
|
897
|
-
console.error("");
|
|
898
|
-
// In development, crash hard
|
|
899
|
-
if (process.env.NODE_ENV === "development") {
|
|
900
|
-
process.exit(1);
|
|
1589
|
+
if (typeof Deno !== "undefined") {
|
|
1590
|
+
const server = sock
|
|
1591
|
+
? Deno.serve({ path: sock, onListen }, app.fetch)
|
|
1592
|
+
: Deno.serve({ port: Number(port), onListen }, app.fetch);
|
|
1593
|
+
return server as never;
|
|
901
1594
|
}
|
|
902
|
-
|
|
903
|
-
|
|
1595
|
+
|
|
1596
|
+
const server = createAdaptorServer(app);
|
|
1597
|
+
server.listen(sock || port, onListen);
|
|
1598
|
+
|
|
1599
|
+
return server as never;
|
|
1600
|
+
};
|
|
1601
|
+
`,Le=`import type { Context, Next } from "hono";
|
|
904
1602
|
|
|
905
1603
|
import type { ValidationDefmap, ValidationOptmap } from "@kosmojs/core";
|
|
906
1604
|
import {
|
|
@@ -1083,29 +1781,20 @@ export const defineRoute: <
|
|
|
1083
1781
|
use: use as never,
|
|
1084
1782
|
});
|
|
1085
1783
|
};
|
|
1086
|
-
`,
|
|
1784
|
+
`,Re=`export * from "./@api/app";
|
|
1785
|
+
export { appFactory as default } from "./@api/app";
|
|
1087
1786
|
export * from "./@api/dev";
|
|
1088
1787
|
export * from "./@api/errors";
|
|
1089
1788
|
export * from "./@api/router";
|
|
1090
1789
|
export * from "./@api/routes";
|
|
1091
1790
|
export * from "./@api/server";
|
|
1092
|
-
`,
|
|
1093
|
-
import
|
|
1094
|
-
|
|
1095
|
-
import { appFactory, routes } from "{{ createImport 'lib' 'api:factory' }}";
|
|
1096
|
-
|
|
1097
|
-
export default appFactory(({ createApp }) => {
|
|
1098
|
-
const app = createApp({ router });
|
|
1791
|
+
`,ze=`import appFactory, { routes } from "{{ createImport 'lib' 'api:factory' }}";
|
|
1792
|
+
import defaultErrorHandler from "./errors";
|
|
1099
1793
|
|
|
1794
|
+
export default appFactory(routes, ({ app }) => {
|
|
1100
1795
|
app.onError(defaultErrorHandler);
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
app.on(methods, [path], ...middleware);
|
|
1104
|
-
}
|
|
1105
|
-
|
|
1106
|
-
return app;
|
|
1107
|
-
});
|
|
1108
|
-
`,_e=`import { getRequestListener } from "@hono/node-server";
|
|
1796
|
+
})
|
|
1797
|
+
`,Be=`import { getRequestListener } from "@hono/node-server";
|
|
1109
1798
|
|
|
1110
1799
|
import app from "./app";
|
|
1111
1800
|
|
|
@@ -1119,45 +1808,50 @@ export default devSetup({
|
|
|
1119
1808
|
// close db connections, server sockets etc.
|
|
1120
1809
|
},
|
|
1121
1810
|
});
|
|
1122
|
-
|
|
1811
|
+
|
|
1812
|
+
process.on("unhandledRejection", (reason) => {
|
|
1813
|
+
console.error("💥 UNHANDLED REJECTION");
|
|
1814
|
+
console.error("Reason:", reason);
|
|
1815
|
+
process.exit(1);
|
|
1816
|
+
});
|
|
1817
|
+
|
|
1818
|
+
`,Ve=`export declare module "{{ createImport 'libApi' }}" {
|
|
1123
1819
|
interface DefaultVariables {}
|
|
1124
1820
|
interface DefaultBindings {}
|
|
1125
1821
|
}
|
|
1126
|
-
`,
|
|
1822
|
+
`,He=`import { accepts } from "hono/accepts";
|
|
1127
1823
|
import { HTTPException } from "hono/http-exception";
|
|
1128
1824
|
|
|
1129
1825
|
import { ValidationError, HTTPError } from "@kosmojs/core/errors";
|
|
1130
1826
|
|
|
1131
1827
|
import { errorHandlerFactory } from "{{ createImport 'lib' 'api:factory' }}";
|
|
1132
1828
|
|
|
1133
|
-
export default errorHandlerFactory(
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
}
|
|
1829
|
+
export default errorHandlerFactory(async (error, ctx) => {
|
|
1830
|
+
// Let Hono's HTTPException handle its own response
|
|
1831
|
+
if (error instanceof HTTPException) {
|
|
1832
|
+
return error.getResponse();
|
|
1833
|
+
}
|
|
1139
1834
|
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1835
|
+
const [status, message] = Array.isArray(error)
|
|
1836
|
+
? error
|
|
1837
|
+
: error instanceof HTTPError
|
|
1838
|
+
? [error.status, error.message]
|
|
1839
|
+
: error instanceof ValidationError
|
|
1840
|
+
? [400, \`\${error.target}: \${error.errorMessage}\`]
|
|
1841
|
+
: [error.statusCode || 500, error.message];
|
|
1842
|
+
|
|
1843
|
+
// Respond based on what the client accepts
|
|
1844
|
+
const type = accepts(ctx, {
|
|
1845
|
+
header: "Accept",
|
|
1846
|
+
supports: ["application/json", "text/plain"],
|
|
1847
|
+
default: "text/plain",
|
|
1848
|
+
});
|
|
1154
1849
|
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
`,be=`import { defineRoute } from "{{ createImport 'libApi' }}";
|
|
1850
|
+
return type === "application/json"
|
|
1851
|
+
? ctx.json({ error: message }, status)
|
|
1852
|
+
: ctx.text(message, status);
|
|
1853
|
+
});
|
|
1854
|
+
`,Ue=`import { defineRoute } from "{{ createImport 'libApi' }}";
|
|
1161
1855
|
|
|
1162
1856
|
export default defineRoute<"{{route.name}}">(({ GET }) => [
|
|
1163
1857
|
GET(async (ctx) => {
|
|
@@ -1166,7 +1860,7 @@ export default defineRoute<"{{route.name}}">(({ GET }) => [
|
|
|
1166
1860
|
return ctx.text("Automatically generated route");
|
|
1167
1861
|
}),
|
|
1168
1862
|
]);
|
|
1169
|
-
`,
|
|
1863
|
+
`,We=`import { use } from "{{ createImport 'libApi' }}";
|
|
1170
1864
|
|
|
1171
1865
|
export type UseT = {};
|
|
1172
1866
|
|
|
@@ -1177,20 +1871,11 @@ export default [
|
|
|
1177
1871
|
return next();
|
|
1178
1872
|
}),
|
|
1179
1873
|
];
|
|
1180
|
-
`,
|
|
1181
|
-
|
|
1182
|
-
export default routerFactory(({ createRouter }) => {
|
|
1183
|
-
const router = createRouter();
|
|
1184
|
-
return router;
|
|
1185
|
-
});
|
|
1186
|
-
`,Ce=`import app from "./app";
|
|
1187
|
-
|
|
1188
|
-
import { serverFactory } from "{{ createImport 'lib' 'api:factory' }}";
|
|
1874
|
+
`,Ge=`import { serve } from "{{ createImport 'lib' 'api:factory' }}";
|
|
1875
|
+
import app from "./app";
|
|
1189
1876
|
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
});
|
|
1193
|
-
`,we=`import { use } from "{{ createImport 'libApi' }}";
|
|
1877
|
+
await serve(app);
|
|
1878
|
+
`,Ke=`import { use } from "{{ createImport 'libApi' }}";
|
|
1194
1879
|
|
|
1195
1880
|
/**
|
|
1196
1881
|
* Define global middleware applied to all routes.
|
|
@@ -1201,9 +1886,10 @@ export default [
|
|
|
1201
1886
|
return next();
|
|
1202
1887
|
}),
|
|
1203
1888
|
];
|
|
1204
|
-
`,
|
|
1889
|
+
`,qe=g((e,n)=>{let{createPath:r,createImportHelpers:i}=y(e),a=e=>e.length===0?`{}`:e.length===1?e[0]:`Override<${e[0]}, ${a(e.slice(1))}>`,{renderToFile:o}=x({helpers:{...i({origin:`lib`}),...w(),paramsDefaults({params:e}){return`[${e.schema.map(()=>`unknown?`).join(`, `)}]`},paramsMappings({params:e}){return`[${e.schema.map(({name:e,kind:t})=>`["${e}", unknown, ${t===`required`?`true`:`false`}]`).join(`, `)}]`},cascadingState({cascadingMiddleware:e}){return a(e.map(({id:e})=>`UseT${e}`))}}}),{renderToFile:s}=x({helpers:i({origin:`src`})}),l=e=>e?.trim().length===0,u=c(n?.templates,Ue),f=async e=>{for(let{kind:t,entry:n}of e)t===`apiRoute`?await s(r.api(n.file),u(n.name,n),{route:n},{overwrite:l}):t===`apiUse`&&await s(r.api(n.file),We,{},{overwrite:l})},m=async e=>{let i=e.flatMap(({kind:e,entry:t})=>e===`apiUse`?[t]:[]),a=e.flatMap(({kind:e,entry:r})=>{if(e!==`apiRoute`)return[];let a=r.name.split(`/`).reduce((e,n)=>{let r=e[e.length-1];return e.push(r?t(r,n):n),e},[]),o={...r,path:r.honoPattern,basename:r.name,cascadingMiddleware:i.flatMap(e=>a.some(t=>e.name===t)?[e]:[])};return[o,...Object.entries({...n?.alias}).flatMap(([e,t])=>{let n=b(e);return t===r.name?[{...o,name:e,basename:r.name,id:`${o.id}_${T(e)}`,alias:d(n),pathTokens:n}]:[]})]}).sort(S);for(let[e,t]of[[`@api/routes.ts`,Fe]])await o(r.lib(e),t,{routes:a,cascadingMiddleware:i})};return{config({command:e}){return{define:{KOSMO_PRODUCTION_BUILD:e===`build`?`true`:`false`}}},async start(){for(let[e,t]of[[`api.ts`,Le],[`api:factory.ts`,Re],[`@api/app.ts`,Ae],[`@api/parsers.ts`,Ne],[`@api/dev.ts`,je],[`@api/errors.ts`,Me],[`@api/router.ts`,Pe],[`@api/server.ts`,Ie]])await o(r.lib(e),t,{});for(let[e,t]of[[`app.ts`,ze],[`dev.ts`,Be],[`errors.ts`,He],[`server.ts`,Ge],[`use.ts`,Ke],[`env.d.ts`,Ve]])await s(r.api(e),t,{},{overwrite:l})},async watch(e,t){await f(e.filter(p(t,[`create`]))),await m(e)},async build(e){await f(e),await m(e)}}}),Je=h({meta:{name:`Hono`,slot:`backend`},dependencies:{hono:V.devDependencies.hono,"@hono/node-server":V.devDependencies[`@hono/node-server`]},factory:qe}),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`}},Ye=`import Router, { type RouterMiddleware } from "@koa/router";
|
|
1890
|
+
import Koa from "koa";
|
|
1205
1891
|
|
|
1206
|
-
import type {
|
|
1892
|
+
import type { Route, RouteDebugOption } from "@kosmojs/core/api";
|
|
1207
1893
|
|
|
1208
1894
|
import type { DefaultContext, DefaultState } from "../api";
|
|
1209
1895
|
|
|
@@ -1211,27 +1897,75 @@ export type App = Koa<DefaultState, DefaultContext>;
|
|
|
1211
1897
|
|
|
1212
1898
|
export type AppOptions = ConstructorParameters<
|
|
1213
1899
|
typeof Koa<DefaultState, DefaultContext>
|
|
1214
|
-
>[0];
|
|
1900
|
+
>[0] & { router?: Router; debug?: RouteDebugOption };
|
|
1901
|
+
|
|
1902
|
+
export function appFactory(
|
|
1903
|
+
routes: Array<Route<RouterMiddleware>>,
|
|
1904
|
+
options: AppOptions,
|
|
1905
|
+
): App;
|
|
1906
|
+
|
|
1907
|
+
export function appFactory(
|
|
1908
|
+
routes: Array<Route<RouterMiddleware>>,
|
|
1909
|
+
fn: (a: { app: App; router: Router<never> }) => void,
|
|
1910
|
+
): App;
|
|
1911
|
+
|
|
1912
|
+
export function appFactory(
|
|
1913
|
+
routes: Array<Route<RouterMiddleware>>,
|
|
1914
|
+
options: AppOptions,
|
|
1915
|
+
fn: (a: { app: App; router: Router<never> }) => void,
|
|
1916
|
+
): App;
|
|
1917
|
+
|
|
1918
|
+
export function appFactory(
|
|
1919
|
+
routes: Array<Route<RouterMiddleware>>,
|
|
1920
|
+
...rest: Array<unknown>
|
|
1921
|
+
): App {
|
|
1922
|
+
const [options, fn] = typeof rest[0] === "function" ? [{}, rest[0]] : rest;
|
|
1215
1923
|
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1924
|
+
const {
|
|
1925
|
+
router = new Router(),
|
|
1926
|
+
debug = undefined,
|
|
1927
|
+
...appOptions
|
|
1928
|
+
} = {
|
|
1929
|
+
...(options ? { ...options } : {}),
|
|
1219
1930
|
};
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1931
|
+
|
|
1932
|
+
for (const route of routes) {
|
|
1933
|
+
if (typeof debug === "function") {
|
|
1934
|
+
(debug as Function)(route.debug, route);
|
|
1935
|
+
} else if (debug) {
|
|
1936
|
+
console.log(route.debug[typeof debug === "string" ? debug : "full"]);
|
|
1937
|
+
}
|
|
1938
|
+
router.register(route.path, route.methods, route.middleware, route);
|
|
1939
|
+
}
|
|
1940
|
+
|
|
1941
|
+
const app = new Koa(appOptions);
|
|
1942
|
+
|
|
1943
|
+
if (typeof fn === "function") {
|
|
1944
|
+
fn({ app, router });
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
return app;
|
|
1948
|
+
}
|
|
1949
|
+
`,Xe=`import type { DevSetup } from "@kosmojs/core/api";
|
|
1223
1950
|
|
|
1224
1951
|
export const devSetup = (setup: DevSetup) => setup;
|
|
1225
|
-
`,
|
|
1952
|
+
`,Ze=`import type {
|
|
1953
|
+
DefaultContext,
|
|
1954
|
+
DefaultState,
|
|
1955
|
+
ParameterizedContext,
|
|
1956
|
+
} from "../api";
|
|
1226
1957
|
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1958
|
+
type ErrorHandler = (
|
|
1959
|
+
error: any,
|
|
1960
|
+
ctx: ParameterizedContext<unknown, DefaultState, DefaultContext>,
|
|
1961
|
+
) => Promise<void> | void;
|
|
1962
|
+
|
|
1963
|
+
export type ErrorHandlerFactory = (handler: ErrorHandler) => ErrorHandler;
|
|
1230
1964
|
|
|
1231
1965
|
export const errorHandlerFactory: ErrorHandlerFactory = (handler) => {
|
|
1232
1966
|
return handler;
|
|
1233
1967
|
};
|
|
1234
|
-
`,
|
|
1968
|
+
`,Qe=`import zlib from "node:zlib";
|
|
1235
1969
|
|
|
1236
1970
|
import type { RouterContext } from "@koa/router";
|
|
1237
1971
|
import Formidable, { type Options as FormidableOptions } from "formidable";
|
|
@@ -1444,8 +2178,7 @@ export const bodyparsers: {
|
|
|
1444
2178
|
return rawParser(stream, rawParserOptions);
|
|
1445
2179
|
},
|
|
1446
2180
|
};
|
|
1447
|
-
|
|
1448
|
-
import { match } from "path-to-regexp";
|
|
2181
|
+
`,$e=`import type { RouterMiddleware } from "@koa/router";
|
|
1449
2182
|
|
|
1450
2183
|
import type {
|
|
1451
2184
|
RequestBodyTarget,
|
|
@@ -1457,7 +2190,6 @@ import {
|
|
|
1457
2190
|
type CreateRouteMiddleware,
|
|
1458
2191
|
createRoutes,
|
|
1459
2192
|
type HTTPMethod,
|
|
1460
|
-
type RouterFactory,
|
|
1461
2193
|
StateKey,
|
|
1462
2194
|
} from "@kosmojs/core/api";
|
|
1463
2195
|
import { ValidationError } from "@kosmojs/core/errors";
|
|
@@ -1473,10 +2205,6 @@ import { type BodyparserOptions, bodyparsers, metaparsers } from "./parsers";
|
|
|
1473
2205
|
import { routeSources } from "./routes";
|
|
1474
2206
|
|
|
1475
2207
|
import globalMiddleware from "{{ createImport 'api' 'use' }}";
|
|
1476
|
-
import { apiRouteMap } from "{{ createImport 'libCore' }}";
|
|
1477
|
-
|
|
1478
|
-
export type Router = import("@koa/router").Router<DefaultState, DefaultContext>;
|
|
1479
|
-
export type RouterOptions = import("@koa/router").RouterOptions;
|
|
1480
2208
|
|
|
1481
2209
|
/**
|
|
1482
2210
|
* Create route-level middleware stack that handles:
|
|
@@ -1493,33 +2221,7 @@ export type RouterOptions = import("@koa/router").RouterOptions;
|
|
|
1493
2221
|
* */
|
|
1494
2222
|
export const createRouteMiddleware: CreateRouteMiddleware<
|
|
1495
2223
|
ParameterizedMiddleware
|
|
1496
|
-
> = ({ name,
|
|
1497
|
-
const route = apiRouteMap[name];
|
|
1498
|
-
|
|
1499
|
-
if (!route) {
|
|
1500
|
-
throw new Error(\`createRouteMiddleware: \${name} route does not exists\`);
|
|
1501
|
-
}
|
|
1502
|
-
|
|
1503
|
-
const { params, numericProperties } = route;
|
|
1504
|
-
|
|
1505
|
-
const pathMatcher = match(pathPattern);
|
|
1506
|
-
|
|
1507
|
-
const matchPath = (path: string) => {
|
|
1508
|
-
try {
|
|
1509
|
-
return pathMatcher(path);
|
|
1510
|
-
} catch (e) {
|
|
1511
|
-
return undefined;
|
|
1512
|
-
}
|
|
1513
|
-
};
|
|
1514
|
-
|
|
1515
|
-
const maybeNumber = (val: unknown) => {
|
|
1516
|
-
if (val === undefined || val === null) {
|
|
1517
|
-
return val;
|
|
1518
|
-
}
|
|
1519
|
-
const n = Number(val);
|
|
1520
|
-
return Number.isFinite(n) ? n : val;
|
|
1521
|
-
};
|
|
1522
|
-
|
|
2224
|
+
> = ({ name, validationSchemas, normalizeParams, normalizeSearchParams }) => {
|
|
1523
2225
|
const validationMiddleware = [
|
|
1524
2226
|
/**
|
|
1525
2227
|
* Extends Koa context with:
|
|
@@ -1560,16 +2262,7 @@ export const createRouteMiddleware: CreateRouteMiddleware<
|
|
|
1560
2262
|
ctx[StateKey].set(
|
|
1561
2263
|
target,
|
|
1562
2264
|
target === "query"
|
|
1563
|
-
?
|
|
1564
|
-
Object.entries(parser(ctx)).map(([k, v]) => [
|
|
1565
|
-
k,
|
|
1566
|
-
numericProperties.query[ctx.method]?.includes(k)
|
|
1567
|
-
? Array.isArray(v)
|
|
1568
|
-
? v.map((e) => maybeNumber(e))
|
|
1569
|
-
: maybeNumber(v)
|
|
1570
|
-
: v,
|
|
1571
|
-
]),
|
|
1572
|
-
)
|
|
2265
|
+
? normalizeSearchParams(parser(ctx), ctx.method as never)
|
|
1573
2266
|
: parser(ctx),
|
|
1574
2267
|
);
|
|
1575
2268
|
}
|
|
@@ -1621,23 +2314,7 @@ export const createRouteMiddleware: CreateRouteMiddleware<
|
|
|
1621
2314
|
* */
|
|
1622
2315
|
use(
|
|
1623
2316
|
function useValidateParams(ctx, next) {
|
|
1624
|
-
const
|
|
1625
|
-
const normalizedParams = params.reduce(
|
|
1626
|
-
(map: Record<string, unknown>, name) => {
|
|
1627
|
-
const value = matched ? matched.params[name] : undefined;
|
|
1628
|
-
if (Array.isArray(value)) {
|
|
1629
|
-
map[name] = numericProperties.params.includes(name)
|
|
1630
|
-
? value.map((e) => maybeNumber(e))
|
|
1631
|
-
: value;
|
|
1632
|
-
} else if (value) {
|
|
1633
|
-
map[name] = numericProperties.params.includes(name)
|
|
1634
|
-
? maybeNumber(value)
|
|
1635
|
-
: value;
|
|
1636
|
-
}
|
|
1637
|
-
return map;
|
|
1638
|
-
},
|
|
1639
|
-
{},
|
|
1640
|
-
);
|
|
2317
|
+
const normalizedParams = normalizeParams(ctx.path);
|
|
1641
2318
|
validationSchemas.params?.validate(normalizedParams);
|
|
1642
2319
|
ctx[StateKey].set("params", normalizedParams);
|
|
1643
2320
|
return next();
|
|
@@ -1866,32 +2543,21 @@ export const routes = createRoutes<ParameterizedMiddleware, RouterMiddleware>(
|
|
|
1866
2543
|
createRouteMiddleware,
|
|
1867
2544
|
},
|
|
1868
2545
|
);
|
|
1869
|
-
|
|
1870
|
-
export const routerFactory: RouterFactory<Router, RouterOptions> = (
|
|
1871
|
-
factory,
|
|
1872
|
-
) => {
|
|
1873
|
-
const createRouter = (options?: RouterOptions): Router => {
|
|
1874
|
-
return new KoaRouter(options);
|
|
1875
|
-
};
|
|
1876
|
-
return factory({ createRouter });
|
|
1877
|
-
};
|
|
1878
|
-
`,Me=`import { join } from "node:path";
|
|
2546
|
+
`,et=`import { join } from "node:path";
|
|
1879
2547
|
|
|
1880
2548
|
import type { RouteSource } from "@kosmojs/core/api";
|
|
1881
2549
|
|
|
1882
|
-
import { base, apiBase } from "{{ createImport 'libCore' }}";
|
|
2550
|
+
import { base, apiBase, apiRouteMap, apiRouteMapper } from "{{ createImport 'libCore' }}";
|
|
1883
2551
|
|
|
1884
2552
|
{{#each routes}}
|
|
1885
2553
|
import {{id}} from "{{ createImport 'api' file }}";
|
|
1886
|
-
import { validationSchemas as {{id}}_schemas } from "{{ createImport 'libApi'
|
|
2554
|
+
import { validationSchemas as {{id}}_schemas } from "{{ createImport 'libApi' basename 'schemas' }}";
|
|
1887
2555
|
{{/each}}
|
|
1888
2556
|
|
|
1889
2557
|
{{#each cascadingMiddleware}}
|
|
1890
2558
|
import {{id}}, { type UseT as UseT{{id}} } from "{{ createImport 'api' file }}";
|
|
1891
2559
|
{{/each}}
|
|
1892
2560
|
|
|
1893
|
-
type Override<A, B> = Omit<A, keyof B> & B;
|
|
1894
|
-
|
|
1895
2561
|
export type RouteMap = {
|
|
1896
2562
|
{{#each routes}}
|
|
1897
2563
|
"{{name}}": {
|
|
@@ -1905,65 +2571,63 @@ export type RouteMap = {
|
|
|
1905
2571
|
export const routeSources: Array<RouteSource<never>> = [
|
|
1906
2572
|
{{#each routes}}
|
|
1907
2573
|
{
|
|
1908
|
-
|
|
1909
|
-
{{
|
|
1910
|
-
path: "{{
|
|
1911
|
-
pathPattern: "{{
|
|
2574
|
+
{{#if alias}}
|
|
2575
|
+
...apiRouteMapper(apiBase, { ...{{serializeApiRoute .}}, pathPattern: "{{alias}}" }),
|
|
2576
|
+
path: "{{alias}}",
|
|
2577
|
+
pathPattern: "{{alias}}",
|
|
1912
2578
|
{{else}}
|
|
2579
|
+
...apiRouteMap["{{name}}"],
|
|
1913
2580
|
path: join(base, apiBase, "{{path}}"),
|
|
1914
2581
|
pathPattern: join(base, apiBase, "{{pathPattern}}"),
|
|
1915
2582
|
{{/if}}
|
|
2583
|
+
name: "{{name}}",
|
|
1916
2584
|
file: "{{file}}",
|
|
1917
2585
|
cascadingMiddleware: [ {{#each cascadingMiddleware}}{{id}}, {{/each}}].flat() as Array<never>,
|
|
1918
2586
|
definitionItems: {{id}} as never,
|
|
1919
2587
|
validationSchemas: {{id}}_schemas,
|
|
1920
2588
|
},
|
|
1921
2589
|
{{/each}}
|
|
1922
|
-
]
|
|
1923
|
-
`,
|
|
2590
|
+
];
|
|
2591
|
+
`,tt=`import { chmod, unlink } from "node:fs/promises";
|
|
1924
2592
|
import { parseArgs, styleText } from "node:util";
|
|
1925
2593
|
|
|
1926
|
-
import type { ServerFactory } from "@kosmojs/core/api";
|
|
1927
|
-
|
|
1928
2594
|
import type { App } from "./app";
|
|
1929
2595
|
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
short: "p",
|
|
1936
|
-
},
|
|
1937
|
-
sock: {
|
|
1938
|
-
type: "string",
|
|
1939
|
-
short: "s",
|
|
1940
|
-
},
|
|
1941
|
-
},
|
|
1942
|
-
});
|
|
1943
|
-
|
|
1944
|
-
const getListenHandles = async () => {
|
|
1945
|
-
const { port, sock } = { ...values };
|
|
2596
|
+
type Handles = {
|
|
2597
|
+
port?: number | undefined;
|
|
2598
|
+
sock?: string | undefined;
|
|
2599
|
+
onListen?: () => Promise<void>;
|
|
2600
|
+
};
|
|
1946
2601
|
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
2602
|
+
const getListenHandles = async (opt?: Handles): Promise<Handles> => {
|
|
2603
|
+
const { port, sock } = opt
|
|
2604
|
+
? opt
|
|
2605
|
+
: parseArgs({
|
|
2606
|
+
options: {
|
|
2607
|
+
port: {
|
|
2608
|
+
type: "string",
|
|
2609
|
+
short: "p",
|
|
2610
|
+
},
|
|
2611
|
+
sock: {
|
|
2612
|
+
type: "string",
|
|
2613
|
+
short: "s",
|
|
2614
|
+
},
|
|
2615
|
+
},
|
|
2616
|
+
}).values;
|
|
1951
2617
|
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
return;
|
|
1956
|
-
}
|
|
1957
|
-
console.error(error.message);
|
|
1958
|
-
process.exit(1);
|
|
1959
|
-
});
|
|
1960
|
-
}
|
|
2618
|
+
if (![port, sock].some(Boolean)) {
|
|
2619
|
+
throw new Error("Please provide either -p/--port number or -s/--sock path");
|
|
2620
|
+
}
|
|
1961
2621
|
|
|
1962
|
-
|
|
1963
|
-
|
|
2622
|
+
if (sock) {
|
|
2623
|
+
await unlink(sock).catch((error) => {
|
|
2624
|
+
if (error.code !== "ENOENT") {
|
|
2625
|
+
throw error;
|
|
2626
|
+
}
|
|
2627
|
+
});
|
|
2628
|
+
}
|
|
1964
2629
|
|
|
1965
2630
|
const onListen = async () => {
|
|
1966
|
-
const { port, sock } = await getListenHandles();
|
|
1967
2631
|
if (sock) {
|
|
1968
2632
|
// Make Unix socket world-writable so other processes (e.g. a reverse proxy)
|
|
1969
2633
|
// can connect without permission issues.
|
|
@@ -1975,30 +2639,19 @@ export const serverFactory: ServerFactory<App> = (factory) => {
|
|
|
1975
2639
|
);
|
|
1976
2640
|
};
|
|
1977
2641
|
|
|
1978
|
-
return
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
},
|
|
1984
|
-
getListenHandles,
|
|
1985
|
-
onListen,
|
|
1986
|
-
});
|
|
2642
|
+
return {
|
|
2643
|
+
port: port ? Number(port) : undefined,
|
|
2644
|
+
sock,
|
|
2645
|
+
onListen: opt?.onListen || onListen,
|
|
2646
|
+
};
|
|
1987
2647
|
};
|
|
1988
2648
|
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
console.error("");
|
|
1996
|
-
// In development, crash hard
|
|
1997
|
-
if (process.env.NODE_ENV === "development") {
|
|
1998
|
-
process.exit(1);
|
|
1999
|
-
}
|
|
2000
|
-
});
|
|
2001
|
-
`,Pe=`import type { RouterContext } from "@koa/router";
|
|
2649
|
+
export const serve = async <T extends App>(app: T, opt?: Handles) => {
|
|
2650
|
+
const { port, sock, onListen } = await getListenHandles(opt);
|
|
2651
|
+
const server = app.listen(port || sock, onListen);
|
|
2652
|
+
return server as never;
|
|
2653
|
+
};
|
|
2654
|
+
`,nt=`import type { RouterContext } from "@koa/router";
|
|
2002
2655
|
import type { Next } from "koa";
|
|
2003
2656
|
|
|
2004
2657
|
import type { ValidationDefmap, ValidationOptmap } from "@kosmojs/core";
|
|
@@ -2160,25 +2813,25 @@ export const defineRoute: <
|
|
|
2160
2813
|
use: use as never,
|
|
2161
2814
|
});
|
|
2162
2815
|
};
|
|
2163
|
-
`,
|
|
2816
|
+
`,rt=`export * from "./@api/app";
|
|
2817
|
+
export { appFactory as default } from "./@api/app";
|
|
2164
2818
|
export * from "./@api/dev";
|
|
2165
2819
|
export * from "./@api/errors";
|
|
2166
2820
|
export * from "./@api/router";
|
|
2167
2821
|
export * from "./@api/routes";
|
|
2168
2822
|
export * from "./@api/server";
|
|
2169
|
-
`,
|
|
2823
|
+
`,it=`import appFactory, { routes } from "{{ createImport 'lib' 'api:factory' }}";
|
|
2824
|
+
import defaultErrorHandler from "./errors";
|
|
2170
2825
|
|
|
2171
|
-
|
|
2826
|
+
export default appFactory(routes, ({ app, router }) => {
|
|
2172
2827
|
|
|
2173
|
-
|
|
2174
|
-
const app = createApp();
|
|
2828
|
+
app.on("error", defaultErrorHandler);
|
|
2175
2829
|
|
|
2176
2830
|
// NOTE: Routes should be added last, after any middleware
|
|
2177
2831
|
app.use(router.routes());
|
|
2178
2832
|
|
|
2179
|
-
return app;
|
|
2180
2833
|
});
|
|
2181
|
-
`,
|
|
2834
|
+
`,at=`import app from "./app";
|
|
2182
2835
|
|
|
2183
2836
|
import { devSetup } from "{{ createImport 'lib' 'api:factory' }}";
|
|
2184
2837
|
|
|
@@ -2190,45 +2843,45 @@ export default devSetup({
|
|
|
2190
2843
|
// close db connections, server sockets etc.
|
|
2191
2844
|
},
|
|
2192
2845
|
});
|
|
2193
|
-
|
|
2846
|
+
|
|
2847
|
+
process.on("unhandledRejection", (reason) => {
|
|
2848
|
+
console.error("💥 UNHANDLED REJECTION");
|
|
2849
|
+
console.error("Reason:", reason);
|
|
2850
|
+
process.exit(1);
|
|
2851
|
+
});
|
|
2852
|
+
`,ot=`export declare module "{{ createImport 'libApi' }}" {
|
|
2194
2853
|
interface DefaultState {}
|
|
2195
2854
|
interface DefaultContext {}
|
|
2196
2855
|
}
|
|
2197
|
-
`,
|
|
2856
|
+
`,st=`import { HTTPError, ValidationError } from "@kosmojs/core/errors";
|
|
2198
2857
|
|
|
2199
2858
|
import { errorHandlerFactory } from "{{ createImport 'lib' 'api:factory' }}";
|
|
2200
2859
|
|
|
2201
|
-
export default errorHandlerFactory(
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
? error
|
|
2208
|
-
: error
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
ctx.body = message;
|
|
2220
|
-
}
|
|
2221
|
-
}
|
|
2222
|
-
},
|
|
2223
|
-
);
|
|
2224
|
-
`,Be=`import { defineRoute } from "{{ createImport 'libApi' }}";
|
|
2860
|
+
export default errorHandlerFactory(async (error, ctx) => {
|
|
2861
|
+
const [status, message] = Array.isArray(error)
|
|
2862
|
+
? error
|
|
2863
|
+
: error instanceof HTTPError
|
|
2864
|
+
? [error.status, error.message]
|
|
2865
|
+
: error instanceof ValidationError
|
|
2866
|
+
? [400, \`\${error.target}: \${error.errorMessage}\`]
|
|
2867
|
+
: [error.statusCode || 500, error.message];
|
|
2868
|
+
|
|
2869
|
+
ctx.status = status;
|
|
2870
|
+
|
|
2871
|
+
if (ctx.accepts("json")) {
|
|
2872
|
+
ctx.body = { error: message };
|
|
2873
|
+
} else {
|
|
2874
|
+
ctx.body = message;
|
|
2875
|
+
}
|
|
2876
|
+
});
|
|
2877
|
+
`,ct=`import { defineRoute } from "{{ createImport 'libApi' }}";
|
|
2225
2878
|
|
|
2226
2879
|
export default defineRoute<"{{route.name}}">(({ GET }) => [
|
|
2227
2880
|
GET(async (ctx) => {
|
|
2228
2881
|
ctx.body = "Automatically generated route";
|
|
2229
2882
|
}),
|
|
2230
2883
|
]);
|
|
2231
|
-
`,
|
|
2884
|
+
`,lt=`import { use } from "{{ createImport 'libApi' }}";
|
|
2232
2885
|
|
|
2233
2886
|
export type UseT = {};
|
|
2234
2887
|
|
|
@@ -2239,46 +2892,32 @@ export default [
|
|
|
2239
2892
|
return next();
|
|
2240
2893
|
}),
|
|
2241
2894
|
];
|
|
2242
|
-
`,
|
|
2243
|
-
|
|
2244
|
-
export default routerFactory(({ createRouter }) => {
|
|
2245
|
-
const router = createRouter();
|
|
2246
|
-
|
|
2247
|
-
for (const { name, path, methods, middleware } of routes) {
|
|
2248
|
-
router.register(path, methods, middleware, { name });
|
|
2249
|
-
}
|
|
2250
|
-
|
|
2251
|
-
return router;
|
|
2252
|
-
});
|
|
2253
|
-
`,Ue=`import app from "./app";
|
|
2254
|
-
|
|
2255
|
-
import { serverFactory } from "{{ createImport 'lib' 'api:factory' }}";
|
|
2256
|
-
|
|
2257
|
-
serverFactory(async ({ createServer }) => {
|
|
2258
|
-
await createServer(app);
|
|
2259
|
-
});
|
|
2260
|
-
`,We=`import defaultErrorHandler from "./errors";
|
|
2895
|
+
`,ut=`import { serve } from "{{ createImport 'lib' 'api:factory' }}";
|
|
2896
|
+
import app from "./app";
|
|
2261
2897
|
|
|
2262
|
-
|
|
2898
|
+
await serve(app);
|
|
2899
|
+
`,dt=`import { use } from "{{ createImport 'libApi' }}";
|
|
2263
2900
|
|
|
2901
|
+
/**
|
|
2902
|
+
* Define global middleware applied to all routes.
|
|
2903
|
+
* Can be overridden on a per-route basis using the slot key.
|
|
2904
|
+
* */
|
|
2264
2905
|
export default [
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
* */
|
|
2269
|
-
use(defaultErrorHandler, { slot: "errorHandler" }),
|
|
2906
|
+
use(async function useExample(ctx, next) {
|
|
2907
|
+
return next();
|
|
2908
|
+
}),
|
|
2270
2909
|
];
|
|
2271
|
-
`,
|
|
2910
|
+
`,ft=g((e,n)=>{let{createPath:r,createImportHelpers:i}=y(e),a=e=>e.length===0?`{}`:e.length===1?e[0]:`Override<${e[0]}, ${a(e.slice(1))}>`,{renderToFile:o}=x({helpers:{...i({origin:`lib`}),...w(),paramsDefaults({params:e}){return`[${e.schema.map(()=>`unknown?`).join(`, `)}]`},paramsMappings({params:e}){return`[${e.schema.map(({name:e,kind:t})=>`["${e}", unknown, ${t===`required`?`true`:`false`}]`).join(`, `)}]`},cascadingState({cascadingMiddleware:e}){return a(e.map(({id:e})=>`UseT${e}`))}}}),{renderToFile:s}=x({helpers:i({origin:`src`})}),l=e=>e?.trim().length===0,u=c(n?.templates,ct),d=async e=>{for(let{kind:t,entry:n}of e)t===`apiRoute`?await s(r.api(n.file),u(n.name,n),{route:n},{overwrite:l}):t===`apiUse`&&await s(r.api(n.file),lt,{},{overwrite:l})},m=async e=>{let i=e.flatMap(({kind:e,entry:t})=>e===`apiUse`?[t]:[]),a=e.flatMap(({kind:e,entry:r})=>{if(e!==`apiRoute`)return[];let a=r.name.split(`/`).reduce((e,n)=>{let r=e[e.length-1];return e.push(r?t(r,n):n),e},[]),o={...r,basename:r.name,path:r.pathPattern,cascadingMiddleware:i.flatMap(e=>a.some(t=>e.name===t)?[e]:[])};return[o,...Object.entries({...n?.alias}).flatMap(([e,t])=>{let n=b(e);return t===r.name?[{...o,name:e,basename:r.name,id:`${o.id}_${T(e)}`,alias:f(n),pathTokens:n}]:[]})]}).sort(S);for(let[e,t]of[[`@api/routes.ts`,et]])await o(r.lib(e),t,{routes:a,cascadingMiddleware:i})};return{config({command:e}){return{define:{KOSMO_PRODUCTION_BUILD:e===`build`?`true`:`false`}}},async start(){for(let[e,t]of[[`api.ts`,nt],[`api:factory.ts`,rt],[`@api/app.ts`,Ye],[`@api/dev.ts`,Xe],[`@api/errors.ts`,Ze],[`@api/parsers.ts`,Qe],[`@api/router.ts`,$e],[`@api/server.ts`,tt]])await o(r.lib(e),t,{});for(let[e,t]of[[`app.ts`,it],[`dev.ts`,at],[`errors.ts`,st],[`server.ts`,ut],[`use.ts`,dt],[`env.d.ts`,ot]])await s(r.api(e),t,{},{overwrite:l})},async watch(e,t){await d(e.filter(p(t,[`create`]))),await m(e)},async build(e){await d(e),await m(e)}}}),pt=h({meta:{name:`Koa`,slot:`backend`,types:[`@types/koa`]},dependencies:{koa:H.devDependencies.koa,"@koa/router":H.devDependencies[`@koa/router`],formidable:H.devDependencies.formidable,"raw-body":H.devDependencies[`raw-body`]},devDependencies:{"@types/koa":H.devDependencies[`@types/koa`],"@types/formidable":H.devDependencies[`@types/formidable`]},factory:ft}),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`}},mt=()=>{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)]},ht=(e,t,n)=>{let{remarkPlugins:r=[],rehypePlugins:i=[]}={...n},a=()=>{let t=[`${l.srcDir}/${e.name}/${l.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,`
|
|
2272
2911
|
if (import.meta.hot) {
|
|
2273
2912
|
import.meta.hot.accept(() => {});
|
|
2274
2913
|
}
|
|
2275
2914
|
`].join(`
|
|
2276
|
-
`)}}}},o=[ne({jsxImportSource:`preact`,providerImportSource:`@mdx-js/preact`,remarkPlugins:r,rehypePlugins:i})];return t===`serve`&&o.push(a()),o},
|
|
2915
|
+
`)}}}},o=[ne({jsxImportSource:`preact`,providerImportSource:`@mdx-js/preact`,remarkPlugins:r,rehypePlugins:i})];return t===`serve`&&o.push(a()),o},gt=`import type { FunctionComponent } from "preact";
|
|
2277
2916
|
|
|
2278
2917
|
export const AppProvider: FunctionComponent = (props) => {
|
|
2279
2918
|
return props.children;
|
|
2280
2919
|
};
|
|
2281
|
-
`,
|
|
2920
|
+
`,_t=`import { render, hydrate as hydrateOrig } from "preact";
|
|
2282
2921
|
import type { RouterFactoryReturn } from "@kosmojs/core";
|
|
2283
2922
|
import { clientRenderFactory } from "@kosmojs/core/generators";
|
|
2284
2923
|
|
|
@@ -2319,7 +2958,7 @@ export const mount = async (
|
|
|
2319
2958
|
}
|
|
2320
2959
|
|
|
2321
2960
|
export default clientRenderFactory();
|
|
2322
|
-
`,
|
|
2961
|
+
`,vt=`import { renderToString as renderToStringOrig } from "preact-render-to-string";
|
|
2323
2962
|
|
|
2324
2963
|
import type {
|
|
2325
2964
|
RenderToStringWrapper,
|
|
@@ -2393,7 +3032,7 @@ export const renderToString: RenderToStringWrapper<
|
|
|
2393
3032
|
}
|
|
2394
3033
|
|
|
2395
3034
|
export default serverRenderFactory<false>();
|
|
2396
|
-
`,
|
|
3035
|
+
`,yt=`declare module "*.mdx" {
|
|
2397
3036
|
import type { ComponentType } from "preact";
|
|
2398
3037
|
export const frontmatter: Record<string, unknown>;
|
|
2399
3038
|
const component: ComponentType;
|
|
@@ -2406,7 +3045,7 @@ declare module "*.md" {
|
|
|
2406
3045
|
const component: ComponentType;
|
|
2407
3046
|
export default component;
|
|
2408
3047
|
}
|
|
2409
|
-
|
|
3048
|
+
`,bt=`import { MDXProvider } from "@mdx-js/preact";
|
|
2410
3049
|
import { match, pathToRegexp } from "path-to-regexp";
|
|
2411
3050
|
import { type ComponentType, createContext, h, type VNode } from "preact";
|
|
2412
3051
|
|
|
@@ -2583,7 +3222,11 @@ export const createRoute = (
|
|
|
2583
3222
|
loader: RawRoute["loader"],
|
|
2584
3223
|
layouts: RawRoute["layouts"],
|
|
2585
3224
|
): RawRoute => {
|
|
2586
|
-
|
|
3225
|
+
// strip trailing slash (keeping a sole "/") so the base-joined index route
|
|
3226
|
+
// matches both with and without it - "/docs/" as a pattern rejects "/docs"
|
|
3227
|
+
const path = \`\${base}/\${pathPattern}\`
|
|
3228
|
+
.replace(/\\/+/g, "/")
|
|
3229
|
+
.replace(/(.+)\\/$/, "$1");
|
|
2587
3230
|
|
|
2588
3231
|
const { regexp } = pathToRegexp(path, { sensitive: true });
|
|
2589
3232
|
const matcher = match<Route["params"]>(path);
|
|
@@ -2591,9 +3234,11 @@ export const createRoute = (
|
|
|
2591
3234
|
return {
|
|
2592
3235
|
name,
|
|
2593
3236
|
regexp,
|
|
3237
|
+
// count segments of the same base-joined path the regexp matches against;
|
|
3238
|
+
// resolve() compares this against the full url pathname's segment count
|
|
2594
3239
|
pathSegments: name.includes("...")
|
|
2595
3240
|
? undefined
|
|
2596
|
-
:
|
|
3241
|
+
: path.split("/").filter(Boolean).length,
|
|
2597
3242
|
extractParams: (path) => {
|
|
2598
3243
|
const match = matcher(path);
|
|
2599
3244
|
return match ? match.params : {};
|
|
@@ -2602,7 +3247,7 @@ export const createRoute = (
|
|
|
2602
3247
|
layouts,
|
|
2603
3248
|
};
|
|
2604
3249
|
};
|
|
2605
|
-
`,
|
|
3250
|
+
`,xt=`/* @jsxImportSource preact */
|
|
2606
3251
|
|
|
2607
3252
|
import styles from "./styles.module.css";
|
|
2608
3253
|
|
|
@@ -2643,7 +3288,7 @@ export default function PageSample(props: {
|
|
|
2643
3288
|
</div>
|
|
2644
3289
|
);
|
|
2645
3290
|
}
|
|
2646
|
-
`,
|
|
3291
|
+
`,St=`/* @jsxImportSource preact */
|
|
2647
3292
|
|
|
2648
3293
|
import styles from "./styles.module.css";
|
|
2649
3294
|
|
|
@@ -2695,7 +3340,7 @@ export default function PageSample(props: {
|
|
|
2695
3340
|
</div>
|
|
2696
3341
|
);
|
|
2697
3342
|
}
|
|
2698
|
-
`,
|
|
3343
|
+
`,Ct=`* {
|
|
2699
3344
|
margin: 0;
|
|
2700
3345
|
padding: 0;
|
|
2701
3346
|
box-sizing: border-box;
|
|
@@ -2830,7 +3475,7 @@ export default function PageSample(props: {
|
|
|
2830
3475
|
align-items: center;
|
|
2831
3476
|
gap: 0.25rem;
|
|
2832
3477
|
}
|
|
2833
|
-
`,
|
|
3478
|
+
`,wt=`/* @jsxImportSource preact */
|
|
2834
3479
|
|
|
2835
3480
|
import styles from "./styles.module.css";
|
|
2836
3481
|
|
|
@@ -2896,7 +3541,7 @@ export default function WelcomePage() {
|
|
|
2896
3541
|
</div>
|
|
2897
3542
|
);
|
|
2898
3543
|
}
|
|
2899
|
-
`,
|
|
3544
|
+
`,Tt=`export type ParamsMap = {
|
|
2900
3545
|
{{#each pageRoutes}}"{{name}}": {{serializeParamsLiteral .}};
|
|
2901
3546
|
{{/each}}
|
|
2902
3547
|
};
|
|
@@ -2905,7 +3550,7 @@ export const paramNames = {
|
|
|
2905
3550
|
{{#each pageRoutes}}"{{name}}": [ {{#each params.schema}}"{{name}}", {{/each}}],
|
|
2906
3551
|
{{/each}}
|
|
2907
3552
|
} as const;
|
|
2908
|
-
`,
|
|
3553
|
+
`,Et=`import type { ComponentType } from "preact";
|
|
2909
3554
|
|
|
2910
3555
|
import type { RouterFactoryReturn } from "@kosmojs/core";
|
|
2911
3556
|
import { createRouterFactory } from "@kosmojs/core/generators";
|
|
@@ -2949,7 +3594,7 @@ export default createRouterFactory<
|
|
|
2949
3594
|
Promise<RouteComponent>,
|
|
2950
3595
|
{ server: { route: Route } }
|
|
2951
3596
|
>();
|
|
2952
|
-
`,
|
|
3597
|
+
`,Dt=`import { join } from "node:path";
|
|
2953
3598
|
|
|
2954
3599
|
import { compile } from "path-to-regexp";
|
|
2955
3600
|
|
|
@@ -2995,7 +3640,7 @@ export default Object.entries(routes)
|
|
|
2995
3640
|
return [];
|
|
2996
3641
|
})
|
|
2997
3642
|
.map((path) => join(base, path));
|
|
2998
|
-
`,
|
|
3643
|
+
`,Ot=`import type { PageRoute } from "@kosmojs/core";
|
|
2999
3644
|
|
|
3000
3645
|
{{#each pageRoutes}}
|
|
3001
3646
|
import * as {{id}} from "{{ createImport 'pages' file }}";
|
|
@@ -3019,7 +3664,7 @@ const routeMap: Record<
|
|
|
3019
3664
|
}
|
|
3020
3665
|
|
|
3021
3666
|
export default routeMap;
|
|
3022
|
-
`,
|
|
3667
|
+
`,kt=`import { useContext } from "preact/hooks";
|
|
3023
3668
|
|
|
3024
3669
|
import { RouterContext } from "./mdx";
|
|
3025
3670
|
|
|
@@ -3065,10 +3710,10 @@ export const useFrontmatter = <
|
|
|
3065
3710
|
>(): T => {
|
|
3066
3711
|
return useRoute().frontmatter as T;
|
|
3067
3712
|
};
|
|
3068
|
-
`,
|
|
3713
|
+
`,At=`import { AppProvider } from "{{ createImport 'lib' 'app' }}";
|
|
3069
3714
|
|
|
3070
3715
|
<AppProvider>{props.children}</AppProvider>
|
|
3071
|
-
`,
|
|
3716
|
+
`,jt=`import { h, type JSX } from "preact";
|
|
3072
3717
|
|
|
3073
3718
|
import { pageRouteMap, type LinkProps } from "{{ createImport 'libCore' }}";
|
|
3074
3719
|
|
|
@@ -3081,11 +3726,11 @@ export default function Link(
|
|
|
3081
3726
|
const { to, query, children, ...restProps } = props;
|
|
3082
3727
|
|
|
3083
3728
|
const [key, ...params] = to;
|
|
3084
|
-
const href = pageRouteMap[key]?.
|
|
3729
|
+
const href = pageRouteMap[key]?.path(params as never, query);
|
|
3085
3730
|
|
|
3086
3731
|
return h("a", { ...restProps, href }, children);
|
|
3087
3732
|
}
|
|
3088
|
-
`,
|
|
3733
|
+
`,Mt=`/**
|
|
3089
3734
|
* MDX component overrides.
|
|
3090
3735
|
*
|
|
3091
3736
|
* Every standard markdown element (headings, links, code blocks, etc.)
|
|
@@ -3108,7 +3753,7 @@ export const components = {
|
|
|
3108
3753
|
declare global {
|
|
3109
3754
|
type MDXProvidedComponents = typeof components;
|
|
3110
3755
|
}
|
|
3111
|
-
`,
|
|
3756
|
+
`,Nt=`import renderFactory, {
|
|
3112
3757
|
createRoutes,
|
|
3113
3758
|
hydrate,
|
|
3114
3759
|
mount,
|
|
@@ -3135,7 +3780,7 @@ if (root) {
|
|
|
3135
3780
|
} else {
|
|
3136
3781
|
console.error("❌ Root element not found!");
|
|
3137
3782
|
}
|
|
3138
|
-
`,
|
|
3783
|
+
`,Pt=`import renderFactory, {
|
|
3139
3784
|
createRoutes,
|
|
3140
3785
|
renderToString,
|
|
3141
3786
|
// no renderToStream on MDX folders
|
|
@@ -3156,7 +3801,7 @@ export default renderFactory(() => {
|
|
|
3156
3801
|
},
|
|
3157
3802
|
};
|
|
3158
3803
|
});
|
|
3159
|
-
`,
|
|
3804
|
+
`,Ft=`<!doctype html>
|
|
3160
3805
|
<html lang="en">
|
|
3161
3806
|
<head>
|
|
3162
3807
|
<meta charset="UTF-8" />
|
|
@@ -3168,13 +3813,13 @@ export default renderFactory(() => {
|
|
|
3168
3813
|
<script type="module" src="/{{ entryDir }}/client.ts"><\/script>
|
|
3169
3814
|
</body>
|
|
3170
3815
|
</html>
|
|
3171
|
-
`,
|
|
3816
|
+
`,It=`import PageSample from "{{ createImport 'lib' 'pageSamples/404.tsx' }}";
|
|
3172
3817
|
|
|
3173
3818
|
export default function Page() {
|
|
3174
3819
|
return <PageSample />;
|
|
3175
3820
|
}
|
|
3176
|
-
`,
|
|
3177
|
-
`,
|
|
3821
|
+
`,Lt=`{props.children}
|
|
3822
|
+
`,Rt=`---
|
|
3178
3823
|
title: "{{title}}"
|
|
3179
3824
|
---
|
|
3180
3825
|
|
|
@@ -3191,7 +3836,7 @@ export const pathMap = {
|
|
|
3191
3836
|
routeName="{{route.name}}"
|
|
3192
3837
|
pathMap={pathMap}
|
|
3193
3838
|
/>
|
|
3194
|
-
`,
|
|
3839
|
+
`,zt=`---
|
|
3195
3840
|
title: Welcome to KosmoJS
|
|
3196
3841
|
description: Content-first development with MDX and Vite
|
|
3197
3842
|
---
|
|
@@ -3199,7 +3844,7 @@ description: Content-first development with MDX and Vite
|
|
|
3199
3844
|
import WelcomePage from "{{ createImport 'lib' 'pageSamples/welcome.tsx' }}"
|
|
3200
3845
|
|
|
3201
3846
|
<WelcomePage />
|
|
3202
|
-
`,
|
|
3847
|
+
`,Bt=`import routerFactory, { createRouters } from "{{ createImport 'lib' 'router' }}";
|
|
3203
3848
|
|
|
3204
3849
|
import app from "./app.mdx";
|
|
3205
3850
|
import { components } from "./components/mdx"
|
|
@@ -3215,12 +3860,12 @@ export default routerFactory((routes) => {
|
|
|
3215
3860
|
},
|
|
3216
3861
|
};
|
|
3217
3862
|
});
|
|
3218
|
-
`,
|
|
3863
|
+
`,Vt=g((e,t)=>{let{createPath:n,createImportHelpers:r}=y(e),{renderToFile:i}=x({helpers:{...r({origin:`lib`}),...w(),serializeParams(e){return JSON.stringify(e.params)}}}),{renderToFile:a}=x({helpers:r({origin:`src`})}),o=e=>!e?.trim().length,s=c(t?.templates,Rt),u=async e=>{for(let{kind:t,entry:r}of e)t===`pageRoute`?await a(n.pages(r.file),r.name===`index`?zt:s(r.name,r),{route:r,title:r.name.replace(/\{([^}]+)\}/g,`$1`),message:mt()},{overwrite:o}):t===`pageLayout`&&await a(n.pages(r.file),Lt,{route:r},{overwrite:o})},d=async e=>{let t=e.flatMap(({kind:e,entry:t})=>e===`pageLayout`?[t]:[]),r=e.flatMap(({kind:e,entry:n})=>{if(e===`pageRoute`){let{name:e,file:r}=n;return[{...n,layouts:t.flatMap(t=>t.name===e||r.startsWith(`${t.name}/`)?[t]:[]).sort(S)}]}return[]}).sort(S);for(let[e,a]of[[`client.ts`,_t],[`server.ts`,vt]])await i(n.libEntry(e),a,{pageRoutes:r,layouts:t});for(let[e,t]of[[`params.ts`,Tt],[`router.ts`,Et],[`ssg:routes.ts`,Ot]])await i(n.lib(e),t,{pageRoutes:r})};return{config({command:n}){return{oxc:{jsx:{importSource:`preact`}},plugins:ht(e,n,t)}},async start(){for(let[e,t]of[[`env.d.ts`,yt],[`app.ts`,gt],[`mdx.ts`,bt],[`use.ts`,kt],[`ssg.ts`,Dt],[`pageSamples/styles.module.css`,Ct],[`pageSamples/welcome.tsx`,wt],[`pageSamples/page.tsx`,St],[`pageSamples/404.tsx`,xt]])await i(n.lib(e),t,{});for(let[e,t]of[[`pages/404.mdx`,It],[`components/Link.tsx`,jt],[`components/mdx.ts`,Mt],[`app.mdx`,At],[`router.ts`,Bt]])await a(n.src(e),t,{entryDir:l.entryDir},{overwrite:o});await a(n.src(`index.html`),Ft,{entryDir:l.entryDir},{overwrite:e=>!e?.trim().length||!e.replace(/<!--[\s\S]*?-->/g,``).trim().length});for(let[e,t]of[[`client.ts`,Nt],[`server.ts`,Pt]])await a(n.entry(e),t,{},{overwrite:o})},async watch(e,t){await u(e.filter(m(t,[`create`]))),await d(e)},async build(e){await u(e),await d(e)}}}),Ht=h({meta:{name:`MDX`,jsxImportSource:`preact`},dependencies:{"path-to-regexp":U.devDependencies[`path-to-regexp`]},devDependencies:{preact:U.devDependencies.preact,"preact-render-to-string":U.devDependencies[`preact-render-to-string`],"@mdx-js/preact":U.devDependencies[`@mdx-js/preact`],"remark-frontmatter":U.devDependencies[`remark-frontmatter`],"remark-mdx-frontmatter":U.devDependencies[`remark-mdx-frontmatter`]},factory:Vt}),Ut={json:`application/json`,form:[`application/x-www-form-urlencoded`,`multipart/form-data`],raw:void 0},Wt=()=>{let e=e=>[`Buffer`,`ArrayBuffer`,`Blob`].includes(e)?{type:`string`,format:`binary`}:oe.Script(e),n=(e,t,n)=>{let r=n?`${t}_${n.replace(/[^\w.-]/g,`_`)}${T(n)}`:t;return`${e.id}_${r}`},r=(e,t,r,i)=>[`#`,`components`,e,n(t,r,i)].join(`/`),i=e=>e.split(`/`).reduce((e,t)=>e+ +!t.includes(`{`),0),o=e=>{if(e.name===`index`)return[`/`];let{tokens:n}=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]=Gt(i,a)||{description:`Success`,content:{[a||`application/json`]:{schema:o?{$ref:r(`schemas`,e,n)}:{type:`object`}}}},t),{}):{200:{description:`Success - TODO: Add response schema`,content:{"text/plain":{schema:{type:`string`}}}}}},l=t=>{let{parameters:r,schemas:i}={parameters:{},schemas:{}};for(let r of t.validationDefinitions)if(r.target===`response`)for(let{id:a,resolvedType:o}of r.variants)o?.typeboxSchema&&(i[n(t,a)]=e(o.typeboxSchema));else if(r.target===`query`){let{id:a,resolvedType:o}=r.schema;for(let r of o?.properties||[])if(r?.typeboxSchema){let o=n(t,a,r.name);i[o]=e(r.typeboxSchema)}}else{let{id:a,resolvedType:o}=r.schema;o?.typeboxSchema&&(i[n(t,a)]=e(o.typeboxSchema))}if(t.params.resolvedType)for(let i of t.params.resolvedType.properties||[])i?.typeboxSchema&&(r[n(t,t.params.id,i.name)]={name:i.name,in:`path`,required:!0,schema:e(i.typeboxSchema)});return{parameters:r,schemas:i}},u=e=>{let t={},n=e.validationDefinitions.flatMap(e=>e.target===`response`?[]:e.schema.resolvedType?[e]:[]);for(let i of o(e))for(let o of e.methods){let l={responses:c(e,o)},u=s(e,i);u&&(l.parameters=u);let d=n.find(e=>e.method===o&&e.target===`query`);if(d?.schema)for(let t of d.schema.resolvedType?.properties||[])l.parameters||=[],l.parameters.push({name:t.name,in:`query`,required:!t.optional,schema:{$ref:r(`schemas`,e,d.schema.id,t.name)}});let f=n.filter(e=>e.method===o&&Object.keys(a).includes(e.target));f.length&&(l.requestBody={required:!0,content:f.reduce((t,n)=>{let{contentType:i=Ut[n.target]}=n;if(i){let a={$ref:r(`schemas`,e,n.schema.id)};for(let e of[i].flat())t[e]={schema:a}}return t},{})}),t[i]||(t[i]={}),t[i][o.toLowerCase()]=l}return t};return{generateComponentId:n,generateComponentPath:r,generatePathVariations:o,generateOpenAPISchema:e=>{let t=new Map;for(let n of e)t.set(n.name,o(n));let{components:n,paths:r}=e.sort(S).flatMap(n=>{let r=t.get(n.name)??[];return r.length>0&&e.some(e=>{if(e.name===n.name)return!1;let i=t.get(e.name)??[],a=new Set(i);return r.every(e=>a.has(e))})?[]:[n]}).reduce((e,t)=>{let n=u(t),{parameters:r,schemas:i}=l(t);return{paths:{...e.paths,...n},components:{parameters:{...e.components.parameters,...r},schemas:{...e.components.schemas,...i}}}},{paths:{},components:{parameters:{},schemas:{}}});return{paths:r,components:n}}}},Gt=(e,t)=>{let n={type:`string`,format:`uri`,...t?{enum:[t]}:{}};return{301:{description:`Moved Permanently`,headers:{Location:{description:`New permanent location`,schema:n}}},302:{description:`Found`,headers:{Location:{description:`Temporary location`,schema:n}}},303:{description:`See Other`,headers:{Location:{description:`Location to GET after POST/PUT/DELETE`,schema:n}}},307:{description:`Temporary Redirect`,headers:{Location:{description:`Temporary location (preserves request method)`,schema:n}}},308:{description:`Permanent Redirect`,headers:{Location:{description:`New permanent location (preserves request method)`,schema:n}}}}[e]},Kt=g((e,t)=>{let{outfile:n=``,...r}={...t},{createPath:i}=y(e),{generateOpenAPISchema:a}=Wt(),o=async e=>{let t=e.flatMap(({kind:e,entry:t})=>e===`apiRoute`?[t]:[]),{paths:o,components:s}=a(t),c={...JSON.parse(JSON.stringify(r)),paths:o,components:s},l=/ya?ml/.test(n)?ie.stringify(c):JSON.stringify(c,null,2);await ee(i.src(n),l,{})};return{async watch(e){await o(e)},async build(e){await o(e)}}}),qt=h({meta:{name:`OpenAPI`,resolveTypes:!0},factory:Kt}),W={type:`module`,private:!0,name:`@kosmojs/react-generator`,version:`0.3.0`,author:`Slee Woo`,license:`MIT`,files:[`pkg/*`],exports:{".":{types:`./pkg/index.d.ts`,default:`./pkg/index.js`}},scripts:{build:`wsbuild src/index.ts`,test:`vitest --root ../.. --project generators/react-generator`},dependencies:{"@kosmojs/core":`workspace:^`,"@kosmojs/lib":`workspace:^`,"@vitejs/plugin-react":`^6.1.0`},devDependencies:{"@tanstack/react-query":`^5.101.4`,"@types/react":`^19.2.18`,"@types/react-dom":`^19.2.4`,"path-to-regexp":`^8.4.2`,react:`^19.2.8`,"react-dom":`^19.2.8`,"react-router":`^8.3.0`}},Jt=e=>{let t=e.map(e=>e.orig).join(`/`),n=e=>e.kind===`splat`?`*`:e.kind===`optional`?`:${e.name}?`:`:${e.name}`;return e.flatMap(e=>e.kind===`static`?[e.parts[0].value]:e.kind===`param`?[n(e.parts[0])]:(/\.\w+$/.test(e.orig)||(console.warn(`❗${r([`red`,`bold`],`WARN`)}: React Router v7 only supports dot-suffix mixed segments (e.g. :param.html).`),console.warn(` ${r([`magenta`],e.orig)} in ${r([`blue`],t)} route won't match as expected.`),console.warn()),[e.parts.map(e=>e.type===`static`?e.value:n(e)).join(``)])).join(`/`)},Yt=()=>{let e=e=>e?.kind===`param`&&e.parts[0]?.kind===`splat`,t=n=>n.flatMap(({index:n,layout:r,children:i})=>{let{name:a,pathTokens:o}={...n,...r};if(!o)return[];let s=`${a}:layout`,c=Jt(o),l=o.at(-1);return e(l)?n&&r?[{name:s,path:c,component:r.id,children:[{name:a,path:`*`,component:n.id}]}]:n?[{path:c,children:[{name:a,path:`*`,component:n.id},...t(i)]}]:r?[{name:s,path:c,component:r.id,children:t(i)}]:[]:n&&r?[{name:s,path:c,component:r.id,children:[{name:a,index:!0,component:n.id},...t(i)]}]:n?[{path:c,children:[{name:a,index:!0,component:n.id},...t(i)]}]:r?[{name:s,path:c,component:r.id,children:t(i)}]:[]});return t},Xt=()=>{let e=[`🎉 Well done! You just created a new React route.`,`🚀 Success! A fresh React route is ready to roll.`,`🌟 Nice work! Another React route added to your app.`,`⚡ Quick and easy! Your new React route is good to go.`,`🥳 Congrats! Your app just leveled up with a new React route.`,`🧩 All set! A new React route has been scaffolded.`,`🔧 Scaffold complete! Your new React route is in place.`,`✨ Fantastic! Your new React route is ready.`,`🎯 Nailed it! A brand new React route just landed.`,`💫 Awesome! Another React route joins the lineup.`];return e[Math.floor(Math.random()*e.length)]},Zt=`import type { ReactNode } from "react";
|
|
3219
3864
|
|
|
3220
3865
|
export const AppProvider = ({ children }: { children: ReactNode }) => {
|
|
3221
3866
|
return children;
|
|
3222
3867
|
}
|
|
3223
|
-
`,
|
|
3868
|
+
`,Qt=`import { type QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
3224
3869
|
import type { ReactNode } from "react";
|
|
3225
3870
|
|
|
3226
3871
|
import { getQueryClient } from "./query";
|
|
@@ -3239,7 +3884,7 @@ export const AppProvider = ({
|
|
|
3239
3884
|
</QueryClientProvider>
|
|
3240
3885
|
);
|
|
3241
3886
|
}
|
|
3242
|
-
|
|
3887
|
+
`,$t=`import { lazy, type JSX } from "react";
|
|
3243
3888
|
|
|
3244
3889
|
import {
|
|
3245
3890
|
createRoot,
|
|
@@ -3293,7 +3938,7 @@ export const mount = async (
|
|
|
3293
3938
|
}
|
|
3294
3939
|
|
|
3295
3940
|
export default clientRenderFactory();
|
|
3296
|
-
`,
|
|
3941
|
+
`,en=`{
|
|
3297
3942
|
{{#if name}}
|
|
3298
3943
|
id: "{{name}}",
|
|
3299
3944
|
{{/if}}
|
|
@@ -3311,7 +3956,7 @@ export default clientRenderFactory();
|
|
|
3311
3956
|
children: [ {{#each children}}{{> routePartial}}, {{/each}}],
|
|
3312
3957
|
{{/if}}
|
|
3313
3958
|
}
|
|
3314
|
-
`,
|
|
3959
|
+
`,tn=`import type { JSX } from "react";
|
|
3315
3960
|
|
|
3316
3961
|
import {
|
|
3317
3962
|
renderToString as renderToStringOrig,
|
|
@@ -3377,7 +4022,7 @@ export const renderToStream: RenderToStreamWrapper<
|
|
|
3377
4022
|
};
|
|
3378
4023
|
|
|
3379
4024
|
export default serverRenderFactory();
|
|
3380
|
-
`,
|
|
4025
|
+
`,nn=`/* @jsxImportSource react */
|
|
3381
4026
|
|
|
3382
4027
|
import styles from "./styles.module.css";
|
|
3383
4028
|
|
|
@@ -3418,7 +4063,7 @@ export default function PageSample(props: {
|
|
|
3418
4063
|
</div>
|
|
3419
4064
|
);
|
|
3420
4065
|
}
|
|
3421
|
-
`,
|
|
4066
|
+
`,rn=`/* @jsxImportSource react */
|
|
3422
4067
|
|
|
3423
4068
|
import styles from "./styles.module.css";
|
|
3424
4069
|
|
|
@@ -3470,7 +4115,7 @@ export default function PageSample(props: {
|
|
|
3470
4115
|
</div>
|
|
3471
4116
|
);
|
|
3472
4117
|
}
|
|
3473
|
-
`,
|
|
4118
|
+
`,an=`* {
|
|
3474
4119
|
margin: 0;
|
|
3475
4120
|
padding: 0;
|
|
3476
4121
|
box-sizing: border-box;
|
|
@@ -3605,7 +4250,7 @@ export default function PageSample(props: {
|
|
|
3605
4250
|
align-items: center;
|
|
3606
4251
|
gap: 0.25rem;
|
|
3607
4252
|
}
|
|
3608
|
-
`,
|
|
4253
|
+
`,on=`/* @jsxImportSource react */
|
|
3609
4254
|
|
|
3610
4255
|
import styles from "./styles.module.css";
|
|
3611
4256
|
|
|
@@ -3671,7 +4316,7 @@ export default function WelcomePage() {
|
|
|
3671
4316
|
</div>
|
|
3672
4317
|
);
|
|
3673
4318
|
}
|
|
3674
|
-
`,
|
|
4319
|
+
`,sn=`import { QueryClient, type QueryClientConfig } from "@tanstack/react-query";
|
|
3675
4320
|
|
|
3676
4321
|
let client: QueryClient | undefined;
|
|
3677
4322
|
|
|
@@ -3686,7 +4331,7 @@ export const getQueryClient = (): QueryClient => {
|
|
|
3686
4331
|
}
|
|
3687
4332
|
return client;
|
|
3688
4333
|
};
|
|
3689
|
-
`,
|
|
4334
|
+
`,cn=`import { QueryClient, type QueryClientConfig } from "@tanstack/react-query";
|
|
3690
4335
|
|
|
3691
4336
|
import { store } from "{{ createImport 'lib' '@ssr/base' }}";
|
|
3692
4337
|
|
|
@@ -3709,7 +4354,7 @@ export const getQueryClient = (): QueryClient => {
|
|
|
3709
4354
|
}
|
|
3710
4355
|
return ctx.tsqClient as QueryClient;
|
|
3711
4356
|
};
|
|
3712
|
-
`,
|
|
4357
|
+
`,ln=`export type ComponentLoader = () => Promise<{
|
|
3713
4358
|
loader?: (arg: unknown) => Promise<unknown>;
|
|
3714
4359
|
}>;
|
|
3715
4360
|
|
|
@@ -3729,7 +4374,7 @@ export const loaderFactory = (opt?: { withPreload?: boolean }) => {
|
|
|
3729
4374
|
return opt?.withPreload ? { loader } : {};
|
|
3730
4375
|
};
|
|
3731
4376
|
};
|
|
3732
|
-
`,
|
|
4377
|
+
`,un=`import type { JSX, ComponentType } from "react";
|
|
3733
4378
|
|
|
3734
4379
|
import {
|
|
3735
4380
|
type RouteObject,
|
|
@@ -3787,7 +4432,7 @@ export const createRouters = (
|
|
|
3787
4432
|
}
|
|
3788
4433
|
|
|
3789
4434
|
export default createRouterFactory<RouteObject, Promise<JSX.Element>>();
|
|
3790
|
-
`,
|
|
4435
|
+
`,dn=`import { Outlet } from "react-router";
|
|
3791
4436
|
import { AppProvider } from "{{ createImport 'lib' 'app' }}";
|
|
3792
4437
|
|
|
3793
4438
|
export default function App() {
|
|
@@ -3797,7 +4442,7 @@ export default function App() {
|
|
|
3797
4442
|
</AppProvider>
|
|
3798
4443
|
);
|
|
3799
4444
|
}
|
|
3800
|
-
`,
|
|
4445
|
+
`,fn=`import {
|
|
3801
4446
|
type LinkProps as RouterLinkProps,
|
|
3802
4447
|
Link as RouterLink,
|
|
3803
4448
|
} from "react-router";
|
|
@@ -3816,7 +4461,7 @@ export default function Link(
|
|
|
3816
4461
|
|
|
3817
4462
|
const href = () => {
|
|
3818
4463
|
const [key, ...params] = to;
|
|
3819
|
-
return pageRouteMap[key]?.
|
|
4464
|
+
return pageRouteMap[key]?.path(params as never, query, { prefix: false });
|
|
3820
4465
|
};
|
|
3821
4466
|
|
|
3822
4467
|
return (
|
|
@@ -3825,7 +4470,7 @@ export default function Link(
|
|
|
3825
4470
|
</RouterLink>
|
|
3826
4471
|
);
|
|
3827
4472
|
}
|
|
3828
|
-
`,
|
|
4473
|
+
`,pn=`import renderFactory, {
|
|
3829
4474
|
createRoutes,
|
|
3830
4475
|
hydrate,
|
|
3831
4476
|
mount,
|
|
@@ -3852,7 +4497,7 @@ if (root) {
|
|
|
3852
4497
|
} else {
|
|
3853
4498
|
console.error("❌ Root element not found!");
|
|
3854
4499
|
}
|
|
3855
|
-
`,
|
|
4500
|
+
`,mn=`import renderFactory, {
|
|
3856
4501
|
createRoutes,
|
|
3857
4502
|
renderToStream,
|
|
3858
4503
|
renderToString,
|
|
@@ -3879,7 +4524,7 @@ export default renderFactory(() => {
|
|
|
3879
4524
|
},
|
|
3880
4525
|
};
|
|
3881
4526
|
});
|
|
3882
|
-
`,
|
|
4527
|
+
`,hn=`<!doctype html>
|
|
3883
4528
|
<html lang="en">
|
|
3884
4529
|
<head>
|
|
3885
4530
|
<meta charset="UTF-8" />
|
|
@@ -3891,17 +4536,17 @@ export default renderFactory(() => {
|
|
|
3891
4536
|
<script type="module" src="/{{ entryDir }}/client.ts"><\/script>
|
|
3892
4537
|
</body>
|
|
3893
4538
|
</html>
|
|
3894
|
-
`,
|
|
4539
|
+
`,gn=`import PageSample from "{{ createImport 'lib' 'pageSamples/404.tsx' }}";
|
|
3895
4540
|
|
|
3896
4541
|
export default function Page() {
|
|
3897
4542
|
return <PageSample />;
|
|
3898
4543
|
}
|
|
3899
|
-
`,
|
|
4544
|
+
`,_n=`import { Outlet } from "react-router";
|
|
3900
4545
|
|
|
3901
4546
|
export default function Layout() {
|
|
3902
4547
|
return <Outlet />;
|
|
3903
4548
|
}
|
|
3904
|
-
`,
|
|
4549
|
+
`,vn=`import PageSample from "{{ createImport 'lib' 'pageSamples/page.tsx' }}";
|
|
3905
4550
|
|
|
3906
4551
|
export default function Page() {
|
|
3907
4552
|
return PageSample({
|
|
@@ -3914,8 +4559,8 @@ export default function Page() {
|
|
|
3914
4559
|
},
|
|
3915
4560
|
});
|
|
3916
4561
|
}
|
|
3917
|
-
`,
|
|
3918
|
-
`,
|
|
4562
|
+
`,yn=`export { default } from "{{ createImport 'lib' 'pageSamples/welcome.tsx' }}";
|
|
4563
|
+
`,bn=`import routerFactory, { createRouters } from "{{ createImport 'lib' 'router' }}";
|
|
3919
4564
|
|
|
3920
4565
|
import app from "./app";
|
|
3921
4566
|
|
|
@@ -3930,12 +4575,12 @@ export default routerFactory((routes) => {
|
|
|
3930
4575
|
},
|
|
3931
4576
|
};
|
|
3932
4577
|
});
|
|
3933
|
-
|
|
4578
|
+
`,xn=g((e,t)=>{let{createPath:n,createImportHelpers:r}=y(e),{renderToFile:i}=x({helpers:{...r({origin:`lib`}),...w()},partials:{routePartial:en}}),{renderToFile:a}=x({helpers:r({origin:`src`})}),o=Yt(),s=e=>!e?.trim().length,u=c(t?.templates,vn),d=async e=>{for(let{kind:t,entry:r}of e)t===`pageRoute`?await a(n.pages(r.file),r.name===`index`?yn:u(r.name,r),{route:r,message:Xt()},{overwrite:s}):t===`pageLayout`&&await a(n.pages(r.file),_n,{route:r},{overwrite:s})},f=async e=>{let t=e.flatMap(({kind:e,entry:t})=>e===`pageRoute`?[t]:[]).sort(S),r=e.flatMap(({kind:e,entry:t})=>e===`pageRoute`||e===`pageLayout`?[t]:[]),a=o(v(r));for(let[e,t]of[[`client.ts`,$t],[`server.ts`,tn]])await i(n.libEntry(e),t,{pageEntries:r,nestedRoutes:a});await i(n.lib(`router.tsx`),un,{entries:e,indexRoutes:t})};return{config(){let{templates:e,...n}={...t};return{plugins:[se(n)]}},async start(){for(let[e,r]of[[`env.d.ts`,``],[`react.ts`,ln],[`pageSamples/styles.module.css`,an],[`pageSamples/welcome.tsx`,on],[`pageSamples/page.tsx`,rn],[`pageSamples/404.tsx`,nn],...t?.tanstack?.query?[[`app.tsx`,Qt],[`query.ts`,sn]]:[[`app.tsx`,Zt],[`query.ts`,`/** tanstack query disabled */`]]])await i(n.lib(e),r,{});for(let[e,t]of[[`pages/404.tsx`,gn],[`components/Link.tsx`,fn],[`app.tsx`,dn],[`router.ts`,bn]])await a(n.src(e),t,{entryDir:l.entryDir},{overwrite:s});await a(n.src(`index.html`),hn,{entryDir:l.entryDir},{overwrite:e=>!e?.trim().length||!e.replace(/<!--[\s\S]*?-->/g,``).trim().length});for(let[e,t]of[[`client.ts`,pn],[`server.ts`,mn]])await a(n.entry(e),t,{},{overwrite:s})},async watch(e,t){await d(e.filter(m(t,[`create`]))),await f(e)},async build(e){await d(e),await f(e)},async ssrBuild(){await i(n.lib(`query.ts`),t?.tanstack?.query?cn:`/** tanstack query disabled */`,{ssrBundle:!0})}}}),Sn=h({meta:{name:`React`,jsx:`preserve`,jsxImportSource:`react`},dependencies(e){return{react:W.devDependencies.react,"react-router":W.devDependencies[`react-router`],"path-to-regexp":W.devDependencies[`path-to-regexp`],...e?.tanstack?.query?{"@tanstack/react-query":W.devDependencies[`@tanstack/react-query`]}:{}}},devDependencies:{"@types/react":W.devDependencies[`@types/react`],"@types/react-dom":W.devDependencies[`@types/react-dom`],"react-dom":W.devDependencies[`react-dom`]},factory:xn}),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.101.4`,"path-to-regexp":`^8.4.2`,"solid-js":`^1.9.15`}},Cn=()=>{let e=e=>e?.kind===`param`&&e.parts[0]?.kind===`splat`,t=t=>t?.kind===`param`?t.parts[0]?.kind===`optional`||e(t):!1,n=r=>r.flatMap(({index:r,layout:i,children:a})=>{let{pathTokens:o}={...r,...i},s=K(o.map((e,n)=>e.kind===`param`&&(t(o[n+1])||a.some(e=>e.index?.pathTokens.some(t)))?{...e,parts:[{...e.parts[0],kind:`required`}]}:e)),c=o.at(-1);if(e(c)){let e=K([c]);return r&&i?[{path:s,component:i.id,children:[{path:e,component:r.id}]}]:r?[{path:s,children:[{path:e,component:r.id},...n(a)]}]:i?[{path:s,component:i.id,children:n(a)}]:[]}return r&&i?[{path:s,component:i.id,children:[{path:`/`,component:r.id},...n(a)]}]:r?[{path:s,children:[{path:`/`,component:r.id},...n(a)]}]:i?[{path:s,component:i.id,children:n(a)}]:[]});return n},K=e=>{let t=e.map(e=>e.orig).join(`/`),n=e=>e.kind===`splat`?`*${e.name}`:e.kind===`optional`?`:${e.name}?`:`:${e.name}`;return e.flatMap(e=>e.kind===`static`?[e.parts[0].value]:e.kind===`param`?[n(e.parts[0])]:(e.parts.length&&(console.warn(`❗${r([`red`,`bold`],`WARN`)}: At the moment Solid Router does not support mixed path segments.`),console.warn(` ${r([`magenta`],e.orig)} segment in ${r([`blue`],t)} route won't match as expected.`),console.warn()),[e.parts.map(e=>e.type===`static`?e.value:n(e)).join(``)])).join(`/`)},wn=()=>{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)]},Tn=`import type { ParentComponent } from "solid-js";
|
|
3934
4579
|
|
|
3935
4580
|
export const AppProvider: ParentComponent = (props) => {
|
|
3936
4581
|
return props.children;
|
|
3937
4582
|
};
|
|
3938
|
-
`,
|
|
4583
|
+
`,En=`import type { ParentComponent } from "solid-js";
|
|
3939
4584
|
import { type QueryClient, QueryClientProvider } from "@tanstack/solid-query";
|
|
3940
4585
|
|
|
3941
4586
|
import { getQueryClient } from "./query";
|
|
@@ -3947,7 +4592,7 @@ export const AppProvider: ParentComponent<{ client?: QueryClient }> = (props) =>
|
|
|
3947
4592
|
</QueryClientProvider>
|
|
3948
4593
|
);
|
|
3949
4594
|
};
|
|
3950
|
-
`,
|
|
4595
|
+
`,Dn=`import { lazy, type JSX } from "solid-js";
|
|
3951
4596
|
import { hydrate as hydrateOrig, render } from "solid-js/web";
|
|
3952
4597
|
import type { RouterFactoryReturn } from "@kosmojs/core";
|
|
3953
4598
|
import { clientRenderFactory } from "@kosmojs/core/generators";
|
|
@@ -3992,7 +4637,7 @@ export const mount = async (
|
|
|
3992
4637
|
}
|
|
3993
4638
|
|
|
3994
4639
|
export default clientRenderFactory();
|
|
3995
|
-
`,
|
|
4640
|
+
`,On=`{
|
|
3996
4641
|
path: "{{path}}",
|
|
3997
4642
|
{{#if component}}
|
|
3998
4643
|
component: {{component}}_component,
|
|
@@ -4002,7 +4647,7 @@ export default clientRenderFactory();
|
|
|
4002
4647
|
children: [ {{#each children}}{{> routePartial}}, {{/each}}],
|
|
4003
4648
|
{{/if}}
|
|
4004
4649
|
}
|
|
4005
|
-
`,
|
|
4650
|
+
`,kn=`import type { JSX } from "solid-js";
|
|
4006
4651
|
|
|
4007
4652
|
import {
|
|
4008
4653
|
generateHydrationScript,
|
|
@@ -4083,7 +4728,7 @@ export const renderToStream: RenderToStreamWrapper<
|
|
|
4083
4728
|
};
|
|
4084
4729
|
|
|
4085
4730
|
export default serverRenderFactory<true>();
|
|
4086
|
-
`,
|
|
4731
|
+
`,An=`/* @jsxImportSource solid-js */
|
|
4087
4732
|
|
|
4088
4733
|
import styles from "./styles.module.css";
|
|
4089
4734
|
|
|
@@ -4124,7 +4769,7 @@ export default function PageSample(props: {
|
|
|
4124
4769
|
</div>
|
|
4125
4770
|
);
|
|
4126
4771
|
}
|
|
4127
|
-
`,
|
|
4772
|
+
`,jn=`/* @jsxImportSource solid-js */
|
|
4128
4773
|
|
|
4129
4774
|
import styles from "./styles.module.css";
|
|
4130
4775
|
|
|
@@ -4176,7 +4821,7 @@ export default function PageSample(props: {
|
|
|
4176
4821
|
</div>
|
|
4177
4822
|
);
|
|
4178
4823
|
}
|
|
4179
|
-
`,
|
|
4824
|
+
`,Mn=`* {
|
|
4180
4825
|
margin: 0;
|
|
4181
4826
|
padding: 0;
|
|
4182
4827
|
box-sizing: border-box;
|
|
@@ -4311,7 +4956,7 @@ export default function PageSample(props: {
|
|
|
4311
4956
|
align-items: center;
|
|
4312
4957
|
gap: 0.25rem;
|
|
4313
4958
|
}
|
|
4314
|
-
`,
|
|
4959
|
+
`,Nn=`/* @jsxImportSource solid-js */
|
|
4315
4960
|
|
|
4316
4961
|
import styles from "./styles.module.css";
|
|
4317
4962
|
|
|
@@ -4377,7 +5022,7 @@ export default function WelcomePage() {
|
|
|
4377
5022
|
</div>
|
|
4378
5023
|
);
|
|
4379
5024
|
}
|
|
4380
|
-
`,
|
|
5025
|
+
`,Pn=`import { QueryClient, type QueryClientConfig } from "@tanstack/solid-query";
|
|
4381
5026
|
|
|
4382
5027
|
let client: QueryClient | undefined;
|
|
4383
5028
|
|
|
@@ -4392,7 +5037,7 @@ export const getQueryClient = (): QueryClient => {
|
|
|
4392
5037
|
}
|
|
4393
5038
|
return client;
|
|
4394
5039
|
};
|
|
4395
|
-
`,
|
|
5040
|
+
`,Fn=`import { QueryClient, type QueryClientConfig } from "@tanstack/solid-query";
|
|
4396
5041
|
|
|
4397
5042
|
import { store } from "{{ createImport 'lib' '@ssr/base' }}";
|
|
4398
5043
|
|
|
@@ -4415,7 +5060,7 @@ export const getQueryClient = (): QueryClient => {
|
|
|
4415
5060
|
}
|
|
4416
5061
|
return ctx.tsqClient as QueryClient;
|
|
4417
5062
|
};
|
|
4418
|
-
`,
|
|
5063
|
+
`,In=`import type { JSX, ParentComponent } from "solid-js";
|
|
4419
5064
|
import { Router, type RouteDefinition } from "@solidjs/router";
|
|
4420
5065
|
import type { RouterFactoryReturn } from "@kosmojs/core";
|
|
4421
5066
|
import { createRouterFactory } from "@kosmojs/core/generators";
|
|
@@ -4451,7 +5096,7 @@ export const createRouters = (
|
|
|
4451
5096
|
}
|
|
4452
5097
|
|
|
4453
5098
|
export default createRouterFactory<RouteDefinition, JSX.Element>();
|
|
4454
|
-
`,
|
|
5099
|
+
`,Ln=`export type ComponentLoader = () => Promise<{
|
|
4455
5100
|
preload?: () => Promise<unknown>;
|
|
4456
5101
|
}>;
|
|
4457
5102
|
|
|
@@ -4466,10 +5111,10 @@ export const loaderFactory = (opt?: { withPreload?: boolean }) => {
|
|
|
4466
5111
|
return opt?.withPreload ? { preload } : {};
|
|
4467
5112
|
};
|
|
4468
5113
|
};
|
|
4469
|
-
`,
|
|
5114
|
+
`,Rn=`export type MaybeWrapped<T> = import("solid-js/store").Store<T> | T;
|
|
4470
5115
|
|
|
4471
5116
|
export { unwrap } from "solid-js/store";
|
|
4472
|
-
`,
|
|
5117
|
+
`,zn=`import type { ParentComponent } from "solid-js";
|
|
4473
5118
|
import { AppProvider } from "{{ createImport 'lib' 'app' }}";
|
|
4474
5119
|
|
|
4475
5120
|
const App: ParentComponent = (props) => {
|
|
@@ -4477,7 +5122,7 @@ const App: ParentComponent = (props) => {
|
|
|
4477
5122
|
};
|
|
4478
5123
|
|
|
4479
5124
|
export default App;
|
|
4480
|
-
`,
|
|
5125
|
+
`,Bn=`import { A, type AnchorProps } from "@solidjs/router";
|
|
4481
5126
|
import { type JSXElement, splitProps } from "solid-js";
|
|
4482
5127
|
|
|
4483
5128
|
import { pageRouteMap, type LinkProps } from "{{ createImport 'libCore' }}";
|
|
@@ -4497,12 +5142,12 @@ export default function Link(
|
|
|
4497
5142
|
|
|
4498
5143
|
const href = () => {
|
|
4499
5144
|
const [key, ...params] = knownProps.to;
|
|
4500
|
-
return pageRouteMap[key]?.
|
|
5145
|
+
return pageRouteMap[key]?.path(params as never, knownProps.query, { prefix: false });
|
|
4501
5146
|
};
|
|
4502
5147
|
|
|
4503
5148
|
return <A {...{ ...restProps, href: href() }}>{knownProps.children}</A>;
|
|
4504
5149
|
}
|
|
4505
|
-
`,
|
|
5150
|
+
`,Vn=`import renderFactory, {
|
|
4506
5151
|
createRoutes,
|
|
4507
5152
|
hydrate,
|
|
4508
5153
|
mount,
|
|
@@ -4529,7 +5174,7 @@ if (root) {
|
|
|
4529
5174
|
} else {
|
|
4530
5175
|
console.error("❌ Root element not found!");
|
|
4531
5176
|
}
|
|
4532
|
-
`,
|
|
5177
|
+
`,Hn=`import renderFactory, {
|
|
4533
5178
|
createRoutes,
|
|
4534
5179
|
renderToStream,
|
|
4535
5180
|
renderToString,
|
|
@@ -4556,7 +5201,7 @@ export default renderFactory(() => {
|
|
|
4556
5201
|
},
|
|
4557
5202
|
};
|
|
4558
5203
|
});
|
|
4559
|
-
`,
|
|
5204
|
+
`,Un=`<!doctype html>
|
|
4560
5205
|
<html lang="en">
|
|
4561
5206
|
<head>
|
|
4562
5207
|
<meta charset="UTF-8" />
|
|
@@ -4568,19 +5213,19 @@ export default renderFactory(() => {
|
|
|
4568
5213
|
<script type="module" src="/{{ entryDir }}/client.ts"><\/script>
|
|
4569
5214
|
</body>
|
|
4570
5215
|
</html>
|
|
4571
|
-
`,
|
|
5216
|
+
`,Wn=`import PageSample from "{{ createImport 'lib' 'pageSamples/404.tsx' }}";
|
|
4572
5217
|
|
|
4573
5218
|
export default function Page() {
|
|
4574
5219
|
return <PageSample />;
|
|
4575
5220
|
}
|
|
4576
|
-
`,
|
|
5221
|
+
`,Gn=`import type { ParentComponent } from "solid-js";
|
|
4577
5222
|
|
|
4578
5223
|
const Layout: ParentComponent = (props) => {
|
|
4579
5224
|
return props.children;
|
|
4580
5225
|
};
|
|
4581
5226
|
|
|
4582
5227
|
export default Layout;
|
|
4583
|
-
`,
|
|
5228
|
+
`,Kn=`import PageSample from "{{ createImport 'lib' 'pageSamples/page.tsx' }}";
|
|
4584
5229
|
|
|
4585
5230
|
export default function Page() {
|
|
4586
5231
|
return PageSample({
|
|
@@ -4593,8 +5238,8 @@ export default function Page() {
|
|
|
4593
5238
|
},
|
|
4594
5239
|
});
|
|
4595
5240
|
}
|
|
4596
|
-
`,
|
|
4597
|
-
`,
|
|
5241
|
+
`,qn=`export { default } from "{{ createImport 'lib' 'pageSamples/welcome.tsx' }}";
|
|
5242
|
+
`,Jn=`import routerFactory, { createRouters } from "{{ createImport 'lib' 'router' }}";
|
|
4598
5243
|
|
|
4599
5244
|
import app from "./app";
|
|
4600
5245
|
|
|
@@ -4609,12 +5254,12 @@ export default routerFactory((routes) => {
|
|
|
4609
5254
|
},
|
|
4610
5255
|
};
|
|
4611
5256
|
});
|
|
4612
|
-
`,
|
|
5257
|
+
`,Yn=g((e,t)=>{let{generators:n=[]}=e.config,{createPath:r,createImportHelpers:i}=y(e),{renderToFile:a}=x({helpers:{...i({origin:`lib`}),...w()},partials:{routePartial:On}}),{renderToFile:o}=x({helpers:i({origin:`src`})}),s=Cn(),u=e=>!e?.trim().length,d=c(t?.templates,Kn),f=async e=>{for(let{kind:t,entry:n}of e)t===`pageRoute`?await o(r.pages(n.file),n.name===`index`?qn:d(n.name,n),{route:n,message:wn()},{overwrite:u}):t===`pageLayout`&&await o(r.pages(n.file),Gn,{route:n},{overwrite:u})},p=async e=>{let t=e.flatMap(({kind:e,entry:t})=>e===`pageRoute`?[t]:[]).sort(S),n=e.flatMap(({kind:e,entry:t})=>e===`pageRoute`||e===`pageLayout`?[t]:[]),i=s(v(n));for(let[e,t]of[[`client.ts`,Dn],[`server.ts`,kn]])await a(r.libEntry(e),t,{pageEntries:n,nestedRoutes:i});await a(r.lib(`router.tsx`),In,{entries:e,indexRoutes:t})};return{config({command:e}){let{templates:r,...i}={...t};return{oxc:{jsx:{importSource:`solid-js`}},plugins:e===`build`?[D({...i,...n.some(e=>e.meta.slot===`ssr`)?{ssr:!0,solid:{...i?.solid,hydratable:!0}}:{}})]:[D({...i,dev:!0,hot:!0})]}},async start(){for(let[e,n]of[[`env.d.ts`,``],[`solid.ts`,Ln],[`unwrap.ts`,Rn],[`pageSamples/styles.module.css`,Mn],[`pageSamples/welcome.tsx`,Nn],[`pageSamples/page.tsx`,jn],[`pageSamples/404.tsx`,An],...t?.tanstack?.query?[[`app.tsx`,En],[`query.ts`,Pn]]:[[`app.tsx`,Tn],[`query.ts`,`/** tanstack query disabled */`]]])await a(r.lib(e),n,{});for(let[e,t]of[[`pages/404.tsx`,Wn],[`components/Link.tsx`,Bn],[`app.tsx`,zn],[`router.ts`,Jn]])await o(r.src(e),t,{entryDir:l.entryDir},{overwrite:u});await o(r.src(`index.html`),Un,{entryDir:l.entryDir},{overwrite:e=>!e?.trim().length||!e.replace(/<!--[\s\S]*?-->/g,``).trim().length});for(let[e,t]of[[`client.ts`,Vn],[`server.ts`,Hn]])await o(r.entry(e),t,{},{overwrite:u})},async watch(e,t){await f(e.filter(m(t,[`create`]))),await p(e)},async build(e){await f(e),await p(e)},async ssrBuild(){await a(r.lib(`query.ts`),t?.tanstack?.query?Fn:`/** tanstack query disabled */`,{ssrBundle:!0})}}}),Xn=h({meta:{name:`SolidJS`,jsx:`preserve`,jsxImportSource:`solid-js`},dependencies(e){return{"solid-js":G.devDependencies[`solid-js`],"@solidjs/router":G.devDependencies[`@solidjs/router`],"path-to-regexp":G.devDependencies[`path-to-regexp`],...e?.tanstack?.query?{"@tanstack/solid-query":G.devDependencies[`@tanstack/solid-query`]}:{}}},factory:Yn}),Zn=g(e=>{let{generators:i=[],refineTypeName:a,...o}={...e.config},{createPath:s}=y(e);return{async postBuild(){let a=s.distDir(`ssg`),c=n(a,`../ssr/server.js`);if(!await ce(c,le.F_OK).then(()=>!0,()=>!1)){console.error(),console.error(r(`red`,`❗Please enable ssrGenerator in ${e.name}/kosmo.config.ts`)),console.error(` SSG generator can not run without SSR server`),console.error();return}let l=te(`${e.name}: SSG`);l.append(`preparing...`);let{createDisposableServer:u}=await import(c);await O(n(a,`../client/assets`),t(a,`assets`),{recursive:!0}),l.append(`bundling routes...`),await E(_(o,...i.map(({factory:t})=>t(e).config?.({kind:`client`,command:`build`})),{root:s.lib(),appType:`custom`,plugins:[C.tsconfigPaths(e),C.nodePrefix()],resolve:{conditions:[`node`]},build:{ssr:s.lib(`ssg.ts`),target:`esnext`,sourcemap:!1,emptyOutDir:!0,rolldownOptions:{output:{dir:a,entryFileNames:`routes.js`,format:`esm`}}}}));try{let e=await import(t(a,`routes.js`)).then(e=>e.default);u(async n=>{for(let[r,i]of e.entries()){l.append(`[ ${r+1} of ${e.length} ] ${i}`);let o=await Qn(n,i);o!==void 0&&(await ue(t(a,i),{recursive:!0}),await de(t(a,t(i,`index.html`)),o,`utf8`))}l.succeed(`done ✨`)})}finally{await k(`${a}/routes.js`)}}}}),Qn=async(e,t)=>{try{let n=`http://localhost:${e}${t}`;return await(await fetch(n)).text()}catch(e){console.error(r(`red`,`✗ SSG: Failed generating ${t} route: ${e.message}`));return}},$n=h({meta:{name:`SSG`,slot:`ssg`},factory:Zn}),q={type:`module`,private:!0,name:`@kosmojs/ssr-generator`,version:`0.3.0`,author:`Slee Woo`,license:`MIT`,files:[`pkg/*`],exports:{".":{types:`./pkg/index.d.ts`,default:`./pkg/index.js`}},scripts:{build:`wsbuild src/index.ts`},dependencies:{"@kosmojs/core":`workspace:^`,"@kosmojs/lib":`workspace:^`,vite:`^8.2.2`},devDependencies:{"@hono/node-server":`^2.1.1`,hono:`^4.13.3`,"light-my-request":`^6.6.0`,tinyglobby:`^0.2.17`}},er=`{{#if apiGenerator}}
|
|
4613
5258
|
export { default as apiApp } from "{{ createImport 'api' 'app' }}";
|
|
4614
5259
|
{{else}}
|
|
4615
5260
|
export const apiApp = undefined;
|
|
4616
5261
|
{{/if}}
|
|
4617
|
-
`,
|
|
5262
|
+
`,tr=`import { AsyncLocalStorage } from "node:async_hooks";
|
|
4618
5263
|
|
|
4619
5264
|
import type { FetchApp, NodeApp } from "@kosmojs/core";
|
|
4620
5265
|
|
|
@@ -4658,7 +5303,7 @@ export const store = new AsyncLocalStorage<RequestContext>();
|
|
|
4658
5303
|
export const isFetchApp = (app: FetchApp | NodeApp): app is FetchApp => {
|
|
4659
5304
|
return typeof (app as FetchApp).fetch === "function";
|
|
4660
5305
|
};
|
|
4661
|
-
`,
|
|
5306
|
+
`,nr=`import { type RequestContext, store } from "./base";
|
|
4662
5307
|
|
|
4663
5308
|
import { renderWrapper } from "{{ createImport 'libEntry' 'server' }}";
|
|
4664
5309
|
|
|
@@ -4680,9 +5325,7 @@ export const withSsrContext = <T>(
|
|
|
4680
5325
|
export const errorProvider = () => {
|
|
4681
5326
|
return store.getStore()?.error;
|
|
4682
5327
|
};
|
|
4683
|
-
`,
|
|
4684
|
-
|
|
4685
|
-
import type { FetchApp, NodeApp } from "@kosmojs/core";
|
|
5328
|
+
`,rr=`import type { FetchApp, NodeApp } from "@kosmojs/core";
|
|
4686
5329
|
import type { Transport } from "@kosmojs/core/fetch";
|
|
4687
5330
|
|
|
4688
5331
|
import {
|
|
@@ -4706,6 +5349,8 @@ const createDispatch = (app: FetchApp | NodeApp) => {
|
|
|
4706
5349
|
return isFetchApp(app)
|
|
4707
5350
|
? app.fetch
|
|
4708
5351
|
: async (request: Request): Promise<Response> => {
|
|
5352
|
+
const { inject } = await import("light-my-request");
|
|
5353
|
+
|
|
4709
5354
|
/**
|
|
4710
5355
|
* Node dispatch: serializes the web Request into light-my-request's
|
|
4711
5356
|
* injection format and lifts the injected response back into a web Response.
|
|
@@ -4824,7 +5469,7 @@ const createTransport = (app: FetchApp | NodeApp): Transport => {
|
|
|
4824
5469
|
};
|
|
4825
5470
|
};
|
|
4826
5471
|
|
|
4827
|
-
const ssrTransport = apiApp ? createTransport(apiApp) : undefined;
|
|
5472
|
+
const ssrTransport = apiApp ? createTransport(apiApp as never) : undefined;
|
|
4828
5473
|
|
|
4829
5474
|
export const transport = ssrTransport
|
|
4830
5475
|
? async (input: RequestInfo | URL, init?: RequestInit) => {
|
|
@@ -4883,12 +5528,12 @@ const pathnameOf = (input: RequestInfo | URL): string => {
|
|
|
4883
5528
|
} catch {}
|
|
4884
5529
|
return String(input);
|
|
4885
5530
|
};
|
|
4886
|
-
`,
|
|
5531
|
+
`,ir=`export const routeMap = [
|
|
4887
5532
|
{{#each pageRoutes}}
|
|
4888
5533
|
{ pathPattern: "{{honoPattern}}", renderMode: "{{renderMode}}" },
|
|
4889
5534
|
{{/each}}
|
|
4890
5535
|
];
|
|
4891
|
-
`,
|
|
5536
|
+
`,ar=`import { access, chmod, constants, readFile, unlink } from "node:fs/promises";
|
|
4892
5537
|
import {
|
|
4893
5538
|
createServer,
|
|
4894
5539
|
type IncomingMessage,
|
|
@@ -5304,14 +5949,14 @@ if (isMain) {
|
|
|
5304
5949
|
process.exit(1);
|
|
5305
5950
|
}
|
|
5306
5951
|
}
|
|
5307
|
-
`,
|
|
5952
|
+
`,or=`string`,sr=g((e,r)=>{let{generators:i=[],refineTypeName:a,...o}=e.config,{createPath:c,createImportHelpers:l}=y(e),{renderToFile:u}=x({helpers:{...l({origin:`lib`})}});return{async build(e){let t=r?.renderMode?typeof r.renderMode==`string`?()=>r.renderMode:s(r?.renderMode,`string`):()=>or,n={renderMode:JSON.stringify(r?.renderMode||null),pageRoutes:e.flatMap(e=>e.kind===`pageRoute`?[{...e.entry,renderMode:t(e.entry.name)}]:[]).sort(S),apiGenerator:i.some(e=>e.meta.slot===`backend`)};for(let[e,t]of[[`ssr.ts`,ar],[`@ssr/api.ts`,er],[`@ssr/__kosmo_ssr_bundle.ts`,nr],[`@ssr/base.ts`,tr],[`@ssr/fetch.ts`,rr],[`@ssr/routes.ts`,ir]])await u(c.lib(e),t,n)},async postBuild(){let r=c.distDir(`ssr`),a=[C.tsconfigPaths(e),C.nodePrefix()];for(let t of i)await t.factory(e).ssrBuild?.();await E(_(o,...i.map(({factory:t})=>t(e).config?.({kind:`client`,command:`build`})),{root:c.src(),plugins:a,define:{KOSMO_PRODUCTION_BUILD:`true`},build:{ssr:c.lib(`@ssr/__kosmo_ssr_bundle`),ssrEmitAssets:!0,sourcemap:!0,emptyOutDir:!0,minify:!1,rolldownOptions:{output:{dir:r,entryFileNames:`app.js`,format:`esm`}}}})),await E({root:c.lib(),configFile:!1,appType:`custom`,plugins:a,resolve:{conditions:[`node`]},build:{ssr:c.lib(`ssr.ts`),target:`esnext`,sourcemap:!0,emptyOutDir:!0,rolldownOptions:{output:{dir:t(r,`server`),entryFileNames:`server.js`,format:`esm`}}}}),await O(n(r,`../client`),r,{recursive:!0});for(let e of[`server.js`,`server.js.map`])await O(`${r}/server/${e}`,`${r}/${e}`);await k(`${r}/server`,{recursive:!0,force:!0})}}}),cr=h({meta:{name:`SSR`,slot:`ssr`},dependencies:{tinyglobby:q.devDependencies.tinyglobby,hono:q.devDependencies.hono,"@hono/node-server":q.devDependencies[`@hono/node-server`],"light-my-request":q.devDependencies[`light-my-request`]},factory:sr}),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.38`,"path-to-regexp":`^8.4.2`,svelte:`^5.56.10`}},lr=()=>{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">
|
|
5308
5953
|
import type { Snippet } from "svelte";
|
|
5309
5954
|
|
|
5310
5955
|
let { children }: { children: Snippet } = $props();
|
|
5311
5956
|
<\/script>
|
|
5312
5957
|
|
|
5313
5958
|
{@render children()}
|
|
5314
|
-
`,
|
|
5959
|
+
`,ur=`<script lang="ts">
|
|
5315
5960
|
import { type QueryClient, QueryClientProvider } from "@tanstack/svelte-query";
|
|
5316
5961
|
import type { Snippet } from "svelte";
|
|
5317
5962
|
|
|
@@ -5328,7 +5973,7 @@ if (isMain) {
|
|
|
5328
5973
|
<QueryClientProvider client={queryClient}>
|
|
5329
5974
|
{@render children()}
|
|
5330
5975
|
</QueryClientProvider>
|
|
5331
|
-
`,
|
|
5976
|
+
`,dr=`import { hydrate as hydrateOrig, mount as mountOrig } from "svelte";
|
|
5332
5977
|
import type { RouterFactoryReturn } from "@kosmojs/core";
|
|
5333
5978
|
import { clientRenderFactory } from "@kosmojs/core/generators";
|
|
5334
5979
|
|
|
@@ -5369,7 +6014,7 @@ export const mount = async (
|
|
|
5369
6014
|
}
|
|
5370
6015
|
|
|
5371
6016
|
export default clientRenderFactory();
|
|
5372
|
-
`,
|
|
6017
|
+
`,fr=`import { render as renderOrig } from "svelte/server";
|
|
5373
6018
|
|
|
5374
6019
|
import type {
|
|
5375
6020
|
RenderToStringWrapper,
|
|
@@ -5435,12 +6080,12 @@ export const renderToString: RenderToStringWrapper<
|
|
|
5435
6080
|
// svelte/server exposes only render() - no web-stream renderer -
|
|
5436
6081
|
// so this folder is string-only SSR.
|
|
5437
6082
|
export default serverRenderFactory<false>();
|
|
5438
|
-
`,
|
|
6083
|
+
`,pr=`declare module "*.svelte" {
|
|
5439
6084
|
import type { Component } from "svelte";
|
|
5440
6085
|
const component: Component;
|
|
5441
6086
|
export default component;
|
|
5442
6087
|
}
|
|
5443
|
-
`,
|
|
6088
|
+
`,mr=`<script lang="ts">
|
|
5444
6089
|
/**
|
|
5445
6090
|
* Folds [app, ...layouts] around the page component.
|
|
5446
6091
|
*
|
|
@@ -5474,7 +6119,7 @@ export default serverRenderFactory<false>();
|
|
|
5474
6119
|
{/snippet}
|
|
5475
6120
|
|
|
5476
6121
|
{@render layer(0)}
|
|
5477
|
-
`,
|
|
6122
|
+
`,hr=`<script lang="ts">
|
|
5478
6123
|
import styles from "./styles.module.css";
|
|
5479
6124
|
|
|
5480
6125
|
let { headline }: { headline?: string } = $props();
|
|
@@ -5506,7 +6151,7 @@ export default serverRenderFactory<false>();
|
|
|
5506
6151
|
</div>
|
|
5507
6152
|
</div>
|
|
5508
6153
|
</div>
|
|
5509
|
-
`,
|
|
6154
|
+
`,gr=`<script lang="ts">
|
|
5510
6155
|
import styles from "./styles.module.css";
|
|
5511
6156
|
|
|
5512
6157
|
let {
|
|
@@ -5551,7 +6196,7 @@ export default serverRenderFactory<false>();
|
|
|
5551
6196
|
</div>
|
|
5552
6197
|
</div>
|
|
5553
6198
|
</div>
|
|
5554
|
-
`,
|
|
6199
|
+
`,_r=`* {
|
|
5555
6200
|
margin: 0;
|
|
5556
6201
|
padding: 0;
|
|
5557
6202
|
box-sizing: border-box;
|
|
@@ -5686,7 +6331,7 @@ export default serverRenderFactory<false>();
|
|
|
5686
6331
|
align-items: center;
|
|
5687
6332
|
gap: 0.25rem;
|
|
5688
6333
|
}
|
|
5689
|
-
`,
|
|
6334
|
+
`,vr=`<script lang="ts">
|
|
5690
6335
|
import styles from "./styles.module.css";
|
|
5691
6336
|
<\/script>
|
|
5692
6337
|
|
|
@@ -5744,7 +6389,7 @@ export default serverRenderFactory<false>();
|
|
|
5744
6389
|
</div>
|
|
5745
6390
|
</div>
|
|
5746
6391
|
</div>
|
|
5747
|
-
`,
|
|
6392
|
+
`,yr=`export type ParamsMap = {
|
|
5748
6393
|
{{#each pageRoutes}}"{{name}}": {{serializeParamsLiteral .}};
|
|
5749
6394
|
{{/each}}
|
|
5750
6395
|
};
|
|
@@ -5753,7 +6398,7 @@ export const paramNames = {
|
|
|
5753
6398
|
{{#each pageRoutes}}"{{name}}": [ {{#each params.schema}}"{{name}}", {{/each}}],
|
|
5754
6399
|
{{/each}}
|
|
5755
6400
|
} as const;
|
|
5756
|
-
|
|
6401
|
+
`,br=`import { QueryClient, type QueryClientConfig } from "@tanstack/svelte-query";
|
|
5757
6402
|
|
|
5758
6403
|
let client: QueryClient | undefined;
|
|
5759
6404
|
|
|
@@ -5768,7 +6413,7 @@ export const getQueryClient = (): QueryClient => {
|
|
|
5768
6413
|
}
|
|
5769
6414
|
return client;
|
|
5770
6415
|
};
|
|
5771
|
-
`,
|
|
6416
|
+
`,xr=`import { QueryClient, type QueryClientConfig } from "@tanstack/svelte-query";
|
|
5772
6417
|
|
|
5773
6418
|
import { store } from "{{ createImport 'lib' '@ssr/base' }}";
|
|
5774
6419
|
|
|
@@ -5791,7 +6436,7 @@ export const getQueryClient = (): QueryClient => {
|
|
|
5791
6436
|
}
|
|
5792
6437
|
return ctx.tsqClient as QueryClient;
|
|
5793
6438
|
};
|
|
5794
|
-
`,
|
|
6439
|
+
`,Sr=`import type { RouterFactoryReturn } from "@kosmojs/core";
|
|
5795
6440
|
import { createRouterFactory } from "@kosmojs/core/generators";
|
|
5796
6441
|
|
|
5797
6442
|
import Layouts from "./Layouts.svelte";
|
|
@@ -5831,7 +6476,7 @@ export default createRouterFactory<
|
|
|
5831
6476
|
Promise<RouteComponent>,
|
|
5832
6477
|
{ server: { route: Route } }
|
|
5833
6478
|
>();
|
|
5834
|
-
`,
|
|
6479
|
+
`,Cr=`import { match, pathToRegexp } from "path-to-regexp";
|
|
5835
6480
|
import { type Component, createContext } from "svelte";
|
|
5836
6481
|
|
|
5837
6482
|
import { parseSearchParams } from "@kosmojs/core";
|
|
@@ -6033,7 +6678,11 @@ export const createRoute = (
|
|
|
6033
6678
|
loader: RawRoute["loader"],
|
|
6034
6679
|
layouts: RawRoute["layouts"],
|
|
6035
6680
|
): RawRoute => {
|
|
6036
|
-
|
|
6681
|
+
// strip trailing slash (keeping a sole "/") so the base-joined index route
|
|
6682
|
+
// matches both with and without it - "/docs/" as a pattern rejects "/docs"
|
|
6683
|
+
const path = \`\${base}/\${pathPattern}\`
|
|
6684
|
+
.replace(/\\/+/g, "/")
|
|
6685
|
+
.replace(/(.+)\\/$/, "$1");
|
|
6037
6686
|
|
|
6038
6687
|
const { regexp } = pathToRegexp(path, { sensitive: true });
|
|
6039
6688
|
const matcher = match<Route["params"]>(path);
|
|
@@ -6041,9 +6690,11 @@ export const createRoute = (
|
|
|
6041
6690
|
return {
|
|
6042
6691
|
name,
|
|
6043
6692
|
regexp,
|
|
6693
|
+
// count segments of the same base-joined path the regexp matches against;
|
|
6694
|
+
// resolve() compares this against the full url pathname's segment count
|
|
6044
6695
|
pathSegments: name.includes("...")
|
|
6045
6696
|
? undefined
|
|
6046
|
-
:
|
|
6697
|
+
: path.split("/").filter(Boolean).length,
|
|
6047
6698
|
extractParams: (path) => {
|
|
6048
6699
|
const match = matcher(path);
|
|
6049
6700
|
return match ? match.params : {};
|
|
@@ -6052,7 +6703,7 @@ export const createRoute = (
|
|
|
6052
6703
|
layouts,
|
|
6053
6704
|
};
|
|
6054
6705
|
};
|
|
6055
|
-
`,
|
|
6706
|
+
`,wr=`import { getRouteContext } from "./svelte";
|
|
6056
6707
|
|
|
6057
6708
|
import type { ParamsMap, paramNames } from "{{ createImport 'lib' 'params' }}";
|
|
6058
6709
|
|
|
@@ -6092,7 +6743,7 @@ export const useLoaderData = <T>(key?: string): T | undefined => {
|
|
|
6092
6743
|
const route = useRoute();
|
|
6093
6744
|
return route.loaderData?.[key || route.name] as T;
|
|
6094
6745
|
};
|
|
6095
|
-
`,
|
|
6746
|
+
`,Tr=`<script lang="ts">
|
|
6096
6747
|
import { AppProvider } from "{{ createImport 'lib' 'app' }}";
|
|
6097
6748
|
import type { Snippet } from "svelte";
|
|
6098
6749
|
|
|
@@ -6102,7 +6753,7 @@ export const useLoaderData = <T>(key?: string): T | undefined => {
|
|
|
6102
6753
|
<AppProvider>
|
|
6103
6754
|
{@render children()}
|
|
6104
6755
|
</AppProvider>
|
|
6105
|
-
`,
|
|
6756
|
+
`,Er=`<script lang="ts">
|
|
6106
6757
|
import type { Snippet } from "svelte";
|
|
6107
6758
|
import type { HTMLAnchorAttributes } from "svelte/elements";
|
|
6108
6759
|
|
|
@@ -6121,12 +6772,12 @@ export const useLoaderData = <T>(key?: string): T | undefined => {
|
|
|
6121
6772
|
|
|
6122
6773
|
const href = $derived.by(() => {
|
|
6123
6774
|
const [key, ...params] = to;
|
|
6124
|
-
return pageRouteMap[key]?.
|
|
6775
|
+
return pageRouteMap[key]?.path(params as never, query);
|
|
6125
6776
|
});
|
|
6126
6777
|
<\/script>
|
|
6127
6778
|
|
|
6128
6779
|
<a {href} {...rest}>{@render children?.()}</a>
|
|
6129
|
-
`,
|
|
6780
|
+
`,Dr=`import renderFactory, {
|
|
6130
6781
|
createRoutes,
|
|
6131
6782
|
hydrate,
|
|
6132
6783
|
mount,
|
|
@@ -6153,7 +6804,7 @@ if (root) {
|
|
|
6153
6804
|
} else {
|
|
6154
6805
|
console.error("❌ Root element not found!");
|
|
6155
6806
|
}
|
|
6156
|
-
`,
|
|
6807
|
+
`,Or=`import renderFactory, {
|
|
6157
6808
|
createRoutes,
|
|
6158
6809
|
renderToString,
|
|
6159
6810
|
// no renderToStream on Svelte folders
|
|
@@ -6174,7 +6825,7 @@ export default renderFactory(() => {
|
|
|
6174
6825
|
},
|
|
6175
6826
|
};
|
|
6176
6827
|
});
|
|
6177
|
-
`,
|
|
6828
|
+
`,kr=`<!doctype html>
|
|
6178
6829
|
<html lang="en">
|
|
6179
6830
|
<head>
|
|
6180
6831
|
<meta charset="UTF-8" />
|
|
@@ -6186,19 +6837,19 @@ export default renderFactory(() => {
|
|
|
6186
6837
|
<script type="module" src="/{{ entryDir }}/client.ts"><\/script>
|
|
6187
6838
|
</body>
|
|
6188
6839
|
</html>
|
|
6189
|
-
`,
|
|
6840
|
+
`,Ar=`<script lang="ts">
|
|
6190
6841
|
import PageSample from "{{ createImport 'lib' 'pageSamples/404.svelte' }}";
|
|
6191
6842
|
<\/script>
|
|
6192
6843
|
|
|
6193
6844
|
<PageSample />
|
|
6194
|
-
`,
|
|
6845
|
+
`,jr=`<script lang="ts">
|
|
6195
6846
|
import type { Snippet } from "svelte";
|
|
6196
6847
|
|
|
6197
6848
|
let { children }: { children: Snippet } = $props();
|
|
6198
6849
|
<\/script>
|
|
6199
6850
|
|
|
6200
6851
|
{@render children()}
|
|
6201
|
-
`,
|
|
6852
|
+
`,Mr=`<script lang="ts">
|
|
6202
6853
|
import PageSample from "{{ createImport 'lib' 'pageSamples/page.svelte' }}";
|
|
6203
6854
|
|
|
6204
6855
|
const pathMap = {
|
|
@@ -6217,7 +6868,7 @@ export default renderFactory(() => {
|
|
|
6217
6868
|
routeName={"{{route.name}}"}
|
|
6218
6869
|
{pathMap}
|
|
6219
6870
|
/>
|
|
6220
|
-
`,
|
|
6871
|
+
`,Nr=`<script lang="ts">
|
|
6221
6872
|
import WelcomePage from "{{ createImport 'lib' 'pageSamples/welcome.svelte' }}";
|
|
6222
6873
|
<\/script>
|
|
6223
6874
|
|
|
@@ -6230,7 +6881,7 @@ export default renderFactory(() => {
|
|
|
6230
6881
|
</svelte:head>
|
|
6231
6882
|
|
|
6232
6883
|
<WelcomePage />
|
|
6233
|
-
`,
|
|
6884
|
+
`,Pr=`import routerFactory, { createRouters } from "{{ createImport 'lib' 'router' }}";
|
|
6234
6885
|
|
|
6235
6886
|
import app from "./app.svelte";
|
|
6236
6887
|
|
|
@@ -6245,7 +6896,7 @@ export default routerFactory((routes) => {
|
|
|
6245
6896
|
},
|
|
6246
6897
|
};
|
|
6247
6898
|
});
|
|
6248
|
-
`,
|
|
6899
|
+
`,Fr=g((e,t)=>{let{createPath:n,createImportHelpers:r}=y(e),{renderToFile:i}=x({helpers:{...r({origin:`lib`}),...w()}}),{renderToFile:a}=x({helpers:r({origin:`src`})}),o=e=>!e?.trim().length,s=c(t?.templates,Mr),u=async e=>{for(let{kind:t,entry:r}of e)t===`pageRoute`?await a(n.pages(r.file),r.name===`index`?Nr:s(r.name,r),{route:r,title:r.name.replace(/\{([^}]+)\}/g,`$1`),message:lr()},{overwrite:o}):t===`pageLayout`&&await a(n.pages(r.file),jr,{route:r},{overwrite:o})},d=async e=>{let t=e.flatMap(({kind:e,entry:t})=>e===`pageLayout`?[t]:[]),r=e.flatMap(({kind:e,entry:n})=>{if(e===`pageRoute`){let{name:e,file:r}=n;return[{...n,layouts:t.flatMap(t=>t.name===e||r.startsWith(`${t.name}/`)?[t]:[]).sort(S)}]}return[]}).sort(S);for(let[e,a]of[[`client.ts`,dr],[`server.ts`,fr]])await i(n.libEntry(e),a,{pageRoutes:r,layouts:t});for(let[e,t]of[[`params.ts`,yr],[`router.ts`,Sr]])await i(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`,pr],[`svelte.ts`,Cr],[`Layouts.svelte`,mr],[`use.ts`,wr],[`pageSamples/styles.module.css`,_r],[`pageSamples/welcome.svelte`,vr],[`pageSamples/page.svelte`,gr],[`pageSamples/404.svelte`,hr],...t?.tanstack?.query?[[`app/app.svelte`,Y],[`app/app-tsq.svelte`,ur],[`app/index.ts`,`export { default as AppProvider } from "./app-tsq.svelte";`],[`query.ts`,br]]:[[`app/app.svelte`,Y],[`app/app-tsq.svelte`,`/** tanstack query disabled */`],[`app/index.ts`,`export { default as AppProvider } from "./app.svelte";`],[`query.ts`,`/** tanstack query disabled */`]]])await i(n.lib(e),r,{});for(let[e,t]of[[`pages/404.svelte`,Ar],[`components/Link.svelte`,Er],[`app.svelte`,Tr],[`router.ts`,Pr]])await a(n.src(e),t,{entryDir:l.entryDir},{overwrite:o});await a(n.src(`index.html`),kr,{entryDir:l.entryDir},{overwrite:e=>!e?.trim().length||!e.replace(/<!--[\s\S]*?-->/g,``).trim().length});for(let[e,t]of[[`client.ts`,Dr],[`server.ts`,Or]])await a(n.entry(e),t,{},{overwrite:o})},async watch(e,t){await u(e.filter(m(t,[`create`]))),await d(e)},async build(e){await u(e),await d(e)},async ssrBuild(){await i(n.lib(`query.ts`),t?.tanstack?.query?xr:`/** tanstack query disabled */`,{ssrBundle:!0})}}}),Ir=h({meta:{name:`Svelte`},dependencies(e){return{svelte:J.devDependencies.svelte,"path-to-regexp":J.devDependencies[`path-to-regexp`],...e?.tanstack?.query?{"@tanstack/svelte-query":J.devDependencies[`@tanstack/svelte-query`]}:{}}},factory:Fr}),Lr={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.16`}},Rr=`import Type from "typebox";
|
|
6249
6900
|
|
|
6250
6901
|
/**
|
|
6251
6902
|
* Custom types for JavaScript constructs that have no JSON Schema
|
|
@@ -6317,7 +6968,7 @@ export default {
|
|
|
6317
6968
|
Buffer: TBuffer(),
|
|
6318
6969
|
ArrayBuffer: TArrayBuffer(),
|
|
6319
6970
|
};
|
|
6320
|
-
`,
|
|
6971
|
+
`,zr=`import type { TValidationError } from "typebox/error";
|
|
6321
6972
|
|
|
6322
6973
|
import type { ValidationErrorEntry } from "@kosmojs/core";
|
|
6323
6974
|
|
|
@@ -7501,7 +8152,7 @@ const format = (fmt: string, ...args: unknown[]): string => {
|
|
|
7501
8152
|
|
|
7502
8153
|
return str;
|
|
7503
8154
|
};
|
|
7504
|
-
`,
|
|
8155
|
+
`,Br=`import Type from "typebox";
|
|
7505
8156
|
import { Compile } from "typebox/compile";
|
|
7506
8157
|
import Value from "typebox/value";
|
|
7507
8158
|
|
|
@@ -7553,14 +8204,14 @@ export const validationSchemaFactory = (
|
|
|
7553
8204
|
},
|
|
7554
8205
|
};
|
|
7555
8206
|
};
|
|
7556
|
-
`,
|
|
8207
|
+
`,Vr=`import { Settings } from "typebox/system";
|
|
7557
8208
|
|
|
7558
8209
|
Settings.Set({{settings}});
|
|
7559
8210
|
|
|
7560
8211
|
export { default as customTypes } from "{{customTypesImport}}";
|
|
7561
8212
|
|
|
7562
8213
|
export const validationMessages = {{validationMessages}};
|
|
7563
|
-
`,
|
|
8214
|
+
`,Hr=`import type { ValidationSchemas } from "@kosmojs/core";
|
|
7564
8215
|
|
|
7565
8216
|
import { validationSchemaFactory } from "{{ createImport 'lib' '@typebox' }}";
|
|
7566
8217
|
|
|
@@ -7621,14 +8272,14 @@ export const validationSchemas: ValidationSchemas = {
|
|
|
7621
8272
|
{{/each}}
|
|
7622
8273
|
},
|
|
7623
8274
|
};
|
|
7624
|
-
`,
|
|
8275
|
+
`,Ur={exactOptionalPropertyTypes:!0},Wr=g((e,t)=>{let{createPath:n,createImport:r,createImportHelpers:i}=y(e),{renderToFile:a}=x({helpers:{...i({origin:`lib`})}}),{validationMessages:s={},customTypesImport:c=r.lib([`@typebox/custom-types`],{origin:`lib`}),settings:l}={...t},u=async e=>{for(let{kind:t,entry:r}of e){if(t!==`apiRoute`)continue;let e=[r.params,...r.validationDefinitions.flatMap(e=>e.target===`response`?e.variants:[e.schema])].flatMap(({resolvedType:e})=>e?[e]:[]),i=[...new Set(r.validationDefinitions.flatMap(({target:e})=>Object.keys(o).includes(e)?[e]:[]))].map(e=>({target:e,methods:r.methods.flatMap(t=>{let n=r.validationDefinitions.find(n=>n.method===t&&n.target===e);return n?[{route:r.name,method:t,target:e,schema:n.schema,...n.runtimeValidation===void 0?{}:{runtimeValidation:JSON.stringify(n.runtimeValidation)},...n.customErrors===void 0?{}:{customErrors:JSON.stringify(n.customErrors)}}]:[]})})),s=r.methods.flatMap(e=>{let t=r.validationDefinitions.find(t=>t.method===e&&t.target===`response`);return t?[{method:e,variants:t.variants.map(e=>({route:r.name,target:`response`,...e,...t.runtimeValidation===void 0?{}:{runtimeValidation:JSON.stringify(t.runtimeValidation)},...t.customErrors===void 0?{}:{customErrors:JSON.stringify(t.customErrors)}}))}]:[]});await a(n.libApi(r.name,`schemas.ts`),Hr,{route:r,resolvedTypes:e,requestSchemas:i,responseSchemas:s})}};return{async start(){for(let[e,t]of[[`custom-types.ts`,Rr],[`error-handler.ts`,zr],[`index.ts`,Br],[`setup.ts`,Vr]])await a(n.lib(`@typebox`,e),t,{validationMessages:JSON.stringify(s),customTypesImport:c,settings:JSON.stringify({...Ur,...l})})},async watch(e,t){await u(e.filter(p(t,[`create`,`update`])))},async build(e){await u(e)}}}),X={PROPERTY:`PROPERTY`,PROPERTIES:`PROPERTIES`,ALLOWED_VALUES:`ALLOWED_VALUES`,FOUND_N_DUPLICATES:`FOUND_N_DUPLICATES`,VALIDATION_PASSED:`VALIDATION_PASSED`,VALIDATION_FAILED_PREFIX:`VALIDATION_FAILED_PREFIX`,ERROR_SUMMARY:`ERROR_SUMMARY`,PLURAL_SUFFIX:`PLURAL_SUFFIX`,FIRST:`FIRST`,SECOND:`SECOND`,THIRD:`THIRD`,FOURTH:`FOURTH`,FIFTH:`FIFTH`,TYPE_INVALID:`TYPE_INVALID`,STRING_MIN_LENGTH:`STRING_MIN_LENGTH`,STRING_MAX_LENGTH:`STRING_MAX_LENGTH`,STRING_PATTERN:`STRING_PATTERN`,STRING_FORMAT:`STRING_FORMAT`,STRING_FORMAT_EMAIL:`STRING_FORMAT_EMAIL`,STRING_FORMAT_DATE:`STRING_FORMAT_DATE`,STRING_FORMAT_DATETIME:`STRING_FORMAT_DATETIME`,STRING_FORMAT_TIME:`STRING_FORMAT_TIME`,STRING_FORMAT_URI:`STRING_FORMAT_URI`,STRING_FORMAT_URL:`STRING_FORMAT_URL`,STRING_FORMAT_UUID:`STRING_FORMAT_UUID`,STRING_FORMAT_IPV4:`STRING_FORMAT_IPV4`,STRING_FORMAT_IPV6:`STRING_FORMAT_IPV6`,STRING_FORMAT_HOSTNAME:`STRING_FORMAT_HOSTNAME`,STRING_FORMAT_JSON_POINTER:`STRING_FORMAT_JSON_POINTER`,STRING_FORMAT_REGEX:`STRING_FORMAT_REGEX`,NUMBER_MINIMUM:`NUMBER_MINIMUM`,NUMBER_MAXIMUM:`NUMBER_MAXIMUM`,NUMBER_EXCLUSIVE_MINIMUM:`NUMBER_EXCLUSIVE_MINIMUM`,NUMBER_EXCLUSIVE_MAXIMUM:`NUMBER_EXCLUSIVE_MAXIMUM`,NUMBER_MULTIPLE_OF:`NUMBER_MULTIPLE_OF`,ARRAY_MIN_ITEMS:`ARRAY_MIN_ITEMS`,ARRAY_MAX_ITEMS:`ARRAY_MAX_ITEMS`,ARRAY_UNIQUE_ITEMS:`ARRAY_UNIQUE_ITEMS`,ARRAY_CONTAINS:`ARRAY_CONTAINS`,ARRAY_MIN_CONTAINS:`ARRAY_MIN_CONTAINS`,ARRAY_MAX_CONTAINS:`ARRAY_MAX_CONTAINS`,ARRAY_PREFIX_ITEMS:`ARRAY_PREFIX_ITEMS`,ARRAY_ITEMS:`ARRAY_ITEMS`,ARRAY_UNEVALUATED_ITEMS:`ARRAY_UNEVALUATED_ITEMS`,TUPLE_MIN_ITEMS:`TUPLE_MIN_ITEMS`,TUPLE_MAX_ITEMS:`TUPLE_MAX_ITEMS`,OBJECT_REQUIRED:`OBJECT_REQUIRED`,OBJECT_ADDITIONAL_PROPERTIES:`OBJECT_ADDITIONAL_PROPERTIES`,OBJECT_MIN_PROPERTIES:`OBJECT_MIN_PROPERTIES`,OBJECT_MAX_PROPERTIES:`OBJECT_MAX_PROPERTIES`,OBJECT_PROPERTY_NAMES:`OBJECT_PROPERTY_NAMES`,OBJECT_DEPENDENCIES:`OBJECT_DEPENDENCIES`,OBJECT_UNEVALUATED_PROPERTIES:`OBJECT_UNEVALUATED_PROPERTIES`,ENUM_MISMATCH:`ENUM_MISMATCH`,CONST_MISMATCH:`CONST_MISMATCH`,CONDITIONAL_IF:`CONDITIONAL_IF`,CONDITIONAL_THEN:`CONDITIONAL_THEN`,CONDITIONAL_ELSE:`CONDITIONAL_ELSE`,COMPOSITION_ONE_OF:`COMPOSITION_ONE_OF`,COMPOSITION_ANY_OF:`COMPOSITION_ANY_OF`,COMPOSITION_ALL_OF:`COMPOSITION_ALL_OF`,COMPOSITION_NOT:`COMPOSITION_NOT`,CONTENT_DISCRIMINATOR:`CONTENT_DISCRIMINATOR`,CONTENT_ENCODING:`CONTENT_ENCODING`,CONTENT_MEDIA_TYPE:`CONTENT_MEDIA_TYPE`,CUSTOM_RANGE:`CUSTOM_RANGE`,CUSTOM_EXCLUSIVE_RANGE:`CUSTOM_EXCLUSIVE_RANGE`,CUSTOM_REGEXP:`CUSTOM_REGEXP`,CUSTOM_DYNAMIC_DEFAULTS:`CUSTOM_DYNAMIC_DEFAULTS`,CUSTOM_SELECT:`CUSTOM_SELECT`,CUSTOM_TRANSFORM:`CUSTOM_TRANSFORM`,CUSTOM_UNIQUE_ITEM_PROPERTIES:`CUSTOM_UNIQUE_ITEM_PROPERTIES`,UNKNOWN:`UNKNOWN`};X.PROPERTY,X.PROPERTIES,X.ALLOWED_VALUES,X.FOUND_N_DUPLICATES,X.VALIDATION_PASSED,X.VALIDATION_FAILED_PREFIX,X.ERROR_SUMMARY,X.PLURAL_SUFFIX,X.FIRST,X.SECOND,X.THIRD,X.FOURTH,X.FIFTH,X.TYPE_INVALID,X.STRING_MIN_LENGTH,X.STRING_MAX_LENGTH,X.STRING_PATTERN,X.STRING_FORMAT,X.STRING_FORMAT_EMAIL,X.STRING_FORMAT_DATE,X.STRING_FORMAT_DATETIME,X.STRING_FORMAT_TIME,X.STRING_FORMAT_URI,X.STRING_FORMAT_URL,X.STRING_FORMAT_UUID,X.STRING_FORMAT_IPV4,X.STRING_FORMAT_IPV6,X.STRING_FORMAT_HOSTNAME,X.STRING_FORMAT_JSON_POINTER,X.STRING_FORMAT_REGEX,X.NUMBER_MINIMUM,X.NUMBER_MAXIMUM,X.NUMBER_EXCLUSIVE_MINIMUM,X.NUMBER_EXCLUSIVE_MAXIMUM,X.NUMBER_MULTIPLE_OF,X.ARRAY_MIN_ITEMS,X.ARRAY_MAX_ITEMS,X.ARRAY_UNIQUE_ITEMS,X.ARRAY_CONTAINS,X.ARRAY_MIN_CONTAINS,X.ARRAY_MAX_CONTAINS,X.ARRAY_PREFIX_ITEMS,X.ARRAY_ITEMS,X.ARRAY_UNEVALUATED_ITEMS,X.TUPLE_MIN_ITEMS,X.TUPLE_MAX_ITEMS,X.OBJECT_REQUIRED,X.OBJECT_ADDITIONAL_PROPERTIES,X.OBJECT_MIN_PROPERTIES,X.OBJECT_MAX_PROPERTIES,X.OBJECT_PROPERTY_NAMES,X.OBJECT_DEPENDENCIES,X.OBJECT_UNEVALUATED_PROPERTIES,X.ENUM_MISMATCH,X.CONST_MISMATCH,X.CONDITIONAL_IF,X.CONDITIONAL_THEN,X.CONDITIONAL_ELSE,X.COMPOSITION_ONE_OF,X.COMPOSITION_ANY_OF,X.COMPOSITION_ALL_OF,X.COMPOSITION_NOT,X.CONTENT_DISCRIMINATOR,X.CONTENT_ENCODING,X.CONTENT_MEDIA_TYPE,X.CUSTOM_RANGE,X.CUSTOM_EXCLUSIVE_RANGE,X.CUSTOM_REGEXP,X.CUSTOM_DYNAMIC_DEFAULTS,X.CUSTOM_SELECT,X.CUSTOM_TRANSFORM,X.CUSTOM_UNIQUE_ITEM_PROPERTIES,X.UNKNOWN;var Gr=h({meta:{name:`TypeBox`,resolveTypes:!0},dependencies:{typebox:Lr.devDependencies.typebox},factory:Wr}),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.101.4`,"path-to-regexp":`^8.4.2`,vue:`^3.5.41`,"vue-router":`^5.2.0`}},Q=e=>{let t=e=>e.kind===`splat`?`:${e.name}(.*)?`:e.kind===`optional`?`:${e.name}?`:`:${e.name}`;return e.flatMap(e=>e.kind===`static`?[e.parts[0].value]:e.kind===`param`?[t(e.parts[0])]:[e.parts.map(e=>e.type===`static`?e.value:t(e)).join(``)]).join(`/`)},Kr=()=>{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},qr=()=>{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)]},Jr=`import type { Plugin } from "vue";
|
|
7625
8276
|
|
|
7626
8277
|
export { default as AppProvider } from "./provider.vue";
|
|
7627
8278
|
|
|
7628
8279
|
export const appProvider: Plugin = {
|
|
7629
8280
|
install() {},
|
|
7630
8281
|
};
|
|
7631
|
-
`,
|
|
8282
|
+
`,Yr=`import { VueQueryPlugin } from "@tanstack/vue-query";
|
|
7632
8283
|
import type { Plugin } from "vue";
|
|
7633
8284
|
|
|
7634
8285
|
import { getQueryClient } from "../query";
|
|
@@ -7640,10 +8291,10 @@ export const appProvider: Plugin = {
|
|
|
7640
8291
|
app.use(VueQueryPlugin, { queryClient: getQueryClient() });
|
|
7641
8292
|
},
|
|
7642
8293
|
};
|
|
7643
|
-
`,
|
|
8294
|
+
`,Xr=`<template>
|
|
7644
8295
|
<slot />
|
|
7645
8296
|
</template>
|
|
7646
|
-
`,
|
|
8297
|
+
`,Zr=`import type { App } from "vue";
|
|
7647
8298
|
import type { RouterFactoryReturn } from "@kosmojs/core";
|
|
7648
8299
|
import { clientRenderFactory } from "@kosmojs/core/generators";
|
|
7649
8300
|
|
|
@@ -7683,7 +8334,7 @@ export const mount = async (
|
|
|
7683
8334
|
}
|
|
7684
8335
|
|
|
7685
8336
|
export default clientRenderFactory();
|
|
7686
|
-
`,
|
|
8337
|
+
`,Qr=`{
|
|
7687
8338
|
path: "{{path}}",
|
|
7688
8339
|
{{#if name}}
|
|
7689
8340
|
name: "{{name}}",
|
|
@@ -7701,7 +8352,7 @@ export default clientRenderFactory();
|
|
|
7701
8352
|
children: [ {{#each children}}{{> routePartial}}, {{/each}}],
|
|
7702
8353
|
{{/if}}
|
|
7703
8354
|
}
|
|
7704
|
-
|
|
8355
|
+
`,$r=`import type { App } from "vue";
|
|
7705
8356
|
|
|
7706
8357
|
import {
|
|
7707
8358
|
renderToString as renderToStringOrig,
|
|
@@ -7797,7 +8448,7 @@ export default serverRenderFactory();
|
|
|
7797
8448
|
const component: DefineComponent<{}, {}, any>;
|
|
7798
8449
|
export default component;
|
|
7799
8450
|
}
|
|
7800
|
-
`,
|
|
8451
|
+
`,ei=`<script setup lang="ts">
|
|
7801
8452
|
import styles from "./styles.module.css";
|
|
7802
8453
|
defineProps<{
|
|
7803
8454
|
headline?: string;
|
|
@@ -7836,7 +8487,7 @@ defineProps<{
|
|
|
7836
8487
|
</div>
|
|
7837
8488
|
</div>
|
|
7838
8489
|
</template>
|
|
7839
|
-
`,
|
|
8490
|
+
`,ti=`<script setup lang="ts">
|
|
7840
8491
|
import styles from "./styles.module.css";
|
|
7841
8492
|
defineProps<{
|
|
7842
8493
|
message: string;
|
|
@@ -7885,7 +8536,7 @@ defineProps<{
|
|
|
7885
8536
|
</div>
|
|
7886
8537
|
</div>
|
|
7887
8538
|
</template>
|
|
7888
|
-
`,
|
|
8539
|
+
`,ni=`* {
|
|
7889
8540
|
margin: 0;
|
|
7890
8541
|
padding: 0;
|
|
7891
8542
|
box-sizing: border-box;
|
|
@@ -8018,7 +8669,7 @@ defineProps<{
|
|
|
8018
8669
|
align-items: center;
|
|
8019
8670
|
gap: 0.25rem;
|
|
8020
8671
|
}
|
|
8021
|
-
`,
|
|
8672
|
+
`,ri=`<script setup lang="ts">
|
|
8022
8673
|
import styles from "./styles.module.css";
|
|
8023
8674
|
<\/script>
|
|
8024
8675
|
|
|
@@ -8082,7 +8733,7 @@ import styles from "./styles.module.css";
|
|
|
8082
8733
|
</div>
|
|
8083
8734
|
</div>
|
|
8084
8735
|
</template>
|
|
8085
|
-
`,
|
|
8736
|
+
`,ii=`import { QueryClient, type QueryClientConfig } from "@tanstack/vue-query";
|
|
8086
8737
|
|
|
8087
8738
|
let client: QueryClient | undefined;
|
|
8088
8739
|
|
|
@@ -8097,7 +8748,7 @@ export const getQueryClient = (): QueryClient => {
|
|
|
8097
8748
|
}
|
|
8098
8749
|
return client;
|
|
8099
8750
|
};
|
|
8100
|
-
`,
|
|
8751
|
+
`,ai=`import { QueryClient, type QueryClientConfig } from "@tanstack/vue-query";
|
|
8101
8752
|
|
|
8102
8753
|
import { store } from "{{ createImport 'lib' '@ssr/base' }}";
|
|
8103
8754
|
|
|
@@ -8120,7 +8771,7 @@ export const getQueryClient = (): QueryClient => {
|
|
|
8120
8771
|
}
|
|
8121
8772
|
return ctx.tsqClient as QueryClient;
|
|
8122
8773
|
};
|
|
8123
|
-
`,
|
|
8774
|
+
`,oi=`import {
|
|
8124
8775
|
type App,
|
|
8125
8776
|
type Component,
|
|
8126
8777
|
createApp,
|
|
@@ -8249,7 +8900,18 @@ export const createRouters = (
|
|
|
8249
8900
|
// would otherwise skip the guard
|
|
8250
8901
|
installLoaderGuard(router);
|
|
8251
8902
|
|
|
8252
|
-
|
|
8903
|
+
let { pathname } = url;
|
|
8904
|
+
|
|
8905
|
+
if (base !== "/") {
|
|
8906
|
+
// strip the base from pushed paths
|
|
8907
|
+
if (pathname === base) {
|
|
8908
|
+
pathname = "/";
|
|
8909
|
+
} else if (pathname.startsWith(\`\${base}/\`)) {
|
|
8910
|
+
pathname = pathname.slice(base.length);
|
|
8911
|
+
}
|
|
8912
|
+
}
|
|
8913
|
+
|
|
8914
|
+
await router.push(pathname + url.search);
|
|
8253
8915
|
|
|
8254
8916
|
await router.isReady();
|
|
8255
8917
|
|
|
@@ -8271,14 +8933,14 @@ export default createRouterFactory<
|
|
|
8271
8933
|
Promise<App>,
|
|
8272
8934
|
{ server: { loaderData: Record<string, unknown> } }
|
|
8273
8935
|
>();
|
|
8274
|
-
`,
|
|
8936
|
+
`,si=`import { type Ref, unref } from "vue";
|
|
8275
8937
|
|
|
8276
8938
|
export type MaybeWrapped<T> = Ref<T> | T;
|
|
8277
8939
|
|
|
8278
8940
|
export function unwrap<T>(value: MaybeWrapped<T>): T {
|
|
8279
8941
|
return unref(value);
|
|
8280
8942
|
}
|
|
8281
|
-
`,
|
|
8943
|
+
`,ci=`import { useRoute, useRouter } from "vue-router";
|
|
8282
8944
|
|
|
8283
8945
|
import type { RouterWithLoaderData } from "./router";
|
|
8284
8946
|
|
|
@@ -8293,7 +8955,7 @@ export const useLoaderData = <T>(key?: string): T | undefined => {
|
|
|
8293
8955
|
const route = useRoute();
|
|
8294
8956
|
return router.__loaderData?.[key || (route.name as string)] as T;
|
|
8295
8957
|
};
|
|
8296
|
-
`,
|
|
8958
|
+
`,li=`<script setup lang="ts">
|
|
8297
8959
|
import { AppProvider } from "_/app";
|
|
8298
8960
|
<\/script>
|
|
8299
8961
|
|
|
@@ -8302,39 +8964,40 @@ import { AppProvider } from "_/app";
|
|
|
8302
8964
|
<RouterView />
|
|
8303
8965
|
</AppProvider>
|
|
8304
8966
|
</template>
|
|
8305
|
-
`,
|
|
8967
|
+
`,ui=`<script setup lang="ts" generic="T extends LinkProps">
|
|
8306
8968
|
import { computed } from "vue";
|
|
8307
8969
|
import { RouterLink } from "vue-router";
|
|
8308
8970
|
|
|
8309
8971
|
import { pageRouteMap, type LinkProps } from "{{ createImport 'libCore' }}";
|
|
8310
8972
|
|
|
8311
|
-
|
|
8312
|
-
to: T
|
|
8313
|
-
query?: Record<string | number, unknown
|
|
8314
|
-
replace?: boolean
|
|
8315
|
-
activeClass?: string
|
|
8316
|
-
exactActiveClass?: string
|
|
8973
|
+
type Props = {
|
|
8974
|
+
to: T;
|
|
8975
|
+
query?: Record<string | number, unknown>;
|
|
8976
|
+
replace?: boolean;
|
|
8977
|
+
activeClass?: string;
|
|
8978
|
+
exactActiveClass?: string;
|
|
8317
8979
|
}
|
|
8318
8980
|
|
|
8319
8981
|
const props = defineProps<Props>();
|
|
8320
8982
|
|
|
8321
8983
|
const href = computed(() => {
|
|
8322
|
-
const [key, ...params] = props.to
|
|
8323
|
-
return pageRouteMap[key]?.
|
|
8984
|
+
const [key, ...params] = props.to;
|
|
8985
|
+
return pageRouteMap[key]?.path(params as never, props.query, { prefix: false });
|
|
8324
8986
|
})
|
|
8987
|
+
|
|
8988
|
+
const linkProps = computed(() => ({
|
|
8989
|
+
...(props.replace !== undefined ? { replace: props.replace } : {}),
|
|
8990
|
+
...(props.activeClass !== undefined ? { activeClass: props.activeClass } : {}),
|
|
8991
|
+
...(props.exactActiveClass !== undefined ? { exactActiveClass: props.exactActiveClass } : {}),
|
|
8992
|
+
}))
|
|
8325
8993
|
<\/script>
|
|
8326
8994
|
|
|
8327
8995
|
<template>
|
|
8328
|
-
<RouterLink
|
|
8329
|
-
:to="href"
|
|
8330
|
-
:replace="replace"
|
|
8331
|
-
:active-class="activeClass"
|
|
8332
|
-
:exact-active-class="exactActiveClass"
|
|
8333
|
-
>
|
|
8996
|
+
<RouterLink :to="href" v-bind="linkProps">
|
|
8334
8997
|
<slot />
|
|
8335
8998
|
</RouterLink>
|
|
8336
8999
|
</template>
|
|
8337
|
-
`,
|
|
9000
|
+
`,di=`import renderFactory, {
|
|
8338
9001
|
createRoutes,
|
|
8339
9002
|
hydrate,
|
|
8340
9003
|
mount,
|
|
@@ -8361,7 +9024,7 @@ if (root) {
|
|
|
8361
9024
|
} else {
|
|
8362
9025
|
console.error("❌ Root element not found!");
|
|
8363
9026
|
}
|
|
8364
|
-
`,
|
|
9027
|
+
`,fi=`import renderFactory, {
|
|
8365
9028
|
createRoutes,
|
|
8366
9029
|
renderToStream,
|
|
8367
9030
|
renderToString,
|
|
@@ -8388,7 +9051,7 @@ export default renderFactory(() => {
|
|
|
8388
9051
|
},
|
|
8389
9052
|
};
|
|
8390
9053
|
});
|
|
8391
|
-
`,
|
|
9054
|
+
`,pi=`<!doctype html>
|
|
8392
9055
|
<html lang="en">
|
|
8393
9056
|
<head>
|
|
8394
9057
|
<meta charset="UTF-8" />
|
|
@@ -8400,17 +9063,17 @@ export default renderFactory(() => {
|
|
|
8400
9063
|
<script type="module" src="/{{ entryDir }}/client.ts"><\/script>
|
|
8401
9064
|
</body>
|
|
8402
9065
|
</html>
|
|
8403
|
-
`,
|
|
9066
|
+
`,mi=`<script setup lang="ts">
|
|
8404
9067
|
import PageSample from "{{ createImport 'lib' 'pageSamples/404.vue' }}";
|
|
8405
9068
|
<\/script>
|
|
8406
9069
|
|
|
8407
9070
|
<template>
|
|
8408
9071
|
<PageSample />
|
|
8409
9072
|
</template>
|
|
8410
|
-
`,
|
|
9073
|
+
`,hi=`<template>
|
|
8411
9074
|
<router-view />
|
|
8412
9075
|
</template>
|
|
8413
|
-
`,
|
|
9076
|
+
`,gi=`<script setup lang="ts">
|
|
8414
9077
|
import PageSample from "{{ createImport 'lib' 'pageSamples/page.vue' }}";
|
|
8415
9078
|
<\/script>
|
|
8416
9079
|
|
|
@@ -8425,14 +9088,14 @@ import PageSample from "{{ createImport 'lib' 'pageSamples/page.vue' }}";
|
|
|
8425
9088
|
}"
|
|
8426
9089
|
/>
|
|
8427
9090
|
</template>
|
|
8428
|
-
`,
|
|
9091
|
+
`,_i=`<script setup lang="ts">
|
|
8429
9092
|
import WelcomePage from "{{ createImport 'lib' 'pageSamples/welcome.vue' }}";
|
|
8430
9093
|
<\/script>
|
|
8431
9094
|
|
|
8432
9095
|
<template>
|
|
8433
9096
|
<WelcomePage />
|
|
8434
9097
|
</template>
|
|
8435
|
-
`,
|
|
9098
|
+
`,vi=`import routerFactory, { createRouters } from "{{ createImport 'lib' 'router' }}";
|
|
8436
9099
|
import { appProvider } from "{{ createImport 'lib' 'app' }}";
|
|
8437
9100
|
|
|
8438
9101
|
import app from "./app.vue";
|
|
@@ -8451,5 +9114,5 @@ export default routerFactory((routes) => {
|
|
|
8451
9114
|
},
|
|
8452
9115
|
};
|
|
8453
9116
|
});
|
|
8454
|
-
`,
|
|
9117
|
+
`,yi=g((e,t)=>{let{createPath:n,createImportHelpers:r}=y(e),{renderToFile:i}=x({helpers:{...r({origin:`lib`}),...w()},partials:{routePartial:Qr}}),{renderToFile:a}=x({helpers:r({origin:`src`})}),o=Kr(),s=e=>!e?.trim().length,u=c(t?.templates,gi),d=async e=>{for(let{kind:t,entry:r}of e)t===`pageRoute`?await a(n.pages(r.file),r.name===`index`?_i:u(r.name,r),{route:r,message:qr()},{overwrite:s}):t===`pageLayout`&&await a(n.pages(r.file),hi,{route:r},{overwrite:s})},f=async e=>{let t=e.flatMap(({kind:e,entry:t})=>e===`pageRoute`?[t]:[]).sort(S),r=e.flatMap(({kind:e,entry:t})=>e===`pageRoute`||e===`pageLayout`?[t]:[]),a=o(v(r));for(let[e,t]of[[`client.ts`,Zr],[`server.ts`,$r]])await i(n.libEntry(e),t,{pageEntries:r,nestedRoutes:a,lazyLoad:e===`client.ts`});await i(n.lib(`router.ts`),oi,{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`,$],[`unwrap.ts`,si],[`use.ts`,ci],[`pageSamples/styles.module.css`,ni],[`pageSamples/welcome.vue`,ri],[`pageSamples/page.vue`,ti],[`pageSamples/404.vue`,ei],[`app/provider.vue`,Xr],...t?.tanstack?.query?[[`app/index.ts`,Yr],[`query.ts`,ii]]:[[`app/index.ts`,Jr],[`query.ts`,`/** tanstack query disabled */`]]])await i(n.lib(e),r,{});for(let[e,t]of[[`pages/404.vue`,mi],[`components/Link.vue`,ui],[`app.vue`,li],[`router.ts`,vi]])await a(n.src(e),t,{entryDir:l.entryDir},{overwrite:s});await a(n.src(`index.html`),pi,{entryDir:l.entryDir},{overwrite:e=>!e?.trim().length||!e.replace(/<!--[\s\S]*?-->/g,``).trim().length});for(let[e,t]of[[`client.ts`,di],[`server.ts`,fi]])await a(n.entry(e),t,{},{overwrite:s})},async watch(e,t){await d(e.filter(m(t,[`create`]))),await f(e)},async build(e){await d(e),await f(e)},async ssrBuild(){await i(n.lib(`query.ts`),t?.tanstack?.query?ai:`/** tanstack query disabled */`,{ssrBundle:!0})}}}),bi=h({meta:{name:`Vue`,jsxImportSource:`vue`},dependencies(e){return{vue:Z.devDependencies.vue,"vue-router":Z.devDependencies[`vue-router`],"path-to-regexp":Z.devDependencies[`path-to-regexp`],...e?.tanstack?.query?{"@tanstack/vue-query":Z.devDependencies[`@tanstack/vue-query`]}:{}}},factory:yi}),xi=e=>{let n=process.env.NODE_ENV||`development`,a=typeof e.base==`string`?e.base:e.base[n];if(!a?.trim())throw Error(r([`red`],`ERROR: Invalid Config - no base provided`));return{...e,base:t(`/`,a),apiBase:t(`/`,e.apiBase||i)}};export{e as coreGenerator,xi as defineConfig,I as fetchGenerator,ke as h3Generator,Je as honoGenerator,pt as koaGenerator,Ht as mdxGenerator,qt as openapiGenerator,Sn as reactGenerator,Xn as solidGenerator,$n as ssgGenerator,cr as ssrGenerator,Ir as svelteGenerator,Gr as typeboxGenerator,bi as vueGenerator};
|
|
8455
9118
|
//# sourceMappingURL=index.js.map
|