@vesk/adapter 0.2.59 → 0.2.60
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/dev-server.d.ts.map +1 -1
- package/dist/dev-server.js +12 -0
- package/dist/hmr.d.ts.map +1 -1
- package/dist/hmr.js +22 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +40 -0
- package/dist/platform-handler.d.ts.map +1 -1
- package/dist/platform-handler.js +14 -0
- package/dist/prod-server.d.ts.map +1 -1
- package/dist/prod-server.js +13 -0
- package/dist/runtime-bundle.d.ts.map +1 -1
- package/dist/runtime-bundle.js +35 -0
- package/dist/ssr-function.d.ts +5 -0
- package/dist/ssr-function.d.ts.map +1 -1
- package/dist/ssr-function.js +89 -5
- package/package.json +4 -4
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;AASjG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AAK7C,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,
|
|
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;AASjG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AAK7C,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,CAorBvG"}
|
package/dist/dev-server.js
CHANGED
|
@@ -567,6 +567,18 @@ export async function startDevServer(appDir, options) {
|
|
|
567
567
|
res.end(lines.join('\n') || '// no ssr data');
|
|
568
568
|
return;
|
|
569
569
|
}
|
|
570
|
+
// Persisted-store pre-paint payload — same token-stash/consume contract as
|
|
571
|
+
// /ssr-data.js above so the dev SPA fallback never serves HTML as JS.
|
|
572
|
+
if (url.pathname === '/store-init.js') {
|
|
573
|
+
const token = url.searchParams.get('t') || '';
|
|
574
|
+
const store = globalThis.__vsk_store_init_payload_store;
|
|
575
|
+
const payload = store?.[token];
|
|
576
|
+
if (payload)
|
|
577
|
+
delete store[token];
|
|
578
|
+
res.writeHead(200, { 'Content-Type': 'application/javascript', 'Cache-Control': 'no-store' });
|
|
579
|
+
res.end(payload ?? '// no store init');
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
570
582
|
if (url.pathname.startsWith('/_vesk/static/')) {
|
|
571
583
|
const relPath = url.pathname.slice('/_vesk/static/'.length);
|
|
572
584
|
const staticPath = resolveWithin(resolve(devDir, 'static'), relPath);
|
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;IACf,gFAAgF;IAChF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;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,CAsGjB;
|
|
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;IACf,gFAAgF;IAChF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;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,CAsGjB;AAqTD,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,CA6KA"}
|
package/dist/hmr.js
CHANGED
|
@@ -5,7 +5,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
5
5
|
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
|
-
import { resolveErrorFile } from '@vesk/adapter/src/ssr-function';
|
|
8
|
+
import { resolveErrorFile, persistedStoreSsrCode } from '@vesk/adapter/src/ssr-function';
|
|
9
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';
|
|
@@ -363,6 +363,7 @@ function regenerateSsrFunction(routeNode, appDir, outDir, componentMap, options)
|
|
|
363
363
|
// serialized by `renderFullPage` under another and the page would ship
|
|
364
364
|
// with no ssr-data script.
|
|
365
365
|
' return withSsrStore(async () => {',
|
|
366
|
+
' resetPersistedStoreKeys();',
|
|
366
367
|
' let page;',
|
|
367
368
|
' let caughtError = null;',
|
|
368
369
|
' try {',
|
|
@@ -382,7 +383,7 @@ function regenerateSsrFunction(routeNode, appDir, outDir, componentMap, options)
|
|
|
382
383
|
" if (_inner.head) _head = _inner.head + _head;",
|
|
383
384
|
' }',
|
|
384
385
|
" 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] });',
|
|
385
|
-
" return new Response(html, { headers: { 'Content-Type': 'text/html' }, status: caughtError ? 500 : 200 });",
|
|
386
|
+
" return new Response(__injectStoreInit(html), { headers: { 'Content-Type': 'text/html' }, status: caughtError ? 500 : 200 });",
|
|
386
387
|
' });',
|
|
387
388
|
].join('\n');
|
|
388
389
|
}
|
|
@@ -390,6 +391,7 @@ function regenerateSsrFunction(routeNode, appDir, outDir, componentMap, options)
|
|
|
390
391
|
renderCode = [
|
|
391
392
|
' return withSsrStore(async () => {',
|
|
392
393
|
' let stream;',
|
|
394
|
+
" const __streamToken = globalThis.__vsk_ssr_token || '';",
|
|
393
395
|
' try {',
|
|
394
396
|
' stream = renderPageStream(_src, _comp, { params }, __componentRegistry, { hydrate: true, cached: _srcCompiled' + bakedOptions + clientScriptOption + dataScriptOption + ", sourcePath: _srcPath });",
|
|
395
397
|
' } catch (err) {',
|
|
@@ -398,13 +400,26 @@ function regenerateSsrFunction(routeNode, appDir, outDir, componentMap, options)
|
|
|
398
400
|
" const message = err && typeof err === 'object' && 'message' in err ? String(err.message) : String(err);",
|
|
399
401
|
" const stack = err && typeof err === 'object' && 'stack' in err ? String(err.stack) : '';",
|
|
400
402
|
" 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 });',
|
|
401
|
-
" return new Response(html, { headers: { 'Content-Type': 'text/html' }, status: 500 });",
|
|
403
|
+
" return new Response(__injectStoreInit(html), { headers: { 'Content-Type': 'text/html' }, status: 500 });",
|
|
402
404
|
' }',
|
|
403
405
|
' return new Response(new ReadableStream({',
|
|
404
406
|
' async start(controller) {',
|
|
405
407
|
' const enc = new TextEncoder();',
|
|
408
|
+
" let __tail = null;",
|
|
409
|
+
' resetPersistedStoreKeys(__streamToken);',
|
|
406
410
|
' for await (const chunk of stream) {',
|
|
407
|
-
' controller.enqueue(enc.encode(
|
|
411
|
+
' if (__tail !== null) controller.enqueue(enc.encode(__tail));',
|
|
412
|
+
' __tail = chunk;',
|
|
413
|
+
' }',
|
|
414
|
+
' if (__tail !== null) {',
|
|
415
|
+
' const __tag = __storeInitTag(__streamToken);',
|
|
416
|
+
" if (__tag !== '') {",
|
|
417
|
+
" const __bi = __tail.lastIndexOf('</body>');",
|
|
418
|
+
" __tail = __bi === -1 ? __tail + __tag : __tail.slice(0, __bi) + __tag + __tail.slice(__bi);",
|
|
419
|
+
' }',
|
|
420
|
+
' controller.enqueue(enc.encode(__tail));',
|
|
421
|
+
' } else {',
|
|
422
|
+
' resetPersistedStoreKeys(__streamToken);',
|
|
408
423
|
' }',
|
|
409
424
|
' controller.close();',
|
|
410
425
|
' },',
|
|
@@ -424,10 +439,12 @@ function regenerateSsrFunction(routeNode, appDir, outDir, componentMap, options)
|
|
|
424
439
|
'}',
|
|
425
440
|
].join('\n');
|
|
426
441
|
const funcCode = [
|
|
427
|
-
"import { renderFullPage, renderPageStream, renderPage, compileFile, setVskHydrate, storeDataScriptGlobal, withSsrStore } from '../runtime.js';",
|
|
442
|
+
"import { renderFullPage, renderPageStream, renderPage, compileFile, setVskHydrate, storeDataScriptGlobal, withSsrStore, installPersistedStoreServerHooks, persistedStoreCookieName, getPersistedStoreKeys, resetPersistedStoreKeys, buildStorePrePaintPayload, storeInitScriptGlobal, storeInitScriptTag } from '../runtime.js';",
|
|
428
443
|
'', registryCode, src, '',
|
|
429
444
|
errorBodyFnCode,
|
|
430
445
|
'',
|
|
446
|
+
persistedStoreSsrCode(),
|
|
447
|
+
'',
|
|
431
448
|
'export async function handle(request) {',
|
|
432
449
|
' const url = new URL(request.url);',
|
|
433
450
|
" const urlParts = url.pathname.split('/').filter(Boolean);",
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EACe,YAAY,EAAE,WAAW,EAC7B,UAAU,EAChC,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EACe,YAAY,EAAE,WAAW,EAC7B,UAAU,EAChC,MAAM,yBAAyB,CAAC;AAoDjC;;;;;;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;AAkDD,wBAAsB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAiXpG;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"}
|
package/dist/index.js
CHANGED
|
@@ -28,6 +28,38 @@ async function resolveCompilerApi(name) {
|
|
|
28
28
|
}
|
|
29
29
|
return import(`@vesk/compiler/src/${name.replace(/\.js$/, '')}`);
|
|
30
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Build gate against two page files claiming one URL.
|
|
33
|
+
*
|
|
34
|
+
* SSR routes are keyed by URL pattern (fullPath) — last write wins in the
|
|
35
|
+
* path->file map — while the client router walks the manifest tree first-match
|
|
36
|
+
* wins, so a group page and a root page both claiming `/` ship a document for
|
|
37
|
+
* one of them and hydrate the other. Both respond 200; the only symptom is a
|
|
38
|
+
* page whose claims land on the layout's elements. Refuse the build instead.
|
|
39
|
+
*/
|
|
40
|
+
function findRouteConflicts(routeTree, appDir) {
|
|
41
|
+
const projectRoot = resolve(appDir, '..');
|
|
42
|
+
const byPath = new Map();
|
|
43
|
+
const walk = (nodes) => {
|
|
44
|
+
for (const node of nodes) {
|
|
45
|
+
if (node.page) {
|
|
46
|
+
const pageFile = join(node.sourceDir, 'page.vsk');
|
|
47
|
+
const files = byPath.get(node.fullPath) ?? [];
|
|
48
|
+
files.push(relative(projectRoot, pageFile));
|
|
49
|
+
byPath.set(node.fullPath, files);
|
|
50
|
+
}
|
|
51
|
+
if (node.children && node.children.length > 0)
|
|
52
|
+
walk(node.children);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
walk(routeTree);
|
|
56
|
+
const conflicts = [];
|
|
57
|
+
for (const [fullPath, files] of byPath) {
|
|
58
|
+
if (files.length > 1)
|
|
59
|
+
conflicts.push({ fullPath, files });
|
|
60
|
+
}
|
|
61
|
+
return conflicts;
|
|
62
|
+
}
|
|
31
63
|
/**
|
|
32
64
|
* Defensive local mirror of the plugin-manager's `filterActivePlugins`
|
|
33
65
|
* (`@vesk/adapter/src/plugins`): keep when there is no matching record, or the
|
|
@@ -214,6 +246,14 @@ export async function build(appDir, options) {
|
|
|
214
246
|
console.error('vesk build: no routes found in', appDir);
|
|
215
247
|
return;
|
|
216
248
|
}
|
|
249
|
+
const routeConflicts = findRouteConflicts(routeTree, appDir);
|
|
250
|
+
if (routeConflicts.length > 0) {
|
|
251
|
+
for (const conflict of routeConflicts) {
|
|
252
|
+
console.error(`vesk build: conflicting routes for ${conflict.fullPath}: ${conflict.files.join(', ')}`);
|
|
253
|
+
}
|
|
254
|
+
const first = routeConflicts[0];
|
|
255
|
+
throw new Error(`conflicting routes: ${first.fullPath} is claimed by both ${first.files.join(' and ')}`);
|
|
256
|
+
}
|
|
217
257
|
const projectRoot = resolve(appDir, '..');
|
|
218
258
|
const componentsDir = resolve(projectRoot, 'components');
|
|
219
259
|
const componentMap = scanComponents(componentsDir);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform-handler.d.ts","sourceRoot":"","sources":["../src/platform-handler.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAIvE,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,SAAS,EAAE,CAAC;IACvB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,iFAAiF;IACjF,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAMpD;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEtC;AAgBD;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,oBAAoB,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"platform-handler.d.ts","sourceRoot":"","sources":["../src/platform-handler.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAIvE,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,SAAS,EAAE,CAAC;IACvB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,iFAAiF;IACjF,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAMpD;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEtC;AAgBD;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,oBAAoB,GAAG,MAAM,CAsMjF;AAED,MAAM,WAAW,qBAAqB;IACpC,kEAAkE;IAClE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsFzF;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,SAAS,EAAE,CAAC;IACvB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB"}
|
package/dist/platform-handler.js
CHANGED
|
@@ -154,6 +154,20 @@ ${serverStoreLine}
|
|
|
154
154
|
});
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
+
// Persisted-store pre-paint payload (buildStorePrePaintPayload) — same
|
|
158
|
+
// token-stash/consume contract as /ssr-data.js, own store so neither handoff
|
|
159
|
+
// can eat the other.
|
|
160
|
+
if (pathname === '/store-init.js') {
|
|
161
|
+
const initToken = url.searchParams.get('t') || '';
|
|
162
|
+
const initStore = (globalThis.__vsk_store_init_payload_store || {});
|
|
163
|
+
const initPayload = initStore[initToken];
|
|
164
|
+
if (initPayload !== undefined) delete initStore[initToken];
|
|
165
|
+
return new Response(initPayload ?? '// no store init', {
|
|
166
|
+
status: 200,
|
|
167
|
+
headers: { 'Content-Type': 'application/javascript', 'Cache-Control': 'no-store' },
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
157
171
|
${eventsStartLine}
|
|
158
172
|
let mwCtx = { params: {}, url, locals: ${localsSeed}, cookies: {}, request, resolveUrl(u) { return new URL(u, request.url).href; }, set() {}, get() { return undefined; } };
|
|
159
173
|
if (${hasMwLiteral}) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prod-server.d.ts","sourceRoot":"","sources":["../src/prod-server.ts"],"names":[],"mappings":"AAEA,OAAO,EAA2D,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AAiDjG,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAIzE;AAkGD,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"prod-server.d.ts","sourceRoot":"","sources":["../src/prod-server.ts"],"names":[],"mappings":"AAEA,OAAO,EAA2D,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AAiDjG,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAIzE;AAkGD,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAqexI"}
|
package/dist/prod-server.js
CHANGED
|
@@ -290,6 +290,19 @@ export async function startProdServer(outDir, options) {
|
|
|
290
290
|
res.end(lines.join('\n') || '// no ssr data');
|
|
291
291
|
return;
|
|
292
292
|
}
|
|
293
|
+
// Persisted-store pre-paint payload (buildStorePrePaintPayload), stashed by
|
|
294
|
+
// storeInitScriptGlobal under its own token store so consuming one never
|
|
295
|
+
// eats the page's /ssr-data.js handoff. Served once, consumed-and-deleted.
|
|
296
|
+
if (url.pathname === '/store-init.js') {
|
|
297
|
+
const token = url.searchParams.get('t') || '';
|
|
298
|
+
const store = globalThis.__vsk_store_init_payload_store;
|
|
299
|
+
const payload = store?.[token];
|
|
300
|
+
if (payload)
|
|
301
|
+
delete store[token];
|
|
302
|
+
res.writeHead(200, { 'Content-Type': 'application/javascript', 'Cache-Control': 'no-store' });
|
|
303
|
+
res.end(payload ?? '// no store init');
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
293
306
|
// Stable alias for the client runtime: the file on disk is content-hashed in
|
|
294
307
|
// production, so the name is resolved from the manifest rather than assumed.
|
|
295
308
|
if (url.pathname === '/_vesk/runtime.js') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-bundle.d.ts","sourceRoot":"","sources":["../src/runtime-bundle.ts"],"names":[],"mappings":"AAuCA,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"runtime-bundle.d.ts","sourceRoot":"","sources":["../src/runtime-bundle.ts"],"names":[],"mappings":"AAuCA,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA+LnF"}
|
package/dist/runtime-bundle.js
CHANGED
|
@@ -42,6 +42,7 @@ export async function bundleRuntime(appDir, outDir) {
|
|
|
42
42
|
`import { renderPage, renderFullPage, renderPageStream, compileFile, setRuntimeModule, setVskHydrate, hydratePrecompile, assertSameOrigin, withSsrStore } from ${JSON.stringify(resolve(compilerRoot, 'server-codegen.js'))};`,
|
|
43
43
|
`import { parseCookies } from ${JSON.stringify(resolve(compilerRoot, 'server-cookies.js'))};`,
|
|
44
44
|
`import * as __veskRuntime from ${JSON.stringify(resolve(runtimeRoot, 'index-server.js'))};`,
|
|
45
|
+
`import * as __persistence from ${JSON.stringify(resolve(runtimeRoot, 'store-persistence.js'))};`,
|
|
45
46
|
'',
|
|
46
47
|
'// Inject runtime module so server-codegen can find components like NavLink, Link, etc.',
|
|
47
48
|
'setRuntimeModule(__veskRuntime);',
|
|
@@ -107,6 +108,40 @@ export async function bundleRuntime(appDir, outDir) {
|
|
|
107
108
|
" return '/ssr-data.js?t=' + token;",
|
|
108
109
|
'}',
|
|
109
110
|
'',
|
|
111
|
+
'// Persisted-store SSR continuity. `installPersistedStoreServerHooks` installs the',
|
|
112
|
+
'// adapter-side read hook; `get/getReset` handle the per-request key registry',
|
|
113
|
+
'// the server drains into the pre-paint payload. The init payload is delivered',
|
|
114
|
+
'// as an origin-served script (/store-init.js?t=...) exactly like /ssr-data.js',
|
|
115
|
+
'// so strict CSP (no unsafe-inline) cannot block it; it is never inlined.',
|
|
116
|
+
'export const installPersistedStoreServerHooks = __persistence.installPersistedStoreServerHooks;',
|
|
117
|
+
'export const persistedStoreCookieName = __persistence.persistedStoreCookieName;',
|
|
118
|
+
'export const getPersistedStoreKeys = __persistence.getPersistedStoreKeys;',
|
|
119
|
+
'export const resetPersistedStoreKeys = __persistence.resetPersistedStoreKeys;',
|
|
120
|
+
'export const buildStorePrePaintPayload = __persistence.buildStorePrePaintPayload;',
|
|
121
|
+
'export const storeInitScriptTag = __persistence.storeInitScriptTag;',
|
|
122
|
+
'',
|
|
123
|
+
'// Stash the pre-paint payload under a CSPRNG token and return the origin URL',
|
|
124
|
+
'// the blocking <head> script points at. Own token store (NOT __vsk_ssr_payload_store)',
|
|
125
|
+
'// so consuming the page hydration handoff never eats the store-init payload',
|
|
126
|
+
'// and vice versa. Same 100-entry bound as /ssr-data.js.',
|
|
127
|
+
'export function storeInitScriptGlobal(payload) {',
|
|
128
|
+
" if (!payload) return null;",
|
|
129
|
+
' const bytes = new Uint8Array(12);',
|
|
130
|
+
' crypto.getRandomValues(bytes);',
|
|
131
|
+
" let tk = '';",
|
|
132
|
+
" for (const b of bytes) tk += b.toString(16).padStart(2, '0');",
|
|
133
|
+
' const token = tk;',
|
|
134
|
+
" const store = (globalThis.__vsk_store_init_payload_store ||= {});",
|
|
135
|
+
" store[token] = payload;",
|
|
136
|
+
" const keys = Object.keys(store);",
|
|
137
|
+
' if (keys.length > 100) {',
|
|
138
|
+
' for (let i = 0; i < keys.length - 100; i++) {',
|
|
139
|
+
' delete store[keys[i]];',
|
|
140
|
+
' }',
|
|
141
|
+
' }',
|
|
142
|
+
" return '/store-init.js?t=' + token;",
|
|
143
|
+
'}',
|
|
144
|
+
'',
|
|
110
145
|
'// Re-export runtime classes used by API routes',
|
|
111
146
|
'export const VeskRequest = __veskRuntime.VeskRequest;',
|
|
112
147
|
'export const PayloadTooLargeError = __veskRuntime.PayloadTooLargeError;',
|
package/dist/ssr-function.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type { RouteNode, SsrFunctionOptions } from '@vesk/adapter/src/types';
|
|
2
2
|
export declare function resolveErrorFile(sourceDir: string, appDir: string): string | null;
|
|
3
|
+
/** Shared persisted-store SSR helper block emitted into every generated SSR
|
|
4
|
+
* function (prod via ssr-function.ts, dev via hmr.ts — keep the two callers
|
|
5
|
+
* in sync by calling this). Emit it AFTER the function declarations so the
|
|
6
|
+
* module-level `installPersistedStoreServerHooks` call runs on import. */
|
|
7
|
+
export declare function persistedStoreSsrCode(): string;
|
|
3
8
|
export declare function generateSsrFunction(routeNode: RouteNode, appDir: string, outDir: string, componentMap?: Map<string, string>, options?: SsrFunctionOptions): {
|
|
4
9
|
funcPath: string;
|
|
5
10
|
funcCode: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssr-function.d.ts","sourceRoot":"","sources":["../src/ssr-function.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAkB,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAI7F,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQjF;AAgED,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,OAAO,CAAC,EAAE,kBAAkB,GAC3B;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"ssr-function.d.ts","sourceRoot":"","sources":["../src/ssr-function.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAkB,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAI7F,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQjF;AAgED;;;2EAG2E;AAC3E,wBAAgB,qBAAqB,IAAI,MAAM,CA4C9C;AAED,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,OAAO,CAAC,EAAE,kBAAkB,GAC3B;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CA4btD"}
|
package/dist/ssr-function.js
CHANGED
|
@@ -77,6 +77,55 @@ function buildParamExtraction(node, urlParts) {
|
|
|
77
77
|
walk(node);
|
|
78
78
|
return parts;
|
|
79
79
|
}
|
|
80
|
+
/** Shared persisted-store SSR helper block emitted into every generated SSR
|
|
81
|
+
* function (prod via ssr-function.ts, dev via hmr.ts — keep the two callers
|
|
82
|
+
* in sync by calling this). Emit it AFTER the function declarations so the
|
|
83
|
+
* module-level `installPersistedStoreServerHooks` call runs on import. */
|
|
84
|
+
export function persistedStoreSsrCode() {
|
|
85
|
+
return [
|
|
86
|
+
'// ── Persisted-store SSR continuity (createStore / createPathStore persist) ──',
|
|
87
|
+
'// Reads a persisted store\'s cookie value through the adapter request context.',
|
|
88
|
+
'// Client writes mirror URL-encoded; decode on the way back (best effort).',
|
|
89
|
+
'function __persistRead(key) {',
|
|
90
|
+
' const cookieName = persistedStoreCookieName(key);',
|
|
91
|
+
' const req = globalThis.__vesk_request;',
|
|
92
|
+
' if (!req) return null;',
|
|
93
|
+
' const c = req.cookies || {};',
|
|
94
|
+
' const v = typeof c.get === \'function\' ? c.get(cookieName) : c[cookieName];',
|
|
95
|
+
' if (v == null) return null;',
|
|
96
|
+
' try { return decodeURIComponent(String(v)); } catch { return String(v); }',
|
|
97
|
+
'}',
|
|
98
|
+
'',
|
|
99
|
+
'// Drain this request\'s registered persisted keys into a served pre-paint',
|
|
100
|
+
'// script (/store-init.js?t=...) then forget them. `token` selects the',
|
|
101
|
+
'// render\'s bucket for callers outside the ALS scope (the no-layout stream',
|
|
102
|
+
'// path captures its token at the renderPageStream call site); the layout',
|
|
103
|
+
'// path runs this inside the scope and relies on the ambient token.',
|
|
104
|
+
'function __storeInitTag(token) {',
|
|
105
|
+
' const keys = getPersistedStoreKeys(token);',
|
|
106
|
+
' if (keys.length === 0) { resetPersistedStoreKeys(token); return \'\'; }',
|
|
107
|
+
' const values = {};',
|
|
108
|
+
' for (let __i = 0; __i < keys.length; __i++) values[keys[__i]] = __persistRead(keys[__i]);',
|
|
109
|
+
' resetPersistedStoreKeys(token);',
|
|
110
|
+
' const payload = buildStorePrePaintPayload(values);',
|
|
111
|
+
' const url = storeInitScriptGlobal(payload);',
|
|
112
|
+
' return url ? storeInitScriptTag(url) : \'\';',
|
|
113
|
+
'}',
|
|
114
|
+
'',
|
|
115
|
+
'// Inject the blocking store-init <script src> into a full HTML string',
|
|
116
|
+
'// (before </head>; append if the document has no head).',
|
|
117
|
+
'function __injectStoreInit(html) {',
|
|
118
|
+
' const tag = __storeInitTag();',
|
|
119
|
+
' if (tag === \'\') return html;',
|
|
120
|
+
' const idx = html.lastIndexOf(\'</head>\');',
|
|
121
|
+
' if (idx === -1) return html + tag;',
|
|
122
|
+
' return html.slice(0, idx) + tag + html.slice(idx);',
|
|
123
|
+
'}',
|
|
124
|
+
'',
|
|
125
|
+
'installPersistedStoreServerHooks({ read: __persistRead });',
|
|
126
|
+
'',
|
|
127
|
+
].join('\n');
|
|
128
|
+
}
|
|
80
129
|
export function generateSsrFunction(routeNode, appDir, outDir, componentMap, options) {
|
|
81
130
|
const ancestorLayouts = options?.ancestorLayouts || [];
|
|
82
131
|
const middlewareCode = options?.middlewareCode || null;
|
|
@@ -167,6 +216,7 @@ export function generateSsrFunction(routeNode, appDir, outDir, componentMap, opt
|
|
|
167
216
|
'',
|
|
168
217
|
'async function __renderHtml(params, requestUrl) {',
|
|
169
218
|
' return withSsrStore(async () => {',
|
|
219
|
+
' resetPersistedStoreKeys();',
|
|
170
220
|
' let page;',
|
|
171
221
|
' let caughtError = null;',
|
|
172
222
|
" const __expose = process.env.NODE_ENV !== 'production';",
|
|
@@ -187,7 +237,7 @@ export function generateSsrFunction(routeNode, appDir, outDir, componentMap, opt
|
|
|
187
237
|
' if (_inner.head) _head = _inner.head + _head;',
|
|
188
238
|
' }',
|
|
189
239
|
" const html = await renderFullPage('', _layoutCompList[0], { params, children: _body }, __componentRegistry, { hydrate: true, cached: _layoutCompiledList[0]" + bakedOptions + clientScriptOption + dataScriptOption + ", pageHead: _head });",
|
|
190
|
-
" return new Response(html, { headers: { 'Content-Type': 'text/html' }, status: caughtError ? 500 : 200 });",
|
|
240
|
+
" return new Response(__injectStoreInit(html), { headers: { 'Content-Type': 'text/html' }, status: caughtError ? 500 : 200 });",
|
|
191
241
|
' });',
|
|
192
242
|
'}',
|
|
193
243
|
'',
|
|
@@ -207,25 +257,48 @@ export function generateSsrFunction(routeNode, appDir, outDir, componentMap, opt
|
|
|
207
257
|
'async function __renderHtml(params, requestUrl) {',
|
|
208
258
|
' return withSsrStore(async () => {',
|
|
209
259
|
' let stream;',
|
|
260
|
+
// The streamed no-layout page emits its <head> before the component body
|
|
261
|
+
// renders, so its persisted stores don't exist yet when the head is
|
|
262
|
+
// flushed — the pre-paint tag therefore goes into the final chunk, right
|
|
263
|
+
// before </body> (still a blocking, pre-paint script). Capture the render
|
|
264
|
+
// token now (renderPageStream adopts this exact ambient store) so the
|
|
265
|
+
// registry drain in the consumer's start() can hit the right bucket even
|
|
266
|
+
// though it runs outside the ALS scope.
|
|
267
|
+
" const __streamToken = globalThis.__vsk_ssr_token || '';",
|
|
210
268
|
' try {',
|
|
211
269
|
" stream = renderPageStream('', _comp, { params }, __componentRegistry, { hydrate: true, cached: _compiled" + bakedOptions + clientScriptOption + dataScriptOption + ' });',
|
|
212
270
|
' } catch (err) {',
|
|
213
271
|
' if (err && (err.name === \'NotFoundError\' || err.name === \'Redirect\')) throw err;',
|
|
214
272
|
' const html = await __renderErrorFullPage(params, requestUrl, err);',
|
|
215
|
-
" return new Response(html, { headers: { 'Content-Type': 'text/html' }, status: 500 });",
|
|
273
|
+
" return new Response(__injectStoreInit(html), { headers: { 'Content-Type': 'text/html' }, status: 500 });",
|
|
216
274
|
' }',
|
|
217
275
|
' return new Response(new ReadableStream({',
|
|
218
276
|
' async start(controller) {',
|
|
219
277
|
' const enc = new TextEncoder();',
|
|
278
|
+
" let __tail = null;",
|
|
279
|
+
' resetPersistedStoreKeys(__streamToken);',
|
|
220
280
|
' try {',
|
|
221
281
|
' for await (const chunk of stream) {',
|
|
222
|
-
' controller.enqueue(enc.encode(
|
|
282
|
+
' if (__tail !== null) controller.enqueue(enc.encode(__tail));',
|
|
283
|
+
' __tail = chunk;',
|
|
284
|
+
' }',
|
|
285
|
+
' if (__tail !== null) {',
|
|
286
|
+
' const __tag = __storeInitTag(__streamToken);',
|
|
287
|
+
' if (__tag !== \'\') {',
|
|
288
|
+
' const __bi = __tail.lastIndexOf(\'</body>\');',
|
|
289
|
+
' __tail = __bi === -1 ? __tail + __tag : __tail.slice(0, __bi) + __tag + __tail.slice(__bi);',
|
|
290
|
+
' }',
|
|
291
|
+
' controller.enqueue(enc.encode(__tail));',
|
|
292
|
+
' } else {',
|
|
293
|
+
' // Empty stream (no chunks) — nothing to attach the tag to; just',
|
|
294
|
+
' // clear the registry so a later render can\'t inherit these keys.',
|
|
295
|
+
' resetPersistedStoreKeys(__streamToken);',
|
|
223
296
|
' }',
|
|
224
297
|
' } catch (err) {',
|
|
225
298
|
' if (err && (err.name === \'NotFoundError\' || err.name === \'Redirect\')) throw err;',
|
|
226
299
|
' try {',
|
|
227
300
|
' const html = await __renderErrorFullPage(params, requestUrl, err);',
|
|
228
|
-
' controller.enqueue(enc.encode(html));',
|
|
301
|
+
' controller.enqueue(enc.encode(__injectStoreInit(html)));',
|
|
229
302
|
' } catch {}',
|
|
230
303
|
' }',
|
|
231
304
|
' controller.close();',
|
|
@@ -236,6 +309,12 @@ export function generateSsrFunction(routeNode, appDir, outDir, componentMap, opt
|
|
|
236
309
|
'',
|
|
237
310
|
].join('\n');
|
|
238
311
|
}
|
|
312
|
+
// Persisted-store SSR continuity (createStore / createPathStore persist).
|
|
313
|
+
// The adapter-installed read hook pulls each store's cookie value through the
|
|
314
|
+
// request context; the tag the generated pages emit points at an origin-served
|
|
315
|
+
// /store-init.js?t=<token> file (CSP-safe, never inlined — see
|
|
316
|
+
// buildStorePrePaintPayload) so the client can pre-paint the user's value.
|
|
317
|
+
const persistCode = persistedStoreSsrCode();
|
|
239
318
|
let dataCode;
|
|
240
319
|
const exposeErr = "process.env.NODE_ENV !== 'production'";
|
|
241
320
|
// SPA data-nav renders page + layouts through renderPage and never runs
|
|
@@ -254,6 +333,9 @@ export function generateSsrFunction(routeNode, appDir, outDir, componentMap, opt
|
|
|
254
333
|
// process-global token — the cross-request data-slot race, for good. The
|
|
255
334
|
// token dies with the withSsrStore scope wrapped around this block instead.
|
|
256
335
|
' delete globalThis.__vsk_ssr_data;',
|
|
336
|
+
// SPA data-nav only runs renderPage, so the persisted-store registration
|
|
337
|
+
// bucket would otherwise keep this request's keys forever.
|
|
338
|
+
' resetPersistedStoreKeys();',
|
|
257
339
|
' }',
|
|
258
340
|
];
|
|
259
341
|
// The data-nav branch never runs renderFullPage/renderPageStream, so it needs
|
|
@@ -446,7 +528,7 @@ export function generateSsrFunction(routeNode, appDir, outDir, componentMap, opt
|
|
|
446
528
|
'',
|
|
447
529
|
].join('\n');
|
|
448
530
|
const funcCode = [
|
|
449
|
-
"import { renderFullPage, renderPageStream, renderPage, hydratePrecompile, parseCookies, getAction, validateActionInput, issuesToFieldMap, storeDataScriptGlobal, withSsrStore, assertSameOrigin, VeskRequest } from '../runtime.js';",
|
|
531
|
+
"import { renderFullPage, renderPageStream, renderPage, hydratePrecompile, parseCookies, getAction, validateActionInput, issuesToFieldMap, storeDataScriptGlobal, withSsrStore, assertSameOrigin, VeskRequest, installPersistedStoreServerHooks, persistedStoreCookieName, getPersistedStoreKeys, resetPersistedStoreKeys, buildStorePrePaintPayload, storeInitScriptGlobal, storeInitScriptTag } from '../runtime.js';",
|
|
450
532
|
'',
|
|
451
533
|
middlewareCode || '',
|
|
452
534
|
registryCode,
|
|
@@ -455,6 +537,8 @@ export function generateSsrFunction(routeNode, appDir, outDir, componentMap, opt
|
|
|
455
537
|
paramsCode,
|
|
456
538
|
htmlFnCode,
|
|
457
539
|
'',
|
|
540
|
+
persistCode,
|
|
541
|
+
'',
|
|
458
542
|
'export async function handle(request) {',
|
|
459
543
|
' const url = new URL(request.url);',
|
|
460
544
|
' const params = __paramsFor(url.pathname);',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vesk/adapter",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.60",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Vesk adapter — builds deployable .vesk/ output for Deno and Node serverless",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
"sharp": "^0.35.3"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@vesk/compiler": "^0.2.
|
|
27
|
-
"@vesk/runtime": "^0.2.
|
|
28
|
-
"@vesk/types": "^0.2.
|
|
26
|
+
"@vesk/compiler": "^0.2.60",
|
|
27
|
+
"@vesk/runtime": "^0.2.60",
|
|
28
|
+
"@vesk/types": "^0.2.60"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@types/ws": "^8.18.1",
|