@vesk/compiler 0.0.1
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/README.md +23 -0
- package/dist/acorn-ts-plugin/index.d.ts +482 -0
- package/dist/acorn-ts-plugin/index.d.ts.map +1 -0
- package/dist/acorn-ts-plugin/index.js +5028 -0
- package/dist/actions.d.ts +22 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +167 -0
- package/dist/api-routes.d.ts +30 -0
- package/dist/api-routes.d.ts.map +1 -0
- package/dist/api-routes.js +350 -0
- package/dist/client-codegen.d.ts +19 -0
- package/dist/client-codegen.d.ts.map +1 -0
- package/dist/client-codegen.js +1523 -0
- package/dist/config.d.ts +6 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +106 -0
- package/dist/errors.d.ts +33 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +210 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/ir-generator.d.ts +10 -0
- package/dist/ir-generator.d.ts.map +1 -0
- package/dist/ir-generator.js +1062 -0
- package/dist/ir.d.ts +160 -0
- package/dist/ir.d.ts.map +1 -0
- package/dist/ir.js +219 -0
- package/dist/middleware.d.ts +15 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +183 -0
- package/dist/package.json +15 -0
- package/dist/parser.d.ts +38 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +242 -0
- package/dist/router.d.ts +31 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +451 -0
- package/dist/scan.d.ts +106 -0
- package/dist/scan.d.ts.map +1 -0
- package/dist/scan.js +438 -0
- package/dist/server-codegen.d.ts +5 -0
- package/dist/server-codegen.d.ts.map +1 -0
- package/dist/server-codegen.js +4 -0
- package/dist/server-cookies.d.ts +2 -0
- package/dist/server-cookies.d.ts.map +1 -0
- package/dist/server-cookies.js +15 -0
- package/dist/server-head.d.ts +10 -0
- package/dist/server-head.d.ts.map +1 -0
- package/dist/server-head.js +289 -0
- package/dist/server-jsgen.d.ts +6 -0
- package/dist/server-jsgen.d.ts.map +1 -0
- package/dist/server-jsgen.js +446 -0
- package/dist/server-render.d.ts +16 -0
- package/dist/server-render.d.ts.map +1 -0
- package/dist/server-render.js +397 -0
- package/dist/server-utils.d.ts +93 -0
- package/dist/server-utils.d.ts.map +1 -0
- package/dist/server-utils.js +747 -0
- package/dist/ssr-store.d.ts +4 -0
- package/dist/ssr-store.d.ts.map +1 -0
- package/dist/ssr-store.js +29 -0
- package/dist/strip-ts.d.ts +25 -0
- package/dist/strip-ts.d.ts.map +1 -0
- package/dist/strip-ts.js +171 -0
- package/dist/tokens.d.ts +50 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +334 -0
- package/dist/typecheck.d.ts +19 -0
- package/dist/typecheck.d.ts.map +1 -0
- package/dist/typecheck.js +365 -0
- package/dist/types.d.ts +147 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +13 -0
- package/dist/vesk-plugin.d.ts +53 -0
- package/dist/vesk-plugin.d.ts.map +1 -0
- package/dist/vesk-plugin.js +413 -0
- package/dist/vsk-imports.d.ts +30 -0
- package/dist/vsk-imports.d.ts.map +1 -0
- package/dist/vsk-imports.js +141 -0
- package/dist/vsk-tsx.d.ts +3 -0
- package/dist/vsk-tsx.d.ts.map +1 -0
- package/dist/vsk-tsx.js +604 -0
- package/package.json +52 -0
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { MapRegion } from '@vesk/compiler/src/ir';
|
|
3
|
+
import { parse } from '@vesk/compiler/src/parser';
|
|
4
|
+
import { generateIR } from '@vesk/compiler/src/ir-generator';
|
|
5
|
+
import { compileClient, isStaticIR } from '@vesk/compiler/src/client-codegen';
|
|
6
|
+
import { isStatic, prettifyHtml, resetVskState, loadRuntimeImports, evalTopLevelCode, callStaticProps, callLoadFunction, } from '@vesk/compiler/src/server-utils';
|
|
7
|
+
import { renderHeadHtml, mergeHeadHtml } from '@vesk/compiler/src/server-head';
|
|
8
|
+
import { buildComponentMap } from '@vesk/compiler/src/server-jsgen';
|
|
9
|
+
import { transformTopLevelForActions } from '@vesk/compiler/src/actions';
|
|
10
|
+
import { collectVskImportPaths } from '@vesk/compiler/src/vsk-imports';
|
|
11
|
+
import { withSsrStore, ssrSink } from '@vesk/compiler/src/ssr-store';
|
|
12
|
+
export function compileFile(source, options) {
|
|
13
|
+
return compileFileInternal(source, options?.sourcePath, new Set());
|
|
14
|
+
}
|
|
15
|
+
function compileFileInternal(source, sourcePath, seenImportFiles) {
|
|
16
|
+
const ast = parse(source);
|
|
17
|
+
const ir = generateIR(ast, source);
|
|
18
|
+
const componentMap = buildComponentMap(ir, true);
|
|
19
|
+
if (sourcePath) {
|
|
20
|
+
for (const importPath of collectVskImportPaths(ir.imports, sourcePath)) {
|
|
21
|
+
if (seenImportFiles.has(importPath))
|
|
22
|
+
continue;
|
|
23
|
+
seenImportFiles.add(importPath);
|
|
24
|
+
try {
|
|
25
|
+
const importedSrc = readFileSync(importPath, 'utf-8');
|
|
26
|
+
const sub = compileFileInternal(importedSrc, importPath, seenImportFiles);
|
|
27
|
+
for (const [name, fn] of sub.componentMap) {
|
|
28
|
+
if (!componentMap.has(name))
|
|
29
|
+
componentMap.set(name, fn);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// skip unresolvable imports
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const __vesk = loadRuntimeImports(ir.imports);
|
|
38
|
+
evalTopLevelCode(transformTopLevelForActions(ir.topLevelCode, 'server'), __vesk);
|
|
39
|
+
return { ir, componentMap, __vesk };
|
|
40
|
+
}
|
|
41
|
+
export function render(source, componentName, props = {}, registry = new Map(), options = {}) {
|
|
42
|
+
resetVskState(!!options.hydrate);
|
|
43
|
+
const compiled = compileFile(source, { sourcePath: options.sourcePath || undefined });
|
|
44
|
+
const componentMap = compiled.componentMap;
|
|
45
|
+
const renderFn = componentMap.get(componentName);
|
|
46
|
+
if (!renderFn)
|
|
47
|
+
throw new Error(`Component "${componentName}" not found in source`);
|
|
48
|
+
const fullRegistry = new Map([...registry, ...componentMap]);
|
|
49
|
+
const __vesk = options.__vesk || compiled.__vesk;
|
|
50
|
+
const targetComp = compiled.ir.components.find((c) => c.name === componentName);
|
|
51
|
+
const isAsyncComp = !!(targetComp && (targetComp.isAsync || targetComp.ssrAwait));
|
|
52
|
+
globalThis.__vsk_ssr = true;
|
|
53
|
+
globalThis.__vsk_ssr_token = Math.random().toString(36).slice(2);
|
|
54
|
+
const renderToken = globalThis.__vsk_ssr_token;
|
|
55
|
+
if (isAsyncComp) {
|
|
56
|
+
return withSsrStore(() => (async () => {
|
|
57
|
+
let bodyHtml;
|
|
58
|
+
try {
|
|
59
|
+
bodyHtml = await renderFn(props, fullRegistry, __vesk);
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
delete globalThis.__vsk_ssr;
|
|
63
|
+
clearSsrCells(renderToken);
|
|
64
|
+
}
|
|
65
|
+
return bodyHtml;
|
|
66
|
+
})());
|
|
67
|
+
}
|
|
68
|
+
let bodyHtml;
|
|
69
|
+
try {
|
|
70
|
+
bodyHtml = withSsrStore(() => renderFn(props, fullRegistry, __vesk));
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
delete globalThis.__vsk_ssr;
|
|
74
|
+
clearSsrCells(renderToken);
|
|
75
|
+
}
|
|
76
|
+
return bodyHtml;
|
|
77
|
+
}
|
|
78
|
+
export function renderPage(source, componentName, props = {}, registry = new Map(), options = {}) {
|
|
79
|
+
resetVskState(!!options.hydrate);
|
|
80
|
+
let __vesk, componentMap, ir;
|
|
81
|
+
if (options.cached) {
|
|
82
|
+
const cached = options.cached;
|
|
83
|
+
ir = cached.ir;
|
|
84
|
+
componentMap = cached.componentMap;
|
|
85
|
+
__vesk = cached.__vesk;
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
const compiled = compileFile(source, { sourcePath: options.sourcePath || undefined });
|
|
89
|
+
ir = compiled.ir;
|
|
90
|
+
componentMap = compiled.componentMap;
|
|
91
|
+
__vesk = compiled.__vesk;
|
|
92
|
+
}
|
|
93
|
+
const renderFn = componentMap.get(componentName);
|
|
94
|
+
if (!renderFn)
|
|
95
|
+
throw new Error(`Component "${componentName}" not found in source`);
|
|
96
|
+
const fullRegistry = new Map([...registry, ...componentMap]);
|
|
97
|
+
const targetComp = ir.components.find((c) => c.name === componentName);
|
|
98
|
+
const doRender = (ssrProps) => {
|
|
99
|
+
globalThis.__vsk_ssr = true;
|
|
100
|
+
globalThis.__vsk_ssr_token = Math.random().toString(36).slice(2);
|
|
101
|
+
const renderToken = globalThis.__vsk_ssr_token;
|
|
102
|
+
if (targetComp && (targetComp.isAsync || targetComp.ssrAwait)) {
|
|
103
|
+
return withSsrStore(() => (async () => {
|
|
104
|
+
let bodyHtml;
|
|
105
|
+
try {
|
|
106
|
+
bodyHtml = await renderFn(ssrProps, fullRegistry, __vesk);
|
|
107
|
+
}
|
|
108
|
+
finally {
|
|
109
|
+
delete globalThis.__vsk_ssr;
|
|
110
|
+
clearSsrCells(renderToken);
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
body: bodyHtml,
|
|
114
|
+
head: renderHeadHtml(targetComp, ssrProps),
|
|
115
|
+
props: ssrProps
|
|
116
|
+
};
|
|
117
|
+
})());
|
|
118
|
+
}
|
|
119
|
+
let bodyHtml;
|
|
120
|
+
try {
|
|
121
|
+
bodyHtml = withSsrStore(() => renderFn(ssrProps, fullRegistry, __vesk));
|
|
122
|
+
}
|
|
123
|
+
finally {
|
|
124
|
+
delete globalThis.__vsk_ssr;
|
|
125
|
+
clearSsrCells(renderToken);
|
|
126
|
+
}
|
|
127
|
+
const headHtml = targetComp ? renderHeadHtml(targetComp, ssrProps) : '';
|
|
128
|
+
return { body: bodyHtml, head: headHtml, props: ssrProps };
|
|
129
|
+
};
|
|
130
|
+
if (ir.loadFn) {
|
|
131
|
+
const loadFn = ir.loadFn;
|
|
132
|
+
return withSsrStore(() => (async () => {
|
|
133
|
+
const loadResult = await callLoadFunction(loadFn, props, __vesk);
|
|
134
|
+
let ssrProps = { ...props };
|
|
135
|
+
if (loadResult && typeof loadResult === 'object') {
|
|
136
|
+
const result = loadResult;
|
|
137
|
+
if (result.props)
|
|
138
|
+
ssrProps = { ...ssrProps, ...result.props };
|
|
139
|
+
else
|
|
140
|
+
ssrProps = { ...ssrProps, ...result };
|
|
141
|
+
}
|
|
142
|
+
return doRender(ssrProps);
|
|
143
|
+
})());
|
|
144
|
+
}
|
|
145
|
+
return withSsrStore(() => doRender(props));
|
|
146
|
+
}
|
|
147
|
+
function clearSsrCells(token) {
|
|
148
|
+
if (!token)
|
|
149
|
+
return;
|
|
150
|
+
delete globalThis[`__vsk_ssr_promises_${token}`];
|
|
151
|
+
const cells = globalThis.__vsk_ssr_cells;
|
|
152
|
+
if (!cells || !(cells instanceof Map))
|
|
153
|
+
return;
|
|
154
|
+
for (const k of cells.keys()) {
|
|
155
|
+
if (typeof k === 'string' && k.startsWith(token))
|
|
156
|
+
cells.delete(k);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
export async function ssg(source, componentName, customProps, options = {}) {
|
|
160
|
+
const ast = parse(source);
|
|
161
|
+
const ir = generateIR(ast, source);
|
|
162
|
+
if (!componentName) {
|
|
163
|
+
const defaultComp = ir.components.find((c) => c.defaultExport);
|
|
164
|
+
const exportedComp = ir.components.find((c) => c.exported);
|
|
165
|
+
componentName = defaultComp?.name || exportedComp?.name || (ir.components.length > 0 ? ir.components[0].name : undefined);
|
|
166
|
+
}
|
|
167
|
+
if (!componentName)
|
|
168
|
+
throw new Error('No component found in source for SSG');
|
|
169
|
+
let props = customProps;
|
|
170
|
+
if (props === undefined && ir.staticProps) {
|
|
171
|
+
const staticResult = await callStaticProps(ir.staticProps);
|
|
172
|
+
if (staticResult && typeof staticResult === 'object') {
|
|
173
|
+
props = staticResult;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (!props)
|
|
177
|
+
props = {};
|
|
178
|
+
const needsClient = ir.components.some((c) => {
|
|
179
|
+
if (c.isClient)
|
|
180
|
+
return true;
|
|
181
|
+
if (c.style)
|
|
182
|
+
return true;
|
|
183
|
+
return !isStatic(c.body);
|
|
184
|
+
});
|
|
185
|
+
const rendered = await renderPage(source, componentName, props, options.registry || new Map(), { hydrate: needsClient });
|
|
186
|
+
const bodyHtml = rendered.body;
|
|
187
|
+
const headHtml = rendered.head;
|
|
188
|
+
const clientCode = needsClient
|
|
189
|
+
? compileClient(source, null, { hydrate: true })
|
|
190
|
+
: '';
|
|
191
|
+
const serializedProps = JSON.stringify(props);
|
|
192
|
+
const hasClient = clientCode.length > 0;
|
|
193
|
+
const scriptBlock = hasClient
|
|
194
|
+
? `\n<script>const __vesk_props = ${serializedProps};\n<\/script>\n<script>${clientCode}</script>\n`
|
|
195
|
+
: `\n<script>const __vesk_props = ${serializedProps};\n<\/script>\n`;
|
|
196
|
+
const cssUrls = options.cssUrls || (options.cssUrl ? [options.cssUrl] : []);
|
|
197
|
+
const cssLink = cssUrls.map(u => `\t<link rel="stylesheet" href="${u}" />\n`).join('');
|
|
198
|
+
const html = `<!DOCTYPE html>
|
|
199
|
+
<html>
|
|
200
|
+
<head>
|
|
201
|
+
\t<meta charset="utf-8" />
|
|
202
|
+
\t<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
203
|
+
${cssLink}${headHtml ? '\t' + headHtml.split('\n').join('\n\t') + '\n' : ''}</head>
|
|
204
|
+
<body>
|
|
205
|
+
${bodyHtml}${scriptBlock}</body>
|
|
206
|
+
</html>
|
|
207
|
+
`;
|
|
208
|
+
const staticLists = ir.components.some((c) => {
|
|
209
|
+
return c.body.some((node) => {
|
|
210
|
+
if (node instanceof MapRegion)
|
|
211
|
+
return isStaticIR(node.bodyTemplate) && isStaticIR(node.alternateNodes);
|
|
212
|
+
return false;
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
return { html, body: bodyHtml, head: headHtml, props: serializedProps, clientCode, static: !hasClient, staticLists };
|
|
216
|
+
}
|
|
217
|
+
export function buildDataScripts(ssrProps, ssrData, external) {
|
|
218
|
+
const meaningfulKeys = ssrProps !== undefined && ssrProps !== null
|
|
219
|
+
? Object.keys(ssrProps).filter((k) => k !== 'children' && k !== 'params')
|
|
220
|
+
: [];
|
|
221
|
+
const hasProps = meaningfulKeys.length > 0;
|
|
222
|
+
const hasData = Object.keys(ssrData).length > 0;
|
|
223
|
+
if (!hasProps && !hasData)
|
|
224
|
+
return [];
|
|
225
|
+
const payload = {};
|
|
226
|
+
if (hasProps) {
|
|
227
|
+
const cleanProps = {};
|
|
228
|
+
for (const k of meaningfulKeys)
|
|
229
|
+
cleanProps[k] = ssrProps[k];
|
|
230
|
+
payload.props = cleanProps;
|
|
231
|
+
}
|
|
232
|
+
if (hasData)
|
|
233
|
+
payload.ssrData = ssrData;
|
|
234
|
+
if (external) {
|
|
235
|
+
const src = external(payload);
|
|
236
|
+
if (src)
|
|
237
|
+
return [`\t<script src="${src}"></script>`];
|
|
238
|
+
}
|
|
239
|
+
const scripts = [];
|
|
240
|
+
if (hasProps)
|
|
241
|
+
scripts.push(`\t<script>const __vesk_props = ${JSON.stringify(payload.props)};</script>`);
|
|
242
|
+
if (hasData)
|
|
243
|
+
scripts.push(`\t<script>globalThis.__vsk_ssr_data = ${JSON.stringify(ssrData)};</script>`);
|
|
244
|
+
return scripts;
|
|
245
|
+
}
|
|
246
|
+
export async function renderFullPage(source, componentName, props = {}, registry = new Map(), options = {}) {
|
|
247
|
+
return withSsrStore(async () => {
|
|
248
|
+
globalThis.__vsk_ssr = true;
|
|
249
|
+
try {
|
|
250
|
+
let ssrProps = { ...props };
|
|
251
|
+
let serializedProps = null;
|
|
252
|
+
const cached = options.cached || undefined;
|
|
253
|
+
const ir = cached ? cached.ir : generateIR(parse(source), source);
|
|
254
|
+
if (ir.loadFn) {
|
|
255
|
+
const __vesk = options.__vesk || cached?.__vesk || loadRuntimeImports(ir.imports);
|
|
256
|
+
const loadResult = await callLoadFunction(ir.loadFn, ssrProps, __vesk);
|
|
257
|
+
if (loadResult && typeof loadResult === 'object') {
|
|
258
|
+
const result = loadResult;
|
|
259
|
+
if (result.props)
|
|
260
|
+
ssrProps = { ...ssrProps, ...result.props };
|
|
261
|
+
else
|
|
262
|
+
ssrProps = { ...ssrProps, ...result };
|
|
263
|
+
}
|
|
264
|
+
serializedProps = JSON.stringify(ssrProps);
|
|
265
|
+
}
|
|
266
|
+
const rendered = await renderPage(source, componentName, ssrProps, registry, { ...options, __vesk: options.__vesk });
|
|
267
|
+
const ssrData = { ...ssrSink.snapshot() };
|
|
268
|
+
let headHtml = rendered.head;
|
|
269
|
+
if (options.pageHead) {
|
|
270
|
+
const merged = mergeHeadHtml(options.pageHead, rendered.head);
|
|
271
|
+
headHtml = merged.html;
|
|
272
|
+
if (merged.conflicts.length > 0) {
|
|
273
|
+
for (const c of merged.conflicts) {
|
|
274
|
+
console.error(`vesk head conflict: ${c.message}`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
const bodyHtml = prettifyHtml(rendered.body);
|
|
279
|
+
const cssUrls = options.cssUrls || (options.cssUrl ? [options.cssUrl] : []);
|
|
280
|
+
const cssLink = cssUrls.map(u => `\t<link rel="stylesheet" href="${u}" />\n`).join('');
|
|
281
|
+
const clientScript = options.clientScriptUrl
|
|
282
|
+
? `\t<script type="module" src="${options.clientScriptUrl}"></script>\n`
|
|
283
|
+
: '';
|
|
284
|
+
const dataScripts = buildDataScripts(ssrProps, ssrData, options.externalDataScript);
|
|
285
|
+
const dataScriptBlock = dataScripts.length > 0 ? '\n' + dataScripts.join('\n') + '\n' : '';
|
|
286
|
+
const headLines = ['\t<meta charset="utf-8" />', '\t<meta name="viewport" content="width=device-width, initial-scale=1" />'];
|
|
287
|
+
if (cssLink)
|
|
288
|
+
headLines.push(cssLink.trimEnd());
|
|
289
|
+
if (headHtml)
|
|
290
|
+
headLines.push('\t' + headHtml.split('\n').join('\n\t'));
|
|
291
|
+
if (options.security) {
|
|
292
|
+
const sec = options.security;
|
|
293
|
+
if (sec.referrerPolicy !== false)
|
|
294
|
+
headLines.push(`\t<meta name="referrer" content="${sec.referrerPolicy || 'strict-origin-when-cross-origin'}" />`);
|
|
295
|
+
if (sec.contentSecurityPolicy !== false)
|
|
296
|
+
headLines.push(`\t<meta http-equiv="Content-Security-Policy" content="${(sec.contentSecurityPolicy || "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; frame-src 'self'; connect-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'").replace(/"/g, '"')}" />`);
|
|
297
|
+
if (sec.autoEscape !== false)
|
|
298
|
+
headLines.push(`\t<!-- vesk: auto-escape enabled -->`);
|
|
299
|
+
}
|
|
300
|
+
return `<!DOCTYPE html>
|
|
301
|
+
<html>
|
|
302
|
+
<head>
|
|
303
|
+
${headLines.join('\n')}</head>
|
|
304
|
+
<body>
|
|
305
|
+
<div id="root">
|
|
306
|
+
${bodyHtml}
|
|
307
|
+
</div>
|
|
308
|
+
${dataScriptBlock}${clientScript}</body>
|
|
309
|
+
</html>`;
|
|
310
|
+
}
|
|
311
|
+
finally {
|
|
312
|
+
delete globalThis.__vsk_ssr;
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
export function renderPageStream(source, componentName, props = {}, registry = new Map(), options = {}) {
|
|
317
|
+
async function* raw() {
|
|
318
|
+
const cached = options.cached || undefined;
|
|
319
|
+
const ir = cached ? cached.ir : generateIR(parse(source), source);
|
|
320
|
+
let ssrProps = { ...props };
|
|
321
|
+
let serializedProps = null;
|
|
322
|
+
let __vesk = options.__vesk || cached?.__vesk || loadRuntimeImports(ir.imports);
|
|
323
|
+
if (ir.loadFn) {
|
|
324
|
+
const loadResult = await callLoadFunction(ir.loadFn, props, __vesk);
|
|
325
|
+
if (loadResult && typeof loadResult === 'object') {
|
|
326
|
+
const result = loadResult;
|
|
327
|
+
if (result.props)
|
|
328
|
+
ssrProps = { ...ssrProps, ...result.props };
|
|
329
|
+
else
|
|
330
|
+
ssrProps = { ...ssrProps, ...result };
|
|
331
|
+
}
|
|
332
|
+
serializedProps = JSON.stringify(ssrProps);
|
|
333
|
+
}
|
|
334
|
+
const componentMap = cached ? cached.componentMap : compileFile(source, { sourcePath: options.sourcePath || undefined }).componentMap;
|
|
335
|
+
const fullRegistry = new Map([...registry, ...componentMap]);
|
|
336
|
+
const renderFn = componentMap.get(componentName);
|
|
337
|
+
if (!renderFn)
|
|
338
|
+
throw new Error(`Component "${componentName}" not found in source`);
|
|
339
|
+
resetVskState(!!options.hydrate);
|
|
340
|
+
const targetComp = ir.components.find((c) => c.name === componentName);
|
|
341
|
+
const cssUrls = options.cssUrls || (options.cssUrl ? [options.cssUrl] : []);
|
|
342
|
+
const cssLink = cssUrls.map(u => `\t<link rel="stylesheet" href="${u}" />\n`).join('');
|
|
343
|
+
yield '<!DOCTYPE html>\n<html>\n<head>\n\t<meta charset="utf-8" />\n\t<meta name="viewport" content="width=device-width, initial-scale=1" />\n';
|
|
344
|
+
if (cssLink)
|
|
345
|
+
yield cssLink;
|
|
346
|
+
if (options.security) {
|
|
347
|
+
const sec = options.security;
|
|
348
|
+
if (sec.referrerPolicy !== false)
|
|
349
|
+
yield `\t<meta name="referrer" content="${sec.referrerPolicy || 'strict-origin-when-cross-origin'}" />\n`;
|
|
350
|
+
if (sec.contentSecurityPolicy !== false)
|
|
351
|
+
yield `\t<meta http-equiv="Content-Security-Policy" content="${(sec.contentSecurityPolicy || "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; frame-src 'self'; connect-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'").replace(/"/g, '"')}" />\n`;
|
|
352
|
+
if (sec.autoEscape !== false)
|
|
353
|
+
yield `\t<!-- vesk: auto-escape enabled -->\n`;
|
|
354
|
+
}
|
|
355
|
+
if (targetComp) {
|
|
356
|
+
let headHtml = renderHeadHtml(targetComp, ssrProps);
|
|
357
|
+
if (options.pageHead) {
|
|
358
|
+
const merged = mergeHeadHtml(options.pageHead, headHtml);
|
|
359
|
+
headHtml = merged.html;
|
|
360
|
+
if (merged.conflicts.length > 0) {
|
|
361
|
+
for (const c of merged.conflicts) {
|
|
362
|
+
console.error(`vesk head conflict: ${c.message}`);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
if (headHtml)
|
|
367
|
+
yield '\t' + headHtml.split('\n').join('\n\t') + '\n';
|
|
368
|
+
}
|
|
369
|
+
yield '</head>\n<body>\n<div id="root">\n';
|
|
370
|
+
globalThis.__vsk_ssr = true;
|
|
371
|
+
globalThis.__vsk_ssr_token = Math.random().toString(36).slice(2);
|
|
372
|
+
const renderToken = globalThis.__vsk_ssr_token;
|
|
373
|
+
let bodyHtml;
|
|
374
|
+
try {
|
|
375
|
+
bodyHtml = await Promise.resolve(renderFn(ssrProps, fullRegistry, __vesk));
|
|
376
|
+
}
|
|
377
|
+
finally {
|
|
378
|
+
delete globalThis.__vsk_ssr;
|
|
379
|
+
clearSsrCells(renderToken);
|
|
380
|
+
}
|
|
381
|
+
yield bodyHtml;
|
|
382
|
+
const ssrData = { ...ssrSink.snapshot() };
|
|
383
|
+
const dataScripts = buildDataScripts(ssrProps, ssrData, options.externalDataScript);
|
|
384
|
+
const dataScriptBlock = dataScripts.length > 0 ? '\n' + dataScripts.join('\n') : '';
|
|
385
|
+
yield `\n</div>${dataScriptBlock}</body>\n</html>\n`;
|
|
386
|
+
}
|
|
387
|
+
const gen = raw();
|
|
388
|
+
async function* scoped() {
|
|
389
|
+
let result;
|
|
390
|
+
do {
|
|
391
|
+
result = (await withSsrStore(() => gen.next()));
|
|
392
|
+
if (!result.done)
|
|
393
|
+
yield result.value;
|
|
394
|
+
} while (!result.done);
|
|
395
|
+
}
|
|
396
|
+
return scoped();
|
|
397
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { IRNode } from '@vesk/compiler/src/ir';
|
|
2
|
+
export declare let __vskHydrate: boolean;
|
|
3
|
+
export declare let __vskId: number;
|
|
4
|
+
export declare let __vskForceClaim: boolean;
|
|
5
|
+
export declare let __vskImportedNames: Set<string> | null;
|
|
6
|
+
export declare function resetVskState(hydrate?: boolean): void;
|
|
7
|
+
export declare function setVskHydrate(v: boolean): void;
|
|
8
|
+
export declare function setVskImportedNames(names: Set<string> | null): void;
|
|
9
|
+
export declare function setVskForceClaim(v: boolean): void;
|
|
10
|
+
export declare function takeVskForceClaim(): boolean;
|
|
11
|
+
export declare function nextVskId(): number;
|
|
12
|
+
export declare function prettifyHtml(html: string): string;
|
|
13
|
+
export declare function isStatic(body: IRNode[]): boolean;
|
|
14
|
+
export declare function escapeHtml(str: string): string;
|
|
15
|
+
export declare function redactLog(str: string): string;
|
|
16
|
+
export declare function setRedactLogging(enabled: boolean): void;
|
|
17
|
+
export declare function raw(value: unknown): string;
|
|
18
|
+
export declare function csrfToken(sessionId?: string, host?: string): string;
|
|
19
|
+
export declare function verifyCsrfToken(token: string, host?: string): boolean;
|
|
20
|
+
export declare function csrfGuard(request: Record<string, unknown>, host?: string): void;
|
|
21
|
+
export declare function signCookie(name: string, value: string, host?: string): Promise<string>;
|
|
22
|
+
export declare function unsignCookie(name: string, signedValue: string, host?: string): Promise<string | null>;
|
|
23
|
+
export interface CookieOptions {
|
|
24
|
+
httpOnly?: boolean;
|
|
25
|
+
secure?: boolean;
|
|
26
|
+
sameSite?: string;
|
|
27
|
+
path?: string;
|
|
28
|
+
maxAge?: number;
|
|
29
|
+
domain?: string;
|
|
30
|
+
}
|
|
31
|
+
export declare function setSignedCookie(name: string, value: string, options?: CookieOptions, host?: string): Promise<string>;
|
|
32
|
+
export declare function readSignedCookie(name: string, cookieString: string, host?: string): Promise<string | null>;
|
|
33
|
+
export interface SecurityConfig {
|
|
34
|
+
security?: {
|
|
35
|
+
xFrameOptions?: string | false;
|
|
36
|
+
referrerPolicy?: string | false;
|
|
37
|
+
hsts?: string | false;
|
|
38
|
+
contentSecurityPolicy?: string | false;
|
|
39
|
+
[key: string]: unknown;
|
|
40
|
+
};
|
|
41
|
+
[key: string]: unknown;
|
|
42
|
+
}
|
|
43
|
+
export declare function securityHeaders(config?: SecurityConfig): Record<string, string>;
|
|
44
|
+
export interface CorsConfig {
|
|
45
|
+
cors?: {
|
|
46
|
+
origin: string | string[];
|
|
47
|
+
methods?: string;
|
|
48
|
+
headers?: string;
|
|
49
|
+
credentials?: boolean;
|
|
50
|
+
maxAge?: number;
|
|
51
|
+
};
|
|
52
|
+
[key: string]: unknown;
|
|
53
|
+
}
|
|
54
|
+
export declare function corsHeaders(security?: CorsConfig, requestOrigin?: string, host?: string): Record<string, string>;
|
|
55
|
+
export declare function corsPreflight(request: Record<string, unknown>, security?: CorsConfig): boolean;
|
|
56
|
+
export declare class CorsResponse extends Error {
|
|
57
|
+
status: number;
|
|
58
|
+
headers: Record<string, string>;
|
|
59
|
+
constructor(headers: Record<string, string>);
|
|
60
|
+
}
|
|
61
|
+
export declare function securityComment(config?: SecurityConfig): string;
|
|
62
|
+
export interface RateLimitOptions {
|
|
63
|
+
windowMs?: number;
|
|
64
|
+
max?: number;
|
|
65
|
+
cleanupIntervalMs?: number;
|
|
66
|
+
}
|
|
67
|
+
export declare function createRateLimiter(options?: RateLimitOptions): {
|
|
68
|
+
check: (key: string) => boolean;
|
|
69
|
+
remaining: (key: string) => number;
|
|
70
|
+
reset: (key: string) => void;
|
|
71
|
+
getConfig: () => {
|
|
72
|
+
windowMs: number;
|
|
73
|
+
max: number;
|
|
74
|
+
};
|
|
75
|
+
middleware: (request: Record<string, unknown>, response?: Record<string, unknown>) => boolean;
|
|
76
|
+
};
|
|
77
|
+
export declare function getClientIp(request: Record<string, unknown> | undefined, trustProxy?: boolean | string): string;
|
|
78
|
+
export declare function getClientProtocol(request: Record<string, unknown> | undefined, trustProxy?: boolean | string): string;
|
|
79
|
+
export declare function applyTrustProxy(ctx: Record<string, unknown>, trustProxy: boolean | string): void;
|
|
80
|
+
export declare function exprJS(raw: string): string;
|
|
81
|
+
export declare function indent(code: string, level?: number): string;
|
|
82
|
+
export declare function tryEvalExpr(raw: string, props: Record<string, unknown>, locals?: Record<string, unknown>): unknown;
|
|
83
|
+
export declare function childrenToHTML(nodes: IRNode[]): string;
|
|
84
|
+
export declare function extractTopLevelNames(topLevelCode: string[]): string[];
|
|
85
|
+
export declare function extractRuntimeNames(importStrs: string[]): string[];
|
|
86
|
+
export declare function buildParamInit(paramNames: string[]): string;
|
|
87
|
+
export declare function resolveComponentName(source: string): string | null;
|
|
88
|
+
export declare function setRuntimeModule(mod: Record<string, unknown>): void;
|
|
89
|
+
export declare function loadRuntimeImports(importStrs: string[]): Record<string, unknown>;
|
|
90
|
+
export declare function evalTopLevelCode(topLevelCode: string[], __vesk: Record<string, unknown>): void;
|
|
91
|
+
export declare function callStaticProps(fnSource: string): Promise<unknown>;
|
|
92
|
+
export declare function callLoadFunction(fnSource: string, currentProps: Record<string, unknown>, __vesk: Record<string, unknown>): Promise<unknown>;
|
|
93
|
+
//# sourceMappingURL=server-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-utils.d.ts","sourceRoot":"","sources":["../src/server-utils.ts"],"names":[],"mappings":"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"}
|