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.
@@ -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
- function debounce(func, wait) {
37
- let timeout = null;
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 createTypeGenerationPlugin(typesConfig) {
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", "@hey-api/schemas", "@hey-api/types");
299
+ args.push("--plugins", "zod", "@hey-api/typescript");
113
300
  }
114
- await execAsync(`npx ${args.join(" ")}`, {
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.2",
3
+ "version": "0.15.0-alpha.4",
4
4
  "type": "module",
5
5
  "description": "Litestar plugin for Vite.",
6
- "keywords": ["litestar", "vite", "vite-plugin"],
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": ["dist/js/**/*", "tools/clean.js"],
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": "1.9.4",
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": "^5.0.0 || ^6.0.0 || ^7.0.0"
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,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { existsSync, readFileSync, readdirSync, unlinkSync } from "node:fs"
3
+ import { existsSync, readdirSync, readFileSync, unlinkSync } from "node:fs"
4
4
  import { dirname } from "node:path"
5
5
 
6
6
  /*
@@ -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";