@vesk/adapter 0.2.13 → 0.2.16
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/dist/client-bundle.d.ts.map +1 -1
- package/dist/client-bundle.js +21 -2
- package/dist/css.d.ts +26 -0
- package/dist/css.d.ts.map +1 -0
- package/dist/css.js +70 -0
- package/dist/dev-server.d.ts +2 -1
- package/dist/dev-server.d.ts.map +1 -1
- package/dist/dev-server.js +52 -0
- package/dist/events.d.ts +9 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +109 -0
- package/dist/hmr.d.ts.map +1 -1
- package/dist/hmr.js +21 -15
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +86 -76
- package/dist/manifest.d.ts +1 -1
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js +3 -1
- package/dist/platform-deploy.d.ts.map +1 -1
- package/dist/platform-deploy.js +1 -0
- package/dist/platform-handler.d.ts +2 -0
- package/dist/platform-handler.d.ts.map +1 -1
- package/dist/platform-handler.js +14 -2
- package/dist/prod-server.d.ts.map +1 -1
- package/dist/prod-server.js +72 -26
- package/dist/runtime-bundle.d.ts.map +1 -1
- package/dist/runtime-bundle.js +10 -0
- package/dist/ssr-function.d.ts.map +1 -1
- package/dist/ssr-function.js +13 -13
- package/dist/static.d.ts +1 -1
- package/dist/static.d.ts.map +1 -1
- package/dist/static.js +4 -3
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-bundle.d.ts","sourceRoot":"","sources":["../src/client-bundle.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,SAAS,EAAE,mBAAmB,EAAE,kBAAkB,EAAqC,MAAM,yBAAyB,CAAC;AAoCrI;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CA8BhE;AAoLD;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAkBxD;AAmCD,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,SAAS,EAAE,EACtB,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,kBAAkB,CAAC,
|
|
1
|
+
{"version":3,"file":"client-bundle.d.ts","sourceRoot":"","sources":["../src/client-bundle.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,SAAS,EAAE,mBAAmB,EAAE,kBAAkB,EAAqC,MAAM,yBAAyB,CAAC;AAoCrI;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CA8BhE;AAoLD;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAkBxD;AAmCD,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,SAAS,EAAE,EACtB,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,kBAAkB,CAAC,CA4T7B;AAMD,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CA+B3D;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAUlE;AAYD;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAuCrG"}
|
package/dist/client-bundle.js
CHANGED
|
@@ -459,6 +459,21 @@ export async function generateClientBundle(routeTree, appDir, componentMap, opti
|
|
|
459
459
|
return slug.replace(/[\[\]]/g, '_');
|
|
460
460
|
}
|
|
461
461
|
const codeSplit = !!(options?.codeSplit);
|
|
462
|
+
const transformPlugins = options?.plugins || [];
|
|
463
|
+
/** Run every active plugin's `onTransformJS` over an emitted bundle/chunk source. */
|
|
464
|
+
async function applyTransformPlugins(code, filePath) {
|
|
465
|
+
if (transformPlugins.length === 0)
|
|
466
|
+
return code;
|
|
467
|
+
let out = code;
|
|
468
|
+
for (const plugin of transformPlugins) {
|
|
469
|
+
if (typeof plugin.onTransformJS === 'function') {
|
|
470
|
+
const result = await plugin.onTransformJS(out, filePath);
|
|
471
|
+
if (typeof result === 'string')
|
|
472
|
+
out = result;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
return out;
|
|
476
|
+
}
|
|
462
477
|
if (codeSplit) {
|
|
463
478
|
const chunkEntries = [];
|
|
464
479
|
function walkSplit(nodes, _chain) {
|
|
@@ -537,7 +552,11 @@ export async function generateClientBundle(routeTree, appDir, componentMap, opti
|
|
|
537
552
|
if (cache)
|
|
538
553
|
cache.mainBundle = { key: mainKey, code: main };
|
|
539
554
|
}
|
|
540
|
-
|
|
555
|
+
const transformedChunks = [];
|
|
556
|
+
for (const chunk of chunks) {
|
|
557
|
+
transformedChunks.push({ ...chunk, code: await applyTransformPlugins(chunk.code, chunk.name) });
|
|
558
|
+
}
|
|
559
|
+
return { main: await applyTransformPlugins(main, 'client.js'), chunks: transformedChunks, cachedFileHits, compiledFiles, mainFromCache, editedSources, editedNames };
|
|
541
560
|
}
|
|
542
561
|
else {
|
|
543
562
|
let componentLines = [];
|
|
@@ -603,7 +622,7 @@ export async function generateClientBundle(routeTree, appDir, componentMap, opti
|
|
|
603
622
|
componentLines, hydratorLines, aliasLines, hydratorAliasLines,
|
|
604
623
|
}, !!options?.hmr, !!options?.importRuntime, runtimeImportNames, options?.routeDataCache);
|
|
605
624
|
// Mono (non-codeSplit) builds are the production path — no incremental cache.
|
|
606
|
-
return { main, chunks: [] };
|
|
625
|
+
return { main: await applyTransformPlugins(main, 'client.js'), chunks: [] };
|
|
607
626
|
}
|
|
608
627
|
}
|
|
609
628
|
function stripTypes(code) {
|
package/dist/css.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export declare const TAILWIND_CSS_URL = "/_vesk/static/_tailwind.css";
|
|
2
|
+
export declare const GLOBAL_CSS_URL = "/_vesk/static/global.css";
|
|
3
|
+
/** Resolve the project's user stylesheet source (`src/global.css`, then `src/app.css`). */
|
|
4
|
+
export declare function resolveUserCssPath(appDir: string): string | null;
|
|
5
|
+
/** True when the project has a user stylesheet source (`src/global.css` or `src/app.css`). */
|
|
6
|
+
export declare function hasUserCss(appDir: string): boolean;
|
|
7
|
+
/** True when a non-empty `_tailwind.css` was produced for the build (prod disk output). */
|
|
8
|
+
export declare function hasBuiltTailwindCss(outDir: string): boolean;
|
|
9
|
+
/** True when the active plugin pipeline includes the tailwind plugin. */
|
|
10
|
+
export declare function isTailwindPlugin(plugins: Array<{
|
|
11
|
+
name?: string;
|
|
12
|
+
}> | undefined | null): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Single source of truth for the `/_vesk/static/*.css` link list. Callers
|
|
15
|
+
* supply environment facts — `tailwind`: tailwind output is available
|
|
16
|
+
* (built-file present + non-empty in prod, active plugin in dev);
|
|
17
|
+
* `userCss`: a user stylesheet exists — so build, request, dev, and prod
|
|
18
|
+
* paths share one ordering.
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveCssUrls(opts: {
|
|
21
|
+
tailwind?: boolean;
|
|
22
|
+
userCss?: boolean;
|
|
23
|
+
}): string[];
|
|
24
|
+
/** Drop tailwind framework directives from user CSS, keeping hand-written rules. */
|
|
25
|
+
export declare function stripTailwindDirectives(css: string): string;
|
|
26
|
+
//# sourceMappingURL=css.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"css.d.ts","sourceRoot":"","sources":["../src/css.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,gBAAgB,gCAAgC,CAAC;AAC9D,eAAO,MAAM,cAAc,6BAA6B,CAAC;AAEzD,2FAA2F;AAC3F,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMhE;AAED,8FAA8F;AAC9F,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAElD;AAED,2FAA2F;AAC3F,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAG3D;AAED,yEAAyE;AACzE,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,CAE9F;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,EAAE,CAKxF;AAED,oFAAoF;AACpF,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAkB3D"}
|
package/dist/css.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared stylesheet resolution for the adapter build, prod server, generated
|
|
3
|
+
* SSR functions, dev server, and action handler. Each environment feeds its
|
|
4
|
+
* facts (`tailwind` output available, user stylesheet present) into
|
|
5
|
+
* `resolveCssUrls`, so the `/_vesk/static/*.css` link list and its ordering
|
|
6
|
+
* come from one place instead of six ad-hoc copies.
|
|
7
|
+
*/
|
|
8
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
9
|
+
import { resolve } from 'node:path';
|
|
10
|
+
import { cssBlockEnd } from '@vesk/compiler/src/scan';
|
|
11
|
+
export const TAILWIND_CSS_URL = '/_vesk/static/_tailwind.css';
|
|
12
|
+
export const GLOBAL_CSS_URL = '/_vesk/static/global.css';
|
|
13
|
+
/** Resolve the project's user stylesheet source (`src/global.css`, then `src/app.css`). */
|
|
14
|
+
export function resolveUserCssPath(appDir) {
|
|
15
|
+
const cssSrc = resolve(appDir, '..', 'src', 'global.css');
|
|
16
|
+
if (existsSync(cssSrc))
|
|
17
|
+
return cssSrc;
|
|
18
|
+
const altCssSrc = resolve(appDir, '..', 'src', 'app.css');
|
|
19
|
+
if (existsSync(altCssSrc))
|
|
20
|
+
return altCssSrc;
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
/** True when the project has a user stylesheet source (`src/global.css` or `src/app.css`). */
|
|
24
|
+
export function hasUserCss(appDir) {
|
|
25
|
+
return resolveUserCssPath(appDir) !== null;
|
|
26
|
+
}
|
|
27
|
+
/** True when a non-empty `_tailwind.css` was produced for the build (prod disk output). */
|
|
28
|
+
export function hasBuiltTailwindCss(outDir) {
|
|
29
|
+
const p = resolve(outDir, 'static', '_tailwind.css');
|
|
30
|
+
return existsSync(p) && readFileSync(p, 'utf-8').trim().length > 0;
|
|
31
|
+
}
|
|
32
|
+
/** True when the active plugin pipeline includes the tailwind plugin. */
|
|
33
|
+
export function isTailwindPlugin(plugins) {
|
|
34
|
+
return (plugins || []).some((p) => String(p && p.name).toLowerCase().includes('tailwind'));
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Single source of truth for the `/_vesk/static/*.css` link list. Callers
|
|
38
|
+
* supply environment facts — `tailwind`: tailwind output is available
|
|
39
|
+
* (built-file present + non-empty in prod, active plugin in dev);
|
|
40
|
+
* `userCss`: a user stylesheet exists — so build, request, dev, and prod
|
|
41
|
+
* paths share one ordering.
|
|
42
|
+
*/
|
|
43
|
+
export function resolveCssUrls(opts) {
|
|
44
|
+
const urls = [];
|
|
45
|
+
if (opts.tailwind)
|
|
46
|
+
urls.push(TAILWIND_CSS_URL);
|
|
47
|
+
if (opts.userCss)
|
|
48
|
+
urls.push(GLOBAL_CSS_URL);
|
|
49
|
+
return urls;
|
|
50
|
+
}
|
|
51
|
+
/** Drop tailwind framework directives from user CSS, keeping hand-written rules. */
|
|
52
|
+
export function stripTailwindDirectives(css) {
|
|
53
|
+
const blockStart = /^\s*@(theme\s*\{|layer\s+(components|utilities)\s*\{|utility\s+[\w-]+\s*\{)/;
|
|
54
|
+
let result = css.replace(/^\s*@import\s+['"]tailwindcss['"]\s*;?\s*$/gm, '');
|
|
55
|
+
result = result.replace(/^\s*@source\s+['"][^'"]+['"]\s*;?\s*$/gm, '');
|
|
56
|
+
const output = [];
|
|
57
|
+
let pos = 0;
|
|
58
|
+
while (pos < result.length) {
|
|
59
|
+
const lineEnd = result.indexOf('\n', pos) === -1 ? result.length : result.indexOf('\n', pos) + 1;
|
|
60
|
+
const line = result.slice(pos, lineEnd);
|
|
61
|
+
if (blockStart.test(line.trim())) {
|
|
62
|
+
const end = cssBlockEnd(result, pos);
|
|
63
|
+
pos = end;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
output.push(line);
|
|
67
|
+
pos = lineEnd;
|
|
68
|
+
}
|
|
69
|
+
return output.join('').trim();
|
|
70
|
+
}
|
package/dist/dev-server.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type Server } from 'node:http';
|
|
2
|
+
import type { HmrErrorPayload } from './hmr';
|
|
2
3
|
import type { DevServerOptions } from '@vesk/adapter/src/types';
|
|
3
4
|
/**
|
|
4
5
|
* Shape returned by the dev HMR state endpoint. Mirrors what the parallel
|
|
@@ -9,7 +10,7 @@ import type { DevServerOptions } from '@vesk/adapter/src/types';
|
|
|
9
10
|
export interface DevHmrState {
|
|
10
11
|
status: 'up' | 'compiling' | 'error' | 'down';
|
|
11
12
|
lastCompileMs: number | null;
|
|
12
|
-
error: Record<string, unknown> | null;
|
|
13
|
+
error: HmrErrorPayload | Record<string, unknown> | null;
|
|
13
14
|
hasError: boolean;
|
|
14
15
|
componentCount: number;
|
|
15
16
|
/** Whether the @vesk/agentic plugin is installed and active (mirrors the
|
package/dist/dev-server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-server.d.ts","sourceRoot":"","sources":["../src/dev-server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,KAAK,MAAM,EAA6C,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"dev-server.d.ts","sourceRoot":"","sources":["../src/dev-server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,KAAK,MAAM,EAA6C,MAAM,WAAW,CAAC;AAOjG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AAI7C,OAAO,KAAK,EAAa,gBAAgB,EAAwB,MAAM,yBAAyB,CAAC;AAgBjG;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,IAAI,GAAG,WAAW,GAAG,OAAO,GAAG,MAAM,CAAC;IAC9C,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,KAAK,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACxD,QAAQ,EAAE,OAAO,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB;+EAC2E;IAC3E,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,mEAAmE;AACnE,wBAAgB,kBAAkB,IAAI,WAAW,CAEhD;AAuCD,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAIzE;AAkBD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,mHAAmH;IACnH,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC7B;;8BAE0B;IAC1B,MAAM,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,UAAU,GAAG,YAAY,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,WAAW,CAAC;IAChC,8EAA8E;IAC9E,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3E;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,wBAAwB,GAAG;IACvE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;CAChH,CAUA;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAa3C;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIrD;AA8CD,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA8hBvG"}
|
package/dist/dev-server.js
CHANGED
|
@@ -192,6 +192,7 @@ const MIME = {
|
|
|
192
192
|
'.svg': 'image/svg+xml', '.css': 'text/css', '.js': 'application/javascript',
|
|
193
193
|
'.png': 'image/png', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg',
|
|
194
194
|
'.ico': 'image/x-icon', '.html': 'text/html', '.json': 'application/json',
|
|
195
|
+
'.webmanifest': 'application/manifest+json',
|
|
195
196
|
'.woff': 'font/woff', '.woff2': 'font/woff2', '.wasm': 'application/wasm',
|
|
196
197
|
};
|
|
197
198
|
export async function startDevServer(appDir, options) {
|
|
@@ -354,6 +355,20 @@ export async function startDevServer(appDir, options) {
|
|
|
354
355
|
let ssrVersion = Date.now();
|
|
355
356
|
let routeTree = [];
|
|
356
357
|
let runtimeBundle = '';
|
|
358
|
+
let eventsMod = null;
|
|
359
|
+
async function reloadEventsMod() {
|
|
360
|
+
const eventsPath = resolve(devDir, 'server', 'events.js');
|
|
361
|
+
if (existsSync(eventsPath)) {
|
|
362
|
+
try {
|
|
363
|
+
eventsMod = await import(`${eventsPath}?t=${Date.now()}`);
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
catch {
|
|
367
|
+
// ignore — events file present but failed to load
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
eventsMod = null;
|
|
371
|
+
}
|
|
357
372
|
async function doBuild() {
|
|
358
373
|
const start = Date.now();
|
|
359
374
|
try {
|
|
@@ -367,6 +382,7 @@ export async function startDevServer(appDir, options) {
|
|
|
367
382
|
const monorepoRoot = resolve(__dirname, '..', '..', '..');
|
|
368
383
|
const runtimeDir = resolve(monorepoRoot, 'packages', 'runtime', 'dist');
|
|
369
384
|
runtimeBundle = buildRuntimeCode(runtimeDir);
|
|
385
|
+
await reloadEventsMod();
|
|
370
386
|
lastBuild = Date.now();
|
|
371
387
|
console.error(`vesk dev: rebuilt in ${Date.now() - start}ms`);
|
|
372
388
|
}
|
|
@@ -504,6 +520,24 @@ export async function startDevServer(appDir, options) {
|
|
|
504
520
|
return;
|
|
505
521
|
}
|
|
506
522
|
}
|
|
523
|
+
if (eventsMod) {
|
|
524
|
+
const serverStore = globalThis.__vesk_server_ctx || {};
|
|
525
|
+
const webRequest = makeWebRequest(req, url.href, maxBodyBytes);
|
|
526
|
+
const evtCtx = {
|
|
527
|
+
request: webRequest,
|
|
528
|
+
params: {},
|
|
529
|
+
url,
|
|
530
|
+
locals: Object.assign({}, serverStore),
|
|
531
|
+
cookies: {},
|
|
532
|
+
};
|
|
533
|
+
globalThis.__vesk_request = evtCtx;
|
|
534
|
+
try {
|
|
535
|
+
await eventsMod.executeRequest?.(evtCtx);
|
|
536
|
+
}
|
|
537
|
+
catch (e) {
|
|
538
|
+
console.error('vesk request: onRequest error:', e instanceof Error ? e.message : e);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
507
541
|
if (config && url.pathname.startsWith('/_vesk/action/')) {
|
|
508
542
|
const actionId = url.pathname.replace('/_vesk/action/', '');
|
|
509
543
|
const actionEntry = config.actions && config.actions.find(a => a.id === actionId);
|
|
@@ -675,6 +709,24 @@ export async function startDevServer(appDir, options) {
|
|
|
675
709
|
catch (e) {
|
|
676
710
|
console.error('vesk dev: file watching unavailable');
|
|
677
711
|
}
|
|
712
|
+
const bootEventsMod = eventsMod;
|
|
713
|
+
try {
|
|
714
|
+
await bootEventsMod?.executeStart?.({ server, port, host });
|
|
715
|
+
}
|
|
716
|
+
catch (e) {
|
|
717
|
+
console.error('vesk dev: onStart error:', e instanceof Error ? e.message : e);
|
|
718
|
+
}
|
|
719
|
+
server.on('close', () => {
|
|
720
|
+
void (async () => {
|
|
721
|
+
const stopEventsMod = eventsMod;
|
|
722
|
+
try {
|
|
723
|
+
await stopEventsMod?.executeStop?.({ server, port, host });
|
|
724
|
+
}
|
|
725
|
+
catch (e) {
|
|
726
|
+
console.error('vesk dev: onStop error:', e instanceof Error ? e.message : e);
|
|
727
|
+
}
|
|
728
|
+
})();
|
|
729
|
+
});
|
|
678
730
|
await new Promise(resolve => {
|
|
679
731
|
server.listen(port, host, () => {
|
|
680
732
|
console.error(`vesk dev server at http://localhost:${port} (listening on ${host})`);
|
package/dist/events.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compile the app's `_events.ts` (if present) into a self-contained
|
|
3
|
+
* `server/events.js` next to the server runtime. Returns true when an events
|
|
4
|
+
* file existed and was compiled. Relative imports inside `_events.ts` are
|
|
5
|
+
* bundled by esbuild; node builtins stay external so node (prod-server) and
|
|
6
|
+
* edge (platform handler) can both resolve them.
|
|
7
|
+
*/
|
|
8
|
+
export declare function compileEvents(appDir: string, outDir: string): Promise<boolean>;
|
|
9
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAqEA;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAiCpF"}
|
package/dist/events.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { writeFileSync, unlinkSync, mkdirSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import * as esbuild from './esbuild-fallback.js';
|
|
4
|
+
import { collectEventsFile } from '@vesk/compiler/src/events';
|
|
5
|
+
let buildId = 0;
|
|
6
|
+
/**
|
|
7
|
+
* Wrapper module bundled into `server/events.js`. It lifts the user's
|
|
8
|
+
* `_events.ts` exports into `executeStart` / `executeRequest` / `executeStop`
|
|
9
|
+
* entry points with a context that routes `set`/`get` into the process-wide
|
|
10
|
+
* server context (`globalThis.__vesk_server_ctx`).
|
|
11
|
+
*
|
|
12
|
+
* The `__vesk_events_started` guard is global (not module-local) so lazy edge
|
|
13
|
+
* isolates and the Node prod server share one lifetime; `onStop` clears it so
|
|
14
|
+
* dev HMR reloads can boot a fresh module.
|
|
15
|
+
*/
|
|
16
|
+
function buildEntry(sourcePath) {
|
|
17
|
+
return [
|
|
18
|
+
`import * as __events from ${JSON.stringify(sourcePath)};`,
|
|
19
|
+
'',
|
|
20
|
+
'const __store = () => (globalThis.__vesk_server_ctx ||= {});',
|
|
21
|
+
'',
|
|
22
|
+
'const __handlers = {};',
|
|
23
|
+
"for (const __name of ['onStart', 'onRequest', 'onStop']) {",
|
|
24
|
+
' const __fn = __events[__name];',
|
|
25
|
+
" if (typeof __fn === 'function') __handlers[__name] = __fn;",
|
|
26
|
+
'}',
|
|
27
|
+
'',
|
|
28
|
+
'function __makeCtx(base) {',
|
|
29
|
+
' const store = __store();',
|
|
30
|
+
' const start = base && typeof base === \'object\' ? base : {};',
|
|
31
|
+
' return Object.assign({}, start, {',
|
|
32
|
+
' server: start.server !== undefined ? start.server : null,',
|
|
33
|
+
' port: start.port !== undefined ? start.port : 0,',
|
|
34
|
+
' host: start.host,',
|
|
35
|
+
' serverLocals: store,',
|
|
36
|
+
' set(key, value) { store[key] = value; return value; },',
|
|
37
|
+
' get(key) { return store[key]; },',
|
|
38
|
+
' });',
|
|
39
|
+
'}',
|
|
40
|
+
'',
|
|
41
|
+
'export async function executeStart(base) {',
|
|
42
|
+
' if (globalThis.__vesk_events_started) return;',
|
|
43
|
+
' globalThis.__vesk_events_started = true;',
|
|
44
|
+
' if (typeof __handlers.onStart === \'function\') await __handlers.onStart(__makeCtx(base));',
|
|
45
|
+
'}',
|
|
46
|
+
'',
|
|
47
|
+
'export async function executeRequest(base) {',
|
|
48
|
+
' if (typeof __handlers.onRequest !== \'function\') return;',
|
|
49
|
+
' await __handlers.onRequest(__makeCtx(base));',
|
|
50
|
+
'}',
|
|
51
|
+
'',
|
|
52
|
+
'export async function executeStop(base) {',
|
|
53
|
+
' if (typeof __handlers.onStop !== \'function\') return;',
|
|
54
|
+
' try {',
|
|
55
|
+
' await __handlers.onStop(__makeCtx(base));',
|
|
56
|
+
' } finally {',
|
|
57
|
+
' globalThis.__vesk_events_started = false;',
|
|
58
|
+
' }',
|
|
59
|
+
'}',
|
|
60
|
+
'',
|
|
61
|
+
'export const onStart = __handlers.onStart;',
|
|
62
|
+
'export const onRequest = __handlers.onRequest;',
|
|
63
|
+
'export const onStop = __handlers.onStop;',
|
|
64
|
+
'',
|
|
65
|
+
].join('\n');
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Compile the app's `_events.ts` (if present) into a self-contained
|
|
69
|
+
* `server/events.js` next to the server runtime. Returns true when an events
|
|
70
|
+
* file existed and was compiled. Relative imports inside `_events.ts` are
|
|
71
|
+
* bundled by esbuild; node builtins stay external so node (prod-server) and
|
|
72
|
+
* edge (platform handler) can both resolve them.
|
|
73
|
+
*/
|
|
74
|
+
export async function compileEvents(appDir, outDir) {
|
|
75
|
+
const sourcePath = collectEventsFile(appDir);
|
|
76
|
+
if (!sourcePath)
|
|
77
|
+
return false;
|
|
78
|
+
const serverDir = resolve(outDir, 'server');
|
|
79
|
+
mkdirSync(serverDir, { recursive: true });
|
|
80
|
+
const entryFile = resolve(serverDir, `.events-entry-${buildId++}.mjs`);
|
|
81
|
+
writeFileSync(entryFile, buildEntry(sourcePath), 'utf-8');
|
|
82
|
+
try {
|
|
83
|
+
const result = await esbuild.build({
|
|
84
|
+
entryPoints: [entryFile],
|
|
85
|
+
bundle: true,
|
|
86
|
+
platform: 'neutral',
|
|
87
|
+
format: 'esm',
|
|
88
|
+
minify: true,
|
|
89
|
+
outfile: resolve(serverDir, 'events.js'),
|
|
90
|
+
external: ['fs', 'node:fs', 'path', 'node:path', 'module', 'node:module', 'node:async_hooks'],
|
|
91
|
+
target: ['es2022'],
|
|
92
|
+
treeShaking: true,
|
|
93
|
+
});
|
|
94
|
+
if (result.errors.length > 0) {
|
|
95
|
+
throw new Error(`esbuild errors: ${result.errors.map((e) => e.text).join(', ')}`);
|
|
96
|
+
}
|
|
97
|
+
if (result.warnings.length > 0) {
|
|
98
|
+
for (const w of result.warnings)
|
|
99
|
+
console.error('vesk build warning:', w.text);
|
|
100
|
+
}
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
try {
|
|
105
|
+
unlinkSync(entryFile);
|
|
106
|
+
}
|
|
107
|
+
catch { /* ignore */ }
|
|
108
|
+
}
|
|
109
|
+
}
|
package/dist/hmr.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hmr.d.ts","sourceRoot":"","sources":["../src/hmr.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"hmr.d.ts","sourceRoot":"","sources":["../src/hmr.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAUxC,OAAO,EAAsC,KAAK,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAEvG,OAAO,KAAK,EAAE,SAAS,EAAkB,MAAM,yBAAyB,CAAC;AAIzE;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAaD,wBAAgB,WAAW,IAAI;IAC7B,MAAM,EAAE,IAAI,GAAG,QAAQ,CAAC;IACxB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAQA;AAED,MAAM,WAAW,wBAAwB;IACvC,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wEAAwE;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,wBAA6B,GAClC,eAAe,CAsEjB;AA0RD,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GACjC;IACD,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAClE,gBAAgB,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvH,WAAW,EAAE,MAAM,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;CACnD,CAyJA"}
|
package/dist/hmr.js
CHANGED
|
@@ -6,6 +6,7 @@ import { compileClient } from '@vesk/compiler/src/client-codegen';
|
|
|
6
6
|
import { buildHmrEvalSnippet } from './client-bundle';
|
|
7
7
|
import { resolveComponentName, randomToken } from '@vesk/compiler/src/server-codegen';
|
|
8
8
|
import { resolveErrorFile } from '@vesk/adapter/src/ssr-function';
|
|
9
|
+
import { resolveCssUrls, hasUserCss, hasBuiltTailwindCss } from '@vesk/adapter/src/css';
|
|
9
10
|
import { isAllowedWsUpgrade } from '@vesk/adapter/src/paths';
|
|
10
11
|
import { parseCompilerError, buildCodeframe } from '@vesk/adapter/src/error-codeframe';
|
|
11
12
|
import { suggestFor } from '@vesk/adapter/src/error-tips';
|
|
@@ -78,11 +79,19 @@ export function buildErrorPayload(error, filename, opts = {}) {
|
|
|
78
79
|
const filePath = typeof opts.appDir === 'string'
|
|
79
80
|
? resolve(opts.appDir, file)
|
|
80
81
|
: undefined;
|
|
82
|
+
// The file header already shows the location; strip the redundant
|
|
83
|
+
// " in <file>" suffix compilers append to messages (e.g. acorn's
|
|
84
|
+
// "Unexpected token in /abs/app/page.vsk").
|
|
85
|
+
const cleanMessage = filePath && message.endsWith(` in ${filePath}`)
|
|
86
|
+
? message.slice(0, -` in ${filePath}`.length).trim()
|
|
87
|
+
: message.endsWith(` in ${file}`)
|
|
88
|
+
? message.slice(0, -` in ${file}`.length).trim()
|
|
89
|
+
: message;
|
|
81
90
|
const payload = {
|
|
82
91
|
file,
|
|
83
92
|
line,
|
|
84
93
|
column,
|
|
85
|
-
message,
|
|
94
|
+
message: cleanMessage,
|
|
86
95
|
};
|
|
87
96
|
if (filePath)
|
|
88
97
|
payload.filePath = filePath;
|
|
@@ -232,19 +241,16 @@ function buildParamExtraction(node, urlParts) {
|
|
|
232
241
|
}
|
|
233
242
|
function regenerateSsrFunction(routeNode, appDir, outDir, componentMap, options) {
|
|
234
243
|
const ancestorLayouts = options?.ancestorLayouts || [];
|
|
244
|
+
const headExtra = options?.headExtra || null;
|
|
235
245
|
const pagePath = resolve(appDir, routeNode.sourceDir, 'page.vsk');
|
|
236
246
|
const layoutPath = resolve(appDir, routeNode.sourceDir, 'layout.vsk');
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
const hasTailwind = existsSync(tailwindPath) && readFileSync(tailwindPath, 'utf-8').trim().length > 0;
|
|
242
|
-
const cssUrls = [];
|
|
243
|
-
if (hasTailwind)
|
|
244
|
-
cssUrls.push('/_vesk/static/_tailwind.css');
|
|
245
|
-
if (hasGlobalCss)
|
|
246
|
-
cssUrls.push('/_vesk/static/global.css');
|
|
247
|
+
const cssUrls = resolveCssUrls({
|
|
248
|
+
tailwind: hasBuiltTailwindCss(outDir),
|
|
249
|
+
userCss: hasUserCss(appDir),
|
|
250
|
+
});
|
|
247
251
|
const cssOption = cssUrls.length > 0 ? `, cssUrls: ${JSON.stringify(cssUrls)}` : '';
|
|
252
|
+
const headExtraOption = headExtra ? `, headExtra: ${JSON.stringify(headExtra)}` : '';
|
|
253
|
+
const bakedOptions = cssOption + headExtraOption;
|
|
248
254
|
const parts = routeNode.fullPath.split('/').filter(Boolean);
|
|
249
255
|
const name = routeName(parts);
|
|
250
256
|
const funcDir = resolve(outDir, 'server', 'functions');
|
|
@@ -323,7 +329,7 @@ function regenerateSsrFunction(routeNode, appDir, outDir, componentMap, options)
|
|
|
323
329
|
" const stack = err && typeof err === 'object' && 'stack' in err ? String(err.stack) : '';",
|
|
324
330
|
" page = { body: await __renderErrorBody({ params, statusCode: 500, error: message, stack, url: url.href }), head: '' };",
|
|
325
331
|
' }',
|
|
326
|
-
' const html = await renderFullPage(_layoutSrc, _layoutComp, { params, children: (caughtError ? \'<!--vesk-ssr-error:\' + (caughtError && typeof caughtError === \'object\' && \'message\' in caughtError ? encodeURIComponent(String(caughtError.message)) : \'\') + \'-->\' : \'\') + page.body }, __componentRegistry, { hydrate: true, cached: _layoutCompiled' +
|
|
332
|
+
' const html = await renderFullPage(_layoutSrc, _layoutComp, { params, children: (caughtError ? \'<!--vesk-ssr-error:\' + (caughtError && typeof caughtError === \'object\' && \'message\' in caughtError ? encodeURIComponent(String(caughtError.message)) : \'\') + \'-->\' : \'\') + page.body }, __componentRegistry, { hydrate: true, cached: _layoutCompiled' + bakedOptions + clientScriptOption + dataScriptOption + ', pageHead: page.head, sourcePath: _layoutPath });',
|
|
327
333
|
" return new Response(html, { headers: { 'Content-Type': 'text/html' }, status: caughtError ? 500 : 200 });",
|
|
328
334
|
].join('\n');
|
|
329
335
|
}
|
|
@@ -340,7 +346,7 @@ function regenerateSsrFunction(routeNode, appDir, outDir, componentMap, options)
|
|
|
340
346
|
" const stack = err && typeof err === 'object' && 'stack' in err ? String(err.stack) : '';",
|
|
341
347
|
" page = { body: await __renderErrorBody({ params, statusCode: 500, error: message, stack, url: url.href }), head: '' };",
|
|
342
348
|
' }',
|
|
343
|
-
' const html = await renderFullPage(_layoutSrc, _layoutComp, { params, children: (caughtError ? \'<!--vesk-ssr-error:\' + (caughtError && typeof caughtError === \'object\' && \'message\' in caughtError ? encodeURIComponent(String(caughtError.message)) : \'\') + \'-->\' : \'\') + page.body }, __componentRegistry, { hydrate: true, cached: _layoutCompiled' +
|
|
349
|
+
' const html = await renderFullPage(_layoutSrc, _layoutComp, { params, children: (caughtError ? \'<!--vesk-ssr-error:\' + (caughtError && typeof caughtError === \'object\' && \'message\' in caughtError ? encodeURIComponent(String(caughtError.message)) : \'\') + \'-->\' : \'\') + page.body }, __componentRegistry, { hydrate: true, cached: _layoutCompiled' + bakedOptions + clientScriptOption + dataScriptOption + ', pageHead: page.head, sourcePath: _layoutPath });',
|
|
344
350
|
" return new Response(html, { headers: { 'Content-Type': 'text/html' }, status: caughtError ? 500 : 200 });",
|
|
345
351
|
].join('\n');
|
|
346
352
|
}
|
|
@@ -348,13 +354,13 @@ function regenerateSsrFunction(routeNode, appDir, outDir, componentMap, options)
|
|
|
348
354
|
renderCode = [
|
|
349
355
|
' let stream;',
|
|
350
356
|
' try {',
|
|
351
|
-
' stream = renderPageStream(_src, _comp, { params }, __componentRegistry, { hydrate: true, cached: _srcCompiled' +
|
|
357
|
+
' stream = renderPageStream(_src, _comp, { params }, __componentRegistry, { hydrate: true, cached: _srcCompiled' + bakedOptions + clientScriptOption + dataScriptOption + ", sourcePath: _srcPath });",
|
|
352
358
|
' } catch (err) {',
|
|
353
359
|
' if (err && (err.name === \'NotFoundError\' || err.name === \'Redirect\')) throw err;',
|
|
354
360
|
' if (!_errorSrc) throw err;',
|
|
355
361
|
" const message = err && typeof err === 'object' && 'message' in err ? String(err.message) : String(err);",
|
|
356
362
|
" const stack = err && typeof err === 'object' && 'stack' in err ? String(err.stack) : '';",
|
|
357
|
-
" const html = await renderFullPage(_errorSrc, _errorComp, { params, statusCode: 500, error: message, stack, url: url.href }, __componentRegistry, { hydrate: true, cached: _errorCompiled" +
|
|
363
|
+
" const html = await renderFullPage(_errorSrc, _errorComp, { params, statusCode: 500, error: message, stack, url: url.href }, __componentRegistry, { hydrate: true, cached: _errorCompiled" + bakedOptions + clientScriptOption + dataScriptOption + ', sourcePath: _errorPath });',
|
|
358
364
|
" return new Response(html, { headers: { 'Content-Type': 'text/html' }, status: 500 });",
|
|
359
365
|
' }',
|
|
360
366
|
' return new Response(new ReadableStream({',
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EACe,YAAY,EAAE,WAAW,EAC7B,UAAU,EAChC,MAAM,yBAAyB,CAAC;AAiBjC;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;CACjB;AACD,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,iBAAiB,EAAE,CAAC;CAC9B;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,UAAU,EAAE,EACrB,OAAO,EAAE,iBAAiB,EAAE,GAAG,IAAI,GAAG,SAAS,GAC9C,UAAU,EAAE,CAQd;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,UAAU,EAAE,EACrB,KAAK,EAAE,eAAe,GAAG,IAAI,GAAG,SAAS,GACxC,UAAU,EAAE,CAGd;AA+BD,wBAAsB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAyUpG;AAED,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAIhE,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,yBAAyB,EACzB,eAAe,GAChB,MAAM,2BAA2B,CAAC;AACnC,YAAY,EACV,mBAAmB,EACnB,YAAY,EACZ,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,aAAa,GACd,MAAM,2BAA2B,CAAC"}
|