@vesk/adapter 0.2.93 → 0.2.95
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 +60 -13
- package/dist/dev-server.d.ts.map +1 -1
- package/dist/dev-server.js +8 -1
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +13 -1
- package/dist/platform-deploy.d.ts +28 -0
- package/dist/platform-deploy.d.ts.map +1 -1
- package/dist/platform-deploy.js +108 -23
- package/dist/platform-handler.d.ts.map +1 -1
- package/dist/platform-handler.js +17 -7
- package/dist/prod-server.d.ts.map +1 -1
- package/dist/prod-server.js +235 -193
- package/dist/server-only.d.ts +9 -0
- package/dist/server-only.d.ts.map +1 -1
- package/dist/server-only.js +11 -0
- package/dist/ssr-function.d.ts.map +1 -1
- package/dist/ssr-function.js +18 -3
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-bundle.d.ts","sourceRoot":"","sources":["../src/client-bundle.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,SAAS,EAAE,mBAAmB,EAAE,kBAAkB,EAAmF,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"client-bundle.d.ts","sourceRoot":"","sources":["../src/client-bundle.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,SAAS,EAAE,mBAAmB,EAAE,kBAAkB,EAAmF,MAAM,yBAAyB,CAAC;AAiFnL;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CA4BhE;AAED;;;;;GAKG;AACH,UAAU,YAAY;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAC7B,EAAE,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACvB,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,CAAC,EAAE;YAAE,IAAI,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAAC,IAAI,CAAC,EAAE;YAAE,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE;gBAAE,IAAI,CAAC,EAAE,MAAM,CAAC;gBAAC,IAAI,CAAC,EAAE,MAAM,CAAA;aAAE,CAAA;SAAE,CAAA;KAAE,CAAC,CAAC;IACtH,WAAW,CAAC,EAAE;QACZ,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE;YAAE,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAC1C,YAAY,CAAC,EAAE,KAAK,CAAC;YAAE,IAAI,CAAC,EAAE;gBAAE,IAAI,CAAC,EAAE,MAAM,CAAC;gBAAC,MAAM,CAAC,EAAE;oBAAE,IAAI,CAAC,EAAE,MAAM,CAAC;oBAAC,IAAI,CAAC,EAAE,MAAM,CAAA;iBAAE,CAAA;aAAE,CAAA;SAAE,CAAC,CAAC;KAC/F,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AA4DD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAKzD;AAkCD;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA+B7D;AAiCD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAyBlD;AA8RD;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA+B5D;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASxD;AA4CD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,GAAG,MAAM,CAoBnG;AAED,yEAAyE;AACzE,eAAO,MAAM,iBAAiB,cAAc,CAAC;AAE7C;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,MAAM,CAKtE;AAED,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,CA41B7B;AAMD,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CA+B3D;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAkClE;AAoCD;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAI/F"}
|
package/dist/client-bundle.js
CHANGED
|
@@ -59,12 +59,24 @@ function fileUnchanged(filePath, cached) {
|
|
|
59
59
|
return false;
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
|
-
function
|
|
62
|
+
function hasServerMiddleware(nodes) {
|
|
63
|
+
for (const node of nodes) {
|
|
64
|
+
if (node.hasMiddleware)
|
|
65
|
+
return true;
|
|
66
|
+
if (node.children?.length && hasServerMiddleware(node.children))
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
function buildRouterOpts(options, serverMiddleware) {
|
|
63
72
|
const ttl = options?.routeDataCache;
|
|
73
|
+
const opts = [];
|
|
74
|
+
if (serverMiddleware)
|
|
75
|
+
opts.push('serverMiddleware: true');
|
|
64
76
|
if (typeof ttl === 'number' && ttl > 0) {
|
|
65
|
-
|
|
77
|
+
opts.push(`routeDataCache: ${ttl}`);
|
|
66
78
|
}
|
|
67
|
-
return '';
|
|
79
|
+
return opts.length ? `, { ${opts.join(', ')} }` : '';
|
|
68
80
|
}
|
|
69
81
|
function findRuntimeSrc(appDir) {
|
|
70
82
|
const monorepoRoot = resolve(__dirname, '..', '..', '..');
|
|
@@ -143,7 +155,7 @@ function isAnyImport(node) {
|
|
|
143
155
|
* map (registrations would land on a detached object).
|
|
144
156
|
*/
|
|
145
157
|
function isRuntimePreamble(node) {
|
|
146
|
-
if (node.type === 'FunctionDeclaration' && (node.id?.name === '__cleanup' || node.id?.name === '__place')) {
|
|
158
|
+
if (node.type === 'FunctionDeclaration' && (node.id?.name === '__cleanup' || node.id?.name === '__place' || node.id?.name === '__reconcileRegion')) {
|
|
147
159
|
return true;
|
|
148
160
|
}
|
|
149
161
|
if (node.type === 'VariableDeclaration') {
|
|
@@ -1617,16 +1629,22 @@ export async function generateClientBundle(routeTree, appDir, componentMap, opti
|
|
|
1617
1629
|
loader: { '.js': 'tsx' },
|
|
1618
1630
|
legalComments: 'none',
|
|
1619
1631
|
...(appTsconfig ? { tsconfig: appTsconfig } : {}),
|
|
1620
|
-
// Stub
|
|
1621
|
-
//
|
|
1622
|
-
//
|
|
1623
|
-
//
|
|
1624
|
-
//
|
|
1632
|
+
// Stub only the OPTIONAL CJS deps (canvas for raster export, @zxing/*
|
|
1633
|
+
// for scan validation). They degrade gracefully and their absence must
|
|
1634
|
+
// not break the bundle.
|
|
1635
|
+
//
|
|
1636
|
+
// `qrcode-generator` must NOT be stubbed: it is the pure-JS encoder
|
|
1637
|
+
// every client-side QR (vesk-qr's dynamic `import("qrcode-generator")`)
|
|
1638
|
+
// runs on. Stubbing it to `export {}` makes `getQrcode()` resolve to an
|
|
1639
|
+
// empty object, so `CofoundrMatrix.generate()` throws
|
|
1640
|
+
// "QREncodingError: generator is not a function" during hydration and
|
|
1641
|
+
// the page falls back to the client error boundary. esbuild bundles it
|
|
1642
|
+
// as CJS fine; only genuinely Node-only/optional deps belong here.
|
|
1625
1643
|
plugins: [
|
|
1626
1644
|
{
|
|
1627
1645
|
name: 'stub-browser-packages',
|
|
1628
1646
|
setup(b) {
|
|
1629
|
-
b.onResolve({ filter: /^(
|
|
1647
|
+
b.onResolve({ filter: /^(canvas|@zxing\/(browser|node))(\/|$)/ }, (args) => ({ path: args.path, namespace: 'browser-stub' }));
|
|
1630
1648
|
b.onLoad({ filter: /.*/, namespace: 'browser-stub' }, () => ({
|
|
1631
1649
|
contents: 'export {}\n',
|
|
1632
1650
|
loader: 'js',
|
|
@@ -1914,6 +1932,31 @@ async function buildMainBundle(routeTree, runtimeDir, codeSplit, mono, hmr, impo
|
|
|
1914
1932
|
'\tfallback.appendChild(end);\n' +
|
|
1915
1933
|
'\tfor (let i = 0; i < nodes.length; i++) fallback.insertBefore(nodes[i], end);\n' +
|
|
1916
1934
|
'}\n';
|
|
1935
|
+
const reconcileRegionFn = 'function __reconcileRegion(parent, id, branch, walker) {\n' +
|
|
1936
|
+
'\tif (!parent) return;\n' +
|
|
1937
|
+
'\tlet start = null;\n' +
|
|
1938
|
+
'\tlet end = null;\n' +
|
|
1939
|
+
'\tfor (let n = parent.firstChild; n; n = n.nextSibling) {\n' +
|
|
1940
|
+
'\t\tif (n.nodeType !== 8) continue;\n' +
|
|
1941
|
+
"\t\tconst text = n.textContent || '';\n" +
|
|
1942
|
+
"\t\tif (text === 'vesk-r:' + id + ':0' || text === 'vesk-r:' + id + ':1') start = n;\n" +
|
|
1943
|
+
"\t\telse if (text === 'vesk-r-end:' + id) end = n;\n" +
|
|
1944
|
+
'\t\tif (start && end) break;\n' +
|
|
1945
|
+
'\t}\n' +
|
|
1946
|
+
'\tif (!start || !end) return;\n' +
|
|
1947
|
+
"\tconst ssrBranch = (start.textContent || '').slice(-2) === ':1' ? 1 : 0;\n" +
|
|
1948
|
+
'\tif (ssrBranch !== branch) {\n' +
|
|
1949
|
+
'\t\tlet n = start.nextSibling;\n' +
|
|
1950
|
+
'\t\twhile (n && n !== end) {\n' +
|
|
1951
|
+
'\t\t\tconst next = n.nextSibling;\n' +
|
|
1952
|
+
'\t\t\tn.remove();\n' +
|
|
1953
|
+
'\t\t\tn = next;\n' +
|
|
1954
|
+
'\t\t}\n' +
|
|
1955
|
+
'\t\tif (walker && walker.retireDetached) walker.retireDetached();\n' +
|
|
1956
|
+
'\t}\n' +
|
|
1957
|
+
'\tstart.remove();\n' +
|
|
1958
|
+
'\tend.remove();\n' +
|
|
1959
|
+
'}\n';
|
|
1917
1960
|
const updateComponentsFn = 'function __updateComponents(nodes) {\n' +
|
|
1918
1961
|
' for (const n of nodes) {\n' +
|
|
1919
1962
|
" if (n._pageName && __components[n._pageName]) n.page = __components[n._pageName];\n" +
|
|
@@ -1950,7 +1993,7 @@ async function buildMainBundle(routeTree, runtimeDir, codeSplit, mono, hmr, impo
|
|
|
1950
1993
|
' }\n' +
|
|
1951
1994
|
' }\n' +
|
|
1952
1995
|
'}\n';
|
|
1953
|
-
const routerOpts = buildRouterOpts({ routeDataCache });
|
|
1996
|
+
const routerOpts = buildRouterOpts({ routeDataCache }, hasServerMiddleware(routeTree));
|
|
1954
1997
|
const startRouterCode = 'const __startRouter = function() {\n' +
|
|
1955
1998
|
' __updateComponents(__routeTree);\n' +
|
|
1956
1999
|
` const __router = createFileRouter(__routeTree${routerOpts});\n` +
|
|
@@ -1983,7 +2026,8 @@ async function buildMainBundle(routeTree, runtimeDir, codeSplit, mono, hmr, impo
|
|
|
1983
2026
|
.join('') +
|
|
1984
2027
|
'globalThis.__runtime_comps = __runtime_comps;\n' +
|
|
1985
2028
|
'globalThis.__cleanup = __cleanup;\n' +
|
|
1986
|
-
'globalThis.__place = __place;\n
|
|
2029
|
+
'globalThis.__place = __place;\n' +
|
|
2030
|
+
'globalThis.__reconcileRegion = __reconcileRegion;\n\n';
|
|
1987
2031
|
const extraGlobals = [...(runtimeImportNames || [])]
|
|
1988
2032
|
.filter(n => n && n !== 'default')
|
|
1989
2033
|
.map(n => `globalThis.${n} = ${n};\n`)
|
|
@@ -2000,6 +2044,7 @@ async function buildMainBundle(routeTree, runtimeDir, codeSplit, mono, hmr, impo
|
|
|
2000
2044
|
(sharedModuleBundle ? sharedModuleBundle + '\n' : '') +
|
|
2001
2045
|
cleanupFn +
|
|
2002
2046
|
placeFn +
|
|
2047
|
+
reconcileRegionFn +
|
|
2003
2048
|
'globalThis.__components = __components;\n' +
|
|
2004
2049
|
resolveNamesFn +
|
|
2005
2050
|
updateComponentsFn +
|
|
@@ -2015,7 +2060,7 @@ async function buildMainBundle(routeTree, runtimeDir, codeSplit, mono, hmr, impo
|
|
|
2015
2060
|
const hydratorAliasLines = mono?.hydratorAliasLines || [];
|
|
2016
2061
|
const aliasCode = aliasLines.length > 0 ? aliasLines.join('\n') + '\n' : '';
|
|
2017
2062
|
const hydratorAliasCode = hydratorAliasLines.length > 0 ? hydratorAliasLines.join('\n') + '\n' : '';
|
|
2018
|
-
const routerOpts = buildRouterOpts({ routeDataCache });
|
|
2063
|
+
const routerOpts = buildRouterOpts({ routeDataCache }, hasServerMiddleware(routeTree));
|
|
2019
2064
|
const code = preamble +
|
|
2020
2065
|
'const __components = {};\n' +
|
|
2021
2066
|
'const __hydrators = {};\n' +
|
|
@@ -2026,10 +2071,12 @@ async function buildMainBundle(routeTree, runtimeDir, codeSplit, mono, hmr, impo
|
|
|
2026
2071
|
hydratorAliasCode +
|
|
2027
2072
|
cleanupFn +
|
|
2028
2073
|
placeFn +
|
|
2074
|
+
reconcileRegionFn +
|
|
2029
2075
|
'globalThis.__components = __components;\n' +
|
|
2030
2076
|
'globalThis.__runtime_comps = __runtime_comps;\n' +
|
|
2031
2077
|
'globalThis.__cleanup = __cleanup;\n' +
|
|
2032
2078
|
'globalThis.__place = __place;\n' +
|
|
2079
|
+
'globalThis.__reconcileRegion = __reconcileRegion;\n' +
|
|
2033
2080
|
allRuntimeImports.map(n => `globalThis.${n} = ${n};\n`).join('') +
|
|
2034
2081
|
'function __resolveNames(nodes) {\n' +
|
|
2035
2082
|
' for (const n of nodes) {\n' +
|
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;AAO7C,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;AAwDD,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,
|
|
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;AAO7C,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;AAwDD,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,CAgBrD;AAUD,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA4sBvG"}
|
package/dist/dev-server.js
CHANGED
|
@@ -150,7 +150,14 @@ export function devBootstrapScript() {
|
|
|
150
150
|
export function injectDevScripts(html) {
|
|
151
151
|
if (!html.includes('</body>'))
|
|
152
152
|
return html;
|
|
153
|
-
|
|
153
|
+
// SSR already emits its own client script (hmr.ts bakes
|
|
154
|
+
// `clientScriptUrl: "/_vesk/static/client.js"`). Injecting a second copy at
|
|
155
|
+
// `/_vesk/client.js` loads the runtime module twice, giving the page two
|
|
156
|
+
// routers and two sets of event listeners — every SPA click then runs
|
|
157
|
+
// navigate() twice and pushes a duplicate history entry. Only add the
|
|
158
|
+
// fallback client script for HTML that has none.
|
|
159
|
+
const hasClientScript = html.includes('/_vesk/static/client.js') || html.includes('/_vesk/client.js');
|
|
160
|
+
const scripts = (hasClientScript ? '' : '\t<script type="module" src="/_vesk/client.js"></script>\n') +
|
|
154
161
|
'\t<script type="module" src="/_vesk/hmr.js"></script>\n' +
|
|
155
162
|
devBootstrapScript() +
|
|
156
163
|
'\n';
|
package/dist/middleware.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAA2B,MAAM,yBAAyB,CAAC;AAS5F,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,mBAAmB,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAA2B,MAAM,yBAAyB,CAAC;AAS5F,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,mBAAmB,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAuFhG;AAED,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAqF5E"}
|
package/dist/middleware.js
CHANGED
|
@@ -4,18 +4,22 @@ function extractMiddlewareBody(src) {
|
|
|
4
4
|
const parts = extractMiddlewareParts(src);
|
|
5
5
|
if (!parts)
|
|
6
6
|
return null;
|
|
7
|
-
return { params: parts.params, body: parts.body };
|
|
7
|
+
return { params: parts.params, body: parts.body, imports: parts.imports };
|
|
8
8
|
}
|
|
9
9
|
export function compileMiddleware(mwChain, _appDir) {
|
|
10
10
|
if (mwChain.length === 0)
|
|
11
11
|
return null;
|
|
12
12
|
const parts = [];
|
|
13
|
+
const imports = [];
|
|
13
14
|
for (let i = 0; i < mwChain.length; i++) {
|
|
14
15
|
const { sourcePath } = mwChain[i];
|
|
15
16
|
const src = readFileSync(sourcePath, 'utf-8');
|
|
16
17
|
const extracted = extractMiddlewareBody(src);
|
|
17
18
|
if (!extracted)
|
|
18
19
|
continue;
|
|
20
|
+
for (const line of extracted.imports)
|
|
21
|
+
if (!imports.includes(line))
|
|
22
|
+
imports.push(line);
|
|
19
23
|
parts.push(`async function mw_${i}(${extracted.params}) {\n${extracted.body}\n}`);
|
|
20
24
|
}
|
|
21
25
|
if (parts.length === 0)
|
|
@@ -23,6 +27,8 @@ export function compileMiddleware(mwChain, _appDir) {
|
|
|
23
27
|
const code = [
|
|
24
28
|
'// Auto-generated middleware chain — do not edit',
|
|
25
29
|
'',
|
|
30
|
+
...imports,
|
|
31
|
+
...(imports.length ? [''] : []),
|
|
26
32
|
parts.join('\n\n'),
|
|
27
33
|
'',
|
|
28
34
|
`const chain = [${parts.map((_, i) => `mw_${i}`).join(', ')}];`,
|
|
@@ -93,10 +99,14 @@ export function compileMiddlewareCode(mwSourceTexts) {
|
|
|
93
99
|
if (!mwSourceTexts || mwSourceTexts.length === 0)
|
|
94
100
|
return null;
|
|
95
101
|
const parts = [];
|
|
102
|
+
const imports = [];
|
|
96
103
|
for (let i = 0; i < mwSourceTexts.length; i++) {
|
|
97
104
|
const extracted = extractMiddlewareBody(mwSourceTexts[i]);
|
|
98
105
|
if (!extracted)
|
|
99
106
|
continue;
|
|
107
|
+
for (const line of extracted.imports)
|
|
108
|
+
if (!imports.includes(line))
|
|
109
|
+
imports.push(line);
|
|
100
110
|
parts.push(`async function mw_${i}(${extracted.params}) {\n${extracted.body}\n}`);
|
|
101
111
|
}
|
|
102
112
|
if (parts.length === 0)
|
|
@@ -104,6 +114,8 @@ export function compileMiddlewareCode(mwSourceTexts) {
|
|
|
104
114
|
const code = [
|
|
105
115
|
'// ── Middleware chain (inline) ──',
|
|
106
116
|
'',
|
|
117
|
+
...imports,
|
|
118
|
+
...(imports.length ? [''] : []),
|
|
107
119
|
parts.join('\n\n'),
|
|
108
120
|
'',
|
|
109
121
|
`const __mwChain = [${parts.map((_, i) => `mw_${i}`).join(', ')}];`,
|
|
@@ -4,6 +4,22 @@ import type { Platform } from '@vesk/adapter/src/platform';
|
|
|
4
4
|
export interface DeployContext extends PlatformBuildContext {
|
|
5
5
|
prerenderedRoutes: SsgRouteResult[];
|
|
6
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* Ship the installed TCP driver packages (and their transitive dependency
|
|
9
|
+
* closures) into a Node function's `node_modules`.
|
|
10
|
+
*
|
|
11
|
+
* A serverless function built by Vesk is otherwise self-contained — esbuild
|
|
12
|
+
* inlines everything. But a driver loaded through a variable `import(spec)`
|
|
13
|
+
* (e.g. `slintorm`'s `importDriver("pg")`) is invisible to esbuild *and* to the
|
|
14
|
+
* host's dependency tracer, and Build Output API functions do not install
|
|
15
|
+
* package.json dependencies. Without this the Postgres driver fails at runtime
|
|
16
|
+
* with `Cannot find module 'pg'` even though it is installed at build time.
|
|
17
|
+
*
|
|
18
|
+
* Only `dependencies`/`optionalDependencies` are followed (never dev deps), and
|
|
19
|
+
* nested `node_modules` are skipped because every dependency is flattened into
|
|
20
|
+
* the function's `node_modules` by name.
|
|
21
|
+
*/
|
|
22
|
+
export declare function shipNodeDriverClosures(projectRoot: string, funcDir: string): void;
|
|
7
23
|
/**
|
|
8
24
|
* Universal deployment emit. The handler, the bundle and the static layout are
|
|
9
25
|
* shared across every platform — only the ~10-line shell each runtime mandates
|
|
@@ -16,4 +32,16 @@ export interface DeployContext extends PlatformBuildContext {
|
|
|
16
32
|
* not a symlink).
|
|
17
33
|
*/
|
|
18
34
|
export declare function emitPlatformOutput(platform: Platform, ctx: DeployContext): Promise<string | null>;
|
|
35
|
+
/**
|
|
36
|
+
* Vercel Node entry source.
|
|
37
|
+
*
|
|
38
|
+
* The request URL is the base that SSR helpers resolve relative
|
|
39
|
+
* `useFetch('/api/…')` calls against. On Vercel, `req.headers.host` can be the
|
|
40
|
+
* deployment-specific host, which sits behind deployment protection, while
|
|
41
|
+
* `x-forwarded-host` carries the public alias the browser used. Preferring the
|
|
42
|
+
* forwarded host/proto keeps internal SSR fetches on the public origin; hitting
|
|
43
|
+
* the protected host follows a redirect to Vercel's auth HTML, which then fails
|
|
44
|
+
* `res.json()` with `Unexpected token '<'`.
|
|
45
|
+
*/
|
|
46
|
+
export declare function vercelBootstrapSource(): string;
|
|
19
47
|
//# sourceMappingURL=platform-deploy.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform-deploy.d.ts","sourceRoot":"","sources":["../src/platform-deploy.ts"],"names":[],"mappings":"AAEA,OAAO,EAAwD,KAAK,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"platform-deploy.d.ts","sourceRoot":"","sources":["../src/platform-deploy.ts"],"names":[],"mappings":"AAEA,OAAO,EAAwD,KAAK,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAGrI,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAE3D,MAAM,WAAW,aAAc,SAAQ,oBAAoB;IACzD,iBAAiB,EAAE,cAAc,EAAE,CAAC;CACrC;AAkBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CA0BjF;AA0BD;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAoFvG;AAqGD;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CA2B9C"}
|
package/dist/platform-deploy.js
CHANGED
|
@@ -1,7 +1,71 @@
|
|
|
1
|
-
import { writeFileSync, mkdirSync, rmSync, cpSync } from 'node:fs';
|
|
2
|
-
import { resolve } from 'node:path';
|
|
1
|
+
import { writeFileSync, mkdirSync, rmSync, cpSync, readFileSync, existsSync } from 'node:fs';
|
|
2
|
+
import { resolve, dirname, relative } from 'node:path';
|
|
3
3
|
import { generatePlatformHandlerSource, bundlePlatformHandler } from '@vesk/adapter/src/platform-handler';
|
|
4
4
|
import { ensureCleanDir, writePlatformStatic, writePrerenderedStatic, listStaticDir, mimeFor } from '@vesk/adapter/src/platform-output';
|
|
5
|
+
import { tcpDriverPackages } from '@vesk/adapter/src/server-only';
|
|
6
|
+
/**
|
|
7
|
+
* Resolve an installed package directory the way Node does: walk up from the
|
|
8
|
+
* project root looking for `node_modules/<name>` (handles npm hoisting and
|
|
9
|
+
* monorepo workspaces). Returns null when the package is not installed.
|
|
10
|
+
*/
|
|
11
|
+
function resolveInstalledPackage(projectRoot, name) {
|
|
12
|
+
let dir = projectRoot;
|
|
13
|
+
while (true) {
|
|
14
|
+
const candidate = resolve(dir, 'node_modules', name);
|
|
15
|
+
if (existsSync(resolve(candidate, 'package.json')))
|
|
16
|
+
return candidate;
|
|
17
|
+
const parent = dirname(dir);
|
|
18
|
+
if (parent === dir)
|
|
19
|
+
return null;
|
|
20
|
+
dir = parent;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Ship the installed TCP driver packages (and their transitive dependency
|
|
25
|
+
* closures) into a Node function's `node_modules`.
|
|
26
|
+
*
|
|
27
|
+
* A serverless function built by Vesk is otherwise self-contained — esbuild
|
|
28
|
+
* inlines everything. But a driver loaded through a variable `import(spec)`
|
|
29
|
+
* (e.g. `slintorm`'s `importDriver("pg")`) is invisible to esbuild *and* to the
|
|
30
|
+
* host's dependency tracer, and Build Output API functions do not install
|
|
31
|
+
* package.json dependencies. Without this the Postgres driver fails at runtime
|
|
32
|
+
* with `Cannot find module 'pg'` even though it is installed at build time.
|
|
33
|
+
*
|
|
34
|
+
* Only `dependencies`/`optionalDependencies` are followed (never dev deps), and
|
|
35
|
+
* nested `node_modules` are skipped because every dependency is flattened into
|
|
36
|
+
* the function's `node_modules` by name.
|
|
37
|
+
*/
|
|
38
|
+
export function shipNodeDriverClosures(projectRoot, funcDir) {
|
|
39
|
+
const destModules = resolve(funcDir, 'node_modules');
|
|
40
|
+
const seen = new Set();
|
|
41
|
+
const queue = tcpDriverPackages();
|
|
42
|
+
while (queue.length > 0) {
|
|
43
|
+
const name = queue.shift();
|
|
44
|
+
if (seen.has(name))
|
|
45
|
+
continue;
|
|
46
|
+
seen.add(name);
|
|
47
|
+
const pkgDir = resolveInstalledPackage(projectRoot, name);
|
|
48
|
+
if (!pkgDir)
|
|
49
|
+
continue;
|
|
50
|
+
const dest = resolve(destModules, name);
|
|
51
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
52
|
+
cpSync(pkgDir, dest, {
|
|
53
|
+
recursive: true,
|
|
54
|
+
filter: (src) => !relative(pkgDir, src).split(/[\\/]/).includes('node_modules'),
|
|
55
|
+
});
|
|
56
|
+
let pkg = {};
|
|
57
|
+
try {
|
|
58
|
+
pkg = JSON.parse(readFileSync(resolve(pkgDir, 'package.json'), 'utf-8'));
|
|
59
|
+
}
|
|
60
|
+
catch { /* unreadable package.json: copy the package as-is */ }
|
|
61
|
+
const deps = {
|
|
62
|
+
...(pkg.dependencies || {}),
|
|
63
|
+
...(pkg.optionalDependencies || {}),
|
|
64
|
+
};
|
|
65
|
+
for (const dep of Object.keys(deps))
|
|
66
|
+
queue.push(dep);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
5
69
|
/**
|
|
6
70
|
* Universal deployment emit. The handler, the bundle and the static layout are
|
|
7
71
|
* shared across every platform — only the ~10-line shell each runtime mandates
|
|
@@ -60,6 +124,8 @@ export async function emitPlatformOutput(platform, ctx) {
|
|
|
60
124
|
}
|
|
61
125
|
handlerRel = `${shell.functionFile.dir}/${shell.functionFile.file}`;
|
|
62
126
|
await bundlePlatformHandler({ entry, outfile: resolve(funcDir, shell.functionFile.file), nodeBuiltins: shell.nodeBuiltins });
|
|
127
|
+
if (shell.nodeBuiltins)
|
|
128
|
+
shipNodeDriverClosures(projectRoot, funcDir);
|
|
63
129
|
}
|
|
64
130
|
else {
|
|
65
131
|
handlerRel = shell.outfile || 'index.js';
|
|
@@ -186,6 +252,45 @@ function serveEmbeddedStatic(request) {
|
|
|
186
252
|
return null;
|
|
187
253
|
}`;
|
|
188
254
|
}
|
|
255
|
+
/**
|
|
256
|
+
* Vercel Node entry source.
|
|
257
|
+
*
|
|
258
|
+
* The request URL is the base that SSR helpers resolve relative
|
|
259
|
+
* `useFetch('/api/…')` calls against. On Vercel, `req.headers.host` can be the
|
|
260
|
+
* deployment-specific host, which sits behind deployment protection, while
|
|
261
|
+
* `x-forwarded-host` carries the public alias the browser used. Preferring the
|
|
262
|
+
* forwarded host/proto keeps internal SSR fetches on the public origin; hitting
|
|
263
|
+
* the protected host follows a redirect to Vercel's auth HTML, which then fails
|
|
264
|
+
* `res.json()` with `Unexpected token '<'`.
|
|
265
|
+
*/
|
|
266
|
+
export function vercelBootstrapSource() {
|
|
267
|
+
return [
|
|
268
|
+
'export default async function veskNodeEntry(req, res) {',
|
|
269
|
+
" const __fwdHost = String(req.headers['x-forwarded-host'] || '').split(',')[0].trim();",
|
|
270
|
+
" const __host = __fwdHost || req.headers.host || 'localhost';",
|
|
271
|
+
" const __fwdProto = String(req.headers['x-forwarded-proto'] || '').split(',')[0].trim();",
|
|
272
|
+
" const __local = __host === 'localhost' || __host.startsWith('127.') || __host === '[::1]';",
|
|
273
|
+
" const __proto = __fwdProto || (__local ? 'http' : 'https');",
|
|
274
|
+
' const url = new URL(req.url, `${__proto}://${__host}`);',
|
|
275
|
+
" const method = req.method || 'GET';",
|
|
276
|
+
' let body;',
|
|
277
|
+
" if (method !== 'GET' && method !== 'HEAD') {",
|
|
278
|
+
' body = await new Promise((resolveBody, reject) => {',
|
|
279
|
+
' const chunks = [];',
|
|
280
|
+
" req.on('data', (c) => chunks.push(c));",
|
|
281
|
+
' req.on("error", reject);',
|
|
282
|
+
' req.on("end", () => resolveBody(Buffer.concat(chunks)));',
|
|
283
|
+
' });',
|
|
284
|
+
' }',
|
|
285
|
+
' const headers = {};',
|
|
286
|
+
' for (const key in req.headers) headers[key] = req.headers[key];',
|
|
287
|
+
' const request = new Request(url, { method, headers, body });',
|
|
288
|
+
' const response = await handleRequest(request);',
|
|
289
|
+
' res.writeHead(response.status, Object.fromEntries(response.headers));',
|
|
290
|
+
' res.end(await response.text());',
|
|
291
|
+
'}',
|
|
292
|
+
].join('\n');
|
|
293
|
+
}
|
|
189
294
|
function shellFor(platform) {
|
|
190
295
|
switch (platform) {
|
|
191
296
|
case 'vercel':
|
|
@@ -206,27 +311,7 @@ function shellFor(platform) {
|
|
|
206
311
|
shouldAddSourcemapSupport: false,
|
|
207
312
|
supportsResponseStreaming: true,
|
|
208
313
|
},
|
|
209
|
-
bootstrap:
|
|
210
|
-
'export default async function veskNodeEntry(req, res) {',
|
|
211
|
-
" const url = new URL(req.url, 'http://' + (req.headers.host || 'localhost'));",
|
|
212
|
-
" const method = req.method || 'GET';",
|
|
213
|
-
' let body;',
|
|
214
|
-
" if (method !== 'GET' && method !== 'HEAD') {",
|
|
215
|
-
' body = await new Promise((resolveBody, reject) => {',
|
|
216
|
-
' const chunks = [];',
|
|
217
|
-
" req.on('data', (c) => chunks.push(c));",
|
|
218
|
-
' req.on("error", reject);',
|
|
219
|
-
' req.on("end", () => resolveBody(Buffer.concat(chunks)));',
|
|
220
|
-
' });',
|
|
221
|
-
' }',
|
|
222
|
-
' const headers = {};',
|
|
223
|
-
' for (const key in req.headers) headers[key] = req.headers[key];',
|
|
224
|
-
' const request = new Request(url, { method, headers, body });',
|
|
225
|
-
' const response = await handleRequest(request);',
|
|
226
|
-
' res.writeHead(response.status, Object.fromEntries(response.headers));',
|
|
227
|
-
' res.end(await response.text());',
|
|
228
|
-
'}',
|
|
229
|
-
].join('\n'),
|
|
314
|
+
bootstrap: vercelBootstrapSource(),
|
|
230
315
|
};
|
|
231
316
|
case 'netlify':
|
|
232
317
|
return {
|
|
@@ -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;AASvE,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,CA4PjF;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,
|
|
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;AASvE,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,CA4PjF;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,CA6JzF;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
|
@@ -348,15 +348,25 @@ export const execSync = () => '';
|
|
|
348
348
|
// their require() calls into `__require` shims that throw in ESM output.
|
|
349
349
|
// esbuild 0.28's string `external` option does not externalize resolvable
|
|
350
350
|
// bare specifiers (it emits `__require` shims instead), so resolve these
|
|
351
|
-
// packages to empty stub modules.
|
|
352
|
-
//
|
|
353
|
-
//
|
|
354
|
-
//
|
|
355
|
-
//
|
|
351
|
+
// packages to empty stub modules. vesk-qr and its optional CJS deps
|
|
352
|
+
// (qrcode-generator, canvas, @zxing/*) are optional at runtime on edge (they
|
|
353
|
+
// fail gracefully), so stubbing them at build time is safe and keeps the
|
|
354
|
+
// bundle valid ESM.
|
|
355
|
+
//
|
|
356
|
+
// Node targets are different: the `createRequire` banner makes the
|
|
357
|
+
// `__require` shim resolve for real, so vesk-qr and its encoder (the CJS
|
|
358
|
+
// `qrcode-generator`) MUST be bundled. A Build Output function ships no
|
|
359
|
+
// package.json deps, and stubbing the encoder makes `buildQrSvg()` throw
|
|
360
|
+
// during SSR (500 on any page that awaits a QR). canvas/@zxing stay
|
|
361
|
+
// stubbed because they are optional and only back raster/scan validation,
|
|
362
|
+
// which degrades gracefully when the decoder is unavailable.
|
|
363
|
+
const qrStubPattern = nodeBuiltins
|
|
364
|
+
? /^(canvas|@zxing\/(browser|node))(\/|$)/
|
|
365
|
+
: /^(vesk-qr|qrcode-generator|canvas|@zxing\/(browser|node))(\/|$)/;
|
|
356
366
|
plugins.push({
|
|
357
|
-
name: 'stub-
|
|
367
|
+
name: 'stub-optional-qr-packages',
|
|
358
368
|
setup(build) {
|
|
359
|
-
build.onResolve({ filter:
|
|
369
|
+
build.onResolve({ filter: qrStubPattern }, (args) => ({ path: args.path, namespace: 'vesk-edge-stub' }));
|
|
360
370
|
build.onLoad({ filter: /.*/, namespace: 'vesk-edge-stub' }, () => ({
|
|
361
371
|
contents: [
|
|
362
372
|
'export const CofoundrMatrix = undefined;\n',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prod-server.d.ts","sourceRoot":"","sources":["../src/prod-server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,KAAK,eAAe,EAAuB,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AAejG,OAAO,KAAK,EAAkB,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAIpG,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,CAAC;AAuIrD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,GAAG,GAAG,CAY9F;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"prod-server.d.ts","sourceRoot":"","sources":["../src/prod-server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,KAAK,eAAe,EAAuB,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AAejG,OAAO,KAAK,EAAkB,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAIpG,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,CAAC;AAuIrD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,GAAG,GAAG,CAY9F;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CA6rBlG"}
|
package/dist/prod-server.js
CHANGED
|
@@ -480,6 +480,37 @@ export async function startProdServer(outDir, options) {
|
|
|
480
480
|
}
|
|
481
481
|
}
|
|
482
482
|
}
|
|
483
|
+
if (url.pathname === '/_vesk/middleware' && middlewareMod) {
|
|
484
|
+
const targetPath = url.searchParams.get('path') || '/';
|
|
485
|
+
const targetUrl = new URL(targetPath, url.origin);
|
|
486
|
+
const middlewareRequest = new Request(targetUrl.href, {
|
|
487
|
+
method: 'GET',
|
|
488
|
+
headers: req.headers,
|
|
489
|
+
});
|
|
490
|
+
const mwEndpointCtx = {
|
|
491
|
+
request: middlewareRequest,
|
|
492
|
+
params: {},
|
|
493
|
+
url: targetUrl,
|
|
494
|
+
locals: Object.assign({}, globalThis.__vesk_server_ctx || {}),
|
|
495
|
+
cookies: {},
|
|
496
|
+
set(key, value) { this.locals[key] = value; },
|
|
497
|
+
get(key) { return this.locals[key]; },
|
|
498
|
+
};
|
|
499
|
+
const mwResult = await middlewareMod.execute(mwEndpointCtx);
|
|
500
|
+
res.writeHead(200, {
|
|
501
|
+
'Content-Type': 'application/json; charset=utf-8',
|
|
502
|
+
'Cache-Control': 'no-store',
|
|
503
|
+
});
|
|
504
|
+
if (mwResult.response) {
|
|
505
|
+
const location = mwResult.response.headers.get('location') || mwResult.response.headers.get('Location');
|
|
506
|
+
if (location) {
|
|
507
|
+
res.end(JSON.stringify({ redirect: location }));
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
res.end(JSON.stringify(mwResult.rewriteUrl ? { rewrite: mwResult.rewriteUrl } : { allow: true }));
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
483
514
|
let mwCtx;
|
|
484
515
|
const serverStore = globalThis.__vesk_server_ctx;
|
|
485
516
|
if (middlewareMod) {
|
|
@@ -526,221 +557,232 @@ export async function startProdServer(outDir, options) {
|
|
|
526
557
|
}
|
|
527
558
|
// Expose root middleware locals to API/SSR handlers (which seed their own
|
|
528
559
|
// ctx.locals from this before running route-level middleware).
|
|
560
|
+
//
|
|
561
|
+
// Scoped to this request: an SSR render can `fetch()` its own API route,
|
|
562
|
+
// which re-enters this handler. Without restoring, that nested request's
|
|
563
|
+
// context (params: {}) stays installed and every later pass of the outer
|
|
564
|
+
// render reads the wrong params.
|
|
565
|
+
const __outerRequest = globalThis.__vesk_request;
|
|
529
566
|
globalThis.__vesk_request = mwCtx;
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
567
|
+
try {
|
|
568
|
+
if (url.pathname.startsWith('/_vesk/action/')) {
|
|
569
|
+
const actionId = url.pathname.replace('/_vesk/action/', '');
|
|
570
|
+
const actionEntry = buildConfig.actions && buildConfig.actions.find(a => a.id === actionId);
|
|
571
|
+
if (!actionEntry) {
|
|
572
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
573
|
+
res.end(JSON.stringify({ ok: false, error: 'Action not found' }));
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
const mod = await loadFunction(actionEntry.function);
|
|
577
|
+
if (!mod || !mod.handleAction) {
|
|
578
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
579
|
+
res.end(JSON.stringify({ ok: false, error: 'Action not found' }));
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
try {
|
|
583
|
+
const webRequest = makeWebRequest(req, url.href, maxBodyBytes);
|
|
584
|
+
const handleAction = mod.handleAction.bind(mod);
|
|
585
|
+
const response = await withSecurityScope(() => handleAction(webRequest, actionId));
|
|
586
|
+
await deliverResponse(res, response);
|
|
587
|
+
}
|
|
588
|
+
catch (e) {
|
|
589
|
+
const status = errorStatus(e, 500);
|
|
590
|
+
const message = status === 500 && process.env.NODE_ENV === 'production'
|
|
591
|
+
? 'Internal Server Error'
|
|
592
|
+
: e instanceof Error ? e.message : String(e);
|
|
593
|
+
res.writeHead(status, { 'Content-Type': 'application/json' });
|
|
594
|
+
res.end(JSON.stringify({ ok: false, error: message }));
|
|
595
|
+
}
|
|
542
596
|
return;
|
|
543
597
|
}
|
|
544
|
-
|
|
545
|
-
const
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
571
|
-
res.end(JSON.stringify({ error: 'Internal Server Error' }));
|
|
598
|
+
if (url.pathname.startsWith('/api')) {
|
|
599
|
+
for (const route of buildConfig.routes) {
|
|
600
|
+
if (route.type === 'api') {
|
|
601
|
+
const params = matchPath(route.path, url.pathname);
|
|
602
|
+
if (params) {
|
|
603
|
+
const mod = await loadFunction(route.function);
|
|
604
|
+
if (!mod) {
|
|
605
|
+
// The route matched, so a 404 would be a lie: the handler is
|
|
606
|
+
// there and could not be loaded.
|
|
607
|
+
if (functionFailure(route.function)) {
|
|
608
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
609
|
+
res.end(JSON.stringify({ error: 'Internal Server Error' }));
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
continue;
|
|
613
|
+
}
|
|
614
|
+
try {
|
|
615
|
+
const webRequest = makeWebRequest(req, url.href, maxBodyBytes);
|
|
616
|
+
const response = await withSecurityScope(() => mod.handle(webRequest));
|
|
617
|
+
await deliverResponse(res, response);
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
catch (e) {
|
|
621
|
+
const status = errorStatus(e, 500);
|
|
622
|
+
res.writeHead(status, { 'Content-Type': 'application/json' });
|
|
623
|
+
res.end(JSON.stringify({ error: status === 500 ? 'Internal Server Error' : e instanceof Error ? e.message : String(e) }));
|
|
572
624
|
return;
|
|
573
625
|
}
|
|
574
|
-
continue;
|
|
575
|
-
}
|
|
576
|
-
try {
|
|
577
|
-
const webRequest = makeWebRequest(req, url.href, maxBodyBytes);
|
|
578
|
-
const response = await withSecurityScope(() => mod.handle(webRequest));
|
|
579
|
-
await deliverResponse(res, response);
|
|
580
|
-
return;
|
|
581
|
-
}
|
|
582
|
-
catch (e) {
|
|
583
|
-
const status = errorStatus(e, 500);
|
|
584
|
-
res.writeHead(status, { 'Content-Type': 'application/json' });
|
|
585
|
-
res.end(JSON.stringify({ error: status === 500 ? 'Internal Server Error' : e instanceof Error ? e.message : String(e) }));
|
|
586
|
-
return;
|
|
587
626
|
}
|
|
588
627
|
}
|
|
589
628
|
}
|
|
590
629
|
}
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
if (!boundaryPath)
|
|
611
|
-
return null;
|
|
612
|
-
const key = `${file}:${boundaryPath}`;
|
|
613
|
-
let html = boundaryCache.has(key) ? boundaryCache.get(key) : null;
|
|
614
|
-
if (html === null) {
|
|
615
|
-
try {
|
|
616
|
-
const runtimePath = resolve(outDir, 'server', 'runtime.js');
|
|
617
|
-
const { renderFullPage, storeDataScriptGlobal } = await import(runtimePath);
|
|
618
|
-
const src = readFileSync(boundaryPath, 'utf-8');
|
|
619
|
-
const compName = resolveComponentName(src) || (file === 'error.vsk' ? 'Error' : 'NotFound');
|
|
620
|
-
html = await renderFullPage(src, compName, props, new Map(), { hydrate: true, cssUrls: pageCssUrls, clientScriptUrl: buildConfig?.assets?.client?.url || '/_vesk/static/client.js', clientScriptIntegrity: buildConfig?.assets?.client?.integrity, security: securityConfig?.security || {}, externalDataScript: storeDataScriptGlobal, sourcePath: boundaryPath, headExtra: bakedHeadExtra });
|
|
621
|
-
}
|
|
622
|
-
catch {
|
|
630
|
+
const appDir = resolve(projectDir, 'app');
|
|
631
|
+
const pageCssUrls = resolveCssUrls({
|
|
632
|
+
enabled: hasBuiltGlobalCss(outDir),
|
|
633
|
+
});
|
|
634
|
+
/**
|
|
635
|
+
* Render the boundary that owns `url.pathname`.
|
|
636
|
+
*
|
|
637
|
+
* Deepest-match over the URL's directories, not a hard read of the root
|
|
638
|
+
* file: `app/admin/not-found.vsk` is the boundary for `/admin/*`, and the
|
|
639
|
+
* root one is the fallback. The generated SSR function does the same walk at
|
|
640
|
+
* build time (`resolveNotFoundFile`) and renders the boundary itself inside
|
|
641
|
+
* the layout stack; this path is what remains for an unmatched URL, for a
|
|
642
|
+
* route with no layout (which streams, so its status is already committed),
|
|
643
|
+
* and for an error thrown outside a page's own try block.
|
|
644
|
+
*/
|
|
645
|
+
const boundaryCache = new Map();
|
|
646
|
+
async function renderBoundaryFile(file, pathname, props) {
|
|
647
|
+
const boundaryPath = resolveBoundaryFileForUrl(pathname, appDir, file);
|
|
648
|
+
if (!boundaryPath)
|
|
623
649
|
return null;
|
|
650
|
+
const key = `${file}:${boundaryPath}`;
|
|
651
|
+
let html = boundaryCache.has(key) ? boundaryCache.get(key) : null;
|
|
652
|
+
if (html === null) {
|
|
653
|
+
try {
|
|
654
|
+
const runtimePath = resolve(outDir, 'server', 'runtime.js');
|
|
655
|
+
const { renderFullPage, storeDataScriptGlobal } = await import(runtimePath);
|
|
656
|
+
const src = readFileSync(boundaryPath, 'utf-8');
|
|
657
|
+
const compName = resolveComponentName(src) || (file === 'error.vsk' ? 'Error' : 'NotFound');
|
|
658
|
+
html = await renderFullPage(src, compName, props, new Map(), { hydrate: true, cssUrls: pageCssUrls, clientScriptUrl: buildConfig?.assets?.client?.url || '/_vesk/static/client.js', clientScriptIntegrity: buildConfig?.assets?.client?.integrity, security: securityConfig?.security || {}, externalDataScript: storeDataScriptGlobal, sourcePath: boundaryPath, headExtra: bakedHeadExtra });
|
|
659
|
+
}
|
|
660
|
+
catch {
|
|
661
|
+
return null;
|
|
662
|
+
}
|
|
624
663
|
}
|
|
664
|
+
return html;
|
|
625
665
|
}
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
input
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
res.
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
res.end(body);
|
|
690
|
-
}
|
|
691
|
-
return;
|
|
692
|
-
}
|
|
693
|
-
catch (e) {
|
|
694
|
-
const err = e instanceof Error ? e : new Error(String(e));
|
|
695
|
-
if (err.name === 'Redirect') {
|
|
696
|
-
const redirect = err;
|
|
697
|
-
res.writeHead(Number(redirect.status) || 302, { Location: typeof redirect.url === 'string' ? redirect.url : '/' });
|
|
698
|
-
res.end();
|
|
666
|
+
let notFoundHtml = null;
|
|
667
|
+
{
|
|
668
|
+
const rendered = await renderBoundaryFile('not-found.vsk', url.pathname, { params: {}, url: url.pathname });
|
|
669
|
+
notFoundHtml = rendered;
|
|
670
|
+
}
|
|
671
|
+
for (const route of buildConfig.routes) {
|
|
672
|
+
if (route.type === 'ssr') {
|
|
673
|
+
const params = matchPath(route.path, url.pathname);
|
|
674
|
+
if (params) {
|
|
675
|
+
const mod = await loadFunction(route.function);
|
|
676
|
+
if (mod) {
|
|
677
|
+
const webRequest = makeWebRequest(req, url.href, maxBodyBytes);
|
|
678
|
+
// During SSR, fetch() with a relative URL (e.g. '/api/student') throws
|
|
679
|
+
// because undici requires an absolute URL and there is no browser
|
|
680
|
+
// origin to resolve against. Wrap globalThis.fetch for the duration
|
|
681
|
+
// of the SSR render so relative API calls resolve against the
|
|
682
|
+
// request's origin — matching what the client does automatically.
|
|
683
|
+
const origin = new URL(url.href).origin;
|
|
684
|
+
const origFetch = globalThis.fetch;
|
|
685
|
+
globalThis.fetch = async (input, init) => {
|
|
686
|
+
if (typeof input === 'string' && input.startsWith('/')) {
|
|
687
|
+
input = origin + input;
|
|
688
|
+
}
|
|
689
|
+
return origFetch(input, init);
|
|
690
|
+
};
|
|
691
|
+
try {
|
|
692
|
+
let cachedResult = null;
|
|
693
|
+
if (route.revalidate && route.revalidate > 0) {
|
|
694
|
+
const { pageIsr } = await import('@vesk/runtime/src/index-server');
|
|
695
|
+
cachedResult = await pageIsr(url.pathname, async () => {
|
|
696
|
+
const response = await withSecurityScope(() => mod.handle(webRequest));
|
|
697
|
+
return { html: await response.text(), headers: Object.fromEntries(response.headers) };
|
|
698
|
+
}, { revalidate: route.revalidate, tags: route.tags || [] });
|
|
699
|
+
}
|
|
700
|
+
if (cachedResult) {
|
|
701
|
+
res.writeHead(200, cachedResult.headers || { 'Content-Type': 'text/html' });
|
|
702
|
+
res.end(cachedResult.html);
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
705
|
+
const response = await withSecurityScope(() => mod.handle(webRequest));
|
|
706
|
+
const headers = Object.fromEntries(response.headers);
|
|
707
|
+
if (!headers['content-type'] && !headers['Content-Type'])
|
|
708
|
+
headers['Content-Type'] = 'text/html';
|
|
709
|
+
if (response.body && typeof response.body.getReader === 'function') {
|
|
710
|
+
res.writeHead(response.status, headers);
|
|
711
|
+
const reader = response.body.getReader();
|
|
712
|
+
const pump = () => {
|
|
713
|
+
reader.read().then(({ done, value }) => {
|
|
714
|
+
if (done) {
|
|
715
|
+
res.end();
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
res.write(value);
|
|
719
|
+
pump();
|
|
720
|
+
}).catch(() => res.end());
|
|
721
|
+
};
|
|
722
|
+
pump();
|
|
723
|
+
}
|
|
724
|
+
else {
|
|
725
|
+
const body = await response.text();
|
|
726
|
+
res.writeHead(response.status, headers);
|
|
727
|
+
res.end(body);
|
|
728
|
+
}
|
|
699
729
|
return;
|
|
700
730
|
}
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
731
|
+
catch (e) {
|
|
732
|
+
const err = e instanceof Error ? e : new Error(String(e));
|
|
733
|
+
if (err.name === 'Redirect') {
|
|
734
|
+
const redirect = err;
|
|
735
|
+
res.writeHead(Number(redirect.status) || 302, { Location: typeof redirect.url === 'string' ? redirect.url : '/' });
|
|
736
|
+
res.end();
|
|
737
|
+
return;
|
|
738
|
+
}
|
|
739
|
+
if (err.name === 'NotFoundError') {
|
|
740
|
+
res.writeHead(404, { 'Content-Type': 'text/html' });
|
|
741
|
+
res.end(notFoundHtml || renderDefaultNotFoundPage({ url: url.pathname, headExtra: bakedHeadExtra }));
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
console.error('vesk ssr error:', err.message);
|
|
745
|
+
// Two seams, both best-effort: a plugin's `onError` (dev-style
|
|
746
|
+
// plugin objects don't exist here) and `_events.ts`'s, which IS
|
|
747
|
+
// baked into the production build.
|
|
748
|
+
await reportServerError(err, {
|
|
749
|
+
url: url.pathname + url.search,
|
|
750
|
+
routePath: route.path,
|
|
751
|
+
target: 'node',
|
|
752
|
+
status: 500,
|
|
753
|
+
buildConfig,
|
|
754
|
+
});
|
|
755
|
+
if (eventsMod) {
|
|
756
|
+
await executeError(err, { url: url.href, routePath: route.path, target: 'node', status: 500 }, eventsMod);
|
|
757
|
+
}
|
|
758
|
+
// Same nearest-boundary walk as not-found above. This is the last resort for a
|
|
759
|
+
// throw the generated function could not absorb — a layout render
|
|
760
|
+
// failure, or the error boundary itself failing — and it must pick
|
|
761
|
+
// the boundary that owns the URL, not the root one.
|
|
762
|
+
const expose = process.env.NODE_ENV !== 'production';
|
|
763
|
+
const errorHtml = await renderBoundaryFile('error.vsk', url.pathname, {
|
|
764
|
+
error: expose ? err.message : 'Internal Server Error',
|
|
765
|
+
stack: expose ? err.stack : '',
|
|
766
|
+
statusCode: 500,
|
|
767
|
+
url: url.pathname,
|
|
768
|
+
});
|
|
769
|
+
res.writeHead(500, { 'Content-Type': 'text/html' });
|
|
770
|
+
res.end(errorHtml || renderDefaultErrorPage({ message: process.env.NODE_ENV !== 'production' ? err.message : undefined, url: url.pathname, headExtra: bakedHeadExtra }));
|
|
704
771
|
return;
|
|
705
772
|
}
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
// plugin objects don't exist here) and `_events.ts`'s, which IS
|
|
709
|
-
// baked into the production build.
|
|
710
|
-
await reportServerError(err, {
|
|
711
|
-
url: url.pathname + url.search,
|
|
712
|
-
routePath: route.path,
|
|
713
|
-
target: 'node',
|
|
714
|
-
status: 500,
|
|
715
|
-
buildConfig,
|
|
716
|
-
});
|
|
717
|
-
if (eventsMod) {
|
|
718
|
-
await executeError(err, { url: url.href, routePath: route.path, target: 'node', status: 500 }, eventsMod);
|
|
773
|
+
finally {
|
|
774
|
+
globalThis.fetch = origFetch;
|
|
719
775
|
}
|
|
720
|
-
// Same nearest-boundary walk as not-found above. This is the last resort for a
|
|
721
|
-
// throw the generated function could not absorb — a layout render
|
|
722
|
-
// failure, or the error boundary itself failing — and it must pick
|
|
723
|
-
// the boundary that owns the URL, not the root one.
|
|
724
|
-
const expose = process.env.NODE_ENV !== 'production';
|
|
725
|
-
const errorHtml = await renderBoundaryFile('error.vsk', url.pathname, {
|
|
726
|
-
error: expose ? err.message : 'Internal Server Error',
|
|
727
|
-
stack: expose ? err.stack : '',
|
|
728
|
-
statusCode: 500,
|
|
729
|
-
url: url.pathname,
|
|
730
|
-
});
|
|
731
|
-
res.writeHead(500, { 'Content-Type': 'text/html' });
|
|
732
|
-
res.end(errorHtml || renderDefaultErrorPage({ message: process.env.NODE_ENV !== 'production' ? err.message : undefined, url: url.pathname, headExtra: bakedHeadExtra }));
|
|
733
|
-
return;
|
|
734
|
-
}
|
|
735
|
-
finally {
|
|
736
|
-
globalThis.fetch = origFetch;
|
|
737
776
|
}
|
|
738
777
|
}
|
|
739
778
|
}
|
|
740
779
|
}
|
|
780
|
+
res.writeHead(404, { 'Content-Type': 'text/html' });
|
|
781
|
+
res.end(notFoundHtml || renderDefaultNotFoundPage({ url: url.pathname, headExtra: bakedHeadExtra }));
|
|
782
|
+
}
|
|
783
|
+
finally {
|
|
784
|
+
globalThis.__vesk_request = __outerRequest;
|
|
741
785
|
}
|
|
742
|
-
res.writeHead(404, { 'Content-Type': 'text/html' });
|
|
743
|
-
res.end(notFoundHtml || renderDefaultNotFoundPage({ url: url.pathname, headExtra: bakedHeadExtra }));
|
|
744
786
|
});
|
|
745
787
|
try {
|
|
746
788
|
await eventsMod?.executeStart?.({ server, port, host });
|
package/dist/server-only.d.ts
CHANGED
|
@@ -52,6 +52,15 @@
|
|
|
52
52
|
* `packages/adapter/AGENTS.md` for the three outcomes the plugin must
|
|
53
53
|
* distinguish.
|
|
54
54
|
*/
|
|
55
|
+
/**
|
|
56
|
+
* The TCP drivers that are real npm packages (not `node:` builtins). A Node
|
|
57
|
+
* serverless function bundles statically-imported code, but a driver loaded
|
|
58
|
+
* through a variable `import(spec)` (e.g. `slintorm`'s `importDriver("pg")`)
|
|
59
|
+
* cannot be traced by the bundler or the platform's dependency tracer. Node
|
|
60
|
+
* targets ship these package closures into the function's `node_modules` so
|
|
61
|
+
* that dynamic import resolves at runtime.
|
|
62
|
+
*/
|
|
63
|
+
export declare function tcpDriverPackages(): string[];
|
|
55
64
|
export type ServerOnlyKind = 'server-only-package' | 'tcp-driver';
|
|
56
65
|
/**
|
|
57
66
|
* Classify a bare import specifier. Returns null for anything that is fine on
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-only.d.ts","sourceRoot":"","sources":["../src/server-only.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AAsCH,MAAM,MAAM,cAAc,GAAG,qBAAqB,GAAG,YAAY,CAAC;AAElE;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAMrE;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,MAAM,CAkB5F;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,cAAc,GAAG,IAAwB,GAAG,MAAM,CAoBjI;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,cAAc,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,2BAA2B;IAC3B,MAAM,EAAE,MAAM,CAAC;CAChB;AAWD;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,GAC3C,mBAAmB,EAAE,CA8BvB;AAYD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,mBAAmB,EAAE,GAAG,KAAK,CAU7E;AAYD,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAGlH;AAMD,sDAAsD;AACtD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,EAAO,GAAG,MAAM,EAAE,CAwB3E;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,mBAAmB,EAAE,CAUzE"}
|
|
1
|
+
{"version":3,"file":"server-only.d.ts","sourceRoot":"","sources":["../src/server-only.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AAsCH;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,EAAE,CAE5C;AAED,MAAM,MAAM,cAAc,GAAG,qBAAqB,GAAG,YAAY,CAAC;AAElE;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAMrE;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,MAAM,CAkB5F;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,cAAc,GAAG,IAAwB,GAAG,MAAM,CAoBjI;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,cAAc,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,2BAA2B;IAC3B,MAAM,EAAE,MAAM,CAAC;CAChB;AAWD;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,GAC3C,mBAAmB,EAAE,CA8BvB;AAYD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,mBAAmB,EAAE,GAAG,KAAK,CAU7E;AAYD,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAGlH;AAMD,sDAAsD;AACtD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,EAAO,GAAG,MAAM,EAAE,CAwB3E;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,mBAAmB,EAAE,CAUzE"}
|
package/dist/server-only.js
CHANGED
|
@@ -85,6 +85,17 @@ const TCP_DRIVERS = new Set([
|
|
|
85
85
|
'node:net',
|
|
86
86
|
'node:tls',
|
|
87
87
|
]);
|
|
88
|
+
/**
|
|
89
|
+
* The TCP drivers that are real npm packages (not `node:` builtins). A Node
|
|
90
|
+
* serverless function bundles statically-imported code, but a driver loaded
|
|
91
|
+
* through a variable `import(spec)` (e.g. `slintorm`'s `importDriver("pg")`)
|
|
92
|
+
* cannot be traced by the bundler or the platform's dependency tracer. Node
|
|
93
|
+
* targets ship these package closures into the function's `node_modules` so
|
|
94
|
+
* that dynamic import resolves at runtime.
|
|
95
|
+
*/
|
|
96
|
+
export function tcpDriverPackages() {
|
|
97
|
+
return [...TCP_DRIVERS].filter((spec) => !spec.startsWith('node:'));
|
|
98
|
+
}
|
|
88
99
|
/**
|
|
89
100
|
* Classify a bare import specifier. Returns null for anything that is fine on
|
|
90
101
|
* the client — including a subpath of a listed package that is itself a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssr-function.d.ts","sourceRoot":"","sources":["../src/ssr-function.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,KAAK,EAAE,SAAS,EAAkB,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7F;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQlG;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAEjF;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAEpF;AAED;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQvG;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,EAC5B,QAAQ,CAAC,EAAE,cAAc,GACxB;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":"AAKA,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,KAAK,EAAE,SAAS,EAAkB,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7F;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQlG;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAEjF;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAEpF;AAED;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQvG;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,EAC5B,QAAQ,CAAC,EAAE,cAAc,GACxB;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAsgBtD"}
|
package/dist/ssr-function.js
CHANGED
|
@@ -428,7 +428,10 @@ export function generateSsrFunction(routeNode, appDir, outDir, componentMap, opt
|
|
|
428
428
|
// its own request scope — otherwise its renderPage mints a token that is
|
|
429
429
|
// still live when the full-page render starts and the two share a data slot.
|
|
430
430
|
const dataNavWrap = (body) => [
|
|
431
|
-
|
|
431
|
+
// Awaited for the same reason as the main render below: the caller restores
|
|
432
|
+
// `__vesk_request` in a finally, and that must happen only after the async
|
|
433
|
+
// data render (which reads params through useParams) has fully resolved.
|
|
434
|
+
' return await withSsrStore(async () => {',
|
|
432
435
|
...body.map((l) => (l ? ' ' + l : l)),
|
|
433
436
|
' });',
|
|
434
437
|
];
|
|
@@ -456,7 +459,13 @@ export function generateSsrFunction(routeNode, appDir, outDir, componentMap, opt
|
|
|
456
459
|
...dataNavCleanup,
|
|
457
460
|
]),
|
|
458
461
|
' }',
|
|
459
|
-
|
|
462
|
+
// Awaited so the surrounding try/finally keeps `__vesk_request` installed
|
|
463
|
+
// for the whole async render. Without the await the finally restores the
|
|
464
|
+
// previous context synchronously, while the async page body is still
|
|
465
|
+
// suspended on its SSR fetches; every render pass after the first `await`
|
|
466
|
+
// then reads an empty params object and `useParams()`-derived keys/URLs
|
|
467
|
+
// collapse (e.g. a verify page rendering its not-found branch).
|
|
468
|
+
' return await __renderHtml(params, url.href);',
|
|
460
469
|
].join('\n');
|
|
461
470
|
}
|
|
462
471
|
else {
|
|
@@ -478,7 +487,13 @@ export function generateSsrFunction(routeNode, appDir, outDir, componentMap, opt
|
|
|
478
487
|
...dataNavCleanup,
|
|
479
488
|
]),
|
|
480
489
|
' }',
|
|
481
|
-
|
|
490
|
+
// Awaited so the surrounding try/finally keeps `__vesk_request` installed
|
|
491
|
+
// for the whole async render. Without the await the finally restores the
|
|
492
|
+
// previous context synchronously, while the async page body is still
|
|
493
|
+
// suspended on its SSR fetches; every render pass after the first `await`
|
|
494
|
+
// then reads an empty params object and `useParams()`-derived keys/URLs
|
|
495
|
+
// collapse (e.g. a verify page rendering its not-found branch).
|
|
496
|
+
' return await __renderHtml(params, url.href);',
|
|
482
497
|
].join('\n');
|
|
483
498
|
}
|
|
484
499
|
const hasMiddleware = !!middlewareCode;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vesk/adapter",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.95",
|
|
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.95",
|
|
27
|
+
"@vesk/runtime": "^0.2.95",
|
|
28
|
+
"@vesk/types": "^0.2.95"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@types/ws": "^8.18.1",
|