litestar-vite-plugin 0.15.0-alpha.3 → 0.15.0-alpha.5
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/README.md +56 -42
- package/dist/js/astro.d.ts +6 -0
- package/dist/js/astro.js +42 -7
- package/dist/js/helpers/htmx.d.ts +68 -0
- package/dist/js/helpers/htmx.js +494 -0
- package/dist/js/helpers/index.d.ts +13 -5
- package/dist/js/helpers/index.js +14 -6
- package/dist/js/index.d.ts +35 -13
- package/dist/js/index.js +233 -60
- package/dist/js/inertia-helpers/index.d.ts +6 -1
- package/dist/js/inertia-helpers/index.js +7 -4
- package/dist/js/litestar-meta.js +20 -4
- package/dist/js/nuxt.d.ts +6 -0
- package/dist/js/nuxt.js +39 -4
- package/dist/js/sveltekit.d.ts +6 -0
- package/dist/js/sveltekit.js +34 -4
- package/package.json +18 -11
- package/tools/clean.js +1 -1
- package/dist/js/helpers/routes.d.ts +0 -159
- package/dist/js/helpers/routes.js +0 -302
package/dist/js/index.js
CHANGED
|
@@ -12,12 +12,13 @@ import { checkBackendAvailability, loadLitestarMeta } from "./litestar-meta.js";
|
|
|
12
12
|
import { debounce } from "./shared/debounce.js";
|
|
13
13
|
const execAsync = promisify(exec);
|
|
14
14
|
let exitHandlersBound = false;
|
|
15
|
+
let warnedMissingRuntimeConfig = false;
|
|
15
16
|
const refreshPaths = ["src/**", "resources/**", "assets/**"].filter((path2) => fs.existsSync(path2.replace(/\*\*$/, "")));
|
|
16
17
|
function litestar(config) {
|
|
17
18
|
const pluginConfig = resolvePluginConfig(config);
|
|
18
19
|
const plugins = [resolveLitestarPlugin(pluginConfig), ...resolveFullReloadConfig(pluginConfig)];
|
|
19
20
|
if (pluginConfig.types !== false && pluginConfig.types.enabled) {
|
|
20
|
-
plugins.push(resolveTypeGenerationPlugin(pluginConfig.types, pluginConfig.executor));
|
|
21
|
+
plugins.push(resolveTypeGenerationPlugin(pluginConfig.types, pluginConfig.executor, pluginConfig.hasPythonConfig));
|
|
21
22
|
}
|
|
22
23
|
return plugins;
|
|
23
24
|
}
|
|
@@ -30,8 +31,8 @@ async function findIndexHtmlPath(server, pluginConfig) {
|
|
|
30
31
|
path.join(root, "index.html"),
|
|
31
32
|
path.join(root, pluginConfig.resourceDirectory.replace(/^\//, ""), "index.html"),
|
|
32
33
|
// Ensure resourceDirectory path is relative to root
|
|
33
|
-
path.join(root, "
|
|
34
|
-
|
|
34
|
+
path.join(root, pluginConfig.publicDir.replace(/^\//, ""), "index.html"),
|
|
35
|
+
path.join(root, pluginConfig.bundleDirectory.replace(/^\//, ""), "index.html")
|
|
35
36
|
];
|
|
36
37
|
for (const indexPath of possiblePaths) {
|
|
37
38
|
try {
|
|
@@ -42,7 +43,7 @@ async function findIndexHtmlPath(server, pluginConfig) {
|
|
|
42
43
|
}
|
|
43
44
|
return null;
|
|
44
45
|
}
|
|
45
|
-
function normalizeAppUrl(appUrl,
|
|
46
|
+
function normalizeAppUrl(appUrl, _fallbackPort) {
|
|
46
47
|
if (!appUrl || appUrl === "__litestar_app_url_missing__") {
|
|
47
48
|
return { url: null, note: "APP_URL missing" };
|
|
48
49
|
}
|
|
@@ -59,6 +60,7 @@ function resolveLitestarPlugin(pluginConfig) {
|
|
|
59
60
|
let resolvedConfig;
|
|
60
61
|
let userConfig;
|
|
61
62
|
let litestarMeta = {};
|
|
63
|
+
let shuttingDown = false;
|
|
62
64
|
const pythonDefaults = loadPythonDefaults();
|
|
63
65
|
const proxyMode = pythonDefaults?.proxyMode ?? "vite_proxy";
|
|
64
66
|
const defaultAliases = {
|
|
@@ -73,11 +75,39 @@ function resolveLitestarPlugin(pluginConfig) {
|
|
|
73
75
|
const env = loadEnv(mode, userConfig.envDir || process.cwd(), "");
|
|
74
76
|
const assetUrl = normalizeAssetUrl(env.ASSET_URL || pluginConfig.assetUrl);
|
|
75
77
|
const serverConfig = command === "serve" ? resolveDevelopmentEnvironmentServerConfig(pluginConfig.detectTls) ?? resolveEnvironmentServerConfig(env) : void 0;
|
|
78
|
+
const withProxyErrorSilencer = (proxyConfig) => {
|
|
79
|
+
if (!proxyConfig) return void 0;
|
|
80
|
+
return Object.fromEntries(
|
|
81
|
+
Object.entries(proxyConfig).map(([key, value]) => {
|
|
82
|
+
if (typeof value !== "object" || value === null) {
|
|
83
|
+
return [key, value];
|
|
84
|
+
}
|
|
85
|
+
const existingConfigure = value.configure;
|
|
86
|
+
return [
|
|
87
|
+
key,
|
|
88
|
+
{
|
|
89
|
+
...value,
|
|
90
|
+
configure(proxy, opts) {
|
|
91
|
+
proxy.on("error", (err) => {
|
|
92
|
+
const msg = String(err?.message ?? "");
|
|
93
|
+
if (shuttingDown || msg.includes("ECONNREFUSED") || msg.includes("ECONNRESET") || msg.includes("socket hang up")) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
if (typeof existingConfigure === "function") {
|
|
98
|
+
existingConfigure(proxy, opts);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
];
|
|
103
|
+
})
|
|
104
|
+
);
|
|
105
|
+
};
|
|
76
106
|
const devBase = pluginConfig.assetUrl.startsWith("/") ? pluginConfig.assetUrl : pluginConfig.assetUrl.replace(/\/+$/, "");
|
|
77
|
-
ensureCommandShouldRunInEnvironment(command, env);
|
|
107
|
+
ensureCommandShouldRunInEnvironment(command, env, mode);
|
|
78
108
|
return {
|
|
79
109
|
base: userConfig.base ?? (command === "build" ? resolveBase(pluginConfig, assetUrl) : devBase),
|
|
80
|
-
publicDir: userConfig.publicDir ?? false,
|
|
110
|
+
publicDir: userConfig.publicDir ?? pluginConfig.publicDir ?? false,
|
|
81
111
|
clearScreen: false,
|
|
82
112
|
build: {
|
|
83
113
|
manifest: userConfig.build?.manifest ?? (ssr ? false : "manifest.json"),
|
|
@@ -101,16 +131,18 @@ function resolveLitestarPlugin(pluginConfig) {
|
|
|
101
131
|
// Auto-configure proxy to forward API requests to Litestar backend
|
|
102
132
|
// This allows the app to work when accessing Vite directly (not through Litestar proxy)
|
|
103
133
|
// Only proxies /api and /schema routes - everything else is handled by Vite
|
|
104
|
-
proxy:
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
134
|
+
proxy: withProxyErrorSilencer(
|
|
135
|
+
userConfig.server?.proxy ?? (env.APP_URL ? {
|
|
136
|
+
"/api": {
|
|
137
|
+
target: env.APP_URL,
|
|
138
|
+
changeOrigin: true
|
|
139
|
+
},
|
|
140
|
+
"/schema": {
|
|
141
|
+
target: env.APP_URL,
|
|
142
|
+
changeOrigin: true
|
|
143
|
+
}
|
|
144
|
+
} : void 0)
|
|
145
|
+
),
|
|
114
146
|
// Always respect VITE_PORT when set by Python (regardless of VITE_ALLOW_REMOTE)
|
|
115
147
|
...process.env.VITE_PORT ? {
|
|
116
148
|
port: userConfig.server?.port ?? Number.parseInt(process.env.VITE_PORT),
|
|
@@ -157,10 +189,23 @@ function resolveLitestarPlugin(pluginConfig) {
|
|
|
157
189
|
base: `${resolvedConfig.base}/`
|
|
158
190
|
};
|
|
159
191
|
}
|
|
192
|
+
if (resolvedConfig.command === "serve" && !pluginConfig.hasPythonConfig && !warnedMissingRuntimeConfig) {
|
|
193
|
+
warnedMissingRuntimeConfig = true;
|
|
194
|
+
if (typeof resolvedConfig.logger?.warn === "function") {
|
|
195
|
+
resolvedConfig.logger.warn(formatMissingConfigWarning());
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
const resourceDir = path.resolve(resolvedConfig.root, pluginConfig.resourceDirectory);
|
|
199
|
+
if (!fs.existsSync(resourceDir) && typeof resolvedConfig.logger?.warn === "function") {
|
|
200
|
+
resolvedConfig.logger.warn(
|
|
201
|
+
`${colors.cyan("litestar-vite")} ${colors.yellow("Resource directory not found:")} ${resourceDir}
|
|
202
|
+
Expected directory: ${colors.dim(pluginConfig.resourceDirectory)}`
|
|
203
|
+
);
|
|
204
|
+
}
|
|
160
205
|
const hint = pluginConfig.types !== false ? pluginConfig.types.routesPath : void 0;
|
|
161
206
|
litestarMeta = await loadLitestarMeta(resolvedConfig, hint);
|
|
162
207
|
},
|
|
163
|
-
transform(code,
|
|
208
|
+
transform(code, _id) {
|
|
164
209
|
if (resolvedConfig.command === "serve" && code.includes("__litestar_vite_placeholder__")) {
|
|
165
210
|
const transformedCode = code.replace(/__litestar_vite_placeholder__/g, viteDevServerUrl);
|
|
166
211
|
return pluginConfig.transformOnServe(transformedCode, viteDevServerUrl);
|
|
@@ -249,9 +294,18 @@ function resolveLitestarPlugin(pluginConfig) {
|
|
|
249
294
|
}
|
|
250
295
|
};
|
|
251
296
|
process.on("exit", clean);
|
|
252
|
-
process.on("SIGINT", () =>
|
|
253
|
-
|
|
254
|
-
|
|
297
|
+
process.on("SIGINT", () => {
|
|
298
|
+
shuttingDown = true;
|
|
299
|
+
process.exit();
|
|
300
|
+
});
|
|
301
|
+
process.on("SIGTERM", () => {
|
|
302
|
+
shuttingDown = true;
|
|
303
|
+
process.exit();
|
|
304
|
+
});
|
|
305
|
+
process.on("SIGHUP", () => {
|
|
306
|
+
shuttingDown = true;
|
|
307
|
+
process.exit();
|
|
308
|
+
});
|
|
255
309
|
exitHandlersBound = true;
|
|
256
310
|
}
|
|
257
311
|
server.middlewares.use(async (req, res, next) => {
|
|
@@ -290,11 +344,14 @@ function resolveLitestarPlugin(pluginConfig) {
|
|
|
290
344
|
}
|
|
291
345
|
};
|
|
292
346
|
}
|
|
293
|
-
function ensureCommandShouldRunInEnvironment(command, env) {
|
|
347
|
+
function ensureCommandShouldRunInEnvironment(command, env, mode) {
|
|
294
348
|
const allowedDevModes = ["dev", "development", "local", "docker"];
|
|
295
349
|
if (command === "build" || env.LITESTAR_BYPASS_ENV_CHECK === "1") {
|
|
296
350
|
return;
|
|
297
351
|
}
|
|
352
|
+
if (mode === "test" || env.VITEST || env.VITE_TEST || env.NODE_ENV === "test") {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
298
355
|
if (typeof env.LITESTAR_MODE !== "undefined" && !allowedDevModes.includes(env.LITESTAR_MODE)) {
|
|
299
356
|
throw Error("Run the Vite dev server only in development. Set LITESTAR_MODE=dev/development/local/docker or set LITESTAR_BYPASS_ENV_CHECK=1 to skip this check.");
|
|
300
357
|
}
|
|
@@ -304,7 +361,7 @@ function ensureCommandShouldRunInEnvironment(command, env) {
|
|
|
304
361
|
);
|
|
305
362
|
}
|
|
306
363
|
}
|
|
307
|
-
function
|
|
364
|
+
function _pluginVersion() {
|
|
308
365
|
try {
|
|
309
366
|
return JSON.parse(fs.readFileSync(path.join(dirname(), "../package.json")).toString())?.version;
|
|
310
367
|
} catch {
|
|
@@ -312,11 +369,19 @@ function pluginVersion() {
|
|
|
312
369
|
}
|
|
313
370
|
}
|
|
314
371
|
function loadPythonDefaults() {
|
|
315
|
-
const
|
|
372
|
+
const isTestEnv = Boolean(process.env.VITEST || process.env.VITE_TEST || process.env.NODE_ENV === "test");
|
|
373
|
+
let configPath = process.env.LITESTAR_VITE_CONFIG_PATH;
|
|
316
374
|
if (!configPath) {
|
|
317
|
-
|
|
375
|
+
const defaultPath = path.join(process.cwd(), ".litestar.json");
|
|
376
|
+
if (fs.existsSync(defaultPath)) {
|
|
377
|
+
configPath = defaultPath;
|
|
378
|
+
} else {
|
|
379
|
+
warnMissingRuntimeConfig("env", isTestEnv);
|
|
380
|
+
return null;
|
|
381
|
+
}
|
|
318
382
|
}
|
|
319
383
|
if (!fs.existsSync(configPath)) {
|
|
384
|
+
warnMissingRuntimeConfig("file", isTestEnv);
|
|
320
385
|
return null;
|
|
321
386
|
}
|
|
322
387
|
try {
|
|
@@ -326,6 +391,48 @@ function loadPythonDefaults() {
|
|
|
326
391
|
return null;
|
|
327
392
|
}
|
|
328
393
|
}
|
|
394
|
+
function formatMissingConfigWarning() {
|
|
395
|
+
const y = colors.yellow;
|
|
396
|
+
const c = colors.cyan;
|
|
397
|
+
const d = colors.dim;
|
|
398
|
+
const b = colors.bold;
|
|
399
|
+
const lines = [
|
|
400
|
+
"",
|
|
401
|
+
y("\u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E"),
|
|
402
|
+
`${y("\u2502")} ${y("\u2502")}`,
|
|
403
|
+
`${y("\u2502")} ${y("\u26A0")} ${b("Litestar backend configuration not found")} ${y("\u2502")}`,
|
|
404
|
+
`${y("\u2502")} ${y("\u2502")}`,
|
|
405
|
+
`${y("\u2502")} The plugin couldn't find ${c(".litestar.json")} which is normally ${y("\u2502")}`,
|
|
406
|
+
`${y("\u2502")} created when the Litestar backend starts. ${y("\u2502")}`,
|
|
407
|
+
`${y("\u2502")} ${y("\u2502")}`,
|
|
408
|
+
`${y("\u2502")} ${b("Quick fix")} - run one of these commands first: ${y("\u2502")}`,
|
|
409
|
+
`${y("\u2502")} ${y("\u2502")}`,
|
|
410
|
+
`${y("\u2502")} ${c("$ litestar run")} ${d("# Start backend only")} ${y("\u2502")}`,
|
|
411
|
+
`${y("\u2502")} ${c("$ litestar assets serve")} ${d("# Start backend + Vite together")} ${y("\u2502")}`,
|
|
412
|
+
`${y("\u2502")} ${y("\u2502")}`,
|
|
413
|
+
`${y("\u2502")} Or manually configure the plugin in ${c("vite.config.ts")}: ${y("\u2502")}`,
|
|
414
|
+
`${y("\u2502")} ${y("\u2502")}`,
|
|
415
|
+
`${y("\u2502")} ${d("litestar({")} ${y("\u2502")}`,
|
|
416
|
+
`${y("\u2502")} ${d(' input: ["src/main.tsx"],')} ${y("\u2502")}`,
|
|
417
|
+
`${y("\u2502")} ${d(' assetUrl: "/static/",')} ${y("\u2502")}`,
|
|
418
|
+
`${y("\u2502")} ${d(' bundleDirectory: "public",')} ${y("\u2502")}`,
|
|
419
|
+
`${y("\u2502")} ${d(" types: false,")} ${y("\u2502")}`,
|
|
420
|
+
`${y("\u2502")} ${d("})")} ${y("\u2502")}`,
|
|
421
|
+
`${y("\u2502")} ${y("\u2502")}`,
|
|
422
|
+
`${y("\u2502")} Docs: ${c("https://docs.litestar.dev/vite/getting-started")} ${y("\u2502")}`,
|
|
423
|
+
`${y("\u2502")} ${y("\u2502")}`,
|
|
424
|
+
y("\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F"),
|
|
425
|
+
"",
|
|
426
|
+
d("Continuing with defaults... some features may not work."),
|
|
427
|
+
""
|
|
428
|
+
];
|
|
429
|
+
return lines.join("\n");
|
|
430
|
+
}
|
|
431
|
+
function warnMissingRuntimeConfig(_reason, suppress) {
|
|
432
|
+
if (warnedMissingRuntimeConfig || suppress) return;
|
|
433
|
+
warnedMissingRuntimeConfig = true;
|
|
434
|
+
console.warn(formatMissingConfigWarning());
|
|
435
|
+
}
|
|
329
436
|
function resolvePluginConfig(config) {
|
|
330
437
|
if (typeof config === "undefined") {
|
|
331
438
|
throw new Error("litestar-vite-plugin: missing configuration.");
|
|
@@ -347,6 +454,12 @@ function resolvePluginConfig(config) {
|
|
|
347
454
|
throw new Error("litestar-vite-plugin: bundleDirectory must be a subdirectory. E.g. 'public'.");
|
|
348
455
|
}
|
|
349
456
|
}
|
|
457
|
+
if (typeof resolvedConfig.publicDir === "string") {
|
|
458
|
+
resolvedConfig.publicDir = resolvedConfig.publicDir.trim().replace(/^\/+/, "").replace(/\/+$/, "");
|
|
459
|
+
if (resolvedConfig.publicDir === "") {
|
|
460
|
+
throw new Error("litestar-vite-plugin: publicDir must be a subdirectory. E.g. 'public'.");
|
|
461
|
+
}
|
|
462
|
+
}
|
|
350
463
|
if (typeof resolvedConfig.ssrOutputDirectory === "string") {
|
|
351
464
|
resolvedConfig.ssrOutputDirectory = resolvedConfig.ssrOutputDirectory.trim().replace(/^\/+/, "").replace(/\/+$/, "");
|
|
352
465
|
}
|
|
@@ -354,17 +467,8 @@ function resolvePluginConfig(config) {
|
|
|
354
467
|
resolvedConfig.refresh = [{ paths: refreshPaths }];
|
|
355
468
|
}
|
|
356
469
|
let typesConfig = false;
|
|
357
|
-
if (
|
|
358
|
-
|
|
359
|
-
enabled: pythonDefaults.types.enabled,
|
|
360
|
-
output: pythonDefaults.types.output,
|
|
361
|
-
openapiPath: pythonDefaults.types.openapiPath,
|
|
362
|
-
routesPath: pythonDefaults.types.routesPath,
|
|
363
|
-
generateZod: pythonDefaults.types.generateZod,
|
|
364
|
-
generateSdk: pythonDefaults.types.generateSdk,
|
|
365
|
-
debounce: 300
|
|
366
|
-
};
|
|
367
|
-
} else if (resolvedConfig.types === true || typeof resolvedConfig.types === "undefined") {
|
|
470
|
+
if (resolvedConfig.types === false) {
|
|
471
|
+
} else if (resolvedConfig.types === true) {
|
|
368
472
|
typesConfig = {
|
|
369
473
|
enabled: true,
|
|
370
474
|
output: "src/generated/types",
|
|
@@ -374,9 +478,21 @@ function resolvePluginConfig(config) {
|
|
|
374
478
|
generateSdk: false,
|
|
375
479
|
debounce: 300
|
|
376
480
|
};
|
|
481
|
+
} else if (resolvedConfig.types === "auto" || typeof resolvedConfig.types === "undefined") {
|
|
482
|
+
if (pythonDefaults?.types) {
|
|
483
|
+
typesConfig = {
|
|
484
|
+
enabled: pythonDefaults.types.enabled,
|
|
485
|
+
output: pythonDefaults.types.output,
|
|
486
|
+
openapiPath: pythonDefaults.types.openapiPath,
|
|
487
|
+
routesPath: pythonDefaults.types.routesPath,
|
|
488
|
+
generateZod: pythonDefaults.types.generateZod,
|
|
489
|
+
generateSdk: pythonDefaults.types.generateSdk,
|
|
490
|
+
debounce: 300
|
|
491
|
+
};
|
|
492
|
+
}
|
|
377
493
|
} else if (typeof resolvedConfig.types === "object" && resolvedConfig.types !== null) {
|
|
378
|
-
const userProvidedOpenapi = Object.
|
|
379
|
-
const userProvidedRoutes = Object.
|
|
494
|
+
const userProvidedOpenapi = Object.hasOwn(resolvedConfig.types, "openapiPath");
|
|
495
|
+
const userProvidedRoutes = Object.hasOwn(resolvedConfig.types, "routesPath");
|
|
380
496
|
typesConfig = {
|
|
381
497
|
enabled: resolvedConfig.types.enabled ?? true,
|
|
382
498
|
output: resolvedConfig.types.output ?? "src/generated/types",
|
|
@@ -398,6 +514,7 @@ function resolvePluginConfig(config) {
|
|
|
398
514
|
assetUrl: normalizeAssetUrl(resolvedConfig.assetUrl ?? pythonDefaults?.assetUrl ?? "/static/"),
|
|
399
515
|
resourceDirectory: resolvedConfig.resourceDirectory ?? pythonDefaults?.resourceDir ?? "resources",
|
|
400
516
|
bundleDirectory: resolvedConfig.bundleDirectory ?? pythonDefaults?.bundleDir ?? "public",
|
|
517
|
+
publicDir: resolvedConfig.publicDir ?? pythonDefaults?.publicDir ?? "public",
|
|
401
518
|
ssr: resolvedConfig.ssr ?? resolvedConfig.input,
|
|
402
519
|
ssrOutputDirectory: resolvedConfig.ssrOutputDirectory ?? pythonDefaults?.ssrOutDir ?? path.join(resolvedConfig.resourceDirectory ?? pythonDefaults?.resourceDir ?? "resources", "bootstrap/ssr"),
|
|
403
520
|
refresh: resolvedConfig.refresh ?? false,
|
|
@@ -406,10 +523,11 @@ function resolvePluginConfig(config) {
|
|
|
406
523
|
autoDetectIndex: resolvedConfig.autoDetectIndex ?? true,
|
|
407
524
|
transformOnServe: resolvedConfig.transformOnServe ?? ((code) => code),
|
|
408
525
|
types: typesConfig,
|
|
409
|
-
executor: resolvedConfig.executor ?? pythonDefaults?.executor
|
|
526
|
+
executor: resolvedConfig.executor ?? pythonDefaults?.executor,
|
|
527
|
+
hasPythonConfig: pythonDefaults !== null
|
|
410
528
|
};
|
|
411
529
|
}
|
|
412
|
-
function resolveBase(
|
|
530
|
+
function resolveBase(_config, assetUrl) {
|
|
413
531
|
if (process.env.NODE_ENV === "development") {
|
|
414
532
|
return assetUrl;
|
|
415
533
|
}
|
|
@@ -557,12 +675,9 @@ declare global {
|
|
|
557
675
|
/**
|
|
558
676
|
* Simple route map (name -> uri) for legacy consumers.
|
|
559
677
|
*/
|
|
560
|
-
routes?:
|
|
561
|
-
serverRoutes?:
|
|
678
|
+
routes?: Record<string, string>
|
|
679
|
+
serverRoutes?: Record<string, string>
|
|
562
680
|
}
|
|
563
|
-
// eslint-disable-next-line no-var
|
|
564
|
-
var routes: typeof routes | undefined
|
|
565
|
-
var serverRoutes: typeof serverRoutes | undefined
|
|
566
681
|
}
|
|
567
682
|
|
|
568
683
|
// Re-export helper functions from litestar-vite-plugin
|
|
@@ -571,12 +686,13 @@ export { getCsrfToken, csrfHeaders, csrfFetch } from "litestar-vite-plugin/helpe
|
|
|
571
686
|
`;
|
|
572
687
|
await fs.promises.writeFile(outFile, `${banner}${body}`, "utf-8");
|
|
573
688
|
}
|
|
574
|
-
function resolveTypeGenerationPlugin(typesConfig, executor) {
|
|
689
|
+
function resolveTypeGenerationPlugin(typesConfig, executor, hasPythonConfig) {
|
|
575
690
|
let lastTypesHash = null;
|
|
576
691
|
let lastRoutesHash = null;
|
|
577
692
|
let server = null;
|
|
578
693
|
let isGenerating = false;
|
|
579
694
|
let resolvedConfig = null;
|
|
695
|
+
let chosenConfigPath = null;
|
|
580
696
|
async function runTypeGeneration() {
|
|
581
697
|
if (isGenerating) {
|
|
582
698
|
return false;
|
|
@@ -584,26 +700,47 @@ function resolveTypeGenerationPlugin(typesConfig, executor) {
|
|
|
584
700
|
isGenerating = true;
|
|
585
701
|
const startTime = Date.now();
|
|
586
702
|
try {
|
|
587
|
-
const
|
|
588
|
-
const
|
|
703
|
+
const projectRoot = resolvedConfig?.root ?? process.cwd();
|
|
704
|
+
const openapiPath = path.resolve(projectRoot, typesConfig.openapiPath);
|
|
705
|
+
const routesPath = path.resolve(projectRoot, typesConfig.routesPath);
|
|
589
706
|
let generated = false;
|
|
590
|
-
|
|
707
|
+
const candidates = [path.resolve(projectRoot, "openapi-ts.config.ts"), path.resolve(projectRoot, "hey-api.config.ts"), path.resolve(projectRoot, ".hey-api.config.ts")];
|
|
708
|
+
const configPath = candidates.find((p) => fs.existsSync(p)) || null;
|
|
709
|
+
chosenConfigPath = configPath;
|
|
710
|
+
const shouldRunOpenApiTs = configPath || typesConfig.generateSdk;
|
|
711
|
+
if (fs.existsSync(openapiPath) && shouldRunOpenApiTs) {
|
|
712
|
+
resolvedConfig?.logger.info(`${colors.cyan("litestar-vite")} ${colors.dim("generating TypeScript types...")}`);
|
|
591
713
|
if (resolvedConfig) {
|
|
592
|
-
resolvedConfig.logger.info(`${colors.cyan("litestar-vite")} ${colors.dim("
|
|
714
|
+
resolvedConfig.logger.info(`${colors.cyan("litestar-vite")} ${colors.dim("openapi-ts config: ")}${configPath ?? "<built-in defaults>"}`);
|
|
593
715
|
}
|
|
594
|
-
const
|
|
595
|
-
|
|
596
|
-
|
|
716
|
+
const sdkOutput = path.join(typesConfig.output, "api");
|
|
717
|
+
let args;
|
|
718
|
+
if (configPath) {
|
|
719
|
+
args = ["@hey-api/openapi-ts", "--file", configPath];
|
|
720
|
+
} else {
|
|
721
|
+
args = ["@hey-api/openapi-ts", "-i", typesConfig.openapiPath, "-o", sdkOutput];
|
|
722
|
+
const plugins = ["@hey-api/typescript", "@hey-api/schemas"];
|
|
723
|
+
if (typesConfig.generateSdk) {
|
|
724
|
+
plugins.push("@hey-api/sdk", "@hey-api/client-axios");
|
|
725
|
+
}
|
|
726
|
+
if (typesConfig.generateZod) {
|
|
727
|
+
plugins.push("zod");
|
|
728
|
+
}
|
|
729
|
+
if (plugins.length) {
|
|
730
|
+
args.push("--plugins", ...plugins);
|
|
731
|
+
}
|
|
597
732
|
}
|
|
598
|
-
if (typesConfig.
|
|
599
|
-
|
|
733
|
+
if (typesConfig.generateZod) {
|
|
734
|
+
try {
|
|
735
|
+
require.resolve("zod", { paths: [process.cwd()] });
|
|
736
|
+
} catch {
|
|
737
|
+
resolvedConfig?.logger.warn(`${colors.cyan("litestar-vite")} ${colors.yellow("zod not installed")} - run: ${resolveInstallHint()} zod`);
|
|
738
|
+
}
|
|
600
739
|
}
|
|
601
740
|
await execAsync(resolvePackageExecutor(args.join(" "), executor), {
|
|
602
|
-
cwd:
|
|
741
|
+
cwd: projectRoot
|
|
603
742
|
});
|
|
604
743
|
generated = true;
|
|
605
|
-
} else if (resolvedConfig) {
|
|
606
|
-
resolvedConfig.logger.warn(`${colors.cyan("litestar-vite")} ${colors.yellow("OpenAPI schema not found:")} ${typesConfig.openapiPath}`);
|
|
607
744
|
}
|
|
608
745
|
if (fs.existsSync(routesPath)) {
|
|
609
746
|
await emitRouteTypes(routesPath, typesConfig.output);
|
|
@@ -628,7 +765,10 @@ function resolveTypeGenerationPlugin(typesConfig, executor) {
|
|
|
628
765
|
if (resolvedConfig) {
|
|
629
766
|
const message = error instanceof Error ? error.message : String(error);
|
|
630
767
|
if (message.includes("not found") || message.includes("ENOENT")) {
|
|
631
|
-
|
|
768
|
+
const zodHint = typesConfig.generateZod ? " zod" : "";
|
|
769
|
+
resolvedConfig.logger.warn(
|
|
770
|
+
`${colors.cyan("litestar-vite")} ${colors.yellow("@hey-api/openapi-ts not installed")} - run: ${resolveInstallHint()} -D @hey-api/openapi-ts${zodHint}`
|
|
771
|
+
);
|
|
632
772
|
} else {
|
|
633
773
|
resolvedConfig.logger.error(`${colors.cyan("litestar-vite")} ${colors.red("type generation failed:")} ${message}`);
|
|
634
774
|
}
|
|
@@ -648,14 +788,47 @@ function resolveTypeGenerationPlugin(typesConfig, executor) {
|
|
|
648
788
|
configureServer(devServer) {
|
|
649
789
|
server = devServer;
|
|
650
790
|
if (typesConfig.enabled) {
|
|
651
|
-
|
|
791
|
+
const root = resolvedConfig?.root ?? process.cwd();
|
|
792
|
+
const openapiAbs = path.resolve(root, typesConfig.openapiPath);
|
|
793
|
+
const routesAbs = path.resolve(root, typesConfig.routesPath);
|
|
794
|
+
resolvedConfig?.logger.info(`${colors.cyan("litestar-vite")} ${colors.dim("watching schema/routes:")} ${colors.yellow(openapiAbs)}, ${colors.yellow(routesAbs)}`);
|
|
795
|
+
if (chosenConfigPath) {
|
|
796
|
+
resolvedConfig?.logger.info(`${colors.cyan("litestar-vite")} ${colors.dim("openapi-ts config:")} ${colors.yellow(chosenConfigPath)}`);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
},
|
|
800
|
+
async buildStart() {
|
|
801
|
+
if (typesConfig.enabled && !hasPythonConfig) {
|
|
802
|
+
const projectRoot = resolvedConfig?.root ?? process.cwd();
|
|
803
|
+
const openapiPath = path.resolve(projectRoot, typesConfig.openapiPath);
|
|
804
|
+
if (!fs.existsSync(openapiPath)) {
|
|
805
|
+
this.warn(
|
|
806
|
+
`Type generation is enabled but .litestar.json was not found.
|
|
807
|
+
The Litestar backend generates this file on startup.
|
|
808
|
+
|
|
809
|
+
Solutions:
|
|
810
|
+
1. Start the backend first: ${colors.cyan("litestar run")}
|
|
811
|
+
2. Use integrated dev: ${colors.cyan("litestar assets serve")}
|
|
812
|
+
3. Disable types: ${colors.cyan("litestar({ input: [...], types: false })")}
|
|
813
|
+
`
|
|
814
|
+
);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
if (typesConfig.enabled) {
|
|
818
|
+
const projectRoot = resolvedConfig?.root ?? process.cwd();
|
|
819
|
+
const openapiPath = path.resolve(projectRoot, typesConfig.openapiPath);
|
|
820
|
+
const routesPath = path.resolve(projectRoot, typesConfig.routesPath);
|
|
821
|
+
if (fs.existsSync(openapiPath) || fs.existsSync(routesPath)) {
|
|
822
|
+
await runTypeGeneration();
|
|
823
|
+
}
|
|
652
824
|
}
|
|
653
825
|
},
|
|
654
826
|
async handleHotUpdate({ file }) {
|
|
655
827
|
if (!typesConfig.enabled) {
|
|
656
828
|
return;
|
|
657
829
|
}
|
|
658
|
-
const
|
|
830
|
+
const root = resolvedConfig?.root ?? process.cwd();
|
|
831
|
+
const relativePath = path.relative(root, file);
|
|
659
832
|
const openapiPath = typesConfig.openapiPath.replace(/^\.\//, "");
|
|
660
833
|
const routesPath = typesConfig.routesPath.replace(/^\.\//, "");
|
|
661
834
|
if (relativePath === openapiPath || relativePath === routesPath || file.endsWith(openapiPath) || file.endsWith(routesPath)) {
|
|
@@ -4,9 +4,14 @@
|
|
|
4
4
|
* This module re-exports common helpers from litestar-vite-plugin/helpers
|
|
5
5
|
* and adds Inertia-specific utilities.
|
|
6
6
|
*
|
|
7
|
+
* For type-safe routing, import from your generated routes file:
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { route, routes, type RouteName } from '@/generated/routes'
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
7
12
|
* @module
|
|
8
13
|
*/
|
|
9
|
-
export {
|
|
14
|
+
export { csrfFetch, csrfHeaders, getCsrfToken, } from "litestar-vite-plugin/helpers";
|
|
10
15
|
/**
|
|
11
16
|
* Unwrap page props that may have content nested under "content" key.
|
|
12
17
|
*
|
|
@@ -4,15 +4,18 @@
|
|
|
4
4
|
* This module re-exports common helpers from litestar-vite-plugin/helpers
|
|
5
5
|
* and adds Inertia-specific utilities.
|
|
6
6
|
*
|
|
7
|
+
* For type-safe routing, import from your generated routes file:
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { route, routes, type RouteName } from '@/generated/routes'
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
7
12
|
* @module
|
|
8
13
|
*/
|
|
9
14
|
// Re-export all helpers from the main helpers module
|
|
10
15
|
// Note: Using package path instead of relative import to ensure proper build output structure
|
|
11
|
-
export {
|
|
16
|
+
export { csrfFetch, csrfHeaders,
|
|
12
17
|
// CSRF utilities
|
|
13
|
-
getCsrfToken,
|
|
14
|
-
// Route utilities
|
|
15
|
-
route, getRoutes, toRoute, currentRoute, isRoute, isCurrentRoute, getRelativeUrlPath, } from "litestar-vite-plugin/helpers";
|
|
18
|
+
getCsrfToken, } from "litestar-vite-plugin/helpers";
|
|
16
19
|
/**
|
|
17
20
|
* Unwrap page props that may have content nested under "content" key.
|
|
18
21
|
*
|
package/dist/js/litestar-meta.js
CHANGED
|
@@ -11,7 +11,11 @@ async function checkBackendAvailability(appUrl) {
|
|
|
11
11
|
const controller = new AbortController();
|
|
12
12
|
const timeout = setTimeout(() => controller.abort(), 2e3);
|
|
13
13
|
const schemaPath = process.env.LITESTAR_OPENAPI_PATH || "/schema";
|
|
14
|
-
const
|
|
14
|
+
const urlObj = new URL(schemaPath, appUrl);
|
|
15
|
+
if (urlObj.hostname === "0.0.0.0") {
|
|
16
|
+
urlObj.hostname = "127.0.0.1";
|
|
17
|
+
}
|
|
18
|
+
const checkUrl = urlObj.href;
|
|
15
19
|
const response = await fetch(checkUrl, {
|
|
16
20
|
method: "GET",
|
|
17
21
|
signal: controller.signal
|
|
@@ -58,11 +62,23 @@ function firstExisting(paths) {
|
|
|
58
62
|
}
|
|
59
63
|
return null;
|
|
60
64
|
}
|
|
65
|
+
function loadVersionFromRuntimeConfig() {
|
|
66
|
+
const cfgPath = process.env.LITESTAR_VITE_CONFIG_PATH;
|
|
67
|
+
if (!cfgPath || !fs.existsSync(cfgPath)) return null;
|
|
68
|
+
try {
|
|
69
|
+
const raw = fs.readFileSync(cfgPath, "utf8");
|
|
70
|
+
const data = JSON.parse(raw);
|
|
71
|
+
const v = data?.litestarVersion;
|
|
72
|
+
return typeof v === "string" && v.trim() ? v.trim() : null;
|
|
73
|
+
} catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
61
77
|
async function loadLitestarMeta(resolvedConfig, routesPathHint) {
|
|
62
78
|
const fromEnv = process.env.LITESTAR_VERSION?.trim();
|
|
63
|
-
if (fromEnv) {
|
|
64
|
-
|
|
65
|
-
}
|
|
79
|
+
if (fromEnv) return { litestarVersion: fromEnv };
|
|
80
|
+
const fromRuntime = loadVersionFromRuntimeConfig();
|
|
81
|
+
if (fromRuntime) return { litestarVersion: fromRuntime };
|
|
66
82
|
const root = resolvedConfig.root ?? process.cwd();
|
|
67
83
|
const candidates = [routesPathHint ? path.resolve(root, routesPathHint) : null, path.resolve(root, "src/generated/routes.json"), path.resolve(root, "routes.json")].filter(
|
|
68
84
|
Boolean
|
package/dist/js/nuxt.d.ts
CHANGED
|
@@ -61,6 +61,12 @@ export interface NuxtTypesConfig {
|
|
|
61
61
|
* @default false
|
|
62
62
|
*/
|
|
63
63
|
generateZod?: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Generate SDK client functions for API calls.
|
|
66
|
+
*
|
|
67
|
+
* @default true
|
|
68
|
+
*/
|
|
69
|
+
generateSdk?: boolean;
|
|
64
70
|
/**
|
|
65
71
|
* Debounce time in milliseconds for type regeneration.
|
|
66
72
|
*
|
package/dist/js/nuxt.js
CHANGED
|
@@ -51,6 +51,7 @@ function resolveConfig(config = {}) {
|
|
|
51
51
|
openapiPath: "openapi.json",
|
|
52
52
|
routesPath: "routes.json",
|
|
53
53
|
generateZod: false,
|
|
54
|
+
generateSdk: true,
|
|
54
55
|
debounce: 300
|
|
55
56
|
};
|
|
56
57
|
} else if (typeof config.types === "object" && config.types !== null) {
|
|
@@ -60,6 +61,7 @@ function resolveConfig(config = {}) {
|
|
|
60
61
|
openapiPath: config.types.openapiPath ?? "openapi.json",
|
|
61
62
|
routesPath: config.types.routesPath ?? "routes.json",
|
|
62
63
|
generateZod: config.types.generateZod ?? false,
|
|
64
|
+
generateSdk: config.types.generateSdk ?? true,
|
|
63
65
|
debounce: config.types.debounce ?? 300
|
|
64
66
|
};
|
|
65
67
|
}
|
|
@@ -96,6 +98,15 @@ function createProxyPlugin(config) {
|
|
|
96
98
|
hmrPort = await getPort();
|
|
97
99
|
return {
|
|
98
100
|
server: {
|
|
101
|
+
// Force IPv4 binding for consistency with Python proxy configuration
|
|
102
|
+
// Without this, Nuxt/Nitro might bind to IPv6 localhost which the proxy can't reach
|
|
103
|
+
host: "127.0.0.1",
|
|
104
|
+
// Set the port from Python config/env to ensure Nuxt uses the expected port
|
|
105
|
+
// strictPort: true prevents auto-incrementing to a different port
|
|
106
|
+
...config.devPort !== void 0 ? {
|
|
107
|
+
port: config.devPort,
|
|
108
|
+
strictPort: true
|
|
109
|
+
} : {},
|
|
99
110
|
// Avoid HMR port collisions by letting Vite pick a free port for WS
|
|
100
111
|
hmr: {
|
|
101
112
|
port: hmrPort,
|
|
@@ -281,12 +292,28 @@ function createTypeGenerationPlugin(typesConfig, executor) {
|
|
|
281
292
|
return false;
|
|
282
293
|
}
|
|
283
294
|
console.log(colors.cyan("[litestar-nuxt]"), colors.dim("Generating TypeScript types..."));
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
|
|
295
|
+
const projectRoot = process.cwd();
|
|
296
|
+
const candidates = [path.resolve(projectRoot, "openapi-ts.config.ts"), path.resolve(projectRoot, "hey-api.config.ts"), path.resolve(projectRoot, ".hey-api.config.ts")];
|
|
297
|
+
const configPath = candidates.find((p) => fs.existsSync(p)) || null;
|
|
298
|
+
let args;
|
|
299
|
+
if (configPath) {
|
|
300
|
+
console.log(colors.cyan("[litestar-nuxt]"), colors.dim("Using config:"), configPath);
|
|
301
|
+
args = ["@hey-api/openapi-ts", "--file", configPath];
|
|
302
|
+
} else {
|
|
303
|
+
args = ["@hey-api/openapi-ts", "-i", typesConfig.openapiPath, "-o", typesConfig.output];
|
|
304
|
+
const plugins = ["@hey-api/typescript", "@hey-api/schemas"];
|
|
305
|
+
if (typesConfig.generateSdk) {
|
|
306
|
+
plugins.push("@hey-api/sdk", "@hey-api/client-nuxt");
|
|
307
|
+
}
|
|
308
|
+
if (typesConfig.generateZod) {
|
|
309
|
+
plugins.push("zod");
|
|
310
|
+
}
|
|
311
|
+
if (plugins.length) {
|
|
312
|
+
args.push("--plugins", ...plugins);
|
|
313
|
+
}
|
|
287
314
|
}
|
|
288
315
|
await execAsync(resolvePackageExecutor(args.join(" "), executor), {
|
|
289
|
-
cwd:
|
|
316
|
+
cwd: projectRoot
|
|
290
317
|
});
|
|
291
318
|
const routesPath = path.resolve(process.cwd(), typesConfig.routesPath);
|
|
292
319
|
if (fs.existsSync(routesPath)) {
|
|
@@ -325,6 +352,14 @@ function createTypeGenerationPlugin(typesConfig, executor) {
|
|
|
325
352
|
server = devServer;
|
|
326
353
|
console.log(colors.cyan("[litestar-nuxt]"), colors.dim("Watching for schema changes:"), colors.yellow(typesConfig.openapiPath));
|
|
327
354
|
},
|
|
355
|
+
async buildStart() {
|
|
356
|
+
if (typesConfig.enabled) {
|
|
357
|
+
const openapiPath = path.resolve(process.cwd(), typesConfig.openapiPath);
|
|
358
|
+
if (fs.existsSync(openapiPath)) {
|
|
359
|
+
await runTypeGeneration();
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
},
|
|
328
363
|
handleHotUpdate({ file }) {
|
|
329
364
|
if (!typesConfig.enabled) {
|
|
330
365
|
return;
|