@zenithbuild/cli 0.7.3 → 0.7.5
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 +18 -13
- package/dist/adapters/adapter-netlify.d.ts +1 -1
- package/dist/adapters/adapter-netlify.js +56 -13
- package/dist/adapters/adapter-node.js +8 -0
- package/dist/adapters/adapter-static-export.d.ts +5 -0
- package/dist/adapters/adapter-static-export.js +115 -0
- package/dist/adapters/adapter-types.d.ts +3 -1
- package/dist/adapters/adapter-types.js +5 -2
- package/dist/adapters/adapter-vercel.d.ts +1 -1
- package/dist/adapters/adapter-vercel.js +70 -13
- package/dist/adapters/copy-hosted-page-runtime.d.ts +1 -0
- package/dist/adapters/copy-hosted-page-runtime.js +49 -0
- package/dist/adapters/resolve-adapter.js +4 -0
- package/dist/adapters/route-rules.d.ts +5 -0
- package/dist/adapters/route-rules.js +9 -0
- package/dist/adapters/validate-hosted-resource-routes.d.ts +1 -0
- package/dist/adapters/validate-hosted-resource-routes.js +13 -0
- package/dist/auth/route-auth.d.ts +6 -0
- package/dist/auth/route-auth.js +236 -0
- package/dist/build/compiler-runtime.d.ts +10 -9
- package/dist/build/compiler-runtime.js +58 -2
- package/dist/build/compiler-signal-expression.d.ts +1 -0
- package/dist/build/compiler-signal-expression.js +155 -0
- package/dist/build/expression-rewrites.d.ts +1 -6
- package/dist/build/expression-rewrites.js +61 -65
- package/dist/build/page-component-loop.d.ts +3 -13
- package/dist/build/page-component-loop.js +21 -46
- package/dist/build/page-ir-normalization.d.ts +0 -8
- package/dist/build/page-ir-normalization.js +13 -234
- package/dist/build/page-loop-state.d.ts +6 -9
- package/dist/build/page-loop-state.js +9 -8
- package/dist/build/page-loop.js +27 -22
- package/dist/build/scoped-identifier-rewrite.d.ts +37 -44
- package/dist/build/scoped-identifier-rewrite.js +28 -128
- package/dist/build/server-script.d.ts +3 -1
- package/dist/build/server-script.js +35 -5
- package/dist/build-output-manifest.d.ts +3 -2
- package/dist/build-output-manifest.js +3 -0
- package/dist/build.js +32 -18
- package/dist/component-instance-ir.js +158 -52
- package/dist/dev-build-session.js +20 -6
- package/dist/dev-server.js +152 -55
- package/dist/download-result.d.ts +14 -0
- package/dist/download-result.js +148 -0
- package/dist/framework-components/Image.zen +1 -1
- package/dist/images/materialization-plan.d.ts +1 -0
- package/dist/images/materialization-plan.js +6 -0
- package/dist/images/materialize.d.ts +5 -3
- package/dist/images/materialize.js +24 -109
- package/dist/images/router-manifest.d.ts +1 -0
- package/dist/images/router-manifest.js +49 -0
- package/dist/images/service.d.ts +13 -1
- package/dist/images/service.js +45 -15
- package/dist/index.js +8 -2
- package/dist/manifest.d.ts +15 -1
- package/dist/manifest.js +27 -7
- package/dist/preview.d.ts +13 -4
- package/dist/preview.js +261 -101
- package/dist/request-body.d.ts +1 -0
- package/dist/request-body.js +7 -0
- package/dist/request-origin.d.ts +2 -0
- package/dist/request-origin.js +45 -0
- package/dist/resource-manifest.d.ts +16 -0
- package/dist/resource-manifest.js +53 -0
- package/dist/resource-response.d.ts +34 -0
- package/dist/resource-response.js +71 -0
- package/dist/resource-route-module.d.ts +15 -0
- package/dist/resource-route-module.js +129 -0
- package/dist/route-check-support.d.ts +1 -0
- package/dist/route-check-support.js +4 -0
- package/dist/server-contract.d.ts +29 -6
- package/dist/server-contract.js +304 -42
- package/dist/server-error.d.ts +4 -0
- package/dist/server-error.js +36 -0
- package/dist/server-output.d.ts +4 -1
- package/dist/server-output.js +71 -10
- package/dist/server-runtime/node-server.js +67 -31
- package/dist/server-runtime/route-render.d.ts +27 -3
- package/dist/server-runtime/route-render.js +94 -53
- package/dist/server-script-composition.d.ts +13 -5
- package/dist/server-script-composition.js +29 -11
- package/dist/static-export-paths.d.ts +3 -0
- package/dist/static-export-paths.js +160 -0
- package/package.json +6 -3
package/dist/server-output.js
CHANGED
|
@@ -3,6 +3,7 @@ import { cp, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
|
3
3
|
import { createRequire } from 'node:module';
|
|
4
4
|
import { basename, dirname, extname, join, relative, resolve } from 'node:path';
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
6
|
+
import { loadResourceRouteManifest } from './resource-manifest.js';
|
|
6
7
|
const PACKAGE_REQUIRE = createRequire(import.meta.url);
|
|
7
8
|
const RELATIVE_SPECIFIER_RE = /((?:import|export)\s+(?:[^'"]*?\s+from\s+)?|import\s*\()\s*(['"])([^'"]+)\2/g;
|
|
8
9
|
const SERVER_RUNTIME_FILES = [
|
|
@@ -14,6 +15,10 @@ const SERVER_RUNTIME_FILES = [
|
|
|
14
15
|
from: new URL('./server-contract.js', import.meta.url),
|
|
15
16
|
to: 'server-contract.js'
|
|
16
17
|
},
|
|
18
|
+
{
|
|
19
|
+
from: new URL('./auth/route-auth.js', import.meta.url),
|
|
20
|
+
to: 'auth/route-auth.js'
|
|
21
|
+
},
|
|
17
22
|
{
|
|
18
23
|
from: new URL('./base-path.js', import.meta.url),
|
|
19
24
|
to: 'base-path.js'
|
|
@@ -29,8 +34,32 @@ const SERVER_RUNTIME_FILES = [
|
|
|
29
34
|
{
|
|
30
35
|
from: new URL('./images/shared.js', import.meta.url),
|
|
31
36
|
to: 'images/shared.js'
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
from: new URL('./images/runtime.js', import.meta.url),
|
|
40
|
+
to: 'images/runtime.js'
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
from: new URL('./images/service.js', import.meta.url),
|
|
44
|
+
to: 'images/service.js'
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
from: new URL('./server-error.js', import.meta.url),
|
|
48
|
+
to: 'server-error.js'
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
from: new URL('./resource-response.js', import.meta.url),
|
|
52
|
+
to: 'resource-response.js'
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
from: new URL('./download-result.js', import.meta.url),
|
|
56
|
+
to: 'download-result.js'
|
|
32
57
|
}
|
|
33
58
|
];
|
|
59
|
+
const SPECIAL_SERVER_SPECIFIERS = new Map([
|
|
60
|
+
['zenith:server-contract', 'server-contract.js'],
|
|
61
|
+
['zenith:route-auth', 'auth/route-auth.js']
|
|
62
|
+
]);
|
|
34
63
|
function normalizeRouteName(routePath) {
|
|
35
64
|
if (routePath === '/') {
|
|
36
65
|
return 'index';
|
|
@@ -144,7 +173,7 @@ function outputPathForSource(projectRoot, modulesRoot, sourcePath) {
|
|
|
144
173
|
: relativePath.replace(/\.(tsx|ts|mts|cts|jsx|js|mjs|cjs)$/i, '.js');
|
|
145
174
|
return join(modulesRoot, nextRelative);
|
|
146
175
|
}
|
|
147
|
-
async function compileImportedModule({ projectRoot, modulesRoot, sourcePath, ts, seen }) {
|
|
176
|
+
async function compileImportedModule({ projectRoot, modulesRoot, serverDir, sourcePath, ts, seen }) {
|
|
148
177
|
if (seen.has(sourcePath)) {
|
|
149
178
|
return outputPathForSource(projectRoot, modulesRoot, sourcePath);
|
|
150
179
|
}
|
|
@@ -158,6 +187,12 @@ async function compileImportedModule({ projectRoot, modulesRoot, sourcePath, ts,
|
|
|
158
187
|
const source = await readFile(sourcePath, 'utf8');
|
|
159
188
|
let output = transpileSource(ts, source, sourcePath);
|
|
160
189
|
for (const specifier of gatherSpecifiers(output)) {
|
|
190
|
+
const specialSpecifierPath = SPECIAL_SERVER_SPECIFIERS.get(specifier);
|
|
191
|
+
if (specialSpecifierPath) {
|
|
192
|
+
const nextSpecifier = relative(dirname(outPath), join(serverDir, specialSpecifierPath)).replaceAll('\\', '/');
|
|
193
|
+
output = replaceSpecifier(output, specifier, nextSpecifier.startsWith('.') ? nextSpecifier : `./${nextSpecifier}`);
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
161
196
|
if (!isRelativeSpecifier(specifier)) {
|
|
162
197
|
continue;
|
|
163
198
|
}
|
|
@@ -168,6 +203,7 @@ async function compileImportedModule({ projectRoot, modulesRoot, sourcePath, ts,
|
|
|
168
203
|
const compiledDependencyPath = await compileImportedModule({
|
|
169
204
|
projectRoot,
|
|
170
205
|
modulesRoot,
|
|
206
|
+
serverDir,
|
|
171
207
|
sourcePath: resolvedPath,
|
|
172
208
|
ts,
|
|
173
209
|
seen
|
|
@@ -178,12 +214,18 @@ async function compileImportedModule({ projectRoot, modulesRoot, sourcePath, ts,
|
|
|
178
214
|
await writeFile(outPath, output, 'utf8');
|
|
179
215
|
return outPath;
|
|
180
216
|
}
|
|
181
|
-
async function writeRouteModulePackage({ projectRoot, routeDir, route }) {
|
|
217
|
+
async function writeRouteModulePackage({ projectRoot, serverDir, routeDir, route }) {
|
|
182
218
|
const ts = resolveTypeScriptApi(projectRoot);
|
|
183
219
|
const modulesRoot = join(routeDir, 'modules');
|
|
184
220
|
const seen = new Set();
|
|
185
221
|
let entryOutput = transpileSource(ts, route.server_script || '', route.server_script_path || 'route-entry.ts');
|
|
186
222
|
for (const specifier of gatherSpecifiers(entryOutput)) {
|
|
223
|
+
const specialSpecifierPath = SPECIAL_SERVER_SPECIFIERS.get(specifier);
|
|
224
|
+
if (specialSpecifierPath) {
|
|
225
|
+
const nextSpecifier = relative(join(routeDir, 'route'), join(serverDir, specialSpecifierPath)).replaceAll('\\', '/');
|
|
226
|
+
entryOutput = replaceSpecifier(entryOutput, specifier, nextSpecifier.startsWith('.') ? nextSpecifier : `./${nextSpecifier}`);
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
187
229
|
if (!isRelativeSpecifier(specifier)) {
|
|
188
230
|
continue;
|
|
189
231
|
}
|
|
@@ -194,6 +236,7 @@ async function writeRouteModulePackage({ projectRoot, routeDir, route }) {
|
|
|
194
236
|
const compiledDependencyPath = await compileImportedModule({
|
|
195
237
|
projectRoot,
|
|
196
238
|
modulesRoot,
|
|
239
|
+
serverDir,
|
|
197
240
|
sourcePath: resolvedPath,
|
|
198
241
|
ts,
|
|
199
242
|
seen
|
|
@@ -230,8 +273,15 @@ export async function writeServerOutput({ coreOutputDir, staticDir, projectRoot,
|
|
|
230
273
|
catch {
|
|
231
274
|
routerManifest = { routes: [] };
|
|
232
275
|
}
|
|
233
|
-
const
|
|
234
|
-
const
|
|
276
|
+
const resourceManifest = await loadResourceRouteManifest(staticDir, basePath);
|
|
277
|
+
const pageRoutes = Array.isArray(routerManifest.routes) ? routerManifest.routes : [];
|
|
278
|
+
const serverRoutes = pageRoutes
|
|
279
|
+
.filter((route) => route.server_script && route.prerender !== true)
|
|
280
|
+
.map((route) => ({ ...route, route_kind: 'page' }))
|
|
281
|
+
.concat((Array.isArray(resourceManifest.routes) ? resourceManifest.routes : []).map((route) => ({
|
|
282
|
+
...route,
|
|
283
|
+
route_kind: 'resource'
|
|
284
|
+
})));
|
|
235
285
|
await mkdir(serverDir, { recursive: true });
|
|
236
286
|
await copyRuntimeFiles(serverDir);
|
|
237
287
|
const imageManifestSource = join(staticDir, '_zenith', 'image', 'manifest.json');
|
|
@@ -240,8 +290,10 @@ export async function writeServerOutput({ coreOutputDir, staticDir, projectRoot,
|
|
|
240
290
|
const name = normalizeRouteName(route.path);
|
|
241
291
|
const routeDir = join(serverDir, 'routes', name);
|
|
242
292
|
await mkdir(routeDir, { recursive: true });
|
|
243
|
-
|
|
244
|
-
|
|
293
|
+
if (route.route_kind !== 'resource') {
|
|
294
|
+
const htmlSourcePath = join(staticDir, String(route.output || '').replace(/^\//, ''));
|
|
295
|
+
await copyOptionalFile(htmlSourcePath, join(routeDir, 'route', 'page.html'));
|
|
296
|
+
}
|
|
245
297
|
let pageAssetFile = null;
|
|
246
298
|
if (typeof route.page_asset === 'string' && route.page_asset.length > 0) {
|
|
247
299
|
const assetSourcePath = join(staticDir, route.page_asset.replace(/^\//, ''));
|
|
@@ -251,18 +303,20 @@ export async function writeServerOutput({ coreOutputDir, staticDir, projectRoot,
|
|
|
251
303
|
}
|
|
252
304
|
}
|
|
253
305
|
let imageManifestFile = null;
|
|
254
|
-
if (await copyOptionalFile(imageManifestSource, join(routeDir, 'route', 'image-manifest.json'))) {
|
|
306
|
+
if (route.route_kind !== 'resource' && await copyOptionalFile(imageManifestSource, join(routeDir, 'route', 'image-manifest.json'))) {
|
|
255
307
|
imageManifestFile = 'image-manifest.json';
|
|
256
308
|
}
|
|
257
309
|
await writeRouteModulePackage({
|
|
258
310
|
projectRoot,
|
|
311
|
+
serverDir,
|
|
259
312
|
routeDir,
|
|
260
313
|
route
|
|
261
314
|
});
|
|
262
315
|
const meta = {
|
|
263
316
|
name,
|
|
264
317
|
path: route.path,
|
|
265
|
-
|
|
318
|
+
route_kind: route.route_kind || 'page',
|
|
319
|
+
output: route.output || null,
|
|
266
320
|
base_path: basePath,
|
|
267
321
|
page_asset: route.page_asset || null,
|
|
268
322
|
page_asset_file: pageAssetFile,
|
|
@@ -270,12 +324,19 @@ export async function writeServerOutput({ coreOutputDir, staticDir, projectRoot,
|
|
|
270
324
|
server_script_path: route.server_script_path || null,
|
|
271
325
|
guard_module_ref: route.guard_module_ref || null,
|
|
272
326
|
load_module_ref: route.load_module_ref || null,
|
|
327
|
+
action_module_ref: route.action_module_ref || null,
|
|
273
328
|
has_guard: route.has_guard === true,
|
|
274
329
|
has_load: route.has_load === true,
|
|
275
|
-
|
|
276
|
-
|
|
330
|
+
has_action: route.has_action === true,
|
|
331
|
+
params: Array.isArray(route.params) && route.params.length > 0
|
|
332
|
+
? [...route.params]
|
|
333
|
+
: extractRouteParams(route.path),
|
|
334
|
+
image_manifest_file: route.route_kind === 'resource' ? null : imageManifestFile,
|
|
277
335
|
image_config: config?.images || {}
|
|
278
336
|
};
|
|
337
|
+
if (route.route_kind !== 'resource' && Array.isArray(route.image_materialization) && route.image_materialization.length > 0) {
|
|
338
|
+
meta.image_materialization = route.image_materialization;
|
|
339
|
+
}
|
|
279
340
|
await writeFile(join(routeDir, 'route.json'), `${JSON.stringify(meta, null, 2)}\n`, 'utf8');
|
|
280
341
|
emittedRoutes.push(meta);
|
|
281
342
|
}
|
|
@@ -5,7 +5,9 @@ import { dirname, extname, join, normalize, resolve, sep } from 'node:path';
|
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import { appLocalRedirectLocation, imageEndpointPath, normalizeBasePath, routeCheckPath, stripBasePath } from '../base-path.js';
|
|
7
7
|
import { handleImageRequest } from '../images/service.js';
|
|
8
|
-
import {
|
|
8
|
+
import { createTrustedOriginResolver } from '../request-origin.js';
|
|
9
|
+
import { defaultRouteDenyMessage, logServerException, sanitizeRouteResult } from '../server-error.js';
|
|
10
|
+
import { executeRouteRequest, renderResourceRouteRequest, renderRouteRequest } from './route-render.js';
|
|
9
11
|
import { resolveRequestRoute } from './resolve-request-route.js';
|
|
10
12
|
const __filename = fileURLToPath(import.meta.url);
|
|
11
13
|
const __dirname = dirname(__filename);
|
|
@@ -68,18 +70,6 @@ function toStaticFilePath(staticDir, pathname) {
|
|
|
68
70
|
}
|
|
69
71
|
return resolveWithinRoot(staticDir, resolvedPath);
|
|
70
72
|
}
|
|
71
|
-
function publicHost(host) {
|
|
72
|
-
if (host === '0.0.0.0' || host === '::') {
|
|
73
|
-
return '127.0.0.1';
|
|
74
|
-
}
|
|
75
|
-
return host;
|
|
76
|
-
}
|
|
77
|
-
function createRequestBase(req, fallbackOrigin) {
|
|
78
|
-
if (typeof req.headers.host === 'string' && req.headers.host.length > 0) {
|
|
79
|
-
return `http://${req.headers.host}`;
|
|
80
|
-
}
|
|
81
|
-
return fallbackOrigin;
|
|
82
|
-
}
|
|
83
73
|
async function createWebRequest(req, url) {
|
|
84
74
|
const init = {
|
|
85
75
|
method: req.method || 'GET',
|
|
@@ -107,9 +97,23 @@ async function createWebRequest(req, url) {
|
|
|
107
97
|
}
|
|
108
98
|
return new Request(url.toString(), init);
|
|
109
99
|
}
|
|
100
|
+
function getSetCookieValues(response) {
|
|
101
|
+
if (typeof response?.headers?.getSetCookie === 'function') {
|
|
102
|
+
return response.headers.getSetCookie();
|
|
103
|
+
}
|
|
104
|
+
const value = response?.headers?.get?.('set-cookie');
|
|
105
|
+
return typeof value === 'string' && value.length > 0 ? [value] : [];
|
|
106
|
+
}
|
|
110
107
|
async function sendFetchResponse(res, response, method) {
|
|
111
108
|
res.statusCode = response.status;
|
|
109
|
+
const setCookies = getSetCookieValues(response);
|
|
110
|
+
if (setCookies.length > 0) {
|
|
111
|
+
res.setHeader('set-cookie', setCookies);
|
|
112
|
+
}
|
|
112
113
|
for (const [key, value] of response.headers.entries()) {
|
|
114
|
+
if (key.toLowerCase() === 'set-cookie') {
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
113
117
|
res.setHeader(key, value);
|
|
114
118
|
}
|
|
115
119
|
if (String(method || 'GET').toUpperCase() === 'HEAD') {
|
|
@@ -165,13 +169,16 @@ async function loadRuntimeContext(options = {}) {
|
|
|
165
169
|
base_path: '/'
|
|
166
170
|
});
|
|
167
171
|
const serverManifest = await readJson(join(serverDir, 'manifest.json'), { routes: [] });
|
|
172
|
+
const allServerRoutes = Array.isArray(serverManifest.routes) ? serverManifest.routes : [];
|
|
168
173
|
return {
|
|
169
174
|
distDir,
|
|
170
175
|
serverDir,
|
|
171
176
|
staticDir: resolve(serverDir, config.static_dir || '../static'),
|
|
172
177
|
buildManifest,
|
|
173
178
|
buildRoutes: Array.isArray(buildManifest.routes) ? buildManifest.routes : [],
|
|
174
|
-
serverRoutes:
|
|
179
|
+
serverRoutes: allServerRoutes,
|
|
180
|
+
pageServerRoutes: allServerRoutes.filter((route) => route?.route_kind !== 'resource'),
|
|
181
|
+
resourceServerRoutes: allServerRoutes.filter((route) => route?.route_kind === 'resource'),
|
|
175
182
|
images: config.images || {},
|
|
176
183
|
basePath: normalizeBasePath(config.base_path || '/')
|
|
177
184
|
};
|
|
@@ -216,7 +223,7 @@ async function handleRouteCheck(req, res, url, context) {
|
|
|
216
223
|
}
|
|
217
224
|
let result = { kind: 'allow' };
|
|
218
225
|
let routeId = buildResolved.route.path || '';
|
|
219
|
-
const serverResolved = resolveRequestRoute(canonicalTargetUrl, context.
|
|
226
|
+
const serverResolved = resolveRequestRoute(canonicalTargetUrl, context.pageServerRoutes);
|
|
220
227
|
if (serverResolved.matched && serverResolved.route) {
|
|
221
228
|
routeId = serverResolved.route.route_id || serverResolved.route.name || serverResolved.route.path || routeId;
|
|
222
229
|
try {
|
|
@@ -232,10 +239,11 @@ async function handleRouteCheck(req, res, url, context) {
|
|
|
232
239
|
result = normalizeRouteCheckResult(execution.result, targetUrl, context.basePath);
|
|
233
240
|
}
|
|
234
241
|
catch (error) {
|
|
242
|
+
logServerException('node route-check failed', error);
|
|
235
243
|
result = {
|
|
236
244
|
kind: 'deny',
|
|
237
245
|
status: 500,
|
|
238
|
-
message:
|
|
246
|
+
message: defaultRouteDenyMessage(500)
|
|
239
247
|
};
|
|
240
248
|
}
|
|
241
249
|
}
|
|
@@ -247,13 +255,13 @@ async function handleRouteCheck(req, res, url, context) {
|
|
|
247
255
|
Vary: 'Cookie'
|
|
248
256
|
});
|
|
249
257
|
res.end(JSON.stringify({
|
|
250
|
-
result,
|
|
258
|
+
result: sanitizeRouteResult(result),
|
|
251
259
|
routeId,
|
|
252
260
|
to: targetUrl.toString()
|
|
253
261
|
}));
|
|
254
262
|
}
|
|
255
263
|
async function handleNodeRequest(req, res, context, serverOrigin) {
|
|
256
|
-
const url = new URL(req.url || '/',
|
|
264
|
+
const url = new URL(req.url || '/', serverOrigin);
|
|
257
265
|
const canonicalPath = stripBasePath(url.pathname, context.basePath);
|
|
258
266
|
if (url.pathname === routeCheckPath(context.basePath)) {
|
|
259
267
|
await handleRouteCheck(req, res, url, context);
|
|
@@ -284,7 +292,20 @@ async function handleNodeRequest(req, res, context, serverOrigin) {
|
|
|
284
292
|
await sendStaticFile(res, assetPath, req.method);
|
|
285
293
|
return;
|
|
286
294
|
}
|
|
287
|
-
const
|
|
295
|
+
const resourceResolved = resolveRequestRoute(canonicalUrl, context.resourceServerRoutes);
|
|
296
|
+
if (resourceResolved.matched && resourceResolved.route) {
|
|
297
|
+
const routeDir = join(context.serverDir, 'routes', resourceResolved.route.name);
|
|
298
|
+
const request = await createWebRequest(req, url);
|
|
299
|
+
const response = await renderResourceRouteRequest({
|
|
300
|
+
request,
|
|
301
|
+
route: resourceResolved.route,
|
|
302
|
+
params: resourceResolved.params,
|
|
303
|
+
routeModulePath: join(routeDir, 'route', 'entry.js')
|
|
304
|
+
});
|
|
305
|
+
await sendFetchResponse(res, response, req.method);
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
const serverResolved = resolveRequestRoute(canonicalUrl, context.pageServerRoutes);
|
|
288
309
|
if (serverResolved.matched && serverResolved.route) {
|
|
289
310
|
const routeDir = join(context.serverDir, 'routes', serverResolved.route.name);
|
|
290
311
|
const request = await createWebRequest(req, url);
|
|
@@ -294,9 +315,6 @@ async function handleNodeRequest(req, res, context, serverOrigin) {
|
|
|
294
315
|
params: serverResolved.params,
|
|
295
316
|
routeModulePath: join(routeDir, 'route', 'entry.js'),
|
|
296
317
|
shellHtmlPath: join(routeDir, 'route', 'page.html'),
|
|
297
|
-
pageAssetPath: serverResolved.route.page_asset_file
|
|
298
|
-
? join(routeDir, 'route', serverResolved.route.page_asset_file)
|
|
299
|
-
: null,
|
|
300
318
|
imageManifestPath: serverResolved.route.image_manifest_file
|
|
301
319
|
? join(routeDir, 'route', serverResolved.route.image_manifest_file)
|
|
302
320
|
: null,
|
|
@@ -321,32 +339,50 @@ async function handleNodeRequest(req, res, context, serverOrigin) {
|
|
|
321
339
|
res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
322
340
|
res.end('404 Not Found');
|
|
323
341
|
}
|
|
324
|
-
|
|
325
|
-
const context = await loadRuntimeContext(options);
|
|
326
|
-
const host = publicHost(options.host || '127.0.0.1');
|
|
327
|
-
const port = Number.isInteger(options.port) ? options.port : 3000;
|
|
328
|
-
const serverOrigin = `http://${host}:${port}`;
|
|
342
|
+
function createNodeRequestHandler(context, resolveServerOrigin) {
|
|
329
343
|
return async (req, res) => {
|
|
330
344
|
try {
|
|
331
|
-
await handleNodeRequest(req, res, context,
|
|
345
|
+
await handleNodeRequest(req, res, context, resolveServerOrigin());
|
|
332
346
|
}
|
|
333
347
|
catch (error) {
|
|
348
|
+
logServerException('node request handler failed', error);
|
|
334
349
|
res.writeHead(500, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
335
|
-
res.end(
|
|
350
|
+
res.end(defaultRouteDenyMessage(500));
|
|
336
351
|
}
|
|
337
352
|
};
|
|
338
353
|
}
|
|
354
|
+
export async function createRequestHandler(options = {}) {
|
|
355
|
+
const context = await loadRuntimeContext(options);
|
|
356
|
+
const resolveServerOrigin = createTrustedOriginResolver({
|
|
357
|
+
publicOrigin: options.publicOrigin,
|
|
358
|
+
host: options.host || '127.0.0.1',
|
|
359
|
+
port: Number.isInteger(options.port) ? options.port : undefined,
|
|
360
|
+
label: 'createRequestHandler()'
|
|
361
|
+
});
|
|
362
|
+
resolveServerOrigin();
|
|
363
|
+
return createNodeRequestHandler(context, resolveServerOrigin);
|
|
364
|
+
}
|
|
339
365
|
export async function createNodeServer(options = {}) {
|
|
340
366
|
const { port = 3000, host = '127.0.0.1' } = options;
|
|
341
|
-
const
|
|
367
|
+
const context = await loadRuntimeContext(options);
|
|
368
|
+
let actualPort = Number.isInteger(port) && port > 0 ? port : 0;
|
|
369
|
+
const resolveServerOrigin = createTrustedOriginResolver({
|
|
370
|
+
publicOrigin: options.publicOrigin,
|
|
371
|
+
host,
|
|
372
|
+
getPort: () => actualPort,
|
|
373
|
+
label: 'createNodeServer()'
|
|
374
|
+
});
|
|
375
|
+
const handler = createNodeRequestHandler(context, resolveServerOrigin);
|
|
342
376
|
const server = createServer((req, res) => {
|
|
343
377
|
void handler(req, res);
|
|
344
378
|
});
|
|
345
379
|
return new Promise((resolveServer) => {
|
|
346
380
|
server.listen(port, host, () => {
|
|
381
|
+
const address = server.address();
|
|
382
|
+
actualPort = address && typeof address === 'object' ? address.port : port;
|
|
347
383
|
resolveServer({
|
|
348
384
|
server,
|
|
349
|
-
port:
|
|
385
|
+
port: actualPort,
|
|
350
386
|
close: () => server.close()
|
|
351
387
|
});
|
|
352
388
|
});
|
|
@@ -8,7 +8,7 @@ export function extractInternalParams(requestUrl: any, route: any): {};
|
|
|
8
8
|
* routeModulePath: string,
|
|
9
9
|
* guardOnly?: boolean
|
|
10
10
|
* }} options
|
|
11
|
-
* @returns {Promise<{ publicUrl: URL, result: { kind: string, [key: string]: unknown }, trace: { guard: string, load: string } }>}
|
|
11
|
+
* @returns {Promise<{ publicUrl: URL, result: { kind: string, [key: string]: unknown }, trace: { guard: string, action: string, load: string }, status?: number, setCookies?: string[] }>}
|
|
12
12
|
*/
|
|
13
13
|
export function executeRouteRequest(options: {
|
|
14
14
|
request: Request;
|
|
@@ -30,8 +30,11 @@ export function executeRouteRequest(options: {
|
|
|
30
30
|
};
|
|
31
31
|
trace: {
|
|
32
32
|
guard: string;
|
|
33
|
+
action: string;
|
|
33
34
|
load: string;
|
|
34
35
|
};
|
|
36
|
+
status?: number;
|
|
37
|
+
setCookies?: string[];
|
|
35
38
|
}>;
|
|
36
39
|
/**
|
|
37
40
|
* @param {{
|
|
@@ -40,7 +43,6 @@ export function executeRouteRequest(options: {
|
|
|
40
43
|
* params: Record<string, string>,
|
|
41
44
|
* routeModulePath: string,
|
|
42
45
|
* shellHtmlPath: string,
|
|
43
|
-
* pageAssetPath?: string | null,
|
|
44
46
|
* imageManifestPath?: string | null,
|
|
45
47
|
* imageConfig?: Record<string, unknown>
|
|
46
48
|
* }} options
|
|
@@ -58,7 +60,29 @@ export function renderRouteRequest(options: {
|
|
|
58
60
|
params: Record<string, string>;
|
|
59
61
|
routeModulePath: string;
|
|
60
62
|
shellHtmlPath: string;
|
|
61
|
-
pageAssetPath?: string | null;
|
|
62
63
|
imageManifestPath?: string | null;
|
|
63
64
|
imageConfig?: Record<string, unknown>;
|
|
64
65
|
}): Promise<Response>;
|
|
66
|
+
/**
|
|
67
|
+
* @param {{
|
|
68
|
+
* request: Request,
|
|
69
|
+
* route: { path: string, params?: string[], route_id?: string | null, server_script_path?: string | null, file?: string | null, route_kind?: string | null, base_path?: string | null },
|
|
70
|
+
* params: Record<string, string>,
|
|
71
|
+
* routeModulePath: string
|
|
72
|
+
* }} options
|
|
73
|
+
* @returns {Promise<Response>}
|
|
74
|
+
*/
|
|
75
|
+
export function renderResourceRouteRequest(options: {
|
|
76
|
+
request: Request;
|
|
77
|
+
route: {
|
|
78
|
+
path: string;
|
|
79
|
+
params?: string[];
|
|
80
|
+
route_id?: string | null;
|
|
81
|
+
server_script_path?: string | null;
|
|
82
|
+
file?: string | null;
|
|
83
|
+
route_kind?: string | null;
|
|
84
|
+
base_path?: string | null;
|
|
85
|
+
};
|
|
86
|
+
params: Record<string, string>;
|
|
87
|
+
routeModulePath: string;
|
|
88
|
+
}): Promise<Response>;
|