@vesk/adapter 0.1.1 → 0.2.8
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/api-function.d.ts.map +1 -1
- package/dist/api-function.js +8 -5
- package/dist/client-bundle.d.ts.map +1 -1
- package/dist/client-bundle.js +167 -27
- package/dist/dev-server.d.ts +3 -0
- package/dist/dev-server.d.ts.map +1 -1
- package/dist/dev-server.js +47 -22
- package/dist/esbuild-fallback.d.ts +0 -1
- package/dist/esbuild-fallback.d.ts.map +1 -1
- package/dist/esbuild-fallback.js +10 -20
- package/dist/hmr.d.ts.map +1 -1
- package/dist/hmr.js +19 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +8 -2
- package/dist/paths.d.ts +16 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +81 -0
- package/dist/platform-deploy.js +2 -1
- package/dist/platform-handler.d.ts.map +1 -1
- package/dist/platform-handler.js +32 -9
- package/dist/prod-server.d.ts +5 -0
- package/dist/prod-server.d.ts.map +1 -1
- package/dist/prod-server.js +88 -32
- package/dist/runtime-bundle.d.ts.map +1 -1
- package/dist/runtime-bundle.js +8 -3
- package/dist/ssr-function.d.ts.map +1 -1
- package/dist/ssr-function.js +24 -13
- package/dist/static.d.ts.map +1 -1
- package/dist/static.js +9 -1
- package/dist/types.d.ts +1 -181
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -3
- package/dist/package.json +0 -15
package/dist/hmr.js
CHANGED
|
@@ -3,8 +3,9 @@ import { readFileSync, existsSync, writeFileSync } from 'node:fs';
|
|
|
3
3
|
import { resolve, dirname } from 'node:path';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
5
|
import { compileClient } from '@vesk/compiler/src/client-codegen';
|
|
6
|
-
import { resolveComponentName } from '@vesk/compiler/src/server-codegen';
|
|
6
|
+
import { resolveComponentName, randomToken } from '@vesk/compiler/src/server-codegen';
|
|
7
7
|
import { resolveErrorFile } from '@vesk/adapter/src/ssr-function';
|
|
8
|
+
import { isAllowedWsUpgrade } from '@vesk/adapter/src/paths';
|
|
8
9
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
10
|
function findRouteForSource(routeTree, sourceDir) {
|
|
10
11
|
for (const node of routeTree) {
|
|
@@ -297,15 +298,30 @@ function regenerateSsrFunction(routeNode, appDir, outDir, componentMap, options)
|
|
|
297
298
|
writeFileSync(funcPath, funcCode, 'utf-8');
|
|
298
299
|
}
|
|
299
300
|
export function createHmrServer(httpServer, appDir, devDir, componentMap) {
|
|
300
|
-
|
|
301
|
+
// Per-session nonce gating the client-side HMR eval hook (see
|
|
302
|
+
// appendHmrGlobals in client-bundle.ts). Broadcast with every update.
|
|
303
|
+
const hmrNonce = randomToken(16);
|
|
304
|
+
globalThis.__vesk_hmr_nonce = hmrNonce;
|
|
305
|
+
const wss = new WebSocketServer({ noServer: true });
|
|
301
306
|
const clients = new Set();
|
|
307
|
+
// Origin-checked upgrade: cross-site pages always attach an Origin header
|
|
308
|
+
// to WebSocket handshakes, so a mismatch means a CSWS attempt — destroy it.
|
|
309
|
+
httpServer.on('upgrade', (req, socket, head) => {
|
|
310
|
+
if (req.url !== '/_vesk/hmr' || !isAllowedWsUpgrade(req.headers)) {
|
|
311
|
+
socket.destroy();
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
wss.handleUpgrade(req, socket, head, (ws) => {
|
|
315
|
+
wss.emit('connection', ws, req);
|
|
316
|
+
});
|
|
317
|
+
});
|
|
302
318
|
wss.on('connection', (ws) => {
|
|
303
319
|
clients.add(ws);
|
|
304
320
|
ws.on('close', () => clients.delete(ws));
|
|
305
321
|
ws.on('error', () => clients.delete(ws));
|
|
306
322
|
});
|
|
307
323
|
function broadcast(type, data) {
|
|
308
|
-
const msg = JSON.stringify({ type, ...data });
|
|
324
|
+
const msg = JSON.stringify({ type, nonce: hmrNonce, ...data });
|
|
309
325
|
for (const ws of clients) {
|
|
310
326
|
try {
|
|
311
327
|
ws.send(msg);
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EACe,YAAY,EAAE,WAAW,EAEnD,MAAM,yBAAyB,CAAC;AAgBjC,wBAAsB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EACe,YAAY,EAAE,WAAW,EAEnD,MAAM,yBAAyB,CAAC;AAgBjC,wBAAsB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CA+SpG;AAED,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -27,6 +27,12 @@ export async function build(appDir, options) {
|
|
|
27
27
|
const outDir = resolve(options?.outDir || resolve(appDir, '..', '.vesk'));
|
|
28
28
|
const publicDir = options?.publicDir || resolve(appDir, '..', 'public');
|
|
29
29
|
const plugins = options?.plugins || [];
|
|
30
|
+
// Apply the Markdown policy for this build so SSG prerendering renders
|
|
31
|
+
// (and warns about) raw HTML exactly like the running server will.
|
|
32
|
+
if (options?.md) {
|
|
33
|
+
const { configureMd } = await import('@vesk/runtime/src/md');
|
|
34
|
+
configureMd(options.md);
|
|
35
|
+
}
|
|
30
36
|
for (const plugin of plugins) {
|
|
31
37
|
if (typeof plugin.onBuildStart === 'function') {
|
|
32
38
|
await plugin.onBuildStart();
|
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,CAgDhG;AAED,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CA8C5E"}
|
package/dist/middleware.js
CHANGED
|
@@ -33,14 +33,17 @@ export function compileMiddleware(mwChain, _appDir) {
|
|
|
33
33
|
' if (index >= chain.length) return null;',
|
|
34
34
|
' const fn = chain[index];',
|
|
35
35
|
' let nextCalled = false;',
|
|
36
|
+
' let nextResult = null;',
|
|
36
37
|
' async function next(rewrite) {',
|
|
37
38
|
' if (nextCalled) return null;',
|
|
38
39
|
' nextCalled = true;',
|
|
39
40
|
' if (rewrite) rewriteUrl = rewrite;',
|
|
40
|
-
'
|
|
41
|
+
' nextResult = await run(index + 1);',
|
|
42
|
+
' return nextResult;',
|
|
41
43
|
' }',
|
|
42
44
|
' const result = await fn(ctx, next);',
|
|
43
45
|
' if (result instanceof Response) return result;',
|
|
46
|
+
' if (nextResult instanceof Response) return nextResult;',
|
|
44
47
|
' if (!nextCalled) return run(index + 1);',
|
|
45
48
|
' return null;',
|
|
46
49
|
' }',
|
|
@@ -76,14 +79,17 @@ export function compileMiddlewareCode(mwSourceTexts) {
|
|
|
76
79
|
' if (index >= __mwChain.length) return null;',
|
|
77
80
|
' const fn = __mwChain[index];',
|
|
78
81
|
' let nc = false;',
|
|
82
|
+
' let ncResult = null;',
|
|
79
83
|
' async function next(rewrite) {',
|
|
80
84
|
' if (nc) return null;',
|
|
81
85
|
' nc = true;',
|
|
82
86
|
' if (rewrite) rewriteUrl = rewrite;',
|
|
83
|
-
'
|
|
87
|
+
' ncResult = await run(index + 1);',
|
|
88
|
+
' return ncResult;',
|
|
84
89
|
' }',
|
|
85
90
|
' const result = await fn(ctx, next);',
|
|
86
91
|
' if (result instanceof Response) return result;',
|
|
92
|
+
' if (ncResult instanceof Response) return ncResult;',
|
|
87
93
|
' if (!nc) return run(index + 1);',
|
|
88
94
|
' return null;',
|
|
89
95
|
' }',
|
package/dist/paths.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves `relPath` against `baseDir` and returns the absolute path ONLY if
|
|
3
|
+
* it stays strictly inside `baseDir` (never the directory itself, never a
|
|
4
|
+
* sibling). Returns null otherwise. Single source of truth for static file
|
|
5
|
+
* serving / prerender writes so traversal defenses cannot drift.
|
|
6
|
+
*/
|
|
7
|
+
export declare function resolveWithin(baseDir: string, relPath: string): string | null;
|
|
8
|
+
/**
|
|
9
|
+
* True when an incoming WebSocket upgrade may connect: same-origin when the
|
|
10
|
+
* client sends an Origin header, always allowed for non-browser clients that
|
|
11
|
+
* omit it (matching the HMR threat model — cross-site pages always attach
|
|
12
|
+
* Origin to WS handshakes). Loopback aliases (localhost / 127.0.0.1 / ::1)
|
|
13
|
+
* are treated as equivalent so local dev works over either name.
|
|
14
|
+
*/
|
|
15
|
+
export declare function isAllowedWsUpgrade(headers: Record<string, unknown>): boolean;
|
|
16
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM7E;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAU5E"}
|
package/dist/paths.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { resolve, sep } from 'node:path';
|
|
2
|
+
/**
|
|
3
|
+
* Resolves `relPath` against `baseDir` and returns the absolute path ONLY if
|
|
4
|
+
* it stays strictly inside `baseDir` (never the directory itself, never a
|
|
5
|
+
* sibling). Returns null otherwise. Single source of truth for static file
|
|
6
|
+
* serving / prerender writes so traversal defenses cannot drift.
|
|
7
|
+
*/
|
|
8
|
+
export function resolveWithin(baseDir, relPath) {
|
|
9
|
+
const base = resolve(baseDir);
|
|
10
|
+
const target = resolve(baseDir, relPath);
|
|
11
|
+
const prefix = base + sep;
|
|
12
|
+
if (!target.startsWith(prefix))
|
|
13
|
+
return null;
|
|
14
|
+
return target;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* True when an incoming WebSocket upgrade may connect: same-origin when the
|
|
18
|
+
* client sends an Origin header, always allowed for non-browser clients that
|
|
19
|
+
* omit it (matching the HMR threat model — cross-site pages always attach
|
|
20
|
+
* Origin to WS handshakes). Loopback aliases (localhost / 127.0.0.1 / ::1)
|
|
21
|
+
* are treated as equivalent so local dev works over either name.
|
|
22
|
+
*/
|
|
23
|
+
export function isAllowedWsUpgrade(headers) {
|
|
24
|
+
const origin = typeof headers['origin'] === 'string' ? headers['origin'] : '';
|
|
25
|
+
if (!origin)
|
|
26
|
+
return true;
|
|
27
|
+
const host = typeof headers['host'] === 'string' ? headers['host'] : '';
|
|
28
|
+
if (!host)
|
|
29
|
+
return false;
|
|
30
|
+
const originAuth = urlAuthority(origin);
|
|
31
|
+
if (originAuth === host.toLowerCase().trim())
|
|
32
|
+
return true;
|
|
33
|
+
const a = splitAuthority(originAuth);
|
|
34
|
+
const b = splitAuthority(host.toLowerCase().trim());
|
|
35
|
+
return a.port === b.port && isLoopback(a.hostname) && isLoopback(b.hostname);
|
|
36
|
+
}
|
|
37
|
+
function splitAuthority(authority) {
|
|
38
|
+
// bracketed IPv6 [::1]:3000
|
|
39
|
+
if (authority.startsWith('[')) {
|
|
40
|
+
const close = authority.indexOf(']');
|
|
41
|
+
if (close !== -1) {
|
|
42
|
+
return { hostname: authority.slice(0, close + 1), port: authority.slice(close + 2) };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const colon = authority.lastIndexOf(':');
|
|
46
|
+
if (colon === -1)
|
|
47
|
+
return { hostname: authority, port: '' };
|
|
48
|
+
let multiColon = false;
|
|
49
|
+
for (let i = 0; i < colon; i++) {
|
|
50
|
+
if (authority[i] === ':') {
|
|
51
|
+
multiColon = true;
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (multiColon)
|
|
56
|
+
return { hostname: authority, port: '' };
|
|
57
|
+
return { hostname: authority.slice(0, colon), port: authority.slice(colon + 1) };
|
|
58
|
+
}
|
|
59
|
+
function isLoopback(hostname) {
|
|
60
|
+
const h = hostname.replace(/^\[|\]$/g, '');
|
|
61
|
+
return h === 'localhost' || h === '127.0.0.1' || h === '::1';
|
|
62
|
+
}
|
|
63
|
+
function urlAuthority(url) {
|
|
64
|
+
const schemeIdx = url.indexOf('://');
|
|
65
|
+
if (schemeIdx === -1)
|
|
66
|
+
return '';
|
|
67
|
+
let rest = url.slice(schemeIdx + 3);
|
|
68
|
+
let end = rest.length;
|
|
69
|
+
for (let i = 0; i < rest.length; i++) {
|
|
70
|
+
const c = rest[i];
|
|
71
|
+
if (c === '/' || c === '?' || c === '#') {
|
|
72
|
+
end = i;
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
rest = rest.slice(0, end);
|
|
77
|
+
const at = rest.lastIndexOf('@');
|
|
78
|
+
if (at !== -1)
|
|
79
|
+
rest = rest.slice(at + 1);
|
|
80
|
+
return rest.toLowerCase();
|
|
81
|
+
}
|
package/dist/platform-deploy.js
CHANGED
|
@@ -265,7 +265,8 @@ function shellFor(platform) {
|
|
|
265
265
|
staticServe: 'disk-deno',
|
|
266
266
|
bootstrap: [
|
|
267
267
|
'if (typeof Deno !== "undefined" && typeof Deno.serve === "function") {',
|
|
268
|
-
' Deno.
|
|
268
|
+
' const __veskPort = Number(Deno.env.get("PORT") || 8000);',
|
|
269
|
+
' Deno.serve({ port: __veskPort }, async (request) => {',
|
|
269
270
|
' const staticResponse = await serveEmbeddedStatic(request);',
|
|
270
271
|
' if (staticResponse) return staticResponse;',
|
|
271
272
|
' return handleRequest(request);',
|
|
@@ -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;CACxB;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;AAQD;;;;;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;CACxB;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;AAQD;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,oBAAoB,GAAG,MAAM,CAgIjF;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,CAiFzF;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;CACxB"}
|
package/dist/platform-handler.js
CHANGED
|
@@ -96,8 +96,9 @@ export async function handleRequest(request) {
|
|
|
96
96
|
return new Response(null, { status: 308, headers: { Location: '/_vesk/static/public' + (pathname.endsWith('/') ? pathname + 'index.html' : pathname + '.html') } });
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
let mwCtx = { params: {}, url, locals: {}, cookies: {}, request, set() {}, get() { return undefined; } };
|
|
99
100
|
if (${hasMwLiteral}) {
|
|
100
|
-
|
|
101
|
+
mwCtx = {
|
|
101
102
|
request,
|
|
102
103
|
params: {},
|
|
103
104
|
url,
|
|
@@ -110,6 +111,9 @@ export async function handleRequest(request) {
|
|
|
110
111
|
if (mwResult.response) return mwResult.response;
|
|
111
112
|
if (mwResult.rewriteUrl) url.pathname = mwResult.rewriteUrl;
|
|
112
113
|
}
|
|
114
|
+
// Expose root middleware locals to API/SSR handlers (which seed their own
|
|
115
|
+
// ctx.locals from this before running route-level middleware).
|
|
116
|
+
globalThis.__vesk_request = mwCtx;
|
|
113
117
|
|
|
114
118
|
for (const route of __routes) {
|
|
115
119
|
const params = __matchPath(route.path, url.pathname);
|
|
@@ -154,12 +158,28 @@ export async function bundlePlatformHandler(options) {
|
|
|
154
158
|
plugins.push({
|
|
155
159
|
name: 'empty-node-builtins',
|
|
156
160
|
setup(build) {
|
|
157
|
-
const builtins = /^(
|
|
158
|
-
build.onResolve({ filter: builtins }, () => {
|
|
159
|
-
return { path:
|
|
161
|
+
const builtins = /^(node:)?(fs|path|child_process|os|crypto|net|stream|buffer|events|util|url|querystring|http|https|zlib|tty|async_hooks)$/;
|
|
162
|
+
build.onResolve({ filter: builtins }, (args) => {
|
|
163
|
+
return { path: args.path, namespace: 'empty-node' };
|
|
160
164
|
});
|
|
161
|
-
build.onLoad({ filter: /.*/, namespace: 'empty-node' }, () =>
|
|
162
|
-
|
|
165
|
+
build.onLoad({ filter: /.*/, namespace: 'empty-node' }, (args) => {
|
|
166
|
+
// async_hooks needs a usable AsyncLocalStorage shape (constructor +
|
|
167
|
+
// run/getStore), not a callable-Proxy stub — the runtime's
|
|
168
|
+
// per-request SSR data isolation instantiates it.
|
|
169
|
+
if (/async_hooks$/.test(args.path)) {
|
|
170
|
+
return {
|
|
171
|
+
contents: `
|
|
172
|
+
export class AsyncLocalStorage {
|
|
173
|
+
run(_store, fn) { return fn(); }
|
|
174
|
+
getStore() { return null; }
|
|
175
|
+
enterWith() {}
|
|
176
|
+
exit(fn) { return fn(); }
|
|
177
|
+
}
|
|
178
|
+
`,
|
|
179
|
+
loader: 'js',
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
const contents = `
|
|
163
183
|
const __m = typeof Proxy !== 'undefined' ? new Proxy({}, {
|
|
164
184
|
get(_, key) { return typeof key === 'string' ? () => {} : undefined; },
|
|
165
185
|
has() { return true; },
|
|
@@ -187,9 +207,12 @@ export const spawnSync = () => ({ status: 0 });
|
|
|
187
207
|
export const execSync = () => '';
|
|
188
208
|
export const randomBytes = () => ({});
|
|
189
209
|
export const createHash = () => ({ update: () => {}, digest: () => '' });
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
210
|
+
`;
|
|
211
|
+
return {
|
|
212
|
+
contents,
|
|
213
|
+
loader: 'js',
|
|
214
|
+
};
|
|
215
|
+
});
|
|
193
216
|
},
|
|
194
217
|
});
|
|
195
218
|
}
|
package/dist/prod-server.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { type Server } from 'node:http';
|
|
2
|
+
export declare function bodyTooLarge(maxBytes: number): Error & {
|
|
3
|
+
status: number;
|
|
4
|
+
};
|
|
2
5
|
export declare function startProdServer(outDir: string, options?: {
|
|
3
6
|
port?: number;
|
|
7
|
+
host?: string;
|
|
8
|
+
maxBodyBytes?: number;
|
|
4
9
|
}): Promise<Server>;
|
|
5
10
|
//# sourceMappingURL=prod-server.d.ts.map
|
|
@@ -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;
|
|
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;AAsBjG,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAIzE;AA4FD,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,CA0YxI"}
|
package/dist/prod-server.js
CHANGED
|
@@ -3,17 +3,32 @@ import { resolve, extname, dirname } from 'node:path';
|
|
|
3
3
|
import { createServer } from 'node:http';
|
|
4
4
|
import { createRequire } from 'node:module';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
|
-
import { createRateLimiter, resolveComponentName } from '@vesk/compiler/src/server-codegen';
|
|
7
|
-
import { securityHeaders
|
|
6
|
+
import { createRateLimiter, resolveComponentName, safeJsonForScript, getClientProtocol, DEFAULT_MAX_BODY_BYTES } from '@vesk/compiler/src/server-codegen';
|
|
7
|
+
import { securityHeaders } from '@vesk/compiler/src/server-utils';
|
|
8
|
+
import { resolveWithin } from '@vesk/adapter/src/paths';
|
|
8
9
|
const _require = createRequire(import.meta.url);
|
|
9
10
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
|
-
async function readBody(req) {
|
|
11
|
+
async function readBody(req, maxBytes = DEFAULT_MAX_BODY_BYTES) {
|
|
11
12
|
const chunks = [];
|
|
12
|
-
|
|
13
|
+
let total = 0;
|
|
14
|
+
for await (const chunk of req) {
|
|
15
|
+
total += chunk.byteLength;
|
|
16
|
+
if (total > maxBytes)
|
|
17
|
+
throw bodyTooLarge(maxBytes);
|
|
13
18
|
chunks.push(chunk);
|
|
19
|
+
}
|
|
14
20
|
return Buffer.concat(chunks);
|
|
15
21
|
}
|
|
16
|
-
function
|
|
22
|
+
export function bodyTooLarge(maxBytes) {
|
|
23
|
+
const err = new Error(`Request body exceeds limit (${maxBytes} bytes)`);
|
|
24
|
+
err.status = 413;
|
|
25
|
+
return err;
|
|
26
|
+
}
|
|
27
|
+
function errorStatus(e, fallback) {
|
|
28
|
+
const s = e?.status ?? e?.statusCode;
|
|
29
|
+
return typeof s === 'number' && s >= 400 && s < 600 ? s : fallback;
|
|
30
|
+
}
|
|
31
|
+
function makeWebRequest(nodeReq, url, maxBodyBytes = DEFAULT_MAX_BODY_BYTES) {
|
|
17
32
|
const parsedUrl = new URL(url, `http://${nodeReq.headers.host || 'localhost'}`);
|
|
18
33
|
const method = nodeReq.method || 'GET';
|
|
19
34
|
let _bodyBuffer = null;
|
|
@@ -21,8 +36,13 @@ function makeWebRequest(nodeReq, url) {
|
|
|
21
36
|
if (_bodyBuffer)
|
|
22
37
|
return _bodyBuffer;
|
|
23
38
|
const chunks = [];
|
|
24
|
-
|
|
39
|
+
let total = 0;
|
|
40
|
+
for await (const chunk of nodeReq) {
|
|
41
|
+
total += chunk.byteLength;
|
|
42
|
+
if (total > maxBodyBytes)
|
|
43
|
+
throw bodyTooLarge(maxBodyBytes);
|
|
25
44
|
chunks.push(Buffer.from(chunk));
|
|
45
|
+
}
|
|
26
46
|
_bodyBuffer = Buffer.concat(chunks);
|
|
27
47
|
return _bodyBuffer;
|
|
28
48
|
}
|
|
@@ -70,6 +90,11 @@ const MIME = {
|
|
|
70
90
|
};
|
|
71
91
|
export async function startProdServer(outDir, options) {
|
|
72
92
|
const port = options?.port || 3000;
|
|
93
|
+
const host = options?.host || '127.0.0.1';
|
|
94
|
+
const maxBodyBytes = options?.maxBodyBytes || DEFAULT_MAX_BODY_BYTES;
|
|
95
|
+
// Production default: generated handlers consult this to gate error details.
|
|
96
|
+
if (!process.env.NODE_ENV)
|
|
97
|
+
process.env.NODE_ENV = 'production';
|
|
73
98
|
const staticDir = resolve(outDir, 'static');
|
|
74
99
|
const configPath = resolve(outDir, 'config.json');
|
|
75
100
|
if (!existsSync(configPath)) {
|
|
@@ -81,6 +106,7 @@ export async function startProdServer(outDir, options) {
|
|
|
81
106
|
console.error(`vesk start: serving from ${outDir}`);
|
|
82
107
|
const projectDir = resolve(outDir, '..');
|
|
83
108
|
let securityConfig = {};
|
|
109
|
+
let mdConfig;
|
|
84
110
|
try {
|
|
85
111
|
const veskConfigPath = resolve(projectDir, 'vesk.config.js');
|
|
86
112
|
const veskConfigTsPath = resolve(projectDir, 'vesk.config.ts');
|
|
@@ -98,14 +124,24 @@ export async function startProdServer(outDir, options) {
|
|
|
98
124
|
rawConfig = rawConfig();
|
|
99
125
|
const configObj = rawConfig;
|
|
100
126
|
securityConfig = { security: configObj.security };
|
|
127
|
+
mdConfig = configObj.md;
|
|
101
128
|
}
|
|
102
|
-
catch {
|
|
103
|
-
//
|
|
129
|
+
catch (e) {
|
|
130
|
+
// Fail closed: keep the secure defaults above and warn loudly — a broken
|
|
131
|
+
// config must never silently disable the app's chosen security policy.
|
|
132
|
+
console.error('vesk start: failed to load vesk.config — falling back to secure defaults:', e instanceof Error ? e.message : e);
|
|
133
|
+
}
|
|
134
|
+
if (mdConfig) {
|
|
135
|
+
try {
|
|
136
|
+
const { configureMd } = await import('@vesk/runtime/src/md');
|
|
137
|
+
configureMd(mdConfig);
|
|
138
|
+
}
|
|
139
|
+
catch { /* runtime md module unavailable — keep default escape policy */ }
|
|
104
140
|
}
|
|
105
141
|
let rateLimiter = null;
|
|
106
142
|
if (securityConfig?.rateLimit) {
|
|
107
143
|
const rlConfig = securityConfig.rateLimit;
|
|
108
|
-
rateLimiter = createRateLimiter({ windowMs: rlConfig.windowMs || 60000, max: rlConfig.max || 100 });
|
|
144
|
+
rateLimiter = createRateLimiter({ windowMs: rlConfig.windowMs || 60000, max: rlConfig.max || 100, trustProxy: !!securityConfig?.trustProxy });
|
|
109
145
|
}
|
|
110
146
|
let securityHeadersFn = null;
|
|
111
147
|
try {
|
|
@@ -199,9 +235,8 @@ export async function startProdServer(outDir, options) {
|
|
|
199
235
|
return origWriteHead(statusCode, headers);
|
|
200
236
|
});
|
|
201
237
|
const publicDir = resolve(staticDir, 'public');
|
|
202
|
-
const
|
|
203
|
-
|
|
204
|
-
if (rootFile.startsWith(publicDir) && existsSync(rootFile) && statSync(rootFile).isFile()) {
|
|
238
|
+
const rootFile = url.pathname.length > 1 ? resolveWithin(publicDir, url.pathname.slice(1)) : null;
|
|
239
|
+
if (rootFile && existsSync(rootFile) && statSync(rootFile).isFile()) {
|
|
205
240
|
const ext = extname(rootFile);
|
|
206
241
|
res.writeHead(200, { 'Content-Type': MIME[ext] || 'application/octet-stream' });
|
|
207
242
|
res.end(readFileSync(rootFile));
|
|
@@ -214,10 +249,11 @@ export async function startProdServer(outDir, options) {
|
|
|
214
249
|
if (payload)
|
|
215
250
|
delete store[token];
|
|
216
251
|
const lines = [];
|
|
252
|
+
// script-safe serialization: props may contain user data
|
|
217
253
|
if (payload?.props)
|
|
218
|
-
lines.push(`globalThis.__vesk_props = ${JSON.stringify(payload.props)};`);
|
|
254
|
+
lines.push(`globalThis.__vesk_props = ${safeJsonForScript(JSON.stringify(payload.props))};`);
|
|
219
255
|
if (payload?.ssrData)
|
|
220
|
-
lines.push(`globalThis.__vsk_ssr_data = ${JSON.stringify(payload.ssrData)};`);
|
|
256
|
+
lines.push(`globalThis.__vsk_ssr_data = ${safeJsonForScript(JSON.stringify(payload.ssrData))};`);
|
|
221
257
|
res.writeHead(200, { 'Content-Type': 'application/javascript', 'Cache-Control': 'no-store' });
|
|
222
258
|
res.end(lines.join('\n') || '// no ssr data');
|
|
223
259
|
return;
|
|
@@ -231,9 +267,9 @@ export async function startProdServer(outDir, options) {
|
|
|
231
267
|
}
|
|
232
268
|
}
|
|
233
269
|
if (url.pathname.startsWith('/_vesk/static/')) {
|
|
234
|
-
const relPath = url.pathname.
|
|
235
|
-
const staticPath =
|
|
236
|
-
if (!staticPath
|
|
270
|
+
const relPath = url.pathname.slice('/_vesk/static/'.length);
|
|
271
|
+
const staticPath = resolveWithin(staticDir, relPath);
|
|
272
|
+
if (!staticPath) {
|
|
237
273
|
res.writeHead(403);
|
|
238
274
|
res.end('Forbidden');
|
|
239
275
|
return;
|
|
@@ -256,8 +292,9 @@ export async function startProdServer(outDir, options) {
|
|
|
256
292
|
}
|
|
257
293
|
}
|
|
258
294
|
}
|
|
295
|
+
let mwCtx;
|
|
259
296
|
if (middlewareMod) {
|
|
260
|
-
|
|
297
|
+
mwCtx = {
|
|
261
298
|
request: new Request(url.href, { headers: req.headers, method: req.method || 'GET' }),
|
|
262
299
|
params: {},
|
|
263
300
|
url,
|
|
@@ -277,6 +314,20 @@ export async function startProdServer(outDir, options) {
|
|
|
277
314
|
url.pathname = mwResult.rewriteUrl;
|
|
278
315
|
}
|
|
279
316
|
}
|
|
317
|
+
else {
|
|
318
|
+
mwCtx = {
|
|
319
|
+
params: {},
|
|
320
|
+
url,
|
|
321
|
+
locals: {},
|
|
322
|
+
cookies: {},
|
|
323
|
+
request: null,
|
|
324
|
+
set() { },
|
|
325
|
+
get() { return undefined; },
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
// Expose root middleware locals to API/SSR handlers (which seed their own
|
|
329
|
+
// ctx.locals from this before running route-level middleware).
|
|
330
|
+
globalThis.__vesk_request = mwCtx;
|
|
280
331
|
if (url.pathname.startsWith('/_vesk/action/')) {
|
|
281
332
|
const actionId = url.pathname.replace('/_vesk/action/', '');
|
|
282
333
|
const actionEntry = buildConfig.actions && buildConfig.actions.find(a => a.id === actionId);
|
|
@@ -292,15 +343,18 @@ export async function startProdServer(outDir, options) {
|
|
|
292
343
|
return;
|
|
293
344
|
}
|
|
294
345
|
try {
|
|
295
|
-
const webRequest = makeWebRequest(req, url.href);
|
|
346
|
+
const webRequest = makeWebRequest(req, url.href, maxBodyBytes);
|
|
296
347
|
const response = await mod.handleAction(webRequest, actionId);
|
|
297
348
|
const body = await response.text();
|
|
298
349
|
res.writeHead(response.status, Object.fromEntries(response.headers));
|
|
299
350
|
res.end(body);
|
|
300
351
|
}
|
|
301
352
|
catch (e) {
|
|
302
|
-
const
|
|
303
|
-
|
|
353
|
+
const status = errorStatus(e, 500);
|
|
354
|
+
const message = status === 500 && process.env.NODE_ENV === 'production'
|
|
355
|
+
? 'Internal Server Error'
|
|
356
|
+
: e instanceof Error ? e.message : String(e);
|
|
357
|
+
res.writeHead(status, { 'Content-Type': 'application/json' });
|
|
304
358
|
res.end(JSON.stringify({ ok: false, error: message }));
|
|
305
359
|
}
|
|
306
360
|
return;
|
|
@@ -313,7 +367,7 @@ export async function startProdServer(outDir, options) {
|
|
|
313
367
|
const mod = await loadFunction(route.function);
|
|
314
368
|
if (mod) {
|
|
315
369
|
try {
|
|
316
|
-
const webRequest = makeWebRequest(req, url.href);
|
|
370
|
+
const webRequest = makeWebRequest(req, url.href, maxBodyBytes);
|
|
317
371
|
const response = await mod.handle(webRequest);
|
|
318
372
|
const body = await response.text();
|
|
319
373
|
res.writeHead(response.status, Object.fromEntries(response.headers));
|
|
@@ -321,9 +375,9 @@ export async function startProdServer(outDir, options) {
|
|
|
321
375
|
return;
|
|
322
376
|
}
|
|
323
377
|
catch (e) {
|
|
324
|
-
const
|
|
325
|
-
res.writeHead(
|
|
326
|
-
res.end(JSON.stringify({ error: message }));
|
|
378
|
+
const status = errorStatus(e, 500);
|
|
379
|
+
res.writeHead(status, { 'Content-Type': 'application/json' });
|
|
380
|
+
res.end(JSON.stringify({ error: status === 500 ? 'Internal Server Error' : e instanceof Error ? e.message : String(e) }));
|
|
327
381
|
return;
|
|
328
382
|
}
|
|
329
383
|
}
|
|
@@ -337,10 +391,10 @@ export async function startProdServer(outDir, options) {
|
|
|
337
391
|
if (existsSync(nfPath)) {
|
|
338
392
|
try {
|
|
339
393
|
const runtimePath = resolve(outDir, 'server', 'runtime.js');
|
|
340
|
-
const { renderFullPage } = await import(runtimePath);
|
|
394
|
+
const { renderFullPage, storeDataScriptGlobal } = await import(runtimePath);
|
|
341
395
|
const src = readFileSync(nfPath, 'utf-8');
|
|
342
396
|
const compName = resolveComponentName(src) || 'NotFound';
|
|
343
|
-
notFoundHtml = await renderFullPage(src, compName, { params: {}, url: url.pathname }, new Map(), { hydrate: true, cssUrls: ['/_vesk/static/_tailwind.css', '/_vesk/static/global.css'], security: securityConfig?.security || {}, sourcePath: nfPath });
|
|
397
|
+
notFoundHtml = await renderFullPage(src, compName, { params: {}, url: url.pathname }, new Map(), { hydrate: true, cssUrls: ['/_vesk/static/_tailwind.css', '/_vesk/static/global.css'], security: securityConfig?.security || {}, externalDataScript: storeDataScriptGlobal, sourcePath: nfPath });
|
|
344
398
|
}
|
|
345
399
|
catch { }
|
|
346
400
|
}
|
|
@@ -351,7 +405,7 @@ export async function startProdServer(outDir, options) {
|
|
|
351
405
|
const mod = await loadFunction(route.function);
|
|
352
406
|
if (mod) {
|
|
353
407
|
try {
|
|
354
|
-
const webRequest = makeWebRequest(req, url.href);
|
|
408
|
+
const webRequest = makeWebRequest(req, url.href, maxBodyBytes);
|
|
355
409
|
let cachedResult = null;
|
|
356
410
|
if (route.revalidate && route.revalidate > 0) {
|
|
357
411
|
const { pageIsr } = await import('@vesk/runtime/src/index-server');
|
|
@@ -404,10 +458,12 @@ export async function startProdServer(outDir, options) {
|
|
|
404
458
|
if (existsSync(errPath)) {
|
|
405
459
|
try {
|
|
406
460
|
const runtimePath = resolve(outDir, 'server', 'runtime.js');
|
|
407
|
-
const { renderFullPage } = await import(runtimePath);
|
|
461
|
+
const { renderFullPage, storeDataScriptGlobal } = await import(runtimePath);
|
|
408
462
|
const src = readFileSync(errPath, 'utf-8');
|
|
409
463
|
const compName = resolveComponentName(src) || 'Error';
|
|
410
|
-
|
|
464
|
+
// never leak stack traces / internal messages to prod error pages
|
|
465
|
+
const expose = process.env.NODE_ENV !== 'production';
|
|
466
|
+
errorHtml = await renderFullPage(src, compName, { error: expose ? err.message : 'Internal Server Error', stack: expose ? err.stack : '', statusCode: 500, url: url.pathname }, new Map(), { hydrate: true, cssUrls: ['/_vesk/static/_tailwind.css', '/_vesk/static/global.css'], clientScriptUrl: '/_vesk/static/client.js', security: securityConfig?.security || {}, externalDataScript: storeDataScriptGlobal, sourcePath: errPath });
|
|
411
467
|
}
|
|
412
468
|
catch { }
|
|
413
469
|
}
|
|
@@ -422,8 +478,8 @@ export async function startProdServer(outDir, options) {
|
|
|
422
478
|
res.writeHead(404, { 'Content-Type': 'text/html' });
|
|
423
479
|
res.end(notFoundHtml || '<!DOCTYPE html><html><body><h1>404</h1><p>Not Found</p></body></html>');
|
|
424
480
|
});
|
|
425
|
-
server.listen(port, () => {
|
|
426
|
-
console.error(`vesk production server at http://localhost:${port}`);
|
|
481
|
+
server.listen(port, host, () => {
|
|
482
|
+
console.error(`vesk production server at http://localhost:${port} (listening on ${host})`);
|
|
427
483
|
});
|
|
428
484
|
return server;
|
|
429
485
|
}
|
|
@@ -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,CA2GnF"}
|
package/dist/runtime-bundle.js
CHANGED
|
@@ -39,7 +39,7 @@ export async function bundleRuntime(appDir, outDir) {
|
|
|
39
39
|
const runtimeRoot = findRuntimeSrc(appDir);
|
|
40
40
|
const entryFile = resolve(outDir, 'server', `.runtime-entry-${buildId++}.mjs`);
|
|
41
41
|
const entryContent = [
|
|
42
|
-
`import { renderPage, renderFullPage, renderPageStream, compileFile, setRuntimeModule, setVskHydrate } from ${JSON.stringify(resolve(compilerRoot, 'server-codegen.js'))};`,
|
|
42
|
+
`import { renderPage, renderFullPage, renderPageStream, compileFile, setRuntimeModule, setVskHydrate, assertSameOrigin } 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
45
|
'',
|
|
@@ -77,14 +77,19 @@ export async function bundleRuntime(appDir, outDir) {
|
|
|
77
77
|
' return req.locals || {};',
|
|
78
78
|
'}',
|
|
79
79
|
'',
|
|
80
|
-
'export { renderPage, renderFullPage, renderPageStream, compileFile, setVskHydrate, parseCookies };',
|
|
80
|
+
'export { renderPage, renderFullPage, renderPageStream, compileFile, setVskHydrate, parseCookies, assertSameOrigin };',
|
|
81
81
|
'export { withSsrStore } from "@vesk/compiler/src/ssr-store";',
|
|
82
82
|
'',
|
|
83
83
|
'// Deliver hydration data as an origin-served script so strict CSP (no unsafe-inline)',
|
|
84
84
|
'// does not block it. The prod server serves /ssr-data.js from the global store.',
|
|
85
85
|
'export function storeDataScriptGlobal(payload) {',
|
|
86
86
|
" if (!payload || (!payload.props && !payload.ssrData)) return null;",
|
|
87
|
-
|
|
87
|
+
' // CSPRNG token — this URL gates access to the page\'s hydration payload',
|
|
88
|
+
' const bytes = new Uint8Array(12);',
|
|
89
|
+
' crypto.getRandomValues(bytes);',
|
|
90
|
+
" let tk = '';",
|
|
91
|
+
" for (const b of bytes) tk += b.toString(16).padStart(2, '0');",
|
|
92
|
+
' const token = tk;',
|
|
88
93
|
" const store = (globalThis.__vsk_ssr_data_store ||= {});",
|
|
89
94
|
" store[token] = payload;",
|
|
90
95
|
' // Bound the store: if the browser never fetches /ssr-data.js the entry',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssr-function.d.ts","sourceRoot":"","sources":["../src/ssr-function.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAkB,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAW7F,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQjF;AAiDD,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":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAkB,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAW7F,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQjF;AAiDD,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,CAyWtD"}
|