@vesk/adapter 0.2.15 → 0.2.17

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.
@@ -208,7 +208,7 @@ function tryParseJsObject(src) {
208
208
  while (i < src.length && /\s/.test(src[i]))
209
209
  i++;
210
210
  if (src[i] === '=')
211
- return null; // `key = value` — not a literal object; bail
211
+ return null;
212
212
  if (src[i] !== ':')
213
213
  return null;
214
214
  i++;
@@ -222,10 +222,62 @@ function tryParseJsObject(src) {
222
222
  }
223
223
  return out;
224
224
  }
225
+ /** Skip a balanced (…) expression starting at `i`, returning the index after the closing ')' (or on failure, `i` unchanged). */
226
+ function skipBalancedParens(src, i) {
227
+ if (src[i] !== '(')
228
+ return i;
229
+ let depth = 0;
230
+ let inStr = null;
231
+ let esc = false;
232
+ for (let j = i; j < src.length; j++) {
233
+ const ch = src[j];
234
+ if (inStr) {
235
+ if (esc) {
236
+ esc = false;
237
+ continue;
238
+ }
239
+ if (ch === '\\') {
240
+ esc = true;
241
+ continue;
242
+ }
243
+ if (ch === inStr)
244
+ inStr = null;
245
+ continue;
246
+ }
247
+ if (ch === '"' || ch === "'" || ch === '`') {
248
+ inStr = ch;
249
+ continue;
250
+ }
251
+ if (ch === '(')
252
+ depth++;
253
+ if (ch === ')') {
254
+ depth--;
255
+ if (depth === 0)
256
+ return j + 1;
257
+ }
258
+ }
259
+ return i; // unbalanced — bail
260
+ }
261
+ /**
262
+ * Return a raw source span (used for function calls, variable refs, spreads
263
+ * that can't be round-tripped as literals). The value is stored as a wrapper
264
+ * object so serializeValue can emit it verbatim.
265
+ */
266
+ function rawSpan(src, from, to) {
267
+ return { value: { __veskRaw: src.slice(from, to) }, next: to };
268
+ }
225
269
  function parseLiteralValue(src, i) {
226
270
  const c = src[i];
227
271
  if (c === undefined)
228
272
  return null;
273
+ // spread: ...expr
274
+ if (c === '.' && src.slice(i, i + 3) === '...') {
275
+ const expr = parseLiteralValue(src, i + 3);
276
+ if (expr === null || expr.__invalid)
277
+ return rawSpan(src, i, skipToEndOfRaw(src, i + 3));
278
+ // preserve spread marker in the serialized output
279
+ return { value: { __veskRaw: '...' + serializeValue(expr.value) }, next: expr.next };
280
+ }
229
281
  if (c === '{') {
230
282
  const end = findMatchingBrace(src, i);
231
283
  if (end === -1)
@@ -251,8 +303,10 @@ function parseLiteralValue(src, i) {
251
303
  continue;
252
304
  }
253
305
  const r = parseLiteralValue(src, j);
254
- if (r === null || r.__invalid)
255
- return { value: undefined, next: i, __invalid: true };
306
+ if (r === null || r.__invalid) {
307
+ // Can't parse this array element — fall back to raw span for the whole array
308
+ return rawSpan(src, i, skipToEndOfArray(src, i));
309
+ }
256
310
  vals.push(r.value);
257
311
  j = r.next;
258
312
  }
@@ -268,6 +322,7 @@ function parseLiteralValue(src, i) {
268
322
  }
269
323
  return { value: s, next: j + 1 };
270
324
  }
325
+ // identifiers, numbers, booleans, null, and tokens followed by '(' (function calls)
271
326
  let j = i;
272
327
  while (j < src.length && /[\w.\-]/.test(src[j]))
273
328
  j++;
@@ -280,8 +335,86 @@ function parseLiteralValue(src, i) {
280
335
  return { value: null, next: j };
281
336
  if (/^-?\d+(\.\d+)?([eE][+-]?\d+)?$/.test(token))
282
337
  return { value: Number(token), next: j };
338
+ // token is an identifier or a function name — check if it's followed by '(' (call)
339
+ if (j < src.length && src[j] === '(') {
340
+ const end = skipBalancedParens(src, j);
341
+ return rawSpan(src, i, end);
342
+ }
343
+ // bare variable reference (e.g. `testPlugin`, `tailwindcss`)
344
+ if (token.length > 0)
345
+ return rawSpan(src, i, j);
283
346
  return { value: undefined, next: i, __invalid: true };
284
347
  }
348
+ /** Skip forward from `i` to find the end of a raw expression (used for spread fallback). */
349
+ function skipToEndOfRaw(src, i) {
350
+ let depth = 0;
351
+ let inStr = null;
352
+ let esc = false;
353
+ for (let j = i; j < src.length; j++) {
354
+ const ch = src[j];
355
+ if (inStr) {
356
+ if (esc) {
357
+ esc = false;
358
+ continue;
359
+ }
360
+ if (ch === '\\') {
361
+ esc = true;
362
+ continue;
363
+ }
364
+ if (ch === inStr)
365
+ inStr = null;
366
+ continue;
367
+ }
368
+ if (ch === '"' || ch === "'" || ch === '`') {
369
+ inStr = ch;
370
+ continue;
371
+ }
372
+ if (ch === '(')
373
+ depth++;
374
+ if (ch === ')') {
375
+ if (depth === 0)
376
+ return j;
377
+ depth--;
378
+ }
379
+ if (depth === 0 && (ch === ',' || ch === '}' || ch === ']'))
380
+ return j;
381
+ }
382
+ return src.length;
383
+ }
384
+ /** Skip to the matching ']' for a raw array span. */
385
+ function skipToEndOfArray(src, i) {
386
+ let depth = 0;
387
+ let inStr = null;
388
+ let esc = false;
389
+ for (let j = i; j < src.length; j++) {
390
+ const ch = src[j];
391
+ if (inStr) {
392
+ if (esc) {
393
+ esc = false;
394
+ continue;
395
+ }
396
+ if (ch === '\\') {
397
+ esc = true;
398
+ continue;
399
+ }
400
+ if (ch === inStr)
401
+ inStr = null;
402
+ continue;
403
+ }
404
+ if (ch === '"' || ch === "'" || ch === '`') {
405
+ inStr = ch;
406
+ continue;
407
+ }
408
+ if (ch === '[')
409
+ depth++;
410
+ if (ch === ']') {
411
+ depth--;
412
+ if (depth === 0)
413
+ return j + 1;
414
+ }
415
+ }
416
+ return src.length;
417
+ }
285
418
  function serializeObject(obj) {
286
419
  return Object.keys(obj)
287
420
  .map((k) => `${isBareKey(k) ? k : JSON.stringify(k)}: ${serializeValue(obj[k])}`)
@@ -291,6 +424,9 @@ function isBareKey(k) {
291
424
  return /^[a-zA-Z_$][\w$]*$/.test(k);
292
425
  }
293
426
  function serializeValue(v) {
427
+ if (v !== null && typeof v === 'object' && '__veskRaw' in v) {
428
+ return String(v.__veskRaw);
429
+ }
294
430
  if (v === null)
295
431
  return 'null';
296
432
  if (typeof v === 'string')
@@ -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;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,CAuevG"}
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,CAikBvG"}
@@ -260,7 +260,10 @@ export async function startDevServer(appDir, options) {
260
260
  async function buildAdapterAgenticProvider(cfg) {
261
261
  const providerName = String(cfg.provider || loadAgenticConfig(agenticProjectDir).provider || 'openai');
262
262
  const apiKey = cfg.apiKey || getApiKey(agenticProjectDir, providerName) || '';
263
- const model = cfg.model || loadAgenticConfig(agenticProjectDir).model || (providerName === 'anthropic' ? 'claude-sonnet-4-6' : providerName === 'google' ? 'gemini-2.0-flash' : providerName === 'ollama' ? 'llama3.1' : providerName === 'opencode' ? 'claude-sonnet-4-6' : providerName === 'opencode-go' ? 'opencode-go/kimi-k3' : providerName === 'openrouter' ? 'openrouter/auto' : 'gpt-4o-mini');
263
+ const model = cfg.model || loadAgenticConfig(agenticProjectDir).model || '';
264
+ if (!model) {
265
+ throw new Error('no model configured — open Settings → Agentic and pick a model');
266
+ }
264
267
  const baseUrl = cfg.baseUrl || loadAgenticConfig(agenticProjectDir).baseUrl || undefined;
265
268
  const maxTokens = typeof cfg.maxTokens === 'number' ? cfg.maxTokens : undefined;
266
269
  if (providerName === 'anthropic')
@@ -355,6 +358,20 @@ export async function startDevServer(appDir, options) {
355
358
  let ssrVersion = Date.now();
356
359
  let routeTree = [];
357
360
  let runtimeBundle = '';
361
+ let eventsMod = null;
362
+ async function reloadEventsMod() {
363
+ const eventsPath = resolve(devDir, 'server', 'events.js');
364
+ if (existsSync(eventsPath)) {
365
+ try {
366
+ eventsMod = await import(`${eventsPath}?t=${Date.now()}`);
367
+ return;
368
+ }
369
+ catch {
370
+ // ignore — events file present but failed to load
371
+ }
372
+ }
373
+ eventsMod = null;
374
+ }
358
375
  async function doBuild() {
359
376
  const start = Date.now();
360
377
  try {
@@ -368,6 +385,7 @@ export async function startDevServer(appDir, options) {
368
385
  const monorepoRoot = resolve(__dirname, '..', '..', '..');
369
386
  const runtimeDir = resolve(monorepoRoot, 'packages', 'runtime', 'dist');
370
387
  runtimeBundle = buildRuntimeCode(runtimeDir);
388
+ await reloadEventsMod();
371
389
  lastBuild = Date.now();
372
390
  console.error(`vesk dev: rebuilt in ${Date.now() - start}ms`);
373
391
  }
@@ -505,6 +523,24 @@ export async function startDevServer(appDir, options) {
505
523
  return;
506
524
  }
507
525
  }
526
+ if (eventsMod) {
527
+ const serverStore = globalThis.__vesk_server_ctx || {};
528
+ const webRequest = makeWebRequest(req, url.href, maxBodyBytes);
529
+ const evtCtx = {
530
+ request: webRequest,
531
+ params: {},
532
+ url,
533
+ locals: Object.assign({}, serverStore),
534
+ cookies: {},
535
+ };
536
+ globalThis.__vesk_request = evtCtx;
537
+ try {
538
+ await eventsMod.executeRequest?.(evtCtx);
539
+ }
540
+ catch (e) {
541
+ console.error('vesk request: onRequest error:', e instanceof Error ? e.message : e);
542
+ }
543
+ }
508
544
  if (config && url.pathname.startsWith('/_vesk/action/')) {
509
545
  const actionId = url.pathname.replace('/_vesk/action/', '');
510
546
  const actionEntry = config.actions && config.actions.find(a => a.id === actionId);
@@ -619,6 +655,41 @@ export async function startDevServer(appDir, options) {
619
655
  });
620
656
  const hmr = createHmrServer(server, appDir, devDir, componentMap);
621
657
  hmrSession = hmr;
658
+ // ── Console streaming to devtool ────────────────────────────────────────
659
+ // Read `logs` from vesk.config and wire up server-side console interception
660
+ // so console.log/warn/error/info/debug are forwarded to the devtool Log tab.
661
+ {
662
+ let logsLevels = null;
663
+ try {
664
+ const { readConfig } = await import('@vesk/adapter/src/dev-config');
665
+ const cfgResult = await readConfig(resolve(appDir, '..'));
666
+ const logsCfg = cfgResult.config?.logs;
667
+ if (logsCfg === false) {
668
+ logsLevels = null; // disabled
669
+ }
670
+ else if (typeof logsCfg === 'object' && logsCfg !== null) {
671
+ logsLevels = { log: true, warn: true, error: true, info: true, debug: true, ...logsCfg };
672
+ }
673
+ else {
674
+ logsLevels = { log: true, warn: true, error: true, info: true, debug: true };
675
+ }
676
+ }
677
+ catch {
678
+ logsLevels = { log: true, warn: true, error: true, info: true, debug: true };
679
+ }
680
+ if (logsLevels) {
681
+ const origFns = {};
682
+ for (const lvl of ['log', 'warn', 'error', 'info', 'debug']) {
683
+ origFns[lvl] = console[lvl].bind(console);
684
+ console[lvl] = (...args) => {
685
+ origFns[lvl](...args);
686
+ if (!logsLevels[lvl])
687
+ return;
688
+ hmr.broadcast('console', { level: lvl, message: args.map(String).join(' ') });
689
+ };
690
+ }
691
+ }
692
+ }
622
693
  const srcDir = resolve(appDir, '..', 'src');
623
694
  try {
624
695
  if (existsSync(srcDir)) {
@@ -676,6 +747,24 @@ export async function startDevServer(appDir, options) {
676
747
  catch (e) {
677
748
  console.error('vesk dev: file watching unavailable');
678
749
  }
750
+ const bootEventsMod = eventsMod;
751
+ try {
752
+ await bootEventsMod?.executeStart?.({ server, port, host });
753
+ }
754
+ catch (e) {
755
+ console.error('vesk dev: onStart error:', e instanceof Error ? e.message : e);
756
+ }
757
+ server.on('close', () => {
758
+ void (async () => {
759
+ const stopEventsMod = eventsMod;
760
+ try {
761
+ await stopEventsMod?.executeStop?.({ server, port, host });
762
+ }
763
+ catch (e) {
764
+ console.error('vesk dev: onStop error:', e instanceof Error ? e.message : e);
765
+ }
766
+ })();
767
+ });
679
768
  await new Promise(resolve => {
680
769
  server.listen(port, host, () => {
681
770
  console.error(`vesk dev server at http://localhost:${port} (listening on ${host})`);
@@ -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;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"}
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;AAoRD,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,7 +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
+ import { resolveCssUrls, hasBuiltGlobalCss } from '@vesk/adapter/src/css';
10
10
  import { isAllowedWsUpgrade } from '@vesk/adapter/src/paths';
11
11
  import { parseCompilerError, buildCodeframe } from '@vesk/adapter/src/error-codeframe';
12
12
  import { suggestFor } from '@vesk/adapter/src/error-tips';
@@ -243,10 +243,8 @@ function regenerateSsrFunction(routeNode, appDir, outDir, componentMap, options)
243
243
  const ancestorLayouts = options?.ancestorLayouts || [];
244
244
  const headExtra = options?.headExtra || null;
245
245
  const pagePath = resolve(appDir, routeNode.sourceDir, 'page.vsk');
246
- const layoutPath = resolve(appDir, routeNode.sourceDir, 'layout.vsk');
247
246
  const cssUrls = resolveCssUrls({
248
- tailwind: hasBuiltTailwindCss(outDir),
249
- userCss: hasUserCss(appDir),
247
+ enabled: hasBuiltGlobalCss(outDir),
250
248
  });
251
249
  const cssOption = cssUrls.length > 0 ? `, cssUrls: ${JSON.stringify(cssUrls)}` : '';
252
250
  const headExtraOption = headExtra ? `, headExtra: ${JSON.stringify(headExtra)}` : '';
@@ -255,10 +253,25 @@ function regenerateSsrFunction(routeNode, appDir, outDir, componentMap, options)
255
253
  const name = routeName(parts);
256
254
  const funcDir = resolve(outDir, 'server', 'functions');
257
255
  const funcPath = resolve(funcDir, `${name}.js`);
258
- const hasLayout = !!routeNode.layout;
259
- const hasAncestorLayout = ancestorLayouts.length > 0;
260
256
  const pageSrc = readFileSync(pagePath, 'utf-8');
261
257
  const pageComp = extractCompName(pageSrc) || 'Page';
258
+ const layoutStack = [
259
+ ...ancestorLayouts.map((a) => ({ sourceDir: a.sourceDir, layoutCompName: a.layoutCompName })),
260
+ ...(routeNode.layout ? [{ sourceDir: routeNode.sourceDir, layoutCompName: routeNode.layout }] : []),
261
+ ];
262
+ const layoutDecls = [];
263
+ for (const entry of layoutStack) {
264
+ const entryPath = resolve(appDir, entry.sourceDir, 'layout.vsk');
265
+ const entrySrc = readFileSync(entryPath, 'utf-8');
266
+ const entryComp = extractCompName(entrySrc) || 'Layout';
267
+ const escaped = escapeSource(entrySrc);
268
+ layoutDecls.push({
269
+ src: `\`${escaped}\``,
270
+ comp: JSON.stringify(entryComp),
271
+ path: JSON.stringify(entryPath),
272
+ compiled: `(() => { try { setVskHydrate(true); return compileFile(\`${escaped}\`, { sourcePath: ${JSON.stringify(entryPath)} }); } catch { return null; } finally { setVskHydrate(false); } })()`,
273
+ });
274
+ }
262
275
  const errorPath = resolveErrorFile(routeNode.sourceDir, appDir);
263
276
  const errorSrc = errorPath ? readFileSync(errorPath, 'utf-8') : null;
264
277
  const errorComp = errorPath ? (extractCompName(errorSrc) || 'Error') : null;
@@ -268,28 +281,15 @@ function regenerateSsrFunction(routeNode, appDir, outDir, componentMap, options)
268
281
  const clientScriptOption = ', clientScriptUrl: "/_vesk/static/client.js"';
269
282
  const dataScriptOption = ', externalDataScript: storeDataScriptGlobal';
270
283
  let src = '';
271
- if (hasLayout) {
272
- const layoutSrc = readFileSync(layoutPath, 'utf-8');
273
- const layoutComp = extractCompName(layoutSrc) || 'Layout';
274
- src = `const _layoutSrc = \`${escapeSource(layoutSrc)}\`;\nconst _pageSrc = \`${escapeSource(pageSrc)}\`;\n`;
275
- src += `const _layoutComp = ${JSON.stringify(layoutComp)};\nconst _pageComp = ${JSON.stringify(pageComp)};\n`;
276
- src += `const _layoutPath = ${JSON.stringify(layoutPath)};\nconst _pagePath = ${JSON.stringify(pagePath)};\n`;
277
- src += `const _layoutCompiled = (() => { try { setVskHydrate(true); return compileFile(_layoutSrc, { sourcePath: _layoutPath }); } catch { return null; } finally { setVskHydrate(false); } })();\n`;
278
- src += `const _pageCompiled = (() => { try { setVskHydrate(true); return compileFile(_pageSrc, { sourcePath: _pagePath }); } catch { return null; } finally { setVskHydrate(false); } })();\n`;
279
- src += errorVars;
280
- }
281
- else if (hasAncestorLayout) {
282
- const outerLayout = ancestorLayouts[0];
283
- const outerLayoutPath = resolve(appDir, outerLayout.sourceDir, 'layout.vsk');
284
- const outerLayoutSrc = readFileSync(outerLayoutPath, 'utf-8');
285
- const outerLayoutComp = extractCompName(outerLayoutSrc) || 'Layout';
284
+ if (layoutDecls.length > 0) {
286
285
  src = `const _pageSrc = \`${escapeSource(pageSrc)}\`;\n`;
287
286
  src += `const _pageComp = ${JSON.stringify(pageComp)};\n`;
288
- src += `const _layoutSrc = \`${escapeSource(outerLayoutSrc)}\`;\n`;
289
- src += `const _layoutComp = ${JSON.stringify(outerLayoutComp)};\n`;
290
- src += `const _layoutPath = ${JSON.stringify(outerLayoutPath)};\nconst _pagePath = ${JSON.stringify(pagePath)};\n`;
291
- src += `const _layoutCompiled = (() => { try { setVskHydrate(true); return compileFile(_layoutSrc, { sourcePath: _layoutPath }); } catch { return null; } finally { setVskHydrate(false); } })();\n`;
287
+ src += `const _pagePath = ${JSON.stringify(pagePath)};\n`;
292
288
  src += `const _pageCompiled = (() => { try { setVskHydrate(true); return compileFile(_pageSrc, { sourcePath: _pagePath }); } catch { return null; } finally { setVskHydrate(false); } })();\n`;
289
+ src += `const _layoutSrcList = [\n${layoutDecls.map((d) => ' ' + d.src + ',').join('\n')}\n];\n`;
290
+ src += `const _layoutCompList = [${layoutDecls.map((d) => d.comp).join(', ')}];\n`;
291
+ src += `const _layoutPathList = [${layoutDecls.map((d) => d.path).join(', ')}];\n`;
292
+ src += `const _layoutCompiledList = [\n${layoutDecls.map((d) => ' ' + d.compiled + ',').join('\n')}\n];\n`;
293
293
  src += errorVars;
294
294
  }
295
295
  else {
@@ -316,7 +316,7 @@ function regenerateSsrFunction(routeNode, appDir, outDir, componentMap, options)
316
316
  registryCode = 'const __componentRegistry = new Map();\n';
317
317
  }
318
318
  let renderCode;
319
- if (hasLayout) {
319
+ if (layoutDecls.length > 0) {
320
320
  renderCode = [
321
321
  ' let page;',
322
322
  ' let caughtError = null;',
@@ -329,24 +329,14 @@ function regenerateSsrFunction(routeNode, appDir, outDir, componentMap, options)
329
329
  " const stack = err && typeof err === 'object' && 'stack' in err ? String(err.stack) : '';",
330
330
  " page = { body: await __renderErrorBody({ params, statusCode: 500, error: message, stack, url: url.href }), head: '' };",
331
331
  ' }',
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 });',
333
- " return new Response(html, { headers: { 'Content-Type': 'text/html' }, status: caughtError ? 500 : 200 });",
334
- ].join('\n');
335
- }
336
- else if (hasAncestorLayout) {
337
- renderCode = [
338
- ' let page;',
339
- ' let caughtError = null;',
340
- ' try {',
341
- ' page = await renderPage(_pageSrc, _pageComp, { params }, __componentRegistry, { hydrate: true, cached: _pageCompiled, sourcePath: _pagePath });',
342
- ' } catch (err) {',
343
- " if (err && (err.name === 'NotFoundError' || err.name === 'Redirect')) throw err;",
344
- ' caughtError = err;',
345
- " const message = err && typeof err === 'object' && 'message' in err ? String(err.message) : String(err);",
346
- " const stack = err && typeof err === 'object' && 'stack' in err ? String(err.stack) : '';",
347
- " page = { body: await __renderErrorBody({ params, statusCode: 500, error: message, stack, url: url.href }), head: '' };",
332
+ " let _body = (caughtError ? '<!--vesk-ssr-error:' + (caughtError && typeof caughtError === 'object' && 'message' in caughtError ? encodeURIComponent(String(caughtError.message)) : '') + '-->' : '') + page.body;",
333
+ " let _head = page.head || '';",
334
+ " for (let _i = _layoutSrcList.length - 1; _i > 0; _i--) {",
335
+ " const _inner = await renderPage(_layoutSrcList[_i], _layoutCompList[_i], { params, children: _body }, __componentRegistry, { hydrate: true, cached: _layoutCompiledList[_i], sourcePath: _layoutPathList[_i] });",
336
+ ' _body = _inner.body;',
337
+ " if (_inner.head) _head = _inner.head + _head;",
348
338
  ' }',
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 });',
339
+ " const html = await renderFullPage(_layoutSrcList[0], _layoutCompList[0], { params, children: _body }, __componentRegistry, { hydrate: true, cached: _layoutCompiledList[0]" + bakedOptions + clientScriptOption + dataScriptOption + ', pageHead: _head, sourcePath: _layoutPathList[0] });',
350
340
  " return new Response(html, { headers: { 'Content-Type': 'text/html' }, status: caughtError ? 500 : 200 });",
351
341
  ].join('\n');
352
342
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAYA,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,CAqUpG;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"}
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,CAuTpG;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"}