litestar-vite-plugin 0.15.0-alpha.2 → 0.15.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +91 -20
- package/dist/js/astro.d.ts +85 -23
- package/dist/js/astro.js +300 -9
- package/dist/js/helpers/index.d.ts +2 -2
- package/dist/js/helpers/index.js +2 -2
- package/dist/js/helpers/routes.d.ts +19 -0
- package/dist/js/helpers/routes.js +59 -37
- package/dist/js/index.d.ts +12 -5
- package/dist/js/index.js +40 -27
- package/dist/js/inertia-helpers/{inertia-helpers/index.d.ts → index.d.ts} +12 -1
- package/dist/js/inertia-helpers/index.js +91 -0
- package/dist/js/install-hint.d.ts +9 -0
- package/dist/js/install-hint.js +17 -1
- package/dist/js/nuxt.d.ts +29 -22
- package/dist/js/nuxt.js +269 -45
- package/dist/js/shared/debounce.d.ts +27 -0
- package/dist/js/shared/debounce.js +15 -0
- package/dist/js/sveltekit.d.ts +7 -0
- package/dist/js/sveltekit.js +214 -23
- package/package.json +14 -6
- package/tools/clean.js +1 -1
- package/dist/js/inertia-helpers/helpers/csrf.d.ts +0 -76
- package/dist/js/inertia-helpers/helpers/csrf.js +0 -114
- package/dist/js/inertia-helpers/helpers/index.d.ts +0 -24
- package/dist/js/inertia-helpers/helpers/index.js +0 -26
- package/dist/js/inertia-helpers/helpers/routes.d.ts +0 -140
- package/dist/js/inertia-helpers/helpers/routes.js +0 -280
- package/dist/js/inertia-helpers/inertia-helpers/index.js +0 -47
package/dist/js/sveltekit.js
CHANGED
|
@@ -3,43 +3,79 @@ import fs from "node:fs";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { promisify } from "node:util";
|
|
5
5
|
import colors from "picocolors";
|
|
6
|
-
import { resolveInstallHint } from "./install-hint.js";
|
|
6
|
+
import { resolveInstallHint, resolvePackageExecutor } from "./install-hint.js";
|
|
7
|
+
import { debounce } from "./shared/debounce.js";
|
|
7
8
|
const execAsync = promisify(exec);
|
|
8
9
|
function resolveConfig(config = {}) {
|
|
10
|
+
const runtimeConfigPath = process.env.LITESTAR_VITE_CONFIG_PATH;
|
|
11
|
+
let hotFile;
|
|
12
|
+
let proxyMode = "vite";
|
|
13
|
+
let port;
|
|
14
|
+
let pythonTypesConfig;
|
|
15
|
+
const envPort = process.env.VITE_PORT;
|
|
16
|
+
if (envPort) {
|
|
17
|
+
port = Number.parseInt(envPort, 10);
|
|
18
|
+
if (Number.isNaN(port)) {
|
|
19
|
+
port = void 0;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
let pythonExecutor;
|
|
23
|
+
if (runtimeConfigPath && fs.existsSync(runtimeConfigPath)) {
|
|
24
|
+
try {
|
|
25
|
+
const json = JSON.parse(fs.readFileSync(runtimeConfigPath, "utf-8"));
|
|
26
|
+
const bundleDir = json.bundleDir ?? "public";
|
|
27
|
+
const hot = json.hotFile ?? "hot";
|
|
28
|
+
hotFile = path.resolve(process.cwd(), bundleDir, hot);
|
|
29
|
+
proxyMode = json.proxyMode ?? "vite";
|
|
30
|
+
if (json.port !== void 0) {
|
|
31
|
+
port = json.port;
|
|
32
|
+
}
|
|
33
|
+
pythonExecutor = json.executor;
|
|
34
|
+
if (json.types) {
|
|
35
|
+
pythonTypesConfig = json.types;
|
|
36
|
+
}
|
|
37
|
+
} catch {
|
|
38
|
+
hotFile = void 0;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
9
41
|
let typesConfig = false;
|
|
10
42
|
if (config.types === true) {
|
|
11
43
|
typesConfig = {
|
|
12
44
|
enabled: true,
|
|
13
|
-
output: "src/lib/api",
|
|
14
|
-
openapiPath: "openapi.json",
|
|
15
|
-
routesPath: "routes.json",
|
|
16
|
-
generateZod: false,
|
|
45
|
+
output: pythonTypesConfig?.output ?? "src/lib/api",
|
|
46
|
+
openapiPath: pythonTypesConfig?.openapiPath ?? "openapi.json",
|
|
47
|
+
routesPath: pythonTypesConfig?.routesPath ?? "routes.json",
|
|
48
|
+
generateZod: pythonTypesConfig?.generateZod ?? false,
|
|
17
49
|
debounce: 300
|
|
18
50
|
};
|
|
19
51
|
} else if (typeof config.types === "object" && config.types !== null) {
|
|
20
52
|
typesConfig = {
|
|
21
53
|
enabled: config.types.enabled ?? true,
|
|
22
|
-
output: config.types.output ?? "src/lib/api",
|
|
23
|
-
openapiPath: config.types.openapiPath ?? "openapi.json",
|
|
24
|
-
routesPath: config.types.routesPath ?? "routes.json",
|
|
25
|
-
generateZod: config.types.generateZod ?? false,
|
|
54
|
+
output: config.types.output ?? pythonTypesConfig?.output ?? "src/lib/api",
|
|
55
|
+
openapiPath: config.types.openapiPath ?? pythonTypesConfig?.openapiPath ?? "openapi.json",
|
|
56
|
+
routesPath: config.types.routesPath ?? pythonTypesConfig?.routesPath ?? "routes.json",
|
|
57
|
+
generateZod: config.types.generateZod ?? pythonTypesConfig?.generateZod ?? false,
|
|
26
58
|
debounce: config.types.debounce ?? 300
|
|
27
59
|
};
|
|
60
|
+
} else if (config.types !== false && pythonTypesConfig?.enabled) {
|
|
61
|
+
typesConfig = {
|
|
62
|
+
enabled: true,
|
|
63
|
+
output: pythonTypesConfig.output ?? "src/lib/api",
|
|
64
|
+
openapiPath: pythonTypesConfig.openapiPath ?? "openapi.json",
|
|
65
|
+
routesPath: pythonTypesConfig.routesPath ?? "routes.json",
|
|
66
|
+
generateZod: pythonTypesConfig.generateZod ?? false,
|
|
67
|
+
debounce: 300
|
|
68
|
+
};
|
|
28
69
|
}
|
|
29
70
|
return {
|
|
30
71
|
apiProxy: config.apiProxy ?? "http://localhost:8000",
|
|
31
72
|
apiPrefix: config.apiPrefix ?? "/api",
|
|
32
73
|
types: typesConfig,
|
|
33
|
-
verbose: config.verbose ?? false
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return (...args) => {
|
|
39
|
-
if (timeout) {
|
|
40
|
-
clearTimeout(timeout);
|
|
41
|
-
}
|
|
42
|
-
timeout = setTimeout(() => func(...args), wait);
|
|
74
|
+
verbose: config.verbose ?? false,
|
|
75
|
+
hotFile,
|
|
76
|
+
proxyMode,
|
|
77
|
+
port,
|
|
78
|
+
executor: config.executor ?? pythonExecutor
|
|
43
79
|
};
|
|
44
80
|
}
|
|
45
81
|
function litestarSvelteKit(userConfig = {}) {
|
|
@@ -51,6 +87,12 @@ function litestarSvelteKit(userConfig = {}) {
|
|
|
51
87
|
config() {
|
|
52
88
|
return {
|
|
53
89
|
server: {
|
|
90
|
+
// Set the port from Python config/env to ensure SvelteKit uses the expected port
|
|
91
|
+
// strictPort: true prevents SvelteKit from auto-incrementing to a different port
|
|
92
|
+
...config.port !== void 0 ? {
|
|
93
|
+
port: config.port,
|
|
94
|
+
strictPort: true
|
|
95
|
+
} : {},
|
|
54
96
|
proxy: {
|
|
55
97
|
[config.apiPrefix]: {
|
|
56
98
|
target: config.apiProxy,
|
|
@@ -70,6 +112,26 @@ function litestarSvelteKit(userConfig = {}) {
|
|
|
70
112
|
next();
|
|
71
113
|
});
|
|
72
114
|
}
|
|
115
|
+
if (config.hotFile) {
|
|
116
|
+
const hotFile = config.hotFile;
|
|
117
|
+
server.httpServer?.once("listening", () => {
|
|
118
|
+
const address = server.httpServer?.address();
|
|
119
|
+
if (address && typeof address === "object" && "port" in address) {
|
|
120
|
+
let host = address.address;
|
|
121
|
+
if (host === "::" || host === "::1") {
|
|
122
|
+
host = "localhost";
|
|
123
|
+
} else if (host.includes(":")) {
|
|
124
|
+
host = `[${host}]`;
|
|
125
|
+
}
|
|
126
|
+
const url = `http://${host}:${address.port}`;
|
|
127
|
+
fs.mkdirSync(path.dirname(hotFile), { recursive: true });
|
|
128
|
+
fs.writeFileSync(hotFile, url);
|
|
129
|
+
if (config.verbose) {
|
|
130
|
+
console.log(colors.cyan("[litestar-sveltekit]"), colors.dim(`Hotfile written: ${hotFile} -> ${url}`));
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
73
135
|
server.httpServer?.once("listening", () => {
|
|
74
136
|
setTimeout(() => {
|
|
75
137
|
console.log("");
|
|
@@ -87,11 +149,136 @@ function litestarSvelteKit(userConfig = {}) {
|
|
|
87
149
|
}
|
|
88
150
|
});
|
|
89
151
|
if (config.types !== false && config.types.enabled) {
|
|
90
|
-
plugins.push(createTypeGenerationPlugin(config.types));
|
|
152
|
+
plugins.push(createTypeGenerationPlugin(config.types, config.executor));
|
|
91
153
|
}
|
|
92
154
|
return plugins;
|
|
93
155
|
}
|
|
94
|
-
function
|
|
156
|
+
async function emitRouteTypes(routesPath, outputDir) {
|
|
157
|
+
const contents = await fs.promises.readFile(routesPath, "utf-8");
|
|
158
|
+
const json = JSON.parse(contents);
|
|
159
|
+
const outDir = path.resolve(process.cwd(), outputDir);
|
|
160
|
+
await fs.promises.mkdir(outDir, { recursive: true });
|
|
161
|
+
const outFile = path.join(outDir, "routes.ts");
|
|
162
|
+
const banner = `// AUTO-GENERATED by litestar-vite. Do not edit.
|
|
163
|
+
/* eslint-disable */
|
|
164
|
+
|
|
165
|
+
`;
|
|
166
|
+
const routesData = json.routes || json;
|
|
167
|
+
const routeNames = Object.keys(routesData);
|
|
168
|
+
const routeNameType = routeNames.length > 0 ? routeNames.map((n) => `"${n}"`).join(" | ") : "never";
|
|
169
|
+
const routeParamTypes = [];
|
|
170
|
+
for (const [name, data] of Object.entries(routesData)) {
|
|
171
|
+
const routeData = data;
|
|
172
|
+
if (routeData.parameters && routeData.parameters.length > 0) {
|
|
173
|
+
const params = routeData.parameters.map((p) => `${p}: string | number`).join("; ");
|
|
174
|
+
routeParamTypes.push(` "${name}": { ${params} }`);
|
|
175
|
+
} else {
|
|
176
|
+
routeParamTypes.push(` "${name}": Record<string, never>`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
const body = `/**
|
|
180
|
+
* AUTO-GENERATED by litestar-vite.
|
|
181
|
+
*
|
|
182
|
+
* Exports:
|
|
183
|
+
* - routesMeta: full route metadata
|
|
184
|
+
* - routes: name -> uri map
|
|
185
|
+
* - serverRoutes: alias of routes for clarity in apps
|
|
186
|
+
* - route(): type-safe URL generator
|
|
187
|
+
* - hasRoute(): type guard
|
|
188
|
+
* - csrf helpers re-exported from litestar-vite-plugin/helpers
|
|
189
|
+
*
|
|
190
|
+
* @see https://litestar-vite.litestar.dev/
|
|
191
|
+
*/
|
|
192
|
+
export const routesMeta = ${JSON.stringify(json, null, 2)} as const
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Route name to URI mapping.
|
|
196
|
+
*/
|
|
197
|
+
export const routes = ${JSON.stringify(Object.fromEntries(Object.entries(routesData).map(([name, data]) => [name, data.uri])), null, 2)} as const
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Alias for server-injected route map (more descriptive for consumers).
|
|
201
|
+
*/
|
|
202
|
+
export const serverRoutes = routes
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* All available route names.
|
|
206
|
+
*/
|
|
207
|
+
export type RouteName = ${routeNameType}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Parameter types for each route.
|
|
211
|
+
*/
|
|
212
|
+
export interface RouteParams {
|
|
213
|
+
${routeParamTypes.join("\n")}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Generate a URL for a named route with type-safe parameters.
|
|
218
|
+
*
|
|
219
|
+
* @param name - The route name
|
|
220
|
+
* @param params - Route parameters (required if route has path parameters)
|
|
221
|
+
* @returns The generated URL
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* \`\`\`ts
|
|
225
|
+
* import { route } from '@/generated/routes'
|
|
226
|
+
*
|
|
227
|
+
* // Route without parameters
|
|
228
|
+
* route('home') // "/"
|
|
229
|
+
*
|
|
230
|
+
* // Route with parameters
|
|
231
|
+
* route('user:detail', { user_id: 123 }) // "/users/123"
|
|
232
|
+
* \`\`\`
|
|
233
|
+
*/
|
|
234
|
+
export function route<T extends RouteName>(
|
|
235
|
+
name: T,
|
|
236
|
+
...args: RouteParams[T] extends Record<string, never> ? [] : [params: RouteParams[T]]
|
|
237
|
+
): string {
|
|
238
|
+
let uri = routes[name] as string
|
|
239
|
+
const params = args[0] as Record<string, string | number> | undefined
|
|
240
|
+
|
|
241
|
+
if (params) {
|
|
242
|
+
for (const [key, value] of Object.entries(params)) {
|
|
243
|
+
// Handle both {param} and {param:type} syntax
|
|
244
|
+
uri = uri.replace(new RegExp(\`\\\\{\${key}(?::[^}]+)?\\\\}\`, "g"), String(value))
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return uri
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Check if a route name exists.
|
|
253
|
+
*/
|
|
254
|
+
export function hasRoute(name: string): name is RouteName {
|
|
255
|
+
return name in routes
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
declare global {
|
|
259
|
+
interface Window {
|
|
260
|
+
/**
|
|
261
|
+
* Fully-typed route metadata injected by Litestar.
|
|
262
|
+
*/
|
|
263
|
+
__LITESTAR_ROUTES__?: typeof routesMeta
|
|
264
|
+
/**
|
|
265
|
+
* Simple route map (name -> uri) for legacy consumers.
|
|
266
|
+
*/
|
|
267
|
+
routes?: typeof routes
|
|
268
|
+
serverRoutes?: typeof serverRoutes
|
|
269
|
+
}
|
|
270
|
+
// eslint-disable-next-line no-var
|
|
271
|
+
var routes: typeof routes | undefined
|
|
272
|
+
var serverRoutes: typeof serverRoutes | undefined
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Re-export helper functions from litestar-vite-plugin
|
|
276
|
+
// These work with the routes defined above
|
|
277
|
+
export { getCsrfToken, csrfHeaders, csrfFetch } from "litestar-vite-plugin/helpers"
|
|
278
|
+
`;
|
|
279
|
+
await fs.promises.writeFile(outFile, `${banner}${body}`, "utf-8");
|
|
280
|
+
}
|
|
281
|
+
function createTypeGenerationPlugin(typesConfig, executor) {
|
|
95
282
|
let server = null;
|
|
96
283
|
let isGenerating = false;
|
|
97
284
|
async function runTypeGeneration() {
|
|
@@ -109,11 +296,15 @@ function createTypeGenerationPlugin(typesConfig) {
|
|
|
109
296
|
console.log(colors.cyan("[litestar-sveltekit]"), colors.dim("Generating TypeScript types..."));
|
|
110
297
|
const args = ["@hey-api/openapi-ts", "-i", typesConfig.openapiPath, "-o", typesConfig.output];
|
|
111
298
|
if (typesConfig.generateZod) {
|
|
112
|
-
args.push("--plugins", "
|
|
299
|
+
args.push("--plugins", "zod", "@hey-api/typescript");
|
|
113
300
|
}
|
|
114
|
-
await execAsync(
|
|
301
|
+
await execAsync(resolvePackageExecutor(args.join(" "), executor), {
|
|
115
302
|
cwd: process.cwd()
|
|
116
303
|
});
|
|
304
|
+
const routesPath = path.resolve(process.cwd(), typesConfig.routesPath);
|
|
305
|
+
if (fs.existsSync(routesPath)) {
|
|
306
|
+
await emitRouteTypes(routesPath, typesConfig.output);
|
|
307
|
+
}
|
|
117
308
|
const duration = Date.now() - startTime;
|
|
118
309
|
console.log(colors.cyan("[litestar-sveltekit]"), colors.green("Types generated"), colors.dim(`in ${duration}ms`));
|
|
119
310
|
if (server) {
|
package/package.json
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "litestar-vite-plugin",
|
|
3
|
-
"version": "0.15.0-alpha.
|
|
3
|
+
"version": "0.15.0-alpha.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Litestar plugin for Vite.",
|
|
6
|
-
"keywords": [
|
|
6
|
+
"keywords": [
|
|
7
|
+
"litestar",
|
|
8
|
+
"vite",
|
|
9
|
+
"vite-plugin"
|
|
10
|
+
],
|
|
7
11
|
"homepage": "https://github.com/litestar-org/litestar-vite",
|
|
8
12
|
"repository": {
|
|
9
13
|
"type": "git",
|
|
@@ -40,7 +44,10 @@
|
|
|
40
44
|
}
|
|
41
45
|
},
|
|
42
46
|
"types": "./dist/js/index.d.ts",
|
|
43
|
-
"files": [
|
|
47
|
+
"files": [
|
|
48
|
+
"dist/js/**/*",
|
|
49
|
+
"tools/clean.js"
|
|
50
|
+
],
|
|
44
51
|
"bin": {
|
|
45
52
|
"clean-orphaned-assets": "tools/clean.js"
|
|
46
53
|
},
|
|
@@ -48,7 +55,7 @@
|
|
|
48
55
|
"build": "npm run build-plugin && npm run build-helpers && npm run build-inertia-helpers && npm run build-integrations",
|
|
49
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/",
|
|
50
57
|
"build-plugin-types": "tsc --project src/js/tsconfig.json --emitDeclarationOnly",
|
|
51
|
-
"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",
|
|
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 --platform=node --format=esm --outfile=dist/js/shared/debounce.js",
|
|
52
59
|
"build-helpers": "rm -rf dist/js/helpers && tsc --project src/js/tsconfig.helpers.json",
|
|
53
60
|
"build-inertia-helpers": "rm -rf dist/js/inertia-helpers && tsc --project src/js/tsconfig.inertia-helpers.json",
|
|
54
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",
|
|
@@ -56,8 +63,9 @@
|
|
|
56
63
|
"test": "vitest --config ./src/js/vitest.config.ts run"
|
|
57
64
|
},
|
|
58
65
|
"devDependencies": {
|
|
59
|
-
"@biomejs/biome": "
|
|
66
|
+
"@biomejs/biome": "2.0.6",
|
|
60
67
|
"@types/node": "^22.15.3",
|
|
68
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
61
69
|
"esbuild": "0.25.3",
|
|
62
70
|
"happy-dom": "^20.0.2",
|
|
63
71
|
"typescript": "^5.8.3",
|
|
@@ -65,7 +73,7 @@
|
|
|
65
73
|
"vitest": "^3.1.2"
|
|
66
74
|
},
|
|
67
75
|
"peerDependencies": {
|
|
68
|
-
"vite": "^
|
|
76
|
+
"vite": "^6.0.0 || ^7.0.0"
|
|
69
77
|
},
|
|
70
78
|
"engines": {
|
|
71
79
|
"node": "^20.19.0 || >=22.12.0"
|
package/tools/clean.js
CHANGED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CSRF token utilities for Litestar applications.
|
|
3
|
-
*
|
|
4
|
-
* The CSRF token is injected into the page by Litestar in one of these ways:
|
|
5
|
-
* 1. window.__LITESTAR_CSRF__ (SPA mode)
|
|
6
|
-
* 2. <meta name="csrf-token" content="..."> (template mode)
|
|
7
|
-
* 3. Inertia shared props (Inertia mode)
|
|
8
|
-
*
|
|
9
|
-
* @module
|
|
10
|
-
*/
|
|
11
|
-
declare global {
|
|
12
|
-
interface Window {
|
|
13
|
-
__LITESTAR_CSRF__?: string;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Get the CSRF token from the page.
|
|
18
|
-
*
|
|
19
|
-
* Checks multiple sources in order:
|
|
20
|
-
* 1. window.__LITESTAR_CSRF__ (injected by SPA handler)
|
|
21
|
-
* 2. <meta name="csrf-token"> element
|
|
22
|
-
* 3. Inertia page props (if Inertia is present)
|
|
23
|
-
*
|
|
24
|
-
* @returns The CSRF token or empty string if not found
|
|
25
|
-
*
|
|
26
|
-
* @example
|
|
27
|
-
* ```ts
|
|
28
|
-
* import { getCsrfToken } from 'litestar-vite-plugin/helpers'
|
|
29
|
-
*
|
|
30
|
-
* fetch('/api/submit', {
|
|
31
|
-
* method: 'POST',
|
|
32
|
-
* headers: {
|
|
33
|
-
* 'X-CSRF-Token': getCsrfToken(),
|
|
34
|
-
* },
|
|
35
|
-
* body: JSON.stringify(data),
|
|
36
|
-
* })
|
|
37
|
-
* ```
|
|
38
|
-
*/
|
|
39
|
-
export declare function getCsrfToken(): string;
|
|
40
|
-
/**
|
|
41
|
-
* Create headers object with CSRF token included.
|
|
42
|
-
*
|
|
43
|
-
* @param additionalHeaders - Additional headers to include
|
|
44
|
-
* @returns Headers object with X-CSRF-Token set
|
|
45
|
-
*
|
|
46
|
-
* @example
|
|
47
|
-
* ```ts
|
|
48
|
-
* import { csrfHeaders } from 'litestar-vite-plugin/helpers'
|
|
49
|
-
*
|
|
50
|
-
* fetch('/api/submit', {
|
|
51
|
-
* method: 'POST',
|
|
52
|
-
* headers: csrfHeaders({ 'Content-Type': 'application/json' }),
|
|
53
|
-
* body: JSON.stringify(data),
|
|
54
|
-
* })
|
|
55
|
-
* ```
|
|
56
|
-
*/
|
|
57
|
-
export declare function csrfHeaders(additionalHeaders?: Record<string, string>): Record<string, string>;
|
|
58
|
-
/**
|
|
59
|
-
* Create a fetch wrapper that automatically includes CSRF token.
|
|
60
|
-
*
|
|
61
|
-
* @param input - Request URL or Request object
|
|
62
|
-
* @param init - Request options
|
|
63
|
-
* @returns Fetch response promise
|
|
64
|
-
*
|
|
65
|
-
* @example
|
|
66
|
-
* ```ts
|
|
67
|
-
* import { csrfFetch } from 'litestar-vite-plugin/helpers'
|
|
68
|
-
*
|
|
69
|
-
* // Automatically includes CSRF token
|
|
70
|
-
* csrfFetch('/api/submit', {
|
|
71
|
-
* method: 'POST',
|
|
72
|
-
* body: JSON.stringify(data),
|
|
73
|
-
* })
|
|
74
|
-
* ```
|
|
75
|
-
*/
|
|
76
|
-
export declare function csrfFetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CSRF token utilities for Litestar applications.
|
|
3
|
-
*
|
|
4
|
-
* The CSRF token is injected into the page by Litestar in one of these ways:
|
|
5
|
-
* 1. window.__LITESTAR_CSRF__ (SPA mode)
|
|
6
|
-
* 2. <meta name="csrf-token" content="..."> (template mode)
|
|
7
|
-
* 3. Inertia shared props (Inertia mode)
|
|
8
|
-
*
|
|
9
|
-
* @module
|
|
10
|
-
*/
|
|
11
|
-
/**
|
|
12
|
-
* Get the CSRF token from the page.
|
|
13
|
-
*
|
|
14
|
-
* Checks multiple sources in order:
|
|
15
|
-
* 1. window.__LITESTAR_CSRF__ (injected by SPA handler)
|
|
16
|
-
* 2. <meta name="csrf-token"> element
|
|
17
|
-
* 3. Inertia page props (if Inertia is present)
|
|
18
|
-
*
|
|
19
|
-
* @returns The CSRF token or empty string if not found
|
|
20
|
-
*
|
|
21
|
-
* @example
|
|
22
|
-
* ```ts
|
|
23
|
-
* import { getCsrfToken } from 'litestar-vite-plugin/helpers'
|
|
24
|
-
*
|
|
25
|
-
* fetch('/api/submit', {
|
|
26
|
-
* method: 'POST',
|
|
27
|
-
* headers: {
|
|
28
|
-
* 'X-CSRF-Token': getCsrfToken(),
|
|
29
|
-
* },
|
|
30
|
-
* body: JSON.stringify(data),
|
|
31
|
-
* })
|
|
32
|
-
* ```
|
|
33
|
-
*/
|
|
34
|
-
export function getCsrfToken() {
|
|
35
|
-
// Check window global (SPA mode)
|
|
36
|
-
if (typeof window !== "undefined" && window.__LITESTAR_CSRF__) {
|
|
37
|
-
return window.__LITESTAR_CSRF__;
|
|
38
|
-
}
|
|
39
|
-
// Check meta tag (template mode)
|
|
40
|
-
if (typeof document !== "undefined") {
|
|
41
|
-
const meta = document.querySelector('meta[name="csrf-token"]');
|
|
42
|
-
if (meta) {
|
|
43
|
-
return meta.getAttribute("content") || "";
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
// Check Inertia page props
|
|
47
|
-
if (typeof window !== "undefined") {
|
|
48
|
-
const win = window;
|
|
49
|
-
const inertiaPage = win.__INERTIA_PAGE__;
|
|
50
|
-
if (inertiaPage?.props) {
|
|
51
|
-
const props = inertiaPage.props;
|
|
52
|
-
if (typeof props.csrf_token === "string") {
|
|
53
|
-
return props.csrf_token;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
return "";
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Create headers object with CSRF token included.
|
|
61
|
-
*
|
|
62
|
-
* @param additionalHeaders - Additional headers to include
|
|
63
|
-
* @returns Headers object with X-CSRF-Token set
|
|
64
|
-
*
|
|
65
|
-
* @example
|
|
66
|
-
* ```ts
|
|
67
|
-
* import { csrfHeaders } from 'litestar-vite-plugin/helpers'
|
|
68
|
-
*
|
|
69
|
-
* fetch('/api/submit', {
|
|
70
|
-
* method: 'POST',
|
|
71
|
-
* headers: csrfHeaders({ 'Content-Type': 'application/json' }),
|
|
72
|
-
* body: JSON.stringify(data),
|
|
73
|
-
* })
|
|
74
|
-
* ```
|
|
75
|
-
*/
|
|
76
|
-
export function csrfHeaders(additionalHeaders = {}) {
|
|
77
|
-
const token = getCsrfToken();
|
|
78
|
-
return {
|
|
79
|
-
...additionalHeaders,
|
|
80
|
-
...(token ? { "X-CSRF-Token": token } : {}),
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Create a fetch wrapper that automatically includes CSRF token.
|
|
85
|
-
*
|
|
86
|
-
* @param input - Request URL or Request object
|
|
87
|
-
* @param init - Request options
|
|
88
|
-
* @returns Fetch response promise
|
|
89
|
-
*
|
|
90
|
-
* @example
|
|
91
|
-
* ```ts
|
|
92
|
-
* import { csrfFetch } from 'litestar-vite-plugin/helpers'
|
|
93
|
-
*
|
|
94
|
-
* // Automatically includes CSRF token
|
|
95
|
-
* csrfFetch('/api/submit', {
|
|
96
|
-
* method: 'POST',
|
|
97
|
-
* body: JSON.stringify(data),
|
|
98
|
-
* })
|
|
99
|
-
* ```
|
|
100
|
-
*/
|
|
101
|
-
export function csrfFetch(input, init) {
|
|
102
|
-
const token = getCsrfToken();
|
|
103
|
-
if (!token) {
|
|
104
|
-
return fetch(input, init);
|
|
105
|
-
}
|
|
106
|
-
const headers = new Headers(init?.headers);
|
|
107
|
-
if (!headers.has("X-CSRF-Token")) {
|
|
108
|
-
headers.set("X-CSRF-Token", token);
|
|
109
|
-
}
|
|
110
|
-
return fetch(input, {
|
|
111
|
-
...init,
|
|
112
|
-
headers,
|
|
113
|
-
});
|
|
114
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Litestar Vite Helpers
|
|
3
|
-
*
|
|
4
|
-
* Utilities for working with Litestar applications from the frontend.
|
|
5
|
-
* These helpers work in both SPA and template modes.
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```ts
|
|
9
|
-
* import { route, getCsrfToken, csrfFetch } from 'litestar-vite-plugin/helpers'
|
|
10
|
-
*
|
|
11
|
-
* // Generate a URL for a named route
|
|
12
|
-
* const url = route('user:detail', { user_id: 123 })
|
|
13
|
-
*
|
|
14
|
-
* // Make a fetch request with CSRF token
|
|
15
|
-
* await csrfFetch('/api/submit', {
|
|
16
|
-
* method: 'POST',
|
|
17
|
-
* body: JSON.stringify(data),
|
|
18
|
-
* })
|
|
19
|
-
* ```
|
|
20
|
-
*
|
|
21
|
-
* @module
|
|
22
|
-
*/
|
|
23
|
-
export { getCsrfToken, csrfHeaders, csrfFetch } from "./csrf.js";
|
|
24
|
-
export { route, getRoutes, toRoute, currentRoute, isRoute, isCurrentRoute, getRelativeUrlPath, type RouteDefinition, type RoutesMap, } from "./routes.js";
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Litestar Vite Helpers
|
|
3
|
-
*
|
|
4
|
-
* Utilities for working with Litestar applications from the frontend.
|
|
5
|
-
* These helpers work in both SPA and template modes.
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```ts
|
|
9
|
-
* import { route, getCsrfToken, csrfFetch } from 'litestar-vite-plugin/helpers'
|
|
10
|
-
*
|
|
11
|
-
* // Generate a URL for a named route
|
|
12
|
-
* const url = route('user:detail', { user_id: 123 })
|
|
13
|
-
*
|
|
14
|
-
* // Make a fetch request with CSRF token
|
|
15
|
-
* await csrfFetch('/api/submit', {
|
|
16
|
-
* method: 'POST',
|
|
17
|
-
* body: JSON.stringify(data),
|
|
18
|
-
* })
|
|
19
|
-
* ```
|
|
20
|
-
*
|
|
21
|
-
* @module
|
|
22
|
-
*/
|
|
23
|
-
// CSRF utilities
|
|
24
|
-
export { getCsrfToken, csrfHeaders, csrfFetch } from "./csrf.js";
|
|
25
|
-
// Route utilities
|
|
26
|
-
export { route, getRoutes, toRoute, currentRoute, isRoute, isCurrentRoute, getRelativeUrlPath, } from "./routes.js";
|