@vertz/ui-server 0.2.31 → 0.2.32
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/bun-dev-server.js +47 -2
- package/dist/index.d.ts +301 -233
- package/dist/index.js +79 -149
- package/dist/node-handler.d.ts +76 -23
- package/dist/shared/chunk-gbcsa7h1.js +471 -0
- package/dist/ssr/index.d.ts +119 -57
- package/dist/ssr/index.js +4 -3
- package/package.json +1 -1
- package/dist/shared/chunk-wb5fv233.js +0 -216
package/dist/index.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
createHoles,
|
|
3
|
+
createSSRHandler,
|
|
4
|
+
isAotDebugEnabled,
|
|
5
|
+
loadAotManifest,
|
|
6
|
+
ssrRenderAot
|
|
7
|
+
} from "./shared/chunk-gbcsa7h1.js";
|
|
4
8
|
import {
|
|
5
9
|
createNodeHandler
|
|
6
10
|
} from "./shared/chunk-es0406qq.js";
|
|
@@ -37,21 +41,23 @@ import {
|
|
|
37
41
|
getGlobalSSRTimeout,
|
|
38
42
|
getSSRQueries,
|
|
39
43
|
getSSRUrl,
|
|
40
|
-
installDomShim,
|
|
41
44
|
isInSSR,
|
|
42
45
|
rawHtml,
|
|
43
46
|
registerSSRQuery,
|
|
44
47
|
setGlobalSSRTimeout,
|
|
45
|
-
ssrStorage
|
|
46
|
-
toVNode
|
|
48
|
+
ssrStorage
|
|
47
49
|
} from "./shared/chunk-ybftdw1r.js";
|
|
48
50
|
|
|
51
|
+
// src/index.ts
|
|
52
|
+
import { extractRoutes } from "@vertz/ui-compiler";
|
|
53
|
+
|
|
49
54
|
// src/aot-manifest-build.ts
|
|
50
55
|
import { readdirSync, readFileSync } from "node:fs";
|
|
51
|
-
import { join } from "node:path";
|
|
56
|
+
import { basename, join } from "node:path";
|
|
52
57
|
import { compileForSSRAot } from "@vertz/ui-compiler";
|
|
53
58
|
function generateAotBuildManifest(srcDir) {
|
|
54
59
|
const components = {};
|
|
60
|
+
const compiledFiles = {};
|
|
55
61
|
const classificationLog = [];
|
|
56
62
|
const tsxFiles = collectTsxFiles(srcDir);
|
|
57
63
|
for (const filePath of tsxFiles) {
|
|
@@ -61,7 +67,14 @@ function generateAotBuildManifest(srcDir) {
|
|
|
61
67
|
for (const comp of result.components) {
|
|
62
68
|
components[comp.name] = {
|
|
63
69
|
tier: comp.tier,
|
|
64
|
-
holes: comp.holes
|
|
70
|
+
holes: comp.holes,
|
|
71
|
+
queryKeys: comp.queryKeys
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
if (result.components.length > 0) {
|
|
75
|
+
compiledFiles[filePath] = {
|
|
76
|
+
code: result.code,
|
|
77
|
+
components: result.components
|
|
65
78
|
};
|
|
66
79
|
}
|
|
67
80
|
} catch (e) {
|
|
@@ -88,7 +101,61 @@ function generateAotBuildManifest(srcDir) {
|
|
|
88
101
|
const pct = Math.round(aotCount / total * 100);
|
|
89
102
|
classificationLog.push(`Coverage: ${aotCount}/${total} components (${pct}%)`);
|
|
90
103
|
}
|
|
91
|
-
return { components, classificationLog };
|
|
104
|
+
return { components, compiledFiles, classificationLog };
|
|
105
|
+
}
|
|
106
|
+
function buildAotRouteMap(components, routes) {
|
|
107
|
+
const routeMap = {};
|
|
108
|
+
for (const route of routes) {
|
|
109
|
+
const comp = components[route.componentName];
|
|
110
|
+
if (!comp || comp.tier === "runtime-fallback")
|
|
111
|
+
continue;
|
|
112
|
+
routeMap[route.pattern] = {
|
|
113
|
+
renderFn: `__ssr_${route.componentName}`,
|
|
114
|
+
holes: comp.holes,
|
|
115
|
+
queryKeys: comp.queryKeys
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
return routeMap;
|
|
119
|
+
}
|
|
120
|
+
function generateAotBarrel(compiledFiles, routeMap) {
|
|
121
|
+
const neededFns = new Set;
|
|
122
|
+
for (const entry of Object.values(routeMap)) {
|
|
123
|
+
neededFns.add(entry.renderFn);
|
|
124
|
+
}
|
|
125
|
+
const fnToFile = new Map;
|
|
126
|
+
for (const [filePath, compiled] of Object.entries(compiledFiles)) {
|
|
127
|
+
for (const comp of compiled.components) {
|
|
128
|
+
const fnName = `__ssr_${comp.name}`;
|
|
129
|
+
if (neededFns.has(fnName)) {
|
|
130
|
+
fnToFile.set(fnName, filePath);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const fileToFns = new Map;
|
|
135
|
+
for (const [fnName, filePath] of fnToFile) {
|
|
136
|
+
const existing = fileToFns.get(filePath) ?? [];
|
|
137
|
+
existing.push(fnName);
|
|
138
|
+
fileToFns.set(filePath, existing);
|
|
139
|
+
}
|
|
140
|
+
const lines = [];
|
|
141
|
+
const files = {};
|
|
142
|
+
let fileIndex = 0;
|
|
143
|
+
for (const [filePath, fns] of fileToFns) {
|
|
144
|
+
const moduleName = basename(filePath, ".tsx").replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
145
|
+
const tempFileName = `__aot_${fileIndex}_${moduleName}`;
|
|
146
|
+
const moduleRef = `./${tempFileName}`;
|
|
147
|
+
lines.push(`export { ${fns.sort().join(", ")} } from '${moduleRef}';`);
|
|
148
|
+
const compiled = compiledFiles[filePath];
|
|
149
|
+
if (compiled) {
|
|
150
|
+
files[`${tempFileName}.tsx`] = compiled.code;
|
|
151
|
+
}
|
|
152
|
+
fileIndex++;
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
barrelSource: lines.join(`
|
|
156
|
+
`),
|
|
157
|
+
files
|
|
158
|
+
};
|
|
92
159
|
}
|
|
93
160
|
function collectTsxFiles(dir) {
|
|
94
161
|
const files = [];
|
|
@@ -670,147 +737,6 @@ function createAotManifestManager(options) {
|
|
|
670
737
|
}
|
|
671
738
|
};
|
|
672
739
|
}
|
|
673
|
-
// src/ssr-aot-pipeline.ts
|
|
674
|
-
function createHoles(holeNames, module, url, queryCache, ssrAuth) {
|
|
675
|
-
if (holeNames.length === 0)
|
|
676
|
-
return {};
|
|
677
|
-
const holes = {};
|
|
678
|
-
for (const name of holeNames) {
|
|
679
|
-
holes[name] = () => {
|
|
680
|
-
const holeCtx = createRequestContext(url);
|
|
681
|
-
for (const [key, data] of queryCache) {
|
|
682
|
-
holeCtx.queryCache.set(key, data);
|
|
683
|
-
}
|
|
684
|
-
if (ssrAuth) {
|
|
685
|
-
holeCtx.ssrAuth = ssrAuth;
|
|
686
|
-
}
|
|
687
|
-
holeCtx.resolvedComponents = new Map;
|
|
688
|
-
return ssrStorage.run(holeCtx, () => {
|
|
689
|
-
ensureDomShim();
|
|
690
|
-
const factory = resolveHoleComponent(module, name);
|
|
691
|
-
if (!factory) {
|
|
692
|
-
return `<!-- AOT hole: ${name} not found -->`;
|
|
693
|
-
}
|
|
694
|
-
const node = factory();
|
|
695
|
-
const vnode = toVNode(node);
|
|
696
|
-
return serializeToHtml(vnode);
|
|
697
|
-
});
|
|
698
|
-
};
|
|
699
|
-
}
|
|
700
|
-
return holes;
|
|
701
|
-
}
|
|
702
|
-
function resolveHoleComponent(module, name) {
|
|
703
|
-
const moduleRecord = module;
|
|
704
|
-
const exported = moduleRecord[name];
|
|
705
|
-
if (typeof exported === "function") {
|
|
706
|
-
return exported;
|
|
707
|
-
}
|
|
708
|
-
return;
|
|
709
|
-
}
|
|
710
|
-
async function ssrRenderAot(module, url, options) {
|
|
711
|
-
const { aotManifest, manifest } = options;
|
|
712
|
-
const ssrTimeout = options.ssrTimeout ?? 300;
|
|
713
|
-
const normalizedUrl = url.endsWith("/index.html") ? url.slice(0, -"/index.html".length) || "/" : url;
|
|
714
|
-
const fallbackOptions = {
|
|
715
|
-
ssrTimeout,
|
|
716
|
-
fallbackMetrics: options.fallbackMetrics,
|
|
717
|
-
ssrAuth: options.ssrAuth,
|
|
718
|
-
manifest,
|
|
719
|
-
prefetchSession: options.prefetchSession
|
|
720
|
-
};
|
|
721
|
-
const aotPatterns = Object.keys(aotManifest.routes);
|
|
722
|
-
const matches = matchUrlToPatterns(normalizedUrl, aotPatterns);
|
|
723
|
-
if (matches.length === 0) {
|
|
724
|
-
return ssrRenderSinglePass(module, normalizedUrl, fallbackOptions);
|
|
725
|
-
}
|
|
726
|
-
const match = matches[matches.length - 1];
|
|
727
|
-
if (!match) {
|
|
728
|
-
return ssrRenderSinglePass(module, normalizedUrl, fallbackOptions);
|
|
729
|
-
}
|
|
730
|
-
const aotEntry = aotManifest.routes[match.pattern];
|
|
731
|
-
if (!aotEntry) {
|
|
732
|
-
return ssrRenderSinglePass(module, normalizedUrl, fallbackOptions);
|
|
733
|
-
}
|
|
734
|
-
const queryCache = new Map;
|
|
735
|
-
try {
|
|
736
|
-
setGlobalSSRTimeout(ssrTimeout);
|
|
737
|
-
const holes = createHoles(aotEntry.holes, module, normalizedUrl, queryCache, options.ssrAuth);
|
|
738
|
-
const ctx = {
|
|
739
|
-
holes,
|
|
740
|
-
getData: (key) => queryCache.get(key),
|
|
741
|
-
session: options.prefetchSession,
|
|
742
|
-
params: match.params
|
|
743
|
-
};
|
|
744
|
-
const data = {};
|
|
745
|
-
for (const [key, value] of queryCache) {
|
|
746
|
-
data[key] = value;
|
|
747
|
-
}
|
|
748
|
-
const html = aotEntry.render(data, ctx);
|
|
749
|
-
if (options.diagnostics && isAotDebugEnabled()) {
|
|
750
|
-
try {
|
|
751
|
-
const domResult = await ssrRenderSinglePass(module, normalizedUrl, fallbackOptions);
|
|
752
|
-
if (domResult.html !== html) {
|
|
753
|
-
options.diagnostics.recordDivergence(match.pattern, html, domResult.html);
|
|
754
|
-
}
|
|
755
|
-
} catch {}
|
|
756
|
-
}
|
|
757
|
-
const css = collectCSSFromModule(module, options.fallbackMetrics);
|
|
758
|
-
const ssrData = [];
|
|
759
|
-
for (const [key, data2] of queryCache) {
|
|
760
|
-
ssrData.push({ key, data: data2 });
|
|
761
|
-
}
|
|
762
|
-
return {
|
|
763
|
-
html,
|
|
764
|
-
css: css.cssString,
|
|
765
|
-
ssrData,
|
|
766
|
-
headTags: css.preloadTags
|
|
767
|
-
};
|
|
768
|
-
} finally {
|
|
769
|
-
clearGlobalSSRTimeout();
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
function isAotDebugEnabled() {
|
|
773
|
-
const env = process.env.VERTZ_DEBUG;
|
|
774
|
-
if (!env)
|
|
775
|
-
return false;
|
|
776
|
-
return env === "1" || env.split(",").includes("aot");
|
|
777
|
-
}
|
|
778
|
-
var domShimInstalled = false;
|
|
779
|
-
function ensureDomShim() {
|
|
780
|
-
if (domShimInstalled && typeof document !== "undefined")
|
|
781
|
-
return;
|
|
782
|
-
domShimInstalled = true;
|
|
783
|
-
installDomShim();
|
|
784
|
-
}
|
|
785
|
-
function collectCSSFromModule(module, fallbackMetrics) {
|
|
786
|
-
let themeCss = "";
|
|
787
|
-
let preloadTags = "";
|
|
788
|
-
if (module.theme) {
|
|
789
|
-
try {
|
|
790
|
-
const compiled = compileThemeCached(module.theme, fallbackMetrics);
|
|
791
|
-
themeCss = compiled.css;
|
|
792
|
-
preloadTags = compiled.preloadTags;
|
|
793
|
-
} catch (e) {
|
|
794
|
-
console.error("[vertz] Failed to compile theme export. Ensure your theme is created with defineTheme().", e);
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
const alreadyIncluded = new Set;
|
|
798
|
-
if (themeCss)
|
|
799
|
-
alreadyIncluded.add(themeCss);
|
|
800
|
-
if (module.styles) {
|
|
801
|
-
for (const s of module.styles)
|
|
802
|
-
alreadyIncluded.add(s);
|
|
803
|
-
}
|
|
804
|
-
const componentCss = module.getInjectedCSS ? module.getInjectedCSS().filter((s) => !alreadyIncluded.has(s)) : [];
|
|
805
|
-
const themeTag = themeCss ? `<style data-vertz-css>${themeCss}</style>` : "";
|
|
806
|
-
const globalTag = module.styles && module.styles.length > 0 ? `<style data-vertz-css>${module.styles.join(`
|
|
807
|
-
`)}</style>` : "";
|
|
808
|
-
const componentTag = componentCss.length > 0 ? `<style data-vertz-css>${componentCss.join(`
|
|
809
|
-
`)}</style>` : "";
|
|
810
|
-
const cssString = [themeTag, globalTag, componentTag].filter(Boolean).join(`
|
|
811
|
-
`);
|
|
812
|
-
return { cssString, preloadTags };
|
|
813
|
-
}
|
|
814
740
|
// src/ssr-aot-runtime.ts
|
|
815
741
|
var UNITLESS_PROPERTIES = new Set([
|
|
816
742
|
"animationIterationCount",
|
|
@@ -1094,6 +1020,7 @@ export {
|
|
|
1094
1020
|
reconstructDescriptors,
|
|
1095
1021
|
rawHtml,
|
|
1096
1022
|
matchUrlToPatterns,
|
|
1023
|
+
loadAotManifest,
|
|
1097
1024
|
isInSSR,
|
|
1098
1025
|
isAotDebugEnabled,
|
|
1099
1026
|
inlineCriticalCss,
|
|
@@ -1104,6 +1031,8 @@ export {
|
|
|
1104
1031
|
getAccessSetForSSR,
|
|
1105
1032
|
generateSSRHtml,
|
|
1106
1033
|
generateAotBuildManifest,
|
|
1034
|
+
generateAotBarrel,
|
|
1035
|
+
extractRoutes,
|
|
1107
1036
|
extractFontMetrics,
|
|
1108
1037
|
evaluateAccessRule,
|
|
1109
1038
|
encodeChunk,
|
|
@@ -1121,6 +1050,7 @@ export {
|
|
|
1121
1050
|
createAccessSetScript,
|
|
1122
1051
|
collectStreamChunks,
|
|
1123
1052
|
clearGlobalSSRTimeout,
|
|
1053
|
+
buildAotRouteMap,
|
|
1124
1054
|
__ssr_style_object,
|
|
1125
1055
|
__ssr_spread,
|
|
1126
1056
|
__esc_attr,
|
package/dist/node-handler.d.ts
CHANGED
|
@@ -1,26 +1,5 @@
|
|
|
1
1
|
import { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
-
import { FontFallbackMetrics as
|
|
3
|
-
import { CompiledRoute, Theme } from "@vertz/ui";
|
|
4
|
-
interface SSRModule {
|
|
5
|
-
default?: () => unknown;
|
|
6
|
-
App?: () => unknown;
|
|
7
|
-
theme?: Theme;
|
|
8
|
-
/** Global CSS strings to include in every SSR response (e.g. resets, body styles). */
|
|
9
|
-
styles?: string[];
|
|
10
|
-
/**
|
|
11
|
-
* Return all CSS tracked by the bundled @vertz/ui instance.
|
|
12
|
-
* The Vite SSR build inlines @vertz/ui into the server bundle, creating
|
|
13
|
-
* a separate module instance from @vertz/ui-server's dependency. Without
|
|
14
|
-
* this, component CSS from module-level css() calls is invisible to the
|
|
15
|
-
* SSR renderer. Export `getInjectedCSS` from @vertz/ui in the app entry.
|
|
16
|
-
*/
|
|
17
|
-
getInjectedCSS?: () => string[];
|
|
18
|
-
/** Compiled routes exported from the app for build-time SSG with generateParams. */
|
|
19
|
-
routes?: CompiledRoute[];
|
|
20
|
-
/** Code-generated API client for manifest-driven zero-discovery prefetching. */
|
|
21
|
-
api?: Record<string, Record<string, (...args: unknown[]) => unknown>>;
|
|
22
|
-
}
|
|
23
|
-
import { ExtractedQuery } from "@vertz/ui-compiler";
|
|
2
|
+
import { FontFallbackMetrics as FontFallbackMetrics4 } from "@vertz/ui";
|
|
24
3
|
/**
|
|
25
4
|
* SSR prefetch access rule evaluator.
|
|
26
5
|
*
|
|
@@ -60,6 +39,39 @@ type SerializedAccessRule = {
|
|
|
60
39
|
} | {
|
|
61
40
|
type: "deny";
|
|
62
41
|
};
|
|
42
|
+
/**
|
|
43
|
+
* Minimal session shape needed for prefetch access evaluation.
|
|
44
|
+
* Extracted from the JWT at SSR request time.
|
|
45
|
+
*/
|
|
46
|
+
type PrefetchSession = {
|
|
47
|
+
status: "authenticated";
|
|
48
|
+
roles?: string[];
|
|
49
|
+
entitlements?: Record<string, boolean>;
|
|
50
|
+
tenantId?: string;
|
|
51
|
+
} | {
|
|
52
|
+
status: "unauthenticated";
|
|
53
|
+
};
|
|
54
|
+
import { CompiledRoute, Theme } from "@vertz/ui";
|
|
55
|
+
interface SSRModule {
|
|
56
|
+
default?: () => unknown;
|
|
57
|
+
App?: () => unknown;
|
|
58
|
+
theme?: Theme;
|
|
59
|
+
/** Global CSS strings to include in every SSR response (e.g. resets, body styles). */
|
|
60
|
+
styles?: string[];
|
|
61
|
+
/**
|
|
62
|
+
* Return all CSS tracked by the bundled @vertz/ui instance.
|
|
63
|
+
* The Vite SSR build inlines @vertz/ui into the server bundle, creating
|
|
64
|
+
* a separate module instance from @vertz/ui-server's dependency. Without
|
|
65
|
+
* this, component CSS from module-level css() calls is invisible to the
|
|
66
|
+
* SSR renderer. Export `getInjectedCSS` from @vertz/ui in the app entry.
|
|
67
|
+
*/
|
|
68
|
+
getInjectedCSS?: () => string[];
|
|
69
|
+
/** Compiled routes exported from the app for build-time SSG with generateParams. */
|
|
70
|
+
routes?: CompiledRoute[];
|
|
71
|
+
/** Code-generated API client for manifest-driven zero-discovery prefetching. */
|
|
72
|
+
api?: Record<string, Record<string, (...args: unknown[]) => unknown>>;
|
|
73
|
+
}
|
|
74
|
+
import { ExtractedQuery } from "@vertz/ui-compiler";
|
|
63
75
|
/** Serialized entity access rules from the prefetch manifest. */
|
|
64
76
|
type EntityAccessMap = Record<string, Partial<Record<string, SerializedAccessRule>>>;
|
|
65
77
|
interface SSRPrefetchManifest {
|
|
@@ -72,6 +84,37 @@ interface SSRPrefetchManifest {
|
|
|
72
84
|
queries: ExtractedQuery[];
|
|
73
85
|
}>;
|
|
74
86
|
}
|
|
87
|
+
/** Context passed to AOT render functions for accessing data and runtime holes. */
|
|
88
|
+
interface SSRAotContext {
|
|
89
|
+
/** Pre-generated closures for runtime-rendered components. */
|
|
90
|
+
holes: Record<string, () => string>;
|
|
91
|
+
/** Access query data by cache key. */
|
|
92
|
+
getData(key: string): unknown;
|
|
93
|
+
/** Auth session for conditional rendering. */
|
|
94
|
+
session: PrefetchSession | undefined;
|
|
95
|
+
/** Route params for the current request. */
|
|
96
|
+
params: Record<string, string>;
|
|
97
|
+
}
|
|
98
|
+
/** An AOT render function: takes props/data and context, returns HTML string. */
|
|
99
|
+
type AotRenderFn = (data: Record<string, unknown>, ctx: SSRAotContext) => string;
|
|
100
|
+
/** Per-route AOT entry in the manifest. */
|
|
101
|
+
interface AotRouteEntry {
|
|
102
|
+
/** The pre-compiled render function. */
|
|
103
|
+
render: AotRenderFn;
|
|
104
|
+
/** Component names that need runtime fallback (holes). */
|
|
105
|
+
holes: string[];
|
|
106
|
+
/** Query cache keys this route reads via ctx.getData(). */
|
|
107
|
+
queryKeys?: string[];
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* AOT manifest — maps route patterns to pre-compiled render functions.
|
|
111
|
+
*
|
|
112
|
+
* Generated at build time by the AOT compiler pipeline.
|
|
113
|
+
*/
|
|
114
|
+
interface AotManifest {
|
|
115
|
+
/** Route pattern → AOT entry. */
|
|
116
|
+
routes: Record<string, AotRouteEntry>;
|
|
117
|
+
}
|
|
75
118
|
import { AccessSet } from "@vertz/ui/auth";
|
|
76
119
|
interface SessionData {
|
|
77
120
|
user: {
|
|
@@ -125,7 +168,7 @@ interface SSRHandlerOptions {
|
|
|
125
168
|
*/
|
|
126
169
|
nonce?: string;
|
|
127
170
|
/** Pre-computed font fallback metrics (computed at server startup). */
|
|
128
|
-
fallbackMetrics?: Record<string,
|
|
171
|
+
fallbackMetrics?: Record<string, FontFallbackMetrics4>;
|
|
129
172
|
/** Paths to inject as `<link rel="modulepreload">` in `<head>`. */
|
|
130
173
|
modulepreload?: string[];
|
|
131
174
|
/**
|
|
@@ -164,6 +207,16 @@ interface SSRHandlerOptions {
|
|
|
164
207
|
* which always use buffered rendering.
|
|
165
208
|
*/
|
|
166
209
|
progressiveHTML?: boolean;
|
|
210
|
+
/**
|
|
211
|
+
* AOT manifest with pre-compiled render functions.
|
|
212
|
+
*
|
|
213
|
+
* When provided, routes matching AOT entries are rendered via string-builder
|
|
214
|
+
* functions (no DOM shim), bypassing the reactive runtime for 4-6x speedup.
|
|
215
|
+
* Routes not in the manifest fall back to `ssrRenderSinglePass()`.
|
|
216
|
+
*
|
|
217
|
+
* Load via `loadAotManifest(serverDir)` at startup.
|
|
218
|
+
*/
|
|
219
|
+
aotManifest?: AotManifest;
|
|
167
220
|
}
|
|
168
221
|
type NodeHandlerOptions = SSRHandlerOptions;
|
|
169
222
|
declare function createNodeHandler(options: NodeHandlerOptions): (req: IncomingMessage, res: ServerResponse) => void;
|