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.
@@ -0,0 +1,494 @@
1
+ /**
2
+ * Litestar HTMX Extension
3
+ *
4
+ * Lightweight JSON templating for HTMX with CSRF support.
5
+ *
6
+ * Features:
7
+ * - `hx-swap="json"` - Client-side JSON templating
8
+ * - Automatic CSRF token injection
9
+ * - Template syntax: `ls-for`, `ls-if`, `:attr`, `@event`, `${expr}`
10
+ *
11
+ * For typed routes, import from your generated routes file:
12
+ * ```ts
13
+ * import { route } from '@/generated/routes'
14
+ * ```
15
+ *
16
+ * @example
17
+ * ```html
18
+ * <div hx-get="/api/books" hx-swap="json" hx-ext="litestar">
19
+ * <template ls-for="book in $data">
20
+ * <article :id="`book-${book.id}`">
21
+ * <h3>${book.title}</h3>
22
+ * <p>${book.author} • ${book.year}</p>
23
+ * </article>
24
+ * </template>
25
+ * </div>
26
+ * ```
27
+ *
28
+ * @module
29
+ */
30
+ import { getCsrfToken } from "./csrf.js";
31
+ const DEBUG = typeof process !== "undefined" && process.env?.NODE_ENV !== "production";
32
+ const cache = new Map();
33
+ const memoStore = new WeakMap();
34
+ // =============================================================================
35
+ // Registration
36
+ // =============================================================================
37
+ export function registerHtmxExtension() {
38
+ if (typeof window === "undefined" || !window.htmx)
39
+ return;
40
+ window.htmx.defineExtension("litestar", {
41
+ onEvent(name, evt) {
42
+ if (name === "htmx:configRequest") {
43
+ const token = getCsrfToken();
44
+ if (token)
45
+ evt.detail.headers["X-CSRF-Token"] = token;
46
+ }
47
+ return true;
48
+ },
49
+ transformResponse(text, xhr) {
50
+ if (xhr.getResponseHeader("content-type")?.includes("application/json")) {
51
+ const d = document.createElement("div");
52
+ d.textContent = text;
53
+ return d.innerHTML;
54
+ }
55
+ return text;
56
+ },
57
+ isInlineSwap: (s) => s === "json",
58
+ handleSwap(style, target, frag) {
59
+ if (style === "json") {
60
+ try {
61
+ swapJson(target, JSON.parse(frag.textContent ?? ""));
62
+ }
63
+ catch (e) {
64
+ target.innerHTML = `<div style="color:red;padding:1rem">${e}</div>`;
65
+ }
66
+ return [target];
67
+ }
68
+ return [];
69
+ },
70
+ });
71
+ if (DEBUG)
72
+ console.log("[litestar] htmx extension registered");
73
+ }
74
+ // =============================================================================
75
+ // Note: hx-route functionality removed - use generated routes directly
76
+ // Import route from your generated routes.ts file instead:
77
+ // import { route } from '@/generated/routes'
78
+ // element.setAttribute('hx-get', route('my_route', { id: 123 }))
79
+ // =============================================================================
80
+ // =============================================================================
81
+ // JSON Swap Entry Point
82
+ // =============================================================================
83
+ export function swapJson(el, data) {
84
+ swap(el, rootCtx(data));
85
+ }
86
+ // =============================================================================
87
+ // Core Swap Logic
88
+ // =============================================================================
89
+ function swap(node, ctx, end, parse = false) {
90
+ // Text nodes: interpolate ${expr}
91
+ if (node.nodeType === 3) {
92
+ const g = memo(node, "t", () => {
93
+ const t = node.textContent ?? "";
94
+ return compileTextExpr(t);
95
+ });
96
+ if (!g)
97
+ return null;
98
+ if (!parse)
99
+ node.textContent = String(g(ctx) ?? "");
100
+ return node;
101
+ }
102
+ // Elements
103
+ if (node.nodeType === 1) {
104
+ const el = node;
105
+ // Template: structural directives
106
+ if (el.nodeName === "TEMPLATE") {
107
+ return forDir(el, ctx, end, parse) ?? ifDir(el, ctx, end, parse);
108
+ }
109
+ // Process attribute directives
110
+ let c = ctx;
111
+ const handlers = memo(el, "a", () => {
112
+ const h = [];
113
+ for (const attr of Array.from(el.attributes)) {
114
+ const d = directives.find((x) => x.match(attr));
115
+ if (d) {
116
+ const handler = d.create(el, attr);
117
+ if (handler)
118
+ h.push(handler);
119
+ }
120
+ }
121
+ return h;
122
+ });
123
+ for (const h of handlers) {
124
+ if (!parse && c) {
125
+ const r = h(c, el);
126
+ if (r !== undefined)
127
+ c = r;
128
+ }
129
+ if (!c)
130
+ break;
131
+ }
132
+ if (c === false)
133
+ return el;
134
+ if (!c)
135
+ return null;
136
+ // Recurse children
137
+ swapKids(el.firstChild, undefined, c, parse);
138
+ return el;
139
+ }
140
+ return null;
141
+ }
142
+ function swapKids(start, end, ctx, parse = false) {
143
+ let current = start;
144
+ while (current && current !== end) {
145
+ const r = swap(current, ctx, end, parse);
146
+ current = (r ?? current).nextSibling;
147
+ }
148
+ }
149
+ const directives = [
150
+ // :attr="expr" - attribute binding
151
+ {
152
+ match: (a) => a.name.startsWith(":"),
153
+ create(_el, a) {
154
+ const name = a.name.slice(1);
155
+ const g = expr(a.value);
156
+ if (!g)
157
+ return null;
158
+ return (ctx, el) => {
159
+ const v = g(ctx);
160
+ if (name === "class" && typeof v === "object" && v) {
161
+ for (const [k, on] of Object.entries(v))
162
+ el.classList.toggle(k, Boolean(on));
163
+ }
164
+ else if (v == null || v === false) {
165
+ el.removeAttribute(name);
166
+ }
167
+ else {
168
+ el.setAttribute(name, v === true ? "" : String(v));
169
+ }
170
+ };
171
+ },
172
+ },
173
+ // @event="expr" - event binding
174
+ {
175
+ match: (a) => a.name.startsWith("@"),
176
+ create(_el, a) {
177
+ const name = a.name.slice(1);
178
+ const g = expr(a.value);
179
+ if (!g)
180
+ return null;
181
+ let bound = false;
182
+ return (ctx, el) => {
183
+ if (!bound) {
184
+ bound = true;
185
+ el.addEventListener(name, (e) => g({ ...ctx, $event: e }));
186
+ }
187
+ };
188
+ },
189
+ },
190
+ // ls-scope="expr" - change context
191
+ {
192
+ match: (a) => a.name === "ls-scope",
193
+ create(_, a) {
194
+ const g = expr(a.value);
195
+ if (!g)
196
+ return null;
197
+ return (ctx) => {
198
+ const d = g(ctx);
199
+ return d ? childCtx(ctx, d) : false;
200
+ };
201
+ },
202
+ },
203
+ // ls-text="expr" - text content
204
+ {
205
+ match: (a) => a.name === "ls-text",
206
+ create(_, a) {
207
+ const g = expr(a.value);
208
+ if (!g)
209
+ return null;
210
+ return (ctx, el) => {
211
+ el.textContent = String(g(ctx) ?? "");
212
+ };
213
+ },
214
+ },
215
+ // ls-html="expr" - innerHTML (use carefully)
216
+ {
217
+ match: (a) => a.name === "ls-html",
218
+ create(_, a) {
219
+ const g = expr(a.value);
220
+ if (!g)
221
+ return null;
222
+ return (ctx, el) => {
223
+ el.innerHTML = String(g(ctx) ?? "");
224
+ };
225
+ },
226
+ },
227
+ // ls-show/ls-hide
228
+ {
229
+ match: (a) => a.name === "ls-show",
230
+ create(_, a) {
231
+ const g = expr(a.value);
232
+ if (!g)
233
+ return null;
234
+ return (ctx, el) => {
235
+ ;
236
+ el.style.display = g(ctx) ? "" : "none";
237
+ };
238
+ },
239
+ },
240
+ {
241
+ match: (a) => a.name === "ls-hide",
242
+ create(_, a) {
243
+ const g = expr(a.value);
244
+ if (!g)
245
+ return null;
246
+ return (ctx, el) => {
247
+ ;
248
+ el.style.display = g(ctx) ? "none" : "";
249
+ };
250
+ },
251
+ },
252
+ // name attr on inputs - auto-bind from context
253
+ {
254
+ match: (a) => a.name === "name",
255
+ create(el, a) {
256
+ if (!(el instanceof HTMLInputElement || el instanceof HTMLSelectElement || el instanceof HTMLTextAreaElement))
257
+ return null;
258
+ const key = a.value;
259
+ return (ctx, el) => {
260
+ const v = ctx[key];
261
+ if (v === undefined)
262
+ return;
263
+ const inp = el;
264
+ if (inp.type === "checkbox")
265
+ inp.checked = Boolean(v);
266
+ else if (inp.type === "radio")
267
+ inp.checked = v === inp.value;
268
+ else
269
+ inp.value = String(v ?? "");
270
+ };
271
+ },
272
+ },
273
+ ];
274
+ // =============================================================================
275
+ // Structural: ls-for
276
+ // =============================================================================
277
+ function forDir(tpl, ctx, _parentEnd, parse = false) {
278
+ const raw = tpl.getAttribute("ls-for") ?? tpl.getAttribute("ls-each");
279
+ if (!raw)
280
+ return null;
281
+ preparseTpl(tpl);
282
+ if (parse)
283
+ return tpl;
284
+ // Parse "item in items" or just "items"
285
+ const m = raw.match(/^\s*(\w+)\s+in\s+(.+)$/);
286
+ const [alias, listExpr] = m ? [m[1], m[2]] : [null, raw];
287
+ const g = memo(tpl, "g", () => expr(listExpr));
288
+ if (!g)
289
+ return null;
290
+ const items = toList(g(ctx), tpl, ctx, alias);
291
+ const end = memo(tpl, "end", () => insertComment(tpl, "/ls-for"));
292
+ const old = memo(tpl, "list", () => collectComments(tpl, end));
293
+ let i = 0;
294
+ for (; i < items.length; i++) {
295
+ const [key, item] = items[i];
296
+ const c = childCtx(ctx, item, i, key);
297
+ if (alias)
298
+ c[alias] = item;
299
+ if (i < old.length && old[i][0] === key) {
300
+ // Same key: update in place
301
+ swapKids(old[i][1].nextSibling, old[i + 1]?.[1] ?? end, c);
302
+ }
303
+ else {
304
+ // Insert new
305
+ const clone = tpl.content.cloneNode(true);
306
+ const comment = document.createComment(key);
307
+ const ref = old[i]?.[1] ?? end;
308
+ ref.parentNode?.insertBefore(comment, ref);
309
+ ref.parentNode?.insertBefore(clone, ref);
310
+ swapKids(comment.nextSibling, ref, c);
311
+ // Remove old if exists
312
+ if (i < old.length) {
313
+ removeBetween(old[i][1], old[i + 1]?.[1] ?? end);
314
+ old[i][1].remove();
315
+ }
316
+ old[i] = [key, comment];
317
+ }
318
+ }
319
+ // Remove excess
320
+ while (old.length > items.length) {
321
+ const popped = old.pop();
322
+ if (!popped)
323
+ break;
324
+ const [, c] = popped;
325
+ removeBetween(c, old[old.length]?.[1] ?? end);
326
+ c.remove();
327
+ }
328
+ return end;
329
+ }
330
+ // =============================================================================
331
+ // Structural: ls-if
332
+ // =============================================================================
333
+ function ifDir(tpl, ctx, _parentEnd, parse = false) {
334
+ const raw = tpl.getAttribute("ls-if");
335
+ if (!raw)
336
+ return null;
337
+ preparseTpl(tpl);
338
+ // Find else template
339
+ const elseTpl = tpl.nextElementSibling?.nodeName === "TEMPLATE" && tpl.nextElementSibling.hasAttribute("ls-else") ? tpl.nextElementSibling : null;
340
+ if (elseTpl)
341
+ preparseTpl(elseTpl);
342
+ if (parse)
343
+ return elseTpl ?? tpl;
344
+ const g = memo(tpl, "g", () => expr(raw));
345
+ const anchor = memo(tpl, "anchor", () => insertComment(tpl, ""));
346
+ const end = memo(tpl, "end", () => insertComment(anchor, "/ls-if"));
347
+ const show = g?.(ctx);
348
+ if (show) {
349
+ if (anchor.data !== "if") {
350
+ anchor.data = "if";
351
+ removeBetween(anchor.nextSibling, end);
352
+ end.parentNode?.insertBefore(tpl.content.cloneNode(true), end);
353
+ }
354
+ swapKids(anchor.nextSibling, end, ctx);
355
+ }
356
+ else if (elseTpl) {
357
+ if (anchor.data !== "else") {
358
+ anchor.data = "else";
359
+ removeBetween(anchor.nextSibling, end);
360
+ end.parentNode?.insertBefore(elseTpl.content.cloneNode(true), end);
361
+ }
362
+ swapKids(anchor.nextSibling, end, ctx);
363
+ }
364
+ else {
365
+ anchor.data = "";
366
+ removeBetween(anchor.nextSibling, end);
367
+ }
368
+ return end;
369
+ }
370
+ // =============================================================================
371
+ // Context
372
+ // =============================================================================
373
+ function rootCtx(data) {
374
+ const ctx = {
375
+ $data: data,
376
+ // Note: route and navigate are optional - users can provide their own
377
+ // by importing from their generated routes.ts file
378
+ };
379
+ if (data && typeof data === "object")
380
+ Object.setPrototypeOf(ctx, data);
381
+ return ctx;
382
+ }
383
+ function childCtx(parent, data, index, key) {
384
+ const ctx = Object.create(data && typeof data === "object" ? data : null);
385
+ ctx.$data = data;
386
+ ctx.$parent = parent;
387
+ ctx.$index = index;
388
+ ctx.$key = key;
389
+ ctx.route = parent.route;
390
+ ctx.navigate = parent.navigate;
391
+ return ctx;
392
+ }
393
+ // =============================================================================
394
+ // Expression Compiler
395
+ // =============================================================================
396
+ function expr(s) {
397
+ if (!s)
398
+ return null;
399
+ const cached = cache.get(s);
400
+ if (cached !== undefined)
401
+ return cached;
402
+ try {
403
+ const fn = new Function("ctx", `with(ctx){return(${s})}`);
404
+ cache.set(s, fn);
405
+ return fn;
406
+ }
407
+ catch {
408
+ cache.set(s, null);
409
+ return null;
410
+ }
411
+ }
412
+ /** Compile text with ${expr} interpolation - escapes backticks and backslashes */
413
+ function compileTextExpr(t) {
414
+ if (!t.includes("${"))
415
+ return null;
416
+ // Escape backticks and backslashes for safe template literal compilation
417
+ const escaped = t.replace(/[`\\]/g, "\\$&");
418
+ return expr(`\`${escaped}\``);
419
+ }
420
+ // =============================================================================
421
+ // Utilities
422
+ // =============================================================================
423
+ function memo(node, key, fn) {
424
+ let store = memoStore.get(node);
425
+ if (!store) {
426
+ store = {};
427
+ memoStore.set(node, store);
428
+ }
429
+ if (!(key in store)) {
430
+ store[key] = fn();
431
+ }
432
+ return store[key];
433
+ }
434
+ function preparseTpl(t) {
435
+ memo(t, "p", () => {
436
+ swapKids(t.content.firstChild, undefined, {}, true);
437
+ return true;
438
+ });
439
+ }
440
+ function toList(items, tpl, ctx, alias) {
441
+ const keyAttr = tpl.getAttribute("ls-key");
442
+ const keyFn = keyAttr ? expr(keyAttr) : null;
443
+ if (Array.isArray(items)) {
444
+ return items.map((item, i) => {
445
+ if (!keyFn)
446
+ return [String(i), item];
447
+ // Create a child context with the alias so key expressions like "item.id" work
448
+ const keyCtx = childCtx(ctx, item, i);
449
+ if (alias)
450
+ keyCtx[alias] = item;
451
+ return [String(keyFn(keyCtx)), item];
452
+ });
453
+ }
454
+ if (items && typeof items === "object") {
455
+ return Object.entries(items);
456
+ }
457
+ return [];
458
+ }
459
+ function insertComment(after, text) {
460
+ const c = document.createComment(text);
461
+ after.parentNode?.insertBefore(c, after.nextSibling);
462
+ return c;
463
+ }
464
+ function collectComments(tpl, end) {
465
+ const list = [];
466
+ let n = tpl.nextSibling;
467
+ while (n && n !== end) {
468
+ if (n.nodeType === 8 && !n.data.startsWith("/")) {
469
+ list.push([n.data, n]);
470
+ }
471
+ n = n.nextSibling;
472
+ }
473
+ return list;
474
+ }
475
+ function removeBetween(start, end) {
476
+ let current = start;
477
+ while (current && current !== end) {
478
+ const next = current.nextSibling;
479
+ current.parentNode?.removeChild(current);
480
+ current = next;
481
+ }
482
+ }
483
+ // =============================================================================
484
+ // Public API
485
+ // =============================================================================
486
+ export function setDebug(_on) {
487
+ // Debug flag is const, this is a no-op placeholder
488
+ }
489
+ export function addDirective(dir) {
490
+ directives.push(dir);
491
+ }
492
+ // Auto-register
493
+ if (typeof window !== "undefined" && window.htmx)
494
+ registerHtmxExtension();
@@ -6,10 +6,10 @@
6
6
  *
7
7
  * @example
8
8
  * ```ts
9
- * import { route, getCsrfToken, csrfFetch } from 'litestar-vite-plugin/helpers'
9
+ * import { getCsrfToken, csrfFetch } from 'litestar-vite-plugin/helpers'
10
10
  *
11
- * // Generate a URL for a named route
12
- * const url = route('user:detail', { user_id: 123 })
11
+ * // Get CSRF token
12
+ * const token = getCsrfToken()
13
13
  *
14
14
  * // Make a fetch request with CSRF token
15
15
  * await csrfFetch('/api/submit', {
@@ -18,7 +18,15 @@
18
18
  * })
19
19
  * ```
20
20
  *
21
+ * For type-safe routing, import from your generated routes file:
22
+ * ```ts
23
+ * import { route, routes, type RouteName } from '@/generated/routes'
24
+ *
25
+ * // Type-safe URL generation
26
+ * const url = route('user_detail', { user_id: 123 }) // Compile-time checked!
27
+ * ```
28
+ *
21
29
  * @module
22
30
  */
23
- export { getCsrfToken, csrfHeaders, csrfFetch } from "./csrf.js";
24
- export { route, getRoutes, toRoute, currentRoute, isRoute, isCurrentRoute, getRelativeUrlPath, LITESTAR, type RouteDefinition, type RoutesMap, type LitestarHelpers, } from "./routes.js";
31
+ export { csrfFetch, csrfHeaders, getCsrfToken } from "./csrf.js";
32
+ export { addDirective, registerHtmxExtension, setDebug as setHtmxDebug, swapJson } from "./htmx.js";
@@ -6,10 +6,10 @@
6
6
  *
7
7
  * @example
8
8
  * ```ts
9
- * import { route, getCsrfToken, csrfFetch } from 'litestar-vite-plugin/helpers'
9
+ * import { getCsrfToken, csrfFetch } from 'litestar-vite-plugin/helpers'
10
10
  *
11
- * // Generate a URL for a named route
12
- * const url = route('user:detail', { user_id: 123 })
11
+ * // Get CSRF token
12
+ * const token = getCsrfToken()
13
13
  *
14
14
  * // Make a fetch request with CSRF token
15
15
  * await csrfFetch('/api/submit', {
@@ -18,9 +18,17 @@
18
18
  * })
19
19
  * ```
20
20
  *
21
+ * For type-safe routing, import from your generated routes file:
22
+ * ```ts
23
+ * import { route, routes, type RouteName } from '@/generated/routes'
24
+ *
25
+ * // Type-safe URL generation
26
+ * const url = route('user_detail', { user_id: 123 }) // Compile-time checked!
27
+ * ```
28
+ *
21
29
  * @module
22
30
  */
23
31
  // CSRF utilities
24
- export { getCsrfToken, csrfHeaders, csrfFetch } from "./csrf.js";
25
- // Route utilities
26
- export { route, getRoutes, toRoute, currentRoute, isRoute, isCurrentRoute, getRelativeUrlPath, LITESTAR, } from "./routes.js";
32
+ export { csrfFetch, csrfHeaders, getCsrfToken } from "./csrf.js";
33
+ // HTMX utilities
34
+ export { addDirective, registerHtmxExtension, setDebug as setHtmxDebug, swapJson } from "./htmx.js";
@@ -1,4 +1,3 @@
1
- import { type ConfigEnv, type Plugin, type UserConfig } from "vite";
2
1
  import { type Config as FullReloadConfig } from "vite-plugin-full-reload";
3
2
  /**
4
3
  * Configuration for TypeScript type generation.
@@ -74,6 +73,13 @@ export interface PluginConfig {
74
73
  * @default 'public/dist'
75
74
  */
76
75
  bundleDirectory?: string;
76
+ /**
77
+ * Vite's public directory for static, unprocessed assets.
78
+ * Mirrors Vite's `publicDir` option.
79
+ *
80
+ * @default 'public'
81
+ */
82
+ publicDir?: string;
77
83
  /**
78
84
  * Litestar's public assets directory. These are the assets that Vite will serve when developing.
79
85
  *
@@ -122,18 +128,36 @@ export interface PluginConfig {
122
128
  /**
123
129
  * Enable and configure TypeScript type generation.
124
130
  *
125
- * When set to `true`, enables type generation with default settings.
126
- * When set to a TypesConfig object, enables type generation with custom settings.
131
+ * Configuration priority (highest to lowest):
132
+ * 1. Explicit vite.config.ts value - ALWAYS wins
133
+ * 2. .litestar.json value - used if no explicit config
134
+ * 3. Hardcoded defaults - fallback if nothing else
135
+ *
136
+ * When set to `"auto"` (recommended): reads all config from `.litestar.json`.
137
+ * If `.litestar.json` is missing, type generation is disabled.
138
+ *
139
+ * When set to `true`: enables type generation with hardcoded defaults.
140
+ * When set to `false`: disables type generation entirely.
141
+ * When set to a TypesConfig object: uses your explicit settings.
127
142
  *
128
- * Type generation creates TypeScript types from your Litestar OpenAPI schema
129
- * and route metadata using @hey-api/openapi-ts.
143
+ * When not specified (undefined): behaves like `"auto"` - reads from
144
+ * `.litestar.json` if present, otherwise disabled.
130
145
  *
131
146
  * @example
132
147
  * ```ts
133
- * // Simple enable
148
+ * // Recommended: auto-read from .litestar.json (simplest)
149
+ * litestar({ input: 'src/main.ts' })
150
+ *
151
+ * // Explicit auto mode
152
+ * litestar({ input: 'src/main.ts', types: 'auto' })
153
+ *
154
+ * // Force enable with hardcoded defaults (ignores .litestar.json)
134
155
  * litestar({ input: 'src/main.ts', types: true })
135
156
  *
136
- * // With custom config
157
+ * // Force disable
158
+ * litestar({ input: 'src/main.ts', types: false })
159
+ *
160
+ * // Manual override (ignores .litestar.json for types)
137
161
  * litestar({
138
162
  * input: 'src/main.ts',
139
163
  * types: {
@@ -144,9 +168,9 @@ export interface PluginConfig {
144
168
  * })
145
169
  * ```
146
170
  *
147
- * @default false
171
+ * @default undefined (auto-detect from .litestar.json)
148
172
  */
149
- types?: boolean | TypesConfig;
173
+ types?: boolean | "auto" | TypesConfig;
150
174
  /**
151
175
  * JavaScript runtime executor for package commands.
152
176
  * Used when running tools like @hey-api/openapi-ts.
@@ -162,15 +186,13 @@ interface RefreshConfig {
162
186
  paths: string[];
163
187
  config?: FullReloadConfig;
164
188
  }
165
- interface LitestarPlugin extends Plugin {
166
- config: (config: UserConfig, env: ConfigEnv) => UserConfig;
167
- }
168
189
  type DevServerUrl = `${"http" | "https"}://${string}:${number}`;
169
190
  export declare const refreshPaths: string[];
170
191
  /**
171
192
  * Litestar plugin for Vite.
172
193
  *
173
194
  * @param config - A config object or relative path(s) of the scripts to be compiled.
195
+ * @returns An array of Vite plugins. Return type is `any[]` to avoid cross-version type conflicts.
174
196
  */
175
- export default function litestar(config: string | string[] | PluginConfig): [LitestarPlugin, ...Plugin[]];
197
+ export default function litestar(config: string | string[] | PluginConfig): any[];
176
198
  export {};