litestar-vite-plugin 0.15.0-beta.1 → 0.15.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,7 @@
1
- import { exec } from "node:child_process";
2
1
  import fs from "node:fs";
3
2
  import path from "node:path";
4
- import { promisify } from "node:util";
5
3
  import colors from "picocolors";
6
- import { resolveInstallHint, resolvePackageExecutor } from "./install-hint.js";
7
- import { debounce } from "./shared/debounce.js";
8
- const execAsync = promisify(exec);
4
+ import { createTypeGenerationPlugin } from "./shared/create-type-gen-plugin.js";
9
5
  function resolveConfig(config = {}) {
10
6
  const runtimeConfigPath = process.env.LITESTAR_VITE_CONFIG_PATH;
11
7
  let hotFile;
@@ -155,233 +151,17 @@ function litestarSvelteKit(userConfig = {}) {
155
151
  }
156
152
  });
157
153
  if (config.types !== false && config.types.enabled) {
158
- plugins.push(createTypeGenerationPlugin(config.types, config.executor));
154
+ plugins.push(
155
+ createTypeGenerationPlugin(config.types, {
156
+ frameworkName: "litestar-sveltekit",
157
+ pluginName: "litestar-sveltekit-types",
158
+ clientPlugin: "@hey-api/client-fetch",
159
+ executor: config.executor
160
+ })
161
+ );
159
162
  }
160
163
  return plugins;
161
164
  }
162
- async function emitRouteTypes(routesPath, outputDir) {
163
- const contents = await fs.promises.readFile(routesPath, "utf-8");
164
- const json = JSON.parse(contents);
165
- const outDir = path.resolve(process.cwd(), outputDir);
166
- await fs.promises.mkdir(outDir, { recursive: true });
167
- const outFile = path.join(outDir, "routes.ts");
168
- const banner = `// AUTO-GENERATED by litestar-vite. Do not edit.
169
- /* eslint-disable */
170
-
171
- `;
172
- const routesData = json.routes || json;
173
- const routeNames = Object.keys(routesData);
174
- const routeNameType = routeNames.length > 0 ? routeNames.map((n) => `"${n}"`).join(" | ") : "never";
175
- const routeParamTypes = [];
176
- for (const [name, data] of Object.entries(routesData)) {
177
- const routeData = data;
178
- if (routeData.parameters && routeData.parameters.length > 0) {
179
- const params = routeData.parameters.map((p) => `${p}: string | number`).join("; ");
180
- routeParamTypes.push(` "${name}": { ${params} }`);
181
- } else {
182
- routeParamTypes.push(` "${name}": Record<string, never>`);
183
- }
184
- }
185
- const body = `/**
186
- * AUTO-GENERATED by litestar-vite.
187
- *
188
- * Exports:
189
- * - routesMeta: full route metadata
190
- * - routes: name -> uri map
191
- * - serverRoutes: alias of routes for clarity in apps
192
- * - route(): type-safe URL generator
193
- * - hasRoute(): type guard
194
- * - csrf helpers re-exported from litestar-vite-plugin/helpers
195
- *
196
- * @see https://litestar-vite.litestar.dev/
197
- */
198
- export const routesMeta = ${JSON.stringify(json, null, 2)} as const
199
-
200
- /**
201
- * Route name to URI mapping.
202
- */
203
- export const routes = ${JSON.stringify(Object.fromEntries(Object.entries(routesData).map(([name, data]) => [name, data.uri])), null, 2)} as const
204
-
205
- /**
206
- * Alias for server-injected route map (more descriptive for consumers).
207
- */
208
- export const serverRoutes = routes
209
-
210
- /**
211
- * All available route names.
212
- */
213
- export type RouteName = ${routeNameType}
214
-
215
- /**
216
- * Parameter types for each route.
217
- */
218
- export interface RouteParams {
219
- ${routeParamTypes.join("\n")}
220
- }
221
-
222
- /**
223
- * Generate a URL for a named route with type-safe parameters.
224
- *
225
- * @param name - The route name
226
- * @param params - Route parameters (required if route has path parameters)
227
- * @returns The generated URL
228
- *
229
- * @example
230
- * \`\`\`ts
231
- * import { route } from '@/generated/routes'
232
- *
233
- * // Route without parameters
234
- * route('home') // "/"
235
- *
236
- * // Route with parameters
237
- * route('user:detail', { user_id: 123 }) // "/users/123"
238
- * \`\`\`
239
- */
240
- export function route<T extends RouteName>(
241
- name: T,
242
- ...args: RouteParams[T] extends Record<string, never> ? [] : [params: RouteParams[T]]
243
- ): string {
244
- let uri = routes[name] as string
245
- const params = args[0] as Record<string, string | number> | undefined
246
-
247
- if (params) {
248
- for (const [key, value] of Object.entries(params)) {
249
- // Handle both {param} and {param:type} syntax
250
- uri = uri.replace(new RegExp(\`\\\\{\${key}(?::[^}]+)?\\\\}\`, "g"), String(value))
251
- }
252
- }
253
-
254
- return uri
255
- }
256
-
257
- /**
258
- * Check if a route name exists.
259
- */
260
- export function hasRoute(name: string): name is RouteName {
261
- return name in routes
262
- }
263
-
264
- declare global {
265
- interface Window {
266
- /**
267
- * Fully-typed route metadata injected by Litestar.
268
- */
269
- __LITESTAR_ROUTES__?: typeof routesMeta
270
- /**
271
- * Simple route map (name -> uri) for legacy consumers.
272
- */
273
- routes?: typeof routes
274
- serverRoutes?: typeof serverRoutes
275
- }
276
- // eslint-disable-next-line no-var
277
- var routes: typeof routes | undefined
278
- var serverRoutes: typeof serverRoutes | undefined
279
- }
280
-
281
- // Re-export helper functions from litestar-vite-plugin
282
- // These work with the routes defined above
283
- export { getCsrfToken, csrfHeaders, csrfFetch } from "litestar-vite-plugin/helpers"
284
- `;
285
- await fs.promises.writeFile(outFile, `${banner}${body}`, "utf-8");
286
- }
287
- function createTypeGenerationPlugin(typesConfig, executor) {
288
- let server = null;
289
- let isGenerating = false;
290
- async function runTypeGeneration() {
291
- if (isGenerating) {
292
- return false;
293
- }
294
- isGenerating = true;
295
- const startTime = Date.now();
296
- try {
297
- const openapiPath = path.resolve(process.cwd(), typesConfig.openapiPath);
298
- if (!fs.existsSync(openapiPath)) {
299
- console.log(colors.cyan("[litestar-sveltekit]"), colors.yellow("OpenAPI schema not found:"), typesConfig.openapiPath);
300
- return false;
301
- }
302
- console.log(colors.cyan("[litestar-sveltekit]"), colors.dim("Generating TypeScript types..."));
303
- const projectRoot = process.cwd();
304
- const candidates = [path.resolve(projectRoot, "openapi-ts.config.ts"), path.resolve(projectRoot, "hey-api.config.ts"), path.resolve(projectRoot, ".hey-api.config.ts")];
305
- const configPath = candidates.find((p) => fs.existsSync(p)) || null;
306
- let args;
307
- if (configPath) {
308
- console.log(colors.cyan("[litestar-sveltekit]"), colors.dim("Using config:"), configPath);
309
- args = ["@hey-api/openapi-ts", "--file", configPath];
310
- } else {
311
- args = ["@hey-api/openapi-ts", "-i", typesConfig.openapiPath, "-o", typesConfig.output];
312
- const plugins = ["@hey-api/typescript", "@hey-api/schemas"];
313
- if (typesConfig.generateSdk) {
314
- plugins.push("@hey-api/sdk", "@hey-api/client-fetch");
315
- }
316
- if (typesConfig.generateZod) {
317
- plugins.push("zod");
318
- }
319
- if (plugins.length) {
320
- args.push("--plugins", ...plugins);
321
- }
322
- }
323
- await execAsync(resolvePackageExecutor(args.join(" "), executor), {
324
- cwd: projectRoot
325
- });
326
- const routesPath = path.resolve(process.cwd(), typesConfig.routesPath);
327
- if (fs.existsSync(routesPath)) {
328
- await emitRouteTypes(routesPath, typesConfig.output);
329
- }
330
- const duration = Date.now() - startTime;
331
- console.log(colors.cyan("[litestar-sveltekit]"), colors.green("Types generated"), colors.dim(`in ${duration}ms`));
332
- if (server) {
333
- server.ws.send({
334
- type: "custom",
335
- event: "litestar:types-updated",
336
- data: {
337
- output: typesConfig.output,
338
- timestamp: Date.now()
339
- }
340
- });
341
- }
342
- return true;
343
- } catch (error) {
344
- const message = error instanceof Error ? error.message : String(error);
345
- if (message.includes("not found") || message.includes("ENOENT")) {
346
- console.log(colors.cyan("[litestar-sveltekit]"), colors.yellow("@hey-api/openapi-ts not installed"), "- run:", resolveInstallHint());
347
- } else {
348
- console.error(colors.cyan("[litestar-sveltekit]"), colors.red("Type generation failed:"), message);
349
- }
350
- return false;
351
- } finally {
352
- isGenerating = false;
353
- }
354
- }
355
- const debouncedRunTypeGeneration = debounce(runTypeGeneration, typesConfig.debounce);
356
- return {
357
- name: "litestar-sveltekit-types",
358
- enforce: "pre",
359
- configureServer(devServer) {
360
- server = devServer;
361
- console.log(colors.cyan("[litestar-sveltekit]"), colors.dim("Watching for schema changes:"), colors.yellow(typesConfig.openapiPath));
362
- },
363
- async buildStart() {
364
- if (typesConfig.enabled) {
365
- const openapiPath = path.resolve(process.cwd(), typesConfig.openapiPath);
366
- if (fs.existsSync(openapiPath)) {
367
- await runTypeGeneration();
368
- }
369
- }
370
- },
371
- handleHotUpdate({ file }) {
372
- if (!typesConfig.enabled) {
373
- return;
374
- }
375
- const relativePath = path.relative(process.cwd(), file);
376
- const openapiPath = typesConfig.openapiPath.replace(/^\.\//, "");
377
- const routesPath = typesConfig.routesPath.replace(/^\.\//, "");
378
- if (relativePath === openapiPath || relativePath === routesPath || file.endsWith(openapiPath) || file.endsWith(routesPath)) {
379
- console.log(colors.cyan("[litestar-sveltekit]"), colors.dim("Schema changed:"), colors.yellow(relativePath));
380
- debouncedRunTypeGeneration();
381
- }
382
- }
383
- };
384
- }
385
165
  var sveltekit_default = litestarSvelteKit;
386
166
  export {
387
167
  sveltekit_default as default,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "litestar-vite-plugin",
3
- "version": "0.15.0-beta.1",
3
+ "version": "0.15.0-beta.2",
4
4
  "type": "module",
5
5
  "description": "Litestar plugin for Vite.",
6
6
  "keywords": [
@@ -55,7 +55,7 @@
55
55
  "build": "npm run build-plugin && npm run build-helpers && npm run build-inertia-helpers && npm run build-integrations",
56
56
  "build-plugin": "rm -rf dist/js && npm run build-plugin-types && npm run build-plugin-esm && cp src/js/src/dev-server-index.html dist/js/",
57
57
  "build-plugin-types": "tsc --project src/js/tsconfig.json --emitDeclarationOnly",
58
- "build-plugin-esm": "esbuild src/js/src/index.ts --platform=node --format=esm --outfile=dist/js/index.js && esbuild src/js/src/install-hint.ts --platform=node --format=esm --outfile=dist/js/install-hint.js && esbuild src/js/src/litestar-meta.ts --platform=node --format=esm --outfile=dist/js/litestar-meta.js && mkdir -p dist/js/shared && esbuild src/js/src/shared/debounce.ts src/js/src/shared/format-path.ts src/js/src/shared/logger.ts --platform=node --format=esm --outdir=dist/js/shared",
58
+ "build-plugin-esm": "esbuild src/js/src/index.ts --platform=node --format=esm --outfile=dist/js/index.js && esbuild src/js/src/install-hint.ts --platform=node --format=esm --outfile=dist/js/install-hint.js && esbuild src/js/src/litestar-meta.ts --platform=node --format=esm --outfile=dist/js/litestar-meta.js && mkdir -p dist/js/shared && esbuild src/js/src/shared/debounce.ts src/js/src/shared/format-path.ts src/js/src/shared/logger.ts src/js/src/shared/emit-route-types.ts src/js/src/shared/create-type-gen-plugin.ts --platform=node --format=esm --outdir=dist/js/shared",
59
59
  "build-helpers": "rm -rf dist/js/helpers && tsc --project src/js/tsconfig.helpers.json",
60
60
  "build-inertia-helpers": "rm -rf dist/js/inertia-helpers && tsc --project src/js/tsconfig.inertia-helpers.json",
61
61
  "build-integrations": "esbuild src/js/src/astro.ts src/js/src/sveltekit.ts src/js/src/nuxt.ts --platform=node --format=esm --outdir=dist/js",