@vesk/adapter 0.2.64 → 0.2.66
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.js +27 -2
- package/dist/dev-server.js +12 -2
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js +54 -3
- package/dist/platform-handler.d.ts.map +1 -1
- package/dist/platform-handler.js +9 -4
- package/dist/prod-server.d.ts.map +1 -1
- package/dist/prod-server.js +68 -7
- package/package.json +4 -4
package/dist/client-bundle.js
CHANGED
|
@@ -1504,10 +1504,34 @@ async function buildTreeShakenRuntimeNow(runtimeDir, usedNames) {
|
|
|
1504
1504
|
const missing = unique.filter((n) => !available.has(n));
|
|
1505
1505
|
if (missing.length > 0) {
|
|
1506
1506
|
console.error(`vesk: runtime names not exported — ${missing.join(', ')}; falling back to full runtime`);
|
|
1507
|
+
// Fall back to a FULL esbuild bundle of every name that DOES exist, not
|
|
1508
|
+
// to the legacy concatenation. The concat strips `export ` from whole
|
|
1509
|
+
// runtime files and drops them into ONE module scope, where
|
|
1510
|
+
// hydrate.js and router.js both declare a top-level `hydrateInitial`
|
|
1511
|
+
// (`Identifier 'hydrateInitial' has already been declared`) — a
|
|
1512
|
+
// page-wide SyntaxError. So the "safety net" guaranteed total failure
|
|
1513
|
+
// for every page, which is the opposite of its job. The bundle keeps
|
|
1514
|
+
// the runtime in a closed IIFE, so the unknown names are simply absent
|
|
1515
|
+
// (a clear ReferenceError at the one call site) instead of every page
|
|
1516
|
+
// dying at evaluation.
|
|
1517
|
+
const full = await bundleRuntimeNames(runtimeDir, [...available]);
|
|
1518
|
+
if (full)
|
|
1519
|
+
return full;
|
|
1520
|
+
// esbuild itself failed — last resort is the old concat.
|
|
1507
1521
|
return buildRuntimeCode(runtimeDir);
|
|
1508
1522
|
}
|
|
1523
|
+
return (await bundleRuntimeNames(runtimeDir, unique, true)) ?? buildRuntimeCode(runtimeDir);
|
|
1524
|
+
}
|
|
1525
|
+
/**
|
|
1526
|
+
* Bundles the named runtime exports into one closed IIFE plus an explicit
|
|
1527
|
+
* re-export tail. Returns null when esbuild fails, so callers can fall back.
|
|
1528
|
+
*/
|
|
1529
|
+
async function bundleRuntimeNames(runtimeDir, names, strict = false) {
|
|
1530
|
+
if (names.length === 0)
|
|
1531
|
+
return null;
|
|
1509
1532
|
const entry = runtimeTreeShakeEntry();
|
|
1510
1533
|
const indexClient = esbuildPath(join(runtimeDir, 'index-client.js'));
|
|
1534
|
+
const unique = [...new Set(names)];
|
|
1511
1535
|
try {
|
|
1512
1536
|
try {
|
|
1513
1537
|
mkdirSync(dirname(entry), { recursive: true });
|
|
@@ -1541,8 +1565,9 @@ async function buildTreeShakenRuntimeNow(runtimeDir, usedNames) {
|
|
|
1541
1565
|
return `${bundle}\nconst { ${unique.join(', ')} } = __veskRuntime;\nexport { ${unique.join(', ')} };\n`;
|
|
1542
1566
|
}
|
|
1543
1567
|
catch (e) {
|
|
1544
|
-
|
|
1545
|
-
|
|
1568
|
+
if (strict)
|
|
1569
|
+
console.error('vesk: runtime tree-shake failed, falling back to full runtime:', e.message);
|
|
1570
|
+
return null;
|
|
1546
1571
|
}
|
|
1547
1572
|
finally {
|
|
1548
1573
|
try {
|
package/dist/dev-server.js
CHANGED
|
@@ -903,11 +903,17 @@ function matchPath(pattern, pathname) {
|
|
|
903
903
|
const pathParts = pathname.split('/').filter(Boolean);
|
|
904
904
|
let pi = 0, pp = 0;
|
|
905
905
|
while (pi < pathParts.length && pp < patternParts.length) {
|
|
906
|
-
|
|
906
|
+
const seg = patternParts[pp];
|
|
907
|
+
// `*name` is a catch-all and absorbs the rest of the path.
|
|
908
|
+
if (seg.startsWith('*')) {
|
|
909
|
+
pi = pathParts.length;
|
|
910
|
+
pp++;
|
|
911
|
+
}
|
|
912
|
+
else if (seg.startsWith(':')) {
|
|
907
913
|
pi++;
|
|
908
914
|
pp++;
|
|
909
915
|
}
|
|
910
|
-
else if (
|
|
916
|
+
else if (seg === pathParts[pi]) {
|
|
911
917
|
pi++;
|
|
912
918
|
pp++;
|
|
913
919
|
}
|
|
@@ -915,5 +921,9 @@ function matchPath(pattern, pathname) {
|
|
|
915
921
|
return false;
|
|
916
922
|
}
|
|
917
923
|
}
|
|
924
|
+
// A trailing catch-all still matches an empty tail; the loop above exits as
|
|
925
|
+
// soon as the URL is exhausted, so without this it was never reached.
|
|
926
|
+
if (pp === patternParts.length - 1 && patternParts[pp].startsWith('*'))
|
|
927
|
+
pp++;
|
|
918
928
|
return pp === patternParts.length && pi === pathParts.length;
|
|
919
929
|
}
|
package/dist/manifest.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAqE,cAAc,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAqE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAiCpK,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,SAAS,EAAE,EACnB,SAAS,EAAE,SAAS,EAAE,EACtB,SAAS,EAAE,YAAY,EAAE,EACzB,YAAY,EAAE,cAAc,EAAE,EAC9B,iBAAiB,EAAE,OAAO,EAC1B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,SAAS,CAAC,EAAE,MAAM,EAClB,aAAa,UAAQ,GACpB,QAAQ,CAuEV"}
|
package/dist/manifest.js
CHANGED
|
@@ -1,3 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Specificity key for a route pattern, compared segment by segment: a literal
|
|
3
|
+
* segment outranks a dynamic one, so `/users/me` is tried before
|
|
4
|
+
* `/users/:id`.
|
|
5
|
+
*
|
|
6
|
+
* Every consumer of the manifest — prod-server, adapter dev-server, platform
|
|
7
|
+
* handler — scans `routes` in order and takes the FIRST match, so the order
|
|
8
|
+
* written here IS the routing precedence. Entries came out in directory-scan
|
|
9
|
+
* order, which puts `[id]` ahead of `me`, leaving a static API route
|
|
10
|
+
* permanently unreachable in a production build while the dev tree matcher
|
|
11
|
+
* (which sorts siblings) answered correctly.
|
|
12
|
+
*/
|
|
13
|
+
function specificityKey(path) {
|
|
14
|
+
return path
|
|
15
|
+
.split('/')
|
|
16
|
+
.filter(Boolean)
|
|
17
|
+
// `:x` is one segment, `*x` is the rest of the path — so `*` sorts below
|
|
18
|
+
// `:` and both below a literal.
|
|
19
|
+
.map(seg => (seg.startsWith('*') ? '2' + seg : seg.startsWith(':') ? '1' + seg : '0' + seg));
|
|
20
|
+
}
|
|
21
|
+
function compareSpecificity(a, b) {
|
|
22
|
+
const ka = specificityKey(a);
|
|
23
|
+
const kb = specificityKey(b);
|
|
24
|
+
const len = Math.min(ka.length, kb.length);
|
|
25
|
+
for (let i = 0; i < len; i++) {
|
|
26
|
+
if (ka[i] !== kb[i])
|
|
27
|
+
return ka[i] < kb[i] ? -1 : 1;
|
|
28
|
+
}
|
|
29
|
+
return kb.length - ka.length;
|
|
30
|
+
}
|
|
1
31
|
export function generateManifest(routes, ssrRoutes, apiRoutes, staticRoutes, middlewareEnabled, actionMap, headExtra, eventsEnabled = false) {
|
|
2
32
|
const routeEntries = [];
|
|
3
33
|
for (const r of ssrRoutes) {
|
|
@@ -14,15 +44,36 @@ export function generateManifest(routes, ssrRoutes, apiRoutes, staticRoutes, mid
|
|
|
14
44
|
entry.tags = r._isrTags;
|
|
15
45
|
routeEntries.push(entry);
|
|
16
46
|
}
|
|
47
|
+
const apiEntries = [];
|
|
17
48
|
for (const r of apiRoutes) {
|
|
18
49
|
const urlParts = r.fullPath.split('/').filter(Boolean);
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
50
|
+
// A catch-all segment is emitted as `*name`, not `:name`. They were both
|
|
51
|
+
// written as `:name`, which made `[...rest]` and `[id]` indistinguishable
|
|
52
|
+
// in the manifest — and since every consumer treats `:` as exactly ONE
|
|
53
|
+
// segment, a catch-all API route could never match more than one segment
|
|
54
|
+
// in a production build (`/api/files/a/b/c` never reached `[...rest]`,
|
|
55
|
+
// while the dev tree matcher handled it correctly).
|
|
56
|
+
const parts = urlParts.map((s, i) => {
|
|
57
|
+
const last = i === urlParts.length - 1;
|
|
58
|
+
if (last && r.isCatchAll && s.startsWith(':'))
|
|
59
|
+
return '*' + s.slice(1);
|
|
60
|
+
return s;
|
|
61
|
+
});
|
|
62
|
+
// Strip the `:name` / `*name` prefix from DYNAMIC AND CATCH-ALL segments
|
|
63
|
+
// only. A blanket `slice(1)` also decapitates static segments, which made
|
|
64
|
+
// `/api/posts` point at `server/api/osts.js` while the file on disk is
|
|
65
|
+
// `posts.js` — so every static API route 404'd in a production build.
|
|
66
|
+
const name = parts
|
|
67
|
+
.map(s => (s.startsWith(':') || s.startsWith('*')) ? s.slice(1) || 'param' : s)
|
|
68
|
+
.join('_') || 'index';
|
|
69
|
+
apiEntries.push({
|
|
70
|
+
path: parts.length ? `/api/${parts.join('/')}` : '/api',
|
|
22
71
|
type: 'api',
|
|
23
72
|
function: `server/api/${name}.js`,
|
|
24
73
|
});
|
|
25
74
|
}
|
|
75
|
+
apiEntries.sort((a, b) => compareSpecificity(a.path, b.path));
|
|
76
|
+
routeEntries.push(...apiEntries);
|
|
26
77
|
const ssgEntries = [];
|
|
27
78
|
for (const r of staticRoutes) {
|
|
28
79
|
ssgEntries.push({
|
|
@@ -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,
|
|
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,CA8MjF;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
|
@@ -119,16 +119,21 @@ function __matchPath(pattern, pathname) {
|
|
|
119
119
|
let pi = 0, pp = 0;
|
|
120
120
|
const params = {};
|
|
121
121
|
while (pi < pathParts.length && pp < patternParts.length) {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
122
|
+
const seg = patternParts[pp];
|
|
123
|
+
// A "*name" segment is a catch-all and absorbs the rest of the path.
|
|
124
|
+
if (seg.startsWith('*')) { params[seg.slice(1)] = pathParts.slice(pi).join('/'); pi = pathParts.length; pp++; }
|
|
125
|
+
else if (seg.startsWith(':')) {
|
|
126
|
+
params[seg.slice(1)] = pathParts[pi];
|
|
125
127
|
pi++; pp++;
|
|
126
|
-
} else if (
|
|
128
|
+
} else if (seg === pathParts[pi]) {
|
|
127
129
|
pi++; pp++;
|
|
128
130
|
} else {
|
|
129
131
|
return null;
|
|
130
132
|
}
|
|
131
133
|
}
|
|
134
|
+
// A trailing catch-all still matches an empty tail; the loop above exits as
|
|
135
|
+
// soon as the URL is exhausted, so without this it was never reached.
|
|
136
|
+
if (pp === patternParts.length - 1 && patternParts[pp].startsWith('*')) { params[patternParts[pp].slice(1)] = pathParts.slice(pi).join('/'); pp++; }
|
|
132
137
|
if (pp === patternParts.length && pi === pathParts.length) return params;
|
|
133
138
|
return null;
|
|
134
139
|
}
|
|
@@ -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;AAkDjG,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;AAkDjG,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,CAkiBxI"}
|
package/dist/prod-server.js
CHANGED
|
@@ -215,13 +215,20 @@ export async function startProdServer(outDir, options) {
|
|
|
215
215
|
let pi = 0, pp = 0;
|
|
216
216
|
const params = {};
|
|
217
217
|
while (pi < pathParts.length && pp < patternParts.length) {
|
|
218
|
-
|
|
219
|
-
|
|
218
|
+
const seg = patternParts[pp];
|
|
219
|
+
if (seg.startsWith('*')) {
|
|
220
|
+
// Catch-all: absorbs every remaining segment (possibly none).
|
|
221
|
+
params[seg.slice(1)] = pathParts.slice(pi).join('/');
|
|
222
|
+
pi = pathParts.length;
|
|
223
|
+
pp++;
|
|
224
|
+
}
|
|
225
|
+
else if (seg.startsWith(':')) {
|
|
226
|
+
const name = seg.slice(1);
|
|
220
227
|
params[name] = pathParts[pi];
|
|
221
228
|
pi++;
|
|
222
229
|
pp++;
|
|
223
230
|
}
|
|
224
|
-
else if (
|
|
231
|
+
else if (seg === pathParts[pi]) {
|
|
225
232
|
pi++;
|
|
226
233
|
pp++;
|
|
227
234
|
}
|
|
@@ -229,6 +236,13 @@ export async function startProdServer(outDir, options) {
|
|
|
229
236
|
return null;
|
|
230
237
|
}
|
|
231
238
|
}
|
|
239
|
+
// A trailing catch-all still matches with an empty tail (`/api/files` ->
|
|
240
|
+
// `/api/files/*rest` with rest=''). The loop above exits as soon as the
|
|
241
|
+
// URL is exhausted, so without this the catch-all was never reached.
|
|
242
|
+
if (pp === patternParts.length - 1 && patternParts[pp].startsWith('*')) {
|
|
243
|
+
params[patternParts[pp].slice(1)] = pathParts.slice(pi).join('/');
|
|
244
|
+
pp++;
|
|
245
|
+
}
|
|
232
246
|
if (pp === patternParts.length && pi === pathParts.length)
|
|
233
247
|
return params;
|
|
234
248
|
return null;
|
|
@@ -267,6 +281,52 @@ export async function startProdServer(outDir, options) {
|
|
|
267
281
|
}
|
|
268
282
|
return origWriteHead(statusCode, headers);
|
|
269
283
|
});
|
|
284
|
+
// Per-request security overrides (`request.setCsp()`, `.setSecurityHeader()`,
|
|
285
|
+
// `.setRateLimit()`, `.setCsrf()`) accumulate in the runtime's
|
|
286
|
+
// AsyncLocalStorage bag. The server cannot import the runtime directly (it
|
|
287
|
+
// is injected into generated code as a string), so it reads the bridge it
|
|
288
|
+
// registers on globalThis. Without this every one of those setters was a
|
|
289
|
+
// silent no-op.
|
|
290
|
+
const securityBridge = globalThis.__vesk_security;
|
|
291
|
+
// Rate limiting is enforced BEFORE the handler runs, so a per-request
|
|
292
|
+
// limit set inside the handler cannot apply to this same request. It is
|
|
293
|
+
// surfaced here for the next request on the connection-independent bag;
|
|
294
|
+
// the global limit configured in vesk.config is what gates this one.
|
|
295
|
+
// Wrap a handler call so overrides it records land in a fresh bag that is
|
|
296
|
+
// still readable when the response is written. Falls back to a pass-through
|
|
297
|
+
// when the runtime has not registered its bridge.
|
|
298
|
+
const securityRun = securityBridge?.run;
|
|
299
|
+
const withSecurityScope = securityRun
|
|
300
|
+
? (fn) => securityRun(fn)
|
|
301
|
+
: (fn) => fn();
|
|
302
|
+
const applyOverrideHeaders = (headers) => {
|
|
303
|
+
const overrides = securityBridge?.get?.();
|
|
304
|
+
if (!overrides)
|
|
305
|
+
return headers;
|
|
306
|
+
const next = { ...headers };
|
|
307
|
+
if (typeof overrides.contentSecurityPolicy === 'string') {
|
|
308
|
+
next['Content-Security-Policy'] = overrides.contentSecurityPolicy;
|
|
309
|
+
}
|
|
310
|
+
const custom = overrides.customHeaders;
|
|
311
|
+
if (custom) {
|
|
312
|
+
for (const [name, value] of Object.entries(custom)) {
|
|
313
|
+
if (value === false)
|
|
314
|
+
delete next[name];
|
|
315
|
+
else
|
|
316
|
+
next[name] = value;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return next;
|
|
320
|
+
};
|
|
321
|
+
const origWriteHead2 = res.writeHead.bind(res);
|
|
322
|
+
let overridesApplied = false;
|
|
323
|
+
res.writeHead = ((statusCode, headers) => {
|
|
324
|
+
if (!overridesApplied) {
|
|
325
|
+
overridesApplied = true;
|
|
326
|
+
headers = applyOverrideHeaders((headers || {}));
|
|
327
|
+
}
|
|
328
|
+
return origWriteHead2(statusCode, headers);
|
|
329
|
+
});
|
|
270
330
|
const publicDir = resolve(staticDir, 'public');
|
|
271
331
|
const rootFile = url.pathname.length > 1 ? resolveWithin(publicDir, url.pathname.slice(1)) : null;
|
|
272
332
|
if (rootFile && existsSync(rootFile) && statSync(rootFile).isFile()) {
|
|
@@ -413,7 +473,8 @@ export async function startProdServer(outDir, options) {
|
|
|
413
473
|
}
|
|
414
474
|
try {
|
|
415
475
|
const webRequest = makeWebRequest(req, url.href, maxBodyBytes);
|
|
416
|
-
const
|
|
476
|
+
const handleAction = mod.handleAction.bind(mod);
|
|
477
|
+
const response = await withSecurityScope(() => handleAction(webRequest, actionId));
|
|
417
478
|
await deliverResponse(res, response);
|
|
418
479
|
}
|
|
419
480
|
catch (e) {
|
|
@@ -435,7 +496,7 @@ export async function startProdServer(outDir, options) {
|
|
|
435
496
|
if (mod) {
|
|
436
497
|
try {
|
|
437
498
|
const webRequest = makeWebRequest(req, url.href, maxBodyBytes);
|
|
438
|
-
const response = await mod.handle(webRequest);
|
|
499
|
+
const response = await withSecurityScope(() => mod.handle(webRequest));
|
|
439
500
|
await deliverResponse(res, response);
|
|
440
501
|
return;
|
|
441
502
|
}
|
|
@@ -478,7 +539,7 @@ export async function startProdServer(outDir, options) {
|
|
|
478
539
|
if (route.revalidate && route.revalidate > 0) {
|
|
479
540
|
const { pageIsr } = await import('@vesk/runtime/src/index-server');
|
|
480
541
|
cachedResult = await pageIsr(url.pathname, async () => {
|
|
481
|
-
const response = await mod.handle(webRequest);
|
|
542
|
+
const response = await withSecurityScope(() => mod.handle(webRequest));
|
|
482
543
|
return { html: await response.text(), headers: Object.fromEntries(response.headers) };
|
|
483
544
|
}, { revalidate: route.revalidate, tags: route.tags || [] });
|
|
484
545
|
}
|
|
@@ -487,7 +548,7 @@ export async function startProdServer(outDir, options) {
|
|
|
487
548
|
res.end(cachedResult.html);
|
|
488
549
|
return;
|
|
489
550
|
}
|
|
490
|
-
const response = await mod.handle(webRequest);
|
|
551
|
+
const response = await withSecurityScope(() => mod.handle(webRequest));
|
|
491
552
|
const headers = Object.fromEntries(response.headers);
|
|
492
553
|
if (!headers['content-type'] && !headers['Content-Type'])
|
|
493
554
|
headers['Content-Type'] = 'text/html';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vesk/adapter",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.66",
|
|
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.66",
|
|
27
|
+
"@vesk/runtime": "^0.2.66",
|
|
28
|
+
"@vesk/types": "^0.2.66"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@types/ws": "^8.18.1",
|