litestar-vite-plugin 0.15.0-beta.5 → 0.15.0-beta.6

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.
@@ -0,0 +1,178 @@
1
+ import { exec } from "node:child_process";
2
+ import fs from "node:fs";
3
+ import { createRequire } from "node:module";
4
+ import path from "node:path";
5
+ import { promisify } from "node:util";
6
+ import colors from "picocolors";
7
+ import { resolveInstallHint, resolvePackageExecutor } from "../install-hint.js";
8
+ import { debounce } from "./debounce.js";
9
+ import { emitPagePropsTypes } from "./emit-page-props-types.js";
10
+ import { formatPath } from "./format-path.js";
11
+ const execAsync = promisify(exec);
12
+ const nodeRequire = createRequire(import.meta.url);
13
+ async function getFileMtime(filePath) {
14
+ const stat = await fs.promises.stat(filePath);
15
+ return stat.mtimeMs.toString();
16
+ }
17
+ function createLitestarTypeGenPlugin(typesConfig, options) {
18
+ const { pluginName, frameworkName, sdkClientPlugin, executor, hasPythonConfig } = options;
19
+ let lastTypesHash = null;
20
+ let lastPagePropsHash = null;
21
+ let server = null;
22
+ let isGenerating = false;
23
+ let resolvedConfig = null;
24
+ let _chosenConfigPath = null;
25
+ async function runTypeGeneration() {
26
+ if (isGenerating) {
27
+ return false;
28
+ }
29
+ isGenerating = true;
30
+ const startTime = Date.now();
31
+ try {
32
+ const projectRoot = resolvedConfig?.root ?? process.cwd();
33
+ const openapiPath = path.resolve(projectRoot, typesConfig.openapiPath);
34
+ const pagePropsPath = path.resolve(projectRoot, typesConfig.pagePropsPath);
35
+ let generated = false;
36
+ const candidates = [path.resolve(projectRoot, "openapi-ts.config.ts"), path.resolve(projectRoot, "hey-api.config.ts"), path.resolve(projectRoot, ".hey-api.config.ts")];
37
+ const configPath = candidates.find((p) => fs.existsSync(p)) || null;
38
+ _chosenConfigPath = configPath;
39
+ const shouldRunOpenApiTs = configPath || typesConfig.generateSdk;
40
+ if (fs.existsSync(openapiPath) && shouldRunOpenApiTs) {
41
+ resolvedConfig?.logger.info(`${colors.cyan("\u2022")} Generating TypeScript types...`);
42
+ if (resolvedConfig && configPath) {
43
+ const relConfigPath = formatPath(configPath, resolvedConfig.root);
44
+ resolvedConfig.logger.info(`${colors.cyan("\u2022")} openapi-ts config: ${colors.yellow(relConfigPath)}`);
45
+ }
46
+ const sdkOutput = path.join(typesConfig.output, "api");
47
+ let args;
48
+ if (configPath) {
49
+ args = ["@hey-api/openapi-ts", "--file", configPath];
50
+ } else {
51
+ args = ["@hey-api/openapi-ts", "-i", typesConfig.openapiPath, "-o", sdkOutput];
52
+ const plugins = ["@hey-api/typescript", "@hey-api/schemas"];
53
+ if (typesConfig.generateSdk) {
54
+ plugins.push("@hey-api/sdk", sdkClientPlugin);
55
+ }
56
+ if (typesConfig.generateZod) {
57
+ plugins.push("zod");
58
+ }
59
+ if (plugins.length) {
60
+ args.push("--plugins", ...plugins);
61
+ }
62
+ }
63
+ if (typesConfig.generateZod) {
64
+ try {
65
+ nodeRequire.resolve("zod", { paths: [projectRoot] });
66
+ } catch {
67
+ resolvedConfig?.logger.warn(`${colors.yellow("!")} zod not installed - run: ${resolveInstallHint()} zod`);
68
+ }
69
+ }
70
+ await execAsync(resolvePackageExecutor(args.join(" "), executor), { cwd: projectRoot });
71
+ generated = true;
72
+ }
73
+ if (typesConfig.generatePageProps && fs.existsSync(pagePropsPath)) {
74
+ await emitPagePropsTypes(pagePropsPath, typesConfig.output);
75
+ generated = true;
76
+ }
77
+ if (generated && resolvedConfig) {
78
+ const duration = Date.now() - startTime;
79
+ resolvedConfig.logger.info(`${colors.green("\u2713")} TypeScript artifacts updated ${colors.dim(`(${duration}ms)`)}`);
80
+ }
81
+ if (generated && server) {
82
+ server.ws.send({
83
+ type: "custom",
84
+ event: "litestar:types-updated",
85
+ data: {
86
+ output: typesConfig.output,
87
+ timestamp: Date.now()
88
+ }
89
+ });
90
+ }
91
+ return true;
92
+ } catch (error) {
93
+ const message = error instanceof Error ? error.message : String(error);
94
+ if (resolvedConfig) {
95
+ if (message.includes("not found") || message.includes("ENOENT")) {
96
+ const zodHint = typesConfig.generateZod ? " zod" : "";
97
+ resolvedConfig.logger.warn(
98
+ `${colors.cyan("litestar-vite")} ${colors.yellow("@hey-api/openapi-ts not installed")} - run: ${resolveInstallHint()} -D @hey-api/openapi-ts${zodHint}`
99
+ );
100
+ } else {
101
+ resolvedConfig.logger.error(`${colors.cyan("litestar-vite")} ${colors.red("type generation failed:")} ${message}`);
102
+ }
103
+ }
104
+ return false;
105
+ } finally {
106
+ isGenerating = false;
107
+ }
108
+ }
109
+ const debouncedRunTypeGeneration = debounce(runTypeGeneration, typesConfig.debounce);
110
+ return {
111
+ name: pluginName,
112
+ enforce: "pre",
113
+ configResolved(config) {
114
+ resolvedConfig = config;
115
+ },
116
+ configureServer(devServer) {
117
+ server = devServer;
118
+ if (typesConfig.enabled) {
119
+ const openapiRel = path.basename(typesConfig.openapiPath);
120
+ resolvedConfig?.logger.info(`${colors.cyan("\u2022")} Watching: ${colors.yellow(openapiRel)}`);
121
+ }
122
+ },
123
+ async buildStart() {
124
+ if (typesConfig.enabled && hasPythonConfig === false) {
125
+ const projectRoot = resolvedConfig?.root ?? process.cwd();
126
+ const openapiPath = path.resolve(projectRoot, typesConfig.openapiPath);
127
+ if (!fs.existsSync(openapiPath)) {
128
+ this.warn(
129
+ `Type generation is enabled but .litestar.json was not found.
130
+ The Litestar backend generates this file on startup.
131
+
132
+ Solutions:
133
+ 1. Start the backend first: ${colors.cyan("litestar run")}
134
+ 2. Use integrated dev: ${colors.cyan("litestar assets serve")}
135
+ 3. Disable types: ${colors.cyan("litestar({ input: [...], types: false })")}
136
+ `
137
+ );
138
+ }
139
+ }
140
+ if (typesConfig.enabled) {
141
+ const projectRoot = resolvedConfig?.root ?? process.cwd();
142
+ const openapiPath = path.resolve(projectRoot, typesConfig.openapiPath);
143
+ const pagePropsPath = path.resolve(projectRoot, typesConfig.pagePropsPath);
144
+ const hasOpenapi = fs.existsSync(openapiPath);
145
+ const hasPageProps = typesConfig.generatePageProps && fs.existsSync(pagePropsPath);
146
+ if (hasOpenapi || hasPageProps) {
147
+ await runTypeGeneration();
148
+ }
149
+ }
150
+ },
151
+ async handleHotUpdate({ file }) {
152
+ if (!typesConfig.enabled) {
153
+ return;
154
+ }
155
+ const root = resolvedConfig?.root ?? process.cwd();
156
+ const relativePath = path.relative(root, file);
157
+ const openapiPath = typesConfig.openapiPath.replace(/^\.\//, "");
158
+ const pagePropsPath = typesConfig.pagePropsPath.replace(/^\.\//, "");
159
+ const isOpenapi = relativePath === openapiPath || file.endsWith(openapiPath);
160
+ const isPageProps = typesConfig.generatePageProps && (relativePath === pagePropsPath || file.endsWith(pagePropsPath));
161
+ if (isOpenapi || isPageProps) {
162
+ resolvedConfig?.logger.info(`${colors.cyan(frameworkName)} ${colors.dim("schema changed:")} ${colors.yellow(relativePath)}`);
163
+ const newHash = await getFileMtime(file);
164
+ if (isOpenapi) {
165
+ if (lastTypesHash === newHash) return;
166
+ lastTypesHash = newHash;
167
+ } else if (isPageProps) {
168
+ if (lastPagePropsHash === newHash) return;
169
+ lastPagePropsHash = newHash;
170
+ }
171
+ debouncedRunTypeGeneration();
172
+ }
173
+ }
174
+ };
175
+ }
176
+ export {
177
+ createLitestarTypeGenPlugin
178
+ };
@@ -20,7 +20,7 @@
20
20
  * apiProxy: 'http://localhost:8000',
21
21
  * types: {
22
22
  * enabled: true,
23
- * output: 'src/lib/api',
23
+ * output: 'src/lib/generated',
24
24
  * },
25
25
  * }),
26
26
  * sveltekit(), // SvelteKit plugin comes after
@@ -43,9 +43,9 @@ export interface SvelteKitTypesConfig {
43
43
  enabled?: boolean;
44
44
  /**
45
45
  * Path to output generated TypeScript types.
46
- * Recommended to use SvelteKit's $lib alias path.
46
+ * Relative to the SvelteKit project root.
47
47
  *
48
- * @default 'src/lib/api'
48
+ * @default 'src/lib/generated'
49
49
  */
50
50
  output?: string;
51
51
  /**
@@ -60,6 +60,12 @@ export interface SvelteKitTypesConfig {
60
60
  * @default 'routes.json'
61
61
  */
62
62
  routesPath?: string;
63
+ /**
64
+ * Path where Inertia page props metadata is exported by Litestar.
65
+ *
66
+ * @default 'inertia-pages.json'
67
+ */
68
+ pagePropsPath?: string;
63
69
  /**
64
70
  * Generate Zod schemas in addition to TypeScript types.
65
71
  *
@@ -72,6 +78,24 @@ export interface SvelteKitTypesConfig {
72
78
  * @default true
73
79
  */
74
80
  generateSdk?: boolean;
81
+ /**
82
+ * Generate typed routes.ts from routes.json metadata.
83
+ *
84
+ * @default true
85
+ */
86
+ generateRoutes?: boolean;
87
+ /**
88
+ * Generate Inertia page props types from inertia-pages.json metadata.
89
+ *
90
+ * @default true
91
+ */
92
+ generatePageProps?: boolean;
93
+ /**
94
+ * Register route() globally on window object.
95
+ *
96
+ * @default false
97
+ */
98
+ globalRoute?: boolean;
75
99
  /**
76
100
  * Debounce time in milliseconds for type regeneration.
77
101
  *
@@ -144,7 +168,7 @@ export interface LitestarSvelteKitConfig {
144
168
  * apiPrefix: '/api',
145
169
  * types: {
146
170
  * enabled: true,
147
- * output: 'src/lib/api',
171
+ * output: 'src/lib/generated',
148
172
  * generateZod: true,
149
173
  * },
150
174
  * }),
@@ -157,8 +181,8 @@ export interface LitestarSvelteKitConfig {
157
181
  * ```typescript
158
182
  * // src/routes/users/[id]/+page.ts
159
183
  * import type { PageLoad } from './$types';
160
- * import type { User } from '$lib/api/types.gen';
161
- * import { route } from '$lib/api/routes';
184
+ * import type { User } from '$lib/generated/api/types.gen';
185
+ * import { route } from '$lib/generated/routes';
162
186
  *
163
187
  * export const load: PageLoad = async ({ params, fetch }) => {
164
188
  * const response = await fetch(route('users.show', { id: params.id }));
@@ -1,13 +1,14 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import colors from "picocolors";
4
- import { createTypeGenerationPlugin } from "./shared/create-type-gen-plugin.js";
4
+ import { readBridgeConfig } from "./shared/bridge-schema.js";
5
+ import { createLitestarTypeGenPlugin } from "./shared/typegen-plugin.js";
5
6
  function resolveConfig(config = {}) {
6
- const runtimeConfigPath = process.env.LITESTAR_VITE_CONFIG_PATH;
7
7
  let hotFile;
8
8
  let proxyMode = "vite";
9
9
  let port;
10
10
  let pythonTypesConfig;
11
+ let hasPythonConfig = false;
11
12
  const envPort = process.env.VITE_PORT;
12
13
  if (envPort) {
13
14
  port = Number.parseInt(envPort, 10);
@@ -16,53 +17,59 @@ function resolveConfig(config = {}) {
16
17
  }
17
18
  }
18
19
  let pythonExecutor;
19
- if (runtimeConfigPath && fs.existsSync(runtimeConfigPath)) {
20
- try {
21
- const json = JSON.parse(fs.readFileSync(runtimeConfigPath, "utf-8"));
22
- const bundleDir = json.bundleDir ?? "public";
23
- const hot = json.hotFile ?? "hot";
24
- hotFile = path.resolve(process.cwd(), bundleDir, hot);
25
- proxyMode = json.proxyMode ?? "vite";
26
- if (json.port !== void 0) {
27
- port = json.port;
28
- }
29
- pythonExecutor = json.executor;
30
- if (json.types) {
31
- pythonTypesConfig = json.types;
32
- }
33
- } catch {
34
- hotFile = void 0;
20
+ const runtime = readBridgeConfig();
21
+ if (runtime) {
22
+ hasPythonConfig = true;
23
+ const hot = runtime.hotFile;
24
+ hotFile = path.isAbsolute(hot) ? hot : path.resolve(process.cwd(), runtime.bundleDir, hot);
25
+ proxyMode = runtime.proxyMode;
26
+ port = runtime.port;
27
+ pythonExecutor = runtime.executor;
28
+ if (runtime.types) {
29
+ pythonTypesConfig = runtime.types;
35
30
  }
36
31
  }
37
32
  let typesConfig = false;
38
33
  if (config.types === true) {
39
34
  typesConfig = {
40
35
  enabled: true,
41
- output: pythonTypesConfig?.output ?? "src/lib/api",
36
+ output: pythonTypesConfig?.output ?? "src/lib/generated",
42
37
  openapiPath: pythonTypesConfig?.openapiPath ?? "openapi.json",
43
38
  routesPath: pythonTypesConfig?.routesPath ?? "routes.json",
39
+ pagePropsPath: pythonTypesConfig?.pagePropsPath ?? "inertia-pages.json",
44
40
  generateZod: pythonTypesConfig?.generateZod ?? false,
45
41
  generateSdk: pythonTypesConfig?.generateSdk ?? true,
42
+ generateRoutes: pythonTypesConfig?.generateRoutes ?? true,
43
+ generatePageProps: pythonTypesConfig?.generatePageProps ?? true,
44
+ globalRoute: pythonTypesConfig?.globalRoute ?? false,
46
45
  debounce: 300
47
46
  };
48
47
  } else if (typeof config.types === "object" && config.types !== null) {
49
48
  typesConfig = {
50
49
  enabled: config.types.enabled ?? true,
51
- output: config.types.output ?? pythonTypesConfig?.output ?? "src/lib/api",
50
+ output: config.types.output ?? pythonTypesConfig?.output ?? "src/lib/generated",
52
51
  openapiPath: config.types.openapiPath ?? pythonTypesConfig?.openapiPath ?? "openapi.json",
53
52
  routesPath: config.types.routesPath ?? pythonTypesConfig?.routesPath ?? "routes.json",
53
+ pagePropsPath: config.types.pagePropsPath ?? pythonTypesConfig?.pagePropsPath ?? "inertia-pages.json",
54
54
  generateZod: config.types.generateZod ?? pythonTypesConfig?.generateZod ?? false,
55
55
  generateSdk: config.types.generateSdk ?? pythonTypesConfig?.generateSdk ?? true,
56
+ generateRoutes: config.types.generateRoutes ?? pythonTypesConfig?.generateRoutes ?? true,
57
+ generatePageProps: config.types.generatePageProps ?? pythonTypesConfig?.generatePageProps ?? true,
58
+ globalRoute: config.types.globalRoute ?? pythonTypesConfig?.globalRoute ?? false,
56
59
  debounce: config.types.debounce ?? 300
57
60
  };
58
61
  } else if (config.types !== false && pythonTypesConfig?.enabled) {
59
62
  typesConfig = {
60
63
  enabled: true,
61
- output: pythonTypesConfig.output ?? "src/lib/api",
64
+ output: pythonTypesConfig.output ?? "src/lib/generated",
62
65
  openapiPath: pythonTypesConfig.openapiPath ?? "openapi.json",
63
66
  routesPath: pythonTypesConfig.routesPath ?? "routes.json",
67
+ pagePropsPath: pythonTypesConfig.pagePropsPath ?? "inertia-pages.json",
64
68
  generateZod: pythonTypesConfig.generateZod ?? false,
65
69
  generateSdk: pythonTypesConfig.generateSdk ?? true,
70
+ generateRoutes: pythonTypesConfig.generateRoutes ?? true,
71
+ generatePageProps: pythonTypesConfig.generatePageProps ?? true,
72
+ globalRoute: pythonTypesConfig.globalRoute ?? false,
66
73
  debounce: 300
67
74
  };
68
75
  }
@@ -74,7 +81,8 @@ function resolveConfig(config = {}) {
74
81
  hotFile,
75
82
  proxyMode,
76
83
  port,
77
- executor: config.executor ?? pythonExecutor
84
+ executor: config.executor ?? pythonExecutor,
85
+ hasPythonConfig
78
86
  };
79
87
  }
80
88
  function litestarSvelteKit(userConfig = {}) {
@@ -152,11 +160,12 @@ function litestarSvelteKit(userConfig = {}) {
152
160
  });
153
161
  if (config.types !== false && config.types.enabled) {
154
162
  plugins.push(
155
- createTypeGenerationPlugin(config.types, {
156
- frameworkName: "litestar-sveltekit",
163
+ createLitestarTypeGenPlugin(config.types, {
157
164
  pluginName: "litestar-sveltekit-types",
158
- clientPlugin: "@hey-api/client-fetch",
159
- executor: config.executor
165
+ frameworkName: "litestar-sveltekit",
166
+ sdkClientPlugin: "@hey-api/client-fetch",
167
+ executor: config.executor,
168
+ hasPythonConfig: config.hasPythonConfig
160
169
  })
161
170
  );
162
171
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "litestar-vite-plugin",
3
- "version": "0.15.0-beta.5",
3
+ "version": "0.15.0-beta.6",
4
4
  "type": "module",
5
5
  "description": "Litestar plugin for Vite.",
6
6
  "keywords": [
@@ -24,8 +24,6 @@
24
24
  "types": "./dist/js/helpers/index.d.ts",
25
25
  "import": "./dist/js/helpers/index.js"
26
26
  },
27
- "./install-hint": "./dist/js/install-hint.js",
28
- "./litestar-meta": "./dist/js/litestar-meta.js",
29
27
  "./inertia-helpers": {
30
28
  "types": "./dist/js/inertia-helpers/index.d.ts",
31
29
  "import": "./dist/js/inertia-helpers/index.js"
@@ -55,11 +53,11 @@
55
53
  "build": "npm run build-plugin && npm run build-helpers && npm run build-inertia-helpers && npm run build-integrations",
56
54
  "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
55
  "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 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",
56
+ "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/bridge-schema.ts src/js/src/shared/debounce.ts src/js/src/shared/format-path.ts src/js/src/shared/logger.ts src/js/src/shared/emit-page-props-types.ts src/js/src/shared/typegen-plugin.ts --platform=node --format=esm --outdir=dist/js/shared",
59
57
  "build-helpers": "rm -rf dist/js/helpers && tsc --project src/js/tsconfig.helpers.json",
60
58
  "build-inertia-helpers": "rm -rf dist/js/inertia-helpers && tsc --project src/js/tsconfig.inertia-helpers.json",
61
59
  "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",
62
- "lint": "eslint --ext .ts ./src/js/src ./src/js/tests",
60
+ "lint": "biome check --vcs-enabled=false src/js/src src/js/tests",
63
61
  "test": "vitest --config ./src/js/vitest.config.ts run"
64
62
  },
65
63
  "devDependencies": {
@@ -1,99 +0,0 @@
1
- /**
2
- * Shared type generation Vite plugin.
3
- *
4
- * Creates a Vite plugin that watches for OpenAPI schema and route metadata changes
5
- * and regenerates TypeScript types using @hey-api/openapi-ts.
6
- * Used by Astro, Nuxt, and SvelteKit integrations.
7
- *
8
- * @module
9
- */
10
- import type { Plugin } from "vite";
11
- /**
12
- * Base configuration for type generation.
13
- */
14
- export interface BaseTypesConfig {
15
- /**
16
- * Enable type generation.
17
- * @default false
18
- */
19
- enabled?: boolean;
20
- /**
21
- * Path to output generated TypeScript types.
22
- */
23
- output?: string;
24
- /**
25
- * Path where the OpenAPI schema is exported by Litestar.
26
- * @default 'openapi.json'
27
- */
28
- openapiPath?: string;
29
- /**
30
- * Path where route metadata is exported by Litestar.
31
- * @default 'routes.json'
32
- */
33
- routesPath?: string;
34
- /**
35
- * Generate Zod schemas in addition to TypeScript types.
36
- * @default false
37
- */
38
- generateZod?: boolean;
39
- /**
40
- * Generate SDK client functions for API calls.
41
- * @default true
42
- */
43
- generateSdk?: boolean;
44
- /**
45
- * Debounce time in milliseconds for type regeneration.
46
- * @default 300
47
- */
48
- debounce?: number;
49
- }
50
- /**
51
- * Required version of types config (all fields defined).
52
- */
53
- export interface RequiredTypesConfig {
54
- enabled: boolean;
55
- output: string;
56
- openapiPath: string;
57
- routesPath: string;
58
- generateZod: boolean;
59
- generateSdk: boolean;
60
- debounce: number;
61
- }
62
- /**
63
- * Options for creating the type generation plugin.
64
- */
65
- export interface TypeGenPluginOptions {
66
- /**
67
- * Framework name for logging (e.g., "litestar-astro", "litestar-nuxt").
68
- */
69
- frameworkName: string;
70
- /**
71
- * Vite plugin name.
72
- */
73
- pluginName: string;
74
- /**
75
- * The @hey-api client plugin to use when generating SDK.
76
- * @default '@hey-api/client-fetch'
77
- */
78
- clientPlugin?: string;
79
- /**
80
- * Optional executor for running npx/bunx/pnpm dlx commands.
81
- */
82
- executor?: string;
83
- }
84
- /**
85
- * Create a Vite plugin for type generation from OpenAPI schemas.
86
- *
87
- * @param typesConfig - The type generation configuration
88
- * @param options - Plugin creation options
89
- * @returns A Vite plugin that watches for schema changes and regenerates types
90
- *
91
- * @example
92
- * ```typescript
93
- * const plugin = createTypeGenerationPlugin(
94
- * { enabled: true, output: 'src/generated' },
95
- * { frameworkName: 'litestar-astro', pluginName: 'litestar-astro-types' }
96
- * )
97
- * ```
98
- */
99
- export declare function createTypeGenerationPlugin(typesConfig: RequiredTypesConfig, options: TypeGenPluginOptions): Plugin;
@@ -1,110 +0,0 @@
1
- import { exec } from "node:child_process";
2
- import * as fs from "node:fs";
3
- import * as path from "node:path";
4
- import { promisify } from "node:util";
5
- import colors from "picocolors";
6
- import { resolveInstallHint, resolvePackageExecutor } from "../install-hint.js";
7
- import { debounce } from "./debounce.js";
8
- import { emitRouteTypes } from "./emit-route-types.js";
9
- const execAsync = promisify(exec);
10
- function createTypeGenerationPlugin(typesConfig, options) {
11
- const { frameworkName, pluginName, clientPlugin = "@hey-api/client-fetch", executor } = options;
12
- let server = null;
13
- let isGenerating = false;
14
- async function runTypeGeneration() {
15
- if (isGenerating) {
16
- return false;
17
- }
18
- isGenerating = true;
19
- const startTime = Date.now();
20
- try {
21
- const openapiPath = path.resolve(process.cwd(), typesConfig.openapiPath);
22
- if (!fs.existsSync(openapiPath)) {
23
- console.log(colors.cyan(`[${frameworkName}]`), colors.yellow("OpenAPI schema not found:"), typesConfig.openapiPath);
24
- return false;
25
- }
26
- console.log(colors.cyan(`[${frameworkName}]`), colors.dim("Generating TypeScript types..."));
27
- const projectRoot = process.cwd();
28
- const candidates = [path.resolve(projectRoot, "openapi-ts.config.ts"), path.resolve(projectRoot, "hey-api.config.ts"), path.resolve(projectRoot, ".hey-api.config.ts")];
29
- const configPath = candidates.find((p) => fs.existsSync(p)) || null;
30
- let args;
31
- if (configPath) {
32
- console.log(colors.cyan(`[${frameworkName}]`), colors.dim("Using config:"), configPath);
33
- args = ["@hey-api/openapi-ts", "--file", configPath];
34
- } else {
35
- args = ["@hey-api/openapi-ts", "-i", typesConfig.openapiPath, "-o", typesConfig.output];
36
- const plugins = ["@hey-api/typescript", "@hey-api/schemas"];
37
- if (typesConfig.generateSdk) {
38
- plugins.push("@hey-api/sdk", clientPlugin);
39
- }
40
- if (typesConfig.generateZod) {
41
- plugins.push("zod");
42
- }
43
- if (plugins.length) {
44
- args.push("--plugins", ...plugins);
45
- }
46
- }
47
- const command = executor ? resolvePackageExecutor(args.join(" "), executor) : `npx ${args.join(" ")}`;
48
- await execAsync(command, { cwd: projectRoot });
49
- const routesPath = path.resolve(process.cwd(), typesConfig.routesPath);
50
- if (fs.existsSync(routesPath)) {
51
- await emitRouteTypes(routesPath, typesConfig.output, { declareGlobalVars: true });
52
- }
53
- const duration = Date.now() - startTime;
54
- console.log(colors.cyan(`[${frameworkName}]`), colors.green("Types generated"), colors.dim(`in ${duration}ms`));
55
- if (server) {
56
- server.ws.send({
57
- type: "custom",
58
- event: "litestar:types-updated",
59
- data: {
60
- output: typesConfig.output,
61
- timestamp: Date.now()
62
- }
63
- });
64
- }
65
- return true;
66
- } catch (error) {
67
- const message = error instanceof Error ? error.message : String(error);
68
- if (message.includes("not found") || message.includes("ENOENT")) {
69
- console.log(colors.cyan(`[${frameworkName}]`), colors.yellow("@hey-api/openapi-ts not installed"), "- run:", resolveInstallHint());
70
- } else {
71
- console.error(colors.cyan(`[${frameworkName}]`), colors.red("Type generation failed:"), message);
72
- }
73
- return false;
74
- } finally {
75
- isGenerating = false;
76
- }
77
- }
78
- const debouncedRunTypeGeneration = debounce(runTypeGeneration, typesConfig.debounce);
79
- return {
80
- name: pluginName,
81
- enforce: "pre",
82
- configureServer(devServer) {
83
- server = devServer;
84
- console.log(colors.cyan(`[${frameworkName}]`), colors.dim("Watching for schema changes:"), colors.yellow(typesConfig.openapiPath));
85
- },
86
- async buildStart() {
87
- if (typesConfig.enabled) {
88
- const openapiPath = path.resolve(process.cwd(), typesConfig.openapiPath);
89
- if (fs.existsSync(openapiPath)) {
90
- await runTypeGeneration();
91
- }
92
- }
93
- },
94
- handleHotUpdate({ file }) {
95
- if (!typesConfig.enabled) {
96
- return;
97
- }
98
- const relativePath = path.relative(process.cwd(), file);
99
- const openapiPath = typesConfig.openapiPath.replace(/^\.\//, "");
100
- const routesPath = typesConfig.routesPath.replace(/^\.\//, "");
101
- if (relativePath === openapiPath || relativePath === routesPath || file.endsWith(openapiPath) || file.endsWith(routesPath)) {
102
- console.log(colors.cyan(`[${frameworkName}]`), colors.dim("Schema changed:"), colors.yellow(relativePath));
103
- debouncedRunTypeGeneration();
104
- }
105
- }
106
- };
107
- }
108
- export {
109
- createTypeGenerationPlugin
110
- };
@@ -1,41 +0,0 @@
1
- /**
2
- * Shared route type generation utility.
3
- *
4
- * Generates TypeScript types from routes.json metadata for type-safe routing.
5
- * Used by the main litestar plugin and framework integrations (Astro, Nuxt, SvelteKit).
6
- *
7
- * @module
8
- */
9
- /**
10
- * Options for emitRouteTypes.
11
- */
12
- export interface EmitRouteTypesOptions {
13
- /**
14
- * Whether to register route() on window for global access.
15
- * Only used by the main plugin.
16
- * @default false
17
- */
18
- globalRoute?: boolean;
19
- /**
20
- * Whether to declare global `var routes` and `var serverRoutes`.
21
- * Used by framework integrations for SSR compatibility.
22
- * @default false
23
- */
24
- declareGlobalVars?: boolean;
25
- }
26
- /**
27
- * Generate TypeScript route types from routes.json metadata.
28
- *
29
- * Creates a routes.ts file with:
30
- * - routesMeta: full route metadata
31
- * - routes: name -> uri map
32
- * - serverRoutes: alias of routes
33
- * - route(): type-safe URL generator
34
- * - hasRoute(): type guard
35
- * - CSRF helpers re-exported from litestar-vite-plugin/helpers
36
- *
37
- * @param routesPath - Path to routes.json file
38
- * @param outputDir - Output directory for routes.ts
39
- * @param options - Generation options
40
- */
41
- export declare function emitRouteTypes(routesPath: string, outputDir: string, options?: EmitRouteTypesOptions): Promise<void>;