@zenithbuild/cli 0.7.11 → 0.7.12
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 +10 -1
- package/dist/adapters/adapter-netlify-static.d.ts +2 -5
- package/dist/adapters/adapter-netlify.d.ts +2 -5
- package/dist/adapters/adapter-netlify.js +22 -5
- package/dist/adapters/adapter-types.d.ts +32 -13
- package/dist/adapters/adapter-types.js +0 -59
- package/dist/adapters/adapter-vercel-static.d.ts +2 -5
- package/dist/adapters/adapter-vercel.d.ts +2 -5
- package/dist/adapters/adapter-vercel.js +21 -6
- package/dist/adapters/copy-hosted-page-runtime.d.ts +2 -1
- package/dist/adapters/copy-hosted-page-runtime.js +68 -3
- package/dist/adapters/resolve-adapter.d.ts +6 -4
- package/dist/build/expression-rewrites.d.ts +3 -1
- package/dist/build/expression-rewrites.js +14 -2
- package/dist/build/page-component-loop.d.ts +1 -0
- package/dist/build/page-component-loop.js +66 -6
- package/dist/build/page-ir-normalization.js +7 -0
- package/dist/build/page-loop-state.d.ts +2 -1
- package/dist/build/page-loop-state.js +9 -2
- package/dist/build/page-loop.js +10 -1
- package/dist/build/scoped-expression-context.d.ts +5 -0
- package/dist/build/scoped-expression-context.js +133 -0
- package/dist/build/type-declarations.d.ts +2 -1
- package/dist/build/type-declarations.js +31 -1
- package/dist/build-output-manifest.d.ts +10 -6
- package/dist/build-output-manifest.js +4 -1
- package/dist/build.js +11 -2
- package/dist/component-instance-ir.js +1 -0
- package/dist/component-occurrences.d.ts +9 -0
- package/dist/component-occurrences.js +18 -0
- package/dist/config-plugins.d.ts +12 -0
- package/dist/config-plugins.js +100 -0
- package/dist/config.d.ts +1 -0
- package/dist/config.js +56 -5
- package/dist/dev-server/request-handler.js +46 -4
- package/dist/dev-server.js +92 -4
- package/dist/global-middleware-runtime-source.d.ts +15 -0
- package/dist/global-middleware-runtime-source.js +62 -0
- package/dist/global-middleware.d.ts +13 -0
- package/dist/global-middleware.js +252 -0
- package/dist/manifest.d.ts +9 -1
- package/dist/manifest.js +66 -26
- package/dist/preview/request-handler.js +78 -5
- package/dist/preview/server-runner.d.ts +7 -2
- package/dist/preview/server-runner.js +19 -6
- package/dist/preview/server-script-runner-template.js +97 -29
- package/dist/route-classification.d.ts +2 -1
- package/dist/route-classification.js +6 -2
- package/dist/scoped-server-data/analyze-owner-file.d.ts +3 -0
- package/dist/scoped-server-data/analyze-owner-file.js +149 -0
- package/dist/scoped-server-data/diagnostics.d.ts +18 -0
- package/dist/scoped-server-data/diagnostics.js +32 -0
- package/dist/scoped-server-data/lowering.d.ts +27 -0
- package/dist/scoped-server-data/lowering.js +242 -0
- package/dist/scoped-server-data/manifest-integration.d.ts +4 -0
- package/dist/scoped-server-data/manifest-integration.js +125 -0
- package/dist/scoped-server-data/owner-scanner.d.ts +6 -0
- package/dist/scoped-server-data/owner-scanner.js +55 -0
- package/dist/scoped-server-data/parse-owner-server-block.d.ts +12 -0
- package/dist/scoped-server-data/parse-owner-server-block.js +35 -0
- package/dist/scoped-server-data/runtime.d.ts +24 -0
- package/dist/scoped-server-data/runtime.js +121 -0
- package/dist/scoped-server-data/serialization-set.d.ts +2 -0
- package/dist/scoped-server-data/serialization-set.js +52 -0
- package/dist/scoped-server-data/static-props.d.ts +12 -0
- package/dist/scoped-server-data/static-props.js +307 -0
- package/dist/scoped-server-data/type-declarations.d.ts +10 -0
- package/dist/scoped-server-data/type-declarations.js +368 -0
- package/dist/scoped-server-data/types.d.ts +74 -0
- package/dist/scoped-server-data/types.js +1 -0
- package/dist/server-contract/auth-control-flow.d.ts +1 -0
- package/dist/server-contract/auth-control-flow.js +10 -0
- package/dist/server-contract/resolve.d.ts +19 -0
- package/dist/server-contract/resolve.js +85 -13
- package/dist/server-contract/resolved-envelope.d.ts +9 -0
- package/dist/server-contract/resolved-envelope.js +14 -0
- package/dist/server-contract/stage.js +1 -10
- package/dist/server-module-output.d.ts +9 -0
- package/dist/server-module-output.js +250 -0
- package/dist/server-output.d.ts +7 -1
- package/dist/server-output.js +138 -179
- package/dist/server-runtime/matched-route-pipeline.d.ts +1 -0
- package/dist/server-runtime/matched-route-pipeline.js +1 -0
- package/dist/server-runtime/node-server.js +21 -1
- package/dist/server-runtime/route-render.d.ts +12 -3
- package/dist/server-runtime/route-render.js +67 -13
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ The command-line interface for developing and building Zenith applications.
|
|
|
19
19
|
- `zenith build`
|
|
20
20
|
- `zenith preview`
|
|
21
21
|
|
|
22
|
-
It
|
|
22
|
+
It ships a minimal V1 plugin surface for config-time normalization only.
|
|
23
23
|
|
|
24
24
|
## Features
|
|
25
25
|
|
|
@@ -41,9 +41,18 @@ Current top-level `zenith.config.js` keys:
|
|
|
41
41
|
- `adapter`
|
|
42
42
|
- `strictDomLints`
|
|
43
43
|
- `images`
|
|
44
|
+
- `plugins`
|
|
44
45
|
|
|
45
46
|
There is no separate `assetPrefix` config. Public framework asset URLs follow `basePath`.
|
|
46
47
|
|
|
48
|
+
`plugins` behavior:
|
|
49
|
+
|
|
50
|
+
- Plugins are added in `zenith.config.js` with `plugins: [authPlugin(), mdxPlugin()]`.
|
|
51
|
+
- V1 plugins must be named objects and may only provide a `config()` hook.
|
|
52
|
+
- V1 plugin config patches are shallow top-level patches; nested objects such as `images` replace that config object instead of deep-merging.
|
|
53
|
+
- V1 plugins cannot transform files, register middleware, mutate routes/security, or install compiler/bundler/dev-server hooks.
|
|
54
|
+
- Global middleware is separate Lane 2 work.
|
|
55
|
+
|
|
47
56
|
`pagesDir` resolution:
|
|
48
57
|
|
|
49
58
|
- If `pagesDir` is set, the CLI uses that path relative to the project root.
|
|
@@ -1,5 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
function validateRoutes(manifest: any): void;
|
|
4
|
-
function adapt(options: any): Promise<void>;
|
|
5
|
-
}
|
|
1
|
+
import type { AdapterDriver } from './adapter-types.js';
|
|
2
|
+
export declare const netlifyStaticAdapter: AdapterDriver;
|
|
@@ -2,7 +2,7 @@ import { cp, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { prependBasePath } from '../base-path.js';
|
|
4
4
|
import { compareRouteSpecificity } from '../server/resolve-request-route.js';
|
|
5
|
-
import { copyHostedPageRuntime } from './copy-hosted-page-runtime.js';
|
|
5
|
+
import { copyHostedGlobalMiddlewareRuntime, copyHostedPageRuntime } from './copy-hosted-page-runtime.js';
|
|
6
6
|
import { createNetlifyBasePathAssetRules, createNetlifyImageEndpointRule, createNetlifyRewriteRules } from './route-rules.js';
|
|
7
7
|
import { validateHostedResourceRoutes } from './validate-hosted-resource-routes.js';
|
|
8
8
|
function buildNetlifyServerRules(route, basePath = '/') {
|
|
@@ -32,13 +32,17 @@ function buildNetlifyServerRules(route, basePath = '/') {
|
|
|
32
32
|
const query = route.params.map((param) => `__zenith_param_${param}=:${param}`).join('&');
|
|
33
33
|
return [`${prependBasePath(basePath, sourcePath)} ${destination}?${query} 200!`];
|
|
34
34
|
}
|
|
35
|
-
function createFunctionSource(route) {
|
|
35
|
+
function createFunctionSource(route, globalMiddlewareModulePath) {
|
|
36
|
+
const globalMiddlewarePathExpression = globalMiddlewareModulePath
|
|
37
|
+
? "join(__dirname, '_zenith', 'global-middleware', 'entry.js')"
|
|
38
|
+
: 'null';
|
|
36
39
|
return [
|
|
37
40
|
"import { fileURLToPath } from 'node:url';",
|
|
38
41
|
"import { dirname, join } from 'node:path';",
|
|
39
42
|
"import { renderResourceRouteRequest, renderRouteRequest, extractInternalParams } from './_zenith/runtime/route-render.js';",
|
|
40
43
|
'',
|
|
41
44
|
'const __dirname = dirname(fileURLToPath(import.meta.url));',
|
|
45
|
+
`const globalMiddlewareModulePath = ${globalMiddlewarePathExpression};`,
|
|
42
46
|
`const route = ${JSON.stringify(route, null, 2)};`,
|
|
43
47
|
'',
|
|
44
48
|
'function createHostedUnsupportedResponse(message) {',
|
|
@@ -52,7 +56,8 @@ function createFunctionSource(route) {
|
|
|
52
56
|
' request,',
|
|
53
57
|
' route,',
|
|
54
58
|
' params,',
|
|
55
|
-
` routeModulePath: join(__dirname, '_zenith', 'routes', ${JSON.stringify(route.name)}, 'route', 'entry.js')
|
|
59
|
+
` routeModulePath: join(__dirname, '_zenith', 'routes', ${JSON.stringify(route.name)}, 'route', 'entry.js'),`,
|
|
60
|
+
' globalMiddlewareModulePath',
|
|
56
61
|
' });',
|
|
57
62
|
" if (response.headers.has('content-disposition')) {",
|
|
58
63
|
" return createHostedUnsupportedResponse('Hosted resource downloads are unsupported in this milestone');",
|
|
@@ -64,6 +69,7 @@ function createFunctionSource(route) {
|
|
|
64
69
|
' route,',
|
|
65
70
|
' params,',
|
|
66
71
|
` routeModulePath: join(__dirname, '_zenith', 'routes', ${JSON.stringify(route.name)}, 'route', 'entry.js'),`,
|
|
72
|
+
' globalMiddlewareModulePath,',
|
|
67
73
|
` shellHtmlPath: join(__dirname, '_zenith', 'routes', ${JSON.stringify(route.name)}, 'route', 'page.html'),`,
|
|
68
74
|
` pageAssetPath: ${route.page_asset_file ? "join(__dirname, '_zenith', 'routes', " + JSON.stringify(route.name) + ", 'route', " + JSON.stringify(route.page_asset_file) + ')' : 'null'},`,
|
|
69
75
|
` imageManifestPath: ${route.image_manifest_file ? "join(__dirname, '_zenith', 'routes', " + JSON.stringify(route.name) + ", 'route', " + JSON.stringify(route.image_manifest_file) + ')' : 'null'},`,
|
|
@@ -91,6 +97,12 @@ function createImageFunctionSource(imagesConfig) {
|
|
|
91
97
|
''
|
|
92
98
|
].join('\n');
|
|
93
99
|
}
|
|
100
|
+
function hasHostedScopedServerData(route) {
|
|
101
|
+
return route.route_kind !== 'resource' &&
|
|
102
|
+
route.has_scoped_server_data === true &&
|
|
103
|
+
Array.isArray(route.scoped_server_data) &&
|
|
104
|
+
route.scoped_server_data.length > 0;
|
|
105
|
+
}
|
|
94
106
|
async function loadServerManifest(coreOutput) {
|
|
95
107
|
try {
|
|
96
108
|
const parsed = JSON.parse(await readFile(join(coreOutput, 'server', 'manifest.json'), 'utf8'));
|
|
@@ -144,11 +156,16 @@ export const netlifyAdapter = {
|
|
|
144
156
|
await mkdir(functionsDir, { recursive: true });
|
|
145
157
|
await cp(staticDir, publishDir, { recursive: true, force: true });
|
|
146
158
|
await writeFile(join(functionsDir, 'package.json'), '{\n "type": "module"\n}\n', 'utf8');
|
|
147
|
-
await copyHostedPageRuntime(options.coreOutput, join(functionsDir, '_zenith')
|
|
159
|
+
await copyHostedPageRuntime(options.coreOutput, join(functionsDir, '_zenith'), {
|
|
160
|
+
includeScopedServerData: serverRoutes.some(hasHostedScopedServerData)
|
|
161
|
+
});
|
|
162
|
+
const globalMiddlewareModulePath = serverRoutes.length > 0
|
|
163
|
+
? await copyHostedGlobalMiddlewareRuntime(options.coreOutput, join(functionsDir, '_zenith'))
|
|
164
|
+
: null;
|
|
148
165
|
await writeFile(join(functionsDir, '__zenith_image.mjs'), createImageFunctionSource(options.config?.images || {}), 'utf8');
|
|
149
166
|
for (const route of serverRoutes) {
|
|
150
167
|
await cp(join(options.coreOutput, 'server', 'routes', route.name), join(functionsDir, '_zenith', 'routes', route.name), { recursive: true, force: true });
|
|
151
|
-
await writeFile(join(functionsDir, `__zenith_${route.name}.mjs`), createFunctionSource(route), 'utf8');
|
|
168
|
+
await writeFile(join(functionsDir, `__zenith_${route.name}.mjs`), createFunctionSource(route, globalMiddlewareModulePath), 'utf8');
|
|
152
169
|
}
|
|
153
170
|
await writeFile(join(publishDir, '_redirects'), buildRedirectsFile(options.manifest, serverRoutes), 'utf8');
|
|
154
171
|
await writeFile(join(options.outDir, 'netlify.toml'), [
|
|
@@ -1,21 +1,24 @@
|
|
|
1
|
-
export const KNOWN_TARGETS: string[];
|
|
2
|
-
export type ZenithTarget =
|
|
3
|
-
export type ZenithRenderMode =
|
|
4
|
-
export type ZenithPathKind =
|
|
5
|
-
export
|
|
1
|
+
export declare const KNOWN_TARGETS: string[];
|
|
2
|
+
export type ZenithTarget = 'static' | 'static-export' | 'vercel-static' | 'netlify-static' | 'vercel' | 'netlify' | 'node';
|
|
3
|
+
export type ZenithRenderMode = 'prerender' | 'server';
|
|
4
|
+
export type ZenithPathKind = 'static' | 'dynamic';
|
|
5
|
+
export interface RouteManifestEntry {
|
|
6
6
|
path: string;
|
|
7
7
|
file: string;
|
|
8
8
|
path_kind: ZenithPathKind;
|
|
9
9
|
render_mode: ZenithRenderMode;
|
|
10
10
|
params: string[];
|
|
11
11
|
export_paths?: string[];
|
|
12
|
-
}
|
|
13
|
-
export
|
|
12
|
+
}
|
|
13
|
+
export interface BuildManifest {
|
|
14
14
|
schema_version: number;
|
|
15
15
|
zenith_version: string;
|
|
16
16
|
target: string;
|
|
17
17
|
base_path: string;
|
|
18
18
|
content_hash: string;
|
|
19
|
+
global_middleware?: {
|
|
20
|
+
source_file: string;
|
|
21
|
+
};
|
|
19
22
|
routes: Array<{
|
|
20
23
|
path: string;
|
|
21
24
|
file: string;
|
|
@@ -32,15 +35,31 @@ export type BuildManifest = {
|
|
|
32
35
|
css: string[];
|
|
33
36
|
vendor: string | null;
|
|
34
37
|
};
|
|
35
|
-
}
|
|
36
|
-
export
|
|
38
|
+
}
|
|
39
|
+
export interface AdaptOptions {
|
|
37
40
|
coreOutput: string;
|
|
38
41
|
outDir: string;
|
|
39
42
|
manifest: BuildManifest;
|
|
40
43
|
config: object;
|
|
41
|
-
}
|
|
42
|
-
export type
|
|
44
|
+
}
|
|
45
|
+
export type AdapterResolutionMode = 'adapter' | 'target' | 'legacy';
|
|
46
|
+
export interface AdapterManifestEntry extends RouteManifestEntry {
|
|
47
|
+
route_kind?: 'page' | 'resource';
|
|
48
|
+
server_script?: string;
|
|
49
|
+
server_script_path?: string;
|
|
50
|
+
has_guard?: boolean;
|
|
51
|
+
has_load?: boolean;
|
|
52
|
+
has_action?: boolean;
|
|
53
|
+
}
|
|
54
|
+
export type AdapterRouteManifest = AdapterManifestEntry[];
|
|
55
|
+
export interface AdapterDriver {
|
|
43
56
|
name: string;
|
|
44
|
-
validateRoutes: (manifest:
|
|
57
|
+
validateRoutes: (manifest: AdapterRouteManifest) => void;
|
|
45
58
|
adapt: (options: AdaptOptions) => Promise<void>;
|
|
46
|
-
}
|
|
59
|
+
}
|
|
60
|
+
export interface ResolvedBuildAdapter {
|
|
61
|
+
target: string;
|
|
62
|
+
adapter: AdapterDriver;
|
|
63
|
+
mode: AdapterResolutionMode;
|
|
64
|
+
}
|
|
65
|
+
export type ZenithAdapter = AdapterDriver;
|
|
@@ -7,62 +7,3 @@ export const KNOWN_TARGETS = [
|
|
|
7
7
|
'netlify',
|
|
8
8
|
'node'
|
|
9
9
|
];
|
|
10
|
-
/**
|
|
11
|
-
* @typedef {'static' | 'static-export' | 'vercel-static' | 'netlify-static' | 'vercel' | 'netlify' | 'node'} ZenithTarget
|
|
12
|
-
*/
|
|
13
|
-
/**
|
|
14
|
-
* @typedef {'prerender' | 'server'} ZenithRenderMode
|
|
15
|
-
*/
|
|
16
|
-
/**
|
|
17
|
-
* @typedef {'static' | 'dynamic'} ZenithPathKind
|
|
18
|
-
*/
|
|
19
|
-
/**
|
|
20
|
-
* @typedef {{
|
|
21
|
-
* path: string,
|
|
22
|
-
* file: string,
|
|
23
|
-
* path_kind: ZenithPathKind,
|
|
24
|
-
* render_mode: ZenithRenderMode,
|
|
25
|
-
* params: string[],
|
|
26
|
-
* export_paths?: string[]
|
|
27
|
-
* }} RouteManifestEntry
|
|
28
|
-
*/
|
|
29
|
-
/**
|
|
30
|
-
* @typedef {{
|
|
31
|
-
* schema_version: number,
|
|
32
|
-
* zenith_version: string,
|
|
33
|
-
* target: string,
|
|
34
|
-
* base_path: string,
|
|
35
|
-
* content_hash: string,
|
|
36
|
-
* routes: Array<{
|
|
37
|
-
* path: string,
|
|
38
|
-
* file: string,
|
|
39
|
-
* path_kind: ZenithPathKind,
|
|
40
|
-
* render_mode: ZenithRenderMode,
|
|
41
|
-
* requires_hydration: boolean,
|
|
42
|
-
* params: string[],
|
|
43
|
-
* export_paths?: string[],
|
|
44
|
-
* html: string,
|
|
45
|
-
* assets: string[]
|
|
46
|
-
* }>,
|
|
47
|
-
* assets: {
|
|
48
|
-
* js: string[],
|
|
49
|
-
* css: string[],
|
|
50
|
-
* vendor: string | null
|
|
51
|
-
* }
|
|
52
|
-
* }} BuildManifest
|
|
53
|
-
*/
|
|
54
|
-
/**
|
|
55
|
-
* @typedef {{
|
|
56
|
-
* coreOutput: string,
|
|
57
|
-
* outDir: string,
|
|
58
|
-
* manifest: BuildManifest,
|
|
59
|
-
* config: object
|
|
60
|
-
* }} AdaptOptions
|
|
61
|
-
*/
|
|
62
|
-
/**
|
|
63
|
-
* @typedef {{
|
|
64
|
-
* name: string,
|
|
65
|
-
* validateRoutes: (manifest: RouteManifestEntry[]) => void,
|
|
66
|
-
* adapt: (options: AdaptOptions) => Promise<void>
|
|
67
|
-
* }} ZenithAdapter
|
|
68
|
-
*/
|
|
@@ -1,5 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
function validateRoutes(manifest: any): void;
|
|
4
|
-
function adapt(options: any): Promise<void>;
|
|
5
|
-
}
|
|
1
|
+
import type { AdapterDriver } from './adapter-types.js';
|
|
2
|
+
export declare const vercelStaticAdapter: AdapterDriver;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { cp, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
2
|
-
import {
|
|
2
|
+
import { join } from 'node:path';
|
|
3
3
|
import { compareRouteSpecificity } from '../server/resolve-request-route.js';
|
|
4
|
-
import { copyHostedPageRuntime } from './copy-hosted-page-runtime.js';
|
|
4
|
+
import { copyHostedGlobalMiddlewareRuntime, copyHostedPageRuntime } from './copy-hosted-page-runtime.js';
|
|
5
5
|
import { createVercelBasePathAssetRoutes, createVercelImageEndpointRoute, createVercelRouteSource } from './route-rules.js';
|
|
6
6
|
import { validateHostedResourceRoutes } from './validate-hosted-resource-routes.js';
|
|
7
7
|
function buildVercelServerDest(route) {
|
|
@@ -53,13 +53,17 @@ function createImageFunctionSource(imagesConfig) {
|
|
|
53
53
|
''
|
|
54
54
|
].join('\n');
|
|
55
55
|
}
|
|
56
|
-
function createFunctionSource(route) {
|
|
56
|
+
function createFunctionSource(route, globalMiddlewareModulePath) {
|
|
57
|
+
const globalMiddlewarePathExpression = globalMiddlewareModulePath
|
|
58
|
+
? "join(__dirname, 'global-middleware', 'entry.js')"
|
|
59
|
+
: 'null';
|
|
57
60
|
return [
|
|
58
61
|
"import { fileURLToPath } from 'node:url';",
|
|
59
62
|
"import { dirname, join } from 'node:path';",
|
|
60
63
|
"import { renderResourceRouteRequest, renderRouteRequest, extractInternalParams } from './runtime/route-render.js';",
|
|
61
64
|
'',
|
|
62
65
|
'const __dirname = dirname(fileURLToPath(import.meta.url));',
|
|
66
|
+
`const globalMiddlewareModulePath = ${globalMiddlewarePathExpression};`,
|
|
63
67
|
`const route = ${JSON.stringify(route, null, 2)};`,
|
|
64
68
|
'',
|
|
65
69
|
'function createHostedUnsupportedResponse(message) {',
|
|
@@ -74,7 +78,8 @@ function createFunctionSource(route) {
|
|
|
74
78
|
' request,',
|
|
75
79
|
' route,',
|
|
76
80
|
' params,',
|
|
77
|
-
` routeModulePath: join(__dirname, 'routes', ${JSON.stringify(route.name)}, 'route', 'entry.js')
|
|
81
|
+
` routeModulePath: join(__dirname, 'routes', ${JSON.stringify(route.name)}, 'route', 'entry.js'),`,
|
|
82
|
+
' globalMiddlewareModulePath',
|
|
78
83
|
' });',
|
|
79
84
|
" if (response.headers.has('content-disposition')) {",
|
|
80
85
|
" return createHostedUnsupportedResponse('Hosted resource downloads are unsupported in this milestone');",
|
|
@@ -86,6 +91,7 @@ function createFunctionSource(route) {
|
|
|
86
91
|
' route,',
|
|
87
92
|
' params,',
|
|
88
93
|
` routeModulePath: join(__dirname, 'routes', ${JSON.stringify(route.name)}, 'route', 'entry.js'),`,
|
|
94
|
+
' globalMiddlewareModulePath,',
|
|
89
95
|
` shellHtmlPath: join(__dirname, 'routes', ${JSON.stringify(route.name)}, 'route', 'page.html'),`,
|
|
90
96
|
` pageAssetPath: ${route.page_asset_file ? "join(__dirname, 'routes', " + JSON.stringify(route.name) + ", 'route', " + JSON.stringify(route.page_asset_file) + ')' : 'null'},`,
|
|
91
97
|
` imageManifestPath: ${route.image_manifest_file ? "join(__dirname, 'routes', " + JSON.stringify(route.name) + ", 'route', " + JSON.stringify(route.image_manifest_file) + ')' : 'null'},`,
|
|
@@ -96,6 +102,12 @@ function createFunctionSource(route) {
|
|
|
96
102
|
''
|
|
97
103
|
].join('\n');
|
|
98
104
|
}
|
|
105
|
+
function hasHostedScopedServerData(route) {
|
|
106
|
+
return route.route_kind !== 'resource' &&
|
|
107
|
+
route.has_scoped_server_data === true &&
|
|
108
|
+
Array.isArray(route.scoped_server_data) &&
|
|
109
|
+
route.scoped_server_data.length > 0;
|
|
110
|
+
}
|
|
99
111
|
async function loadServerManifest(coreOutput) {
|
|
100
112
|
try {
|
|
101
113
|
const parsed = JSON.parse(await readFile(join(coreOutput, 'server', 'manifest.json'), 'utf8'));
|
|
@@ -137,10 +149,13 @@ export const vercelAdapter = {
|
|
|
137
149
|
for (const route of serverRoutes) {
|
|
138
150
|
const functionDir = join(options.outDir, 'functions', '__zenith', `${route.name}.func`);
|
|
139
151
|
await mkdir(functionDir, { recursive: true });
|
|
140
|
-
await copyHostedPageRuntime(options.coreOutput, functionDir
|
|
152
|
+
await copyHostedPageRuntime(options.coreOutput, functionDir, {
|
|
153
|
+
includeScopedServerData: hasHostedScopedServerData(route)
|
|
154
|
+
});
|
|
155
|
+
const globalMiddlewareModulePath = await copyHostedGlobalMiddlewareRuntime(options.coreOutput, functionDir);
|
|
141
156
|
await cp(join(options.coreOutput, 'server', 'routes', route.name), join(functionDir, 'routes', route.name), { recursive: true, force: true });
|
|
142
157
|
await writeFile(join(functionDir, 'package.json'), '{\n "type": "module"\n}\n', 'utf8');
|
|
143
|
-
await writeFile(join(functionDir, 'index.js'), createFunctionSource(route), 'utf8');
|
|
158
|
+
await writeFile(join(functionDir, 'index.js'), createFunctionSource(route, globalMiddlewareModulePath), 'utf8');
|
|
144
159
|
await writeFile(join(functionDir, '.vc-config.json'), vercelFunctionConfig(), 'utf8');
|
|
145
160
|
}
|
|
146
161
|
await writeFile(join(options.outDir, 'config.json'), `${JSON.stringify(buildVercelConfig(options.manifest, serverRoutes), null, 2)}\n`, 'utf8');
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export function copyHostedPageRuntime(coreOutput: any, targetDir: any): Promise<void>;
|
|
1
|
+
export function copyHostedPageRuntime(coreOutput: any, targetDir: any, options?: {}): Promise<void>;
|
|
2
|
+
export function copyHostedGlobalMiddlewareRuntime(coreOutput: any, targetDir: any): Promise<string | null>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { cp, mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
1
|
+
import { cp, mkdir, readFile, stat, writeFile } from 'node:fs/promises';
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { join } from 'node:path';
|
|
3
|
+
import { isAbsolute, join, normalize } from 'node:path';
|
|
4
4
|
import { pathToFileURL } from 'node:url';
|
|
5
5
|
const PACKAGE_REQUIRE = createRequire(import.meta.url);
|
|
6
6
|
const HOSTED_PAGE_RUNTIME_DIRS = ['runtime', 'images', 'auth', 'server-contract'];
|
|
@@ -12,6 +12,10 @@ const HOSTED_PAGE_RUNTIME_FILES = [
|
|
|
12
12
|
'resource-response.js',
|
|
13
13
|
'download-result.js'
|
|
14
14
|
];
|
|
15
|
+
const INVALID_GLOBAL_MIDDLEWARE_MODULE_PATH_ERROR = '[Zenith:Middleware] Invalid global middleware module path in server manifest.';
|
|
16
|
+
const MISSING_GLOBAL_MIDDLEWARE_RUNTIME_ERROR = '[Zenith:Middleware] Compiled global middleware runtime is missing from server output.';
|
|
17
|
+
const MISSING_SCOPED_RUNTIME_ERROR = '[Zenith:ScopedServerData] Compiled scoped server data runtime is missing from server output.';
|
|
18
|
+
const MISSING_SCOPED_MODULES_ERROR = '[Zenith:ScopedServerData] Compiled scoped server data modules are missing from server output.';
|
|
15
19
|
function createSharpRuntimeSource() {
|
|
16
20
|
const sharpPath = PACKAGE_REQUIRE.resolve('sharp');
|
|
17
21
|
const fallbackUrl = pathToFileURL(sharpPath).href;
|
|
@@ -31,7 +35,48 @@ function createSharpRuntimeSource() {
|
|
|
31
35
|
''
|
|
32
36
|
].join('\n');
|
|
33
37
|
}
|
|
34
|
-
|
|
38
|
+
async function readServerManifest(coreOutput) {
|
|
39
|
+
try {
|
|
40
|
+
return JSON.parse(await readFile(join(coreOutput, 'server', 'manifest.json'), 'utf8'));
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function normalizeGlobalMiddlewareModulePath(modulePath) {
|
|
47
|
+
if (typeof modulePath !== 'string' || modulePath.length === 0 || isAbsolute(modulePath) || /^[A-Za-z]:[\\/]/.test(modulePath)) {
|
|
48
|
+
throw new Error(INVALID_GLOBAL_MIDDLEWARE_MODULE_PATH_ERROR);
|
|
49
|
+
}
|
|
50
|
+
if (modulePath.split(/[\\/]+/).includes('..')) {
|
|
51
|
+
throw new Error(INVALID_GLOBAL_MIDDLEWARE_MODULE_PATH_ERROR);
|
|
52
|
+
}
|
|
53
|
+
const normalized = normalize(modulePath).replaceAll('\\', '/');
|
|
54
|
+
if (normalized === '.' ||
|
|
55
|
+
normalized.startsWith('../') ||
|
|
56
|
+
normalized.includes('/../') ||
|
|
57
|
+
!normalized.startsWith('global-middleware/')) {
|
|
58
|
+
throw new Error(INVALID_GLOBAL_MIDDLEWARE_MODULE_PATH_ERROR);
|
|
59
|
+
}
|
|
60
|
+
return normalized;
|
|
61
|
+
}
|
|
62
|
+
async function assertPathExists(filePath, message) {
|
|
63
|
+
try {
|
|
64
|
+
await stat(filePath);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
throw new Error(message);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async function copyHostedScopedServerDataRuntime(coreOutput, targetDir) {
|
|
71
|
+
const serverDir = join(coreOutput, 'server');
|
|
72
|
+
const runtimeRoot = join(serverDir, 'scoped-server-data');
|
|
73
|
+
const scopedRoot = join(serverDir, 'scoped');
|
|
74
|
+
await assertPathExists(runtimeRoot, MISSING_SCOPED_RUNTIME_ERROR);
|
|
75
|
+
await assertPathExists(scopedRoot, MISSING_SCOPED_MODULES_ERROR);
|
|
76
|
+
await cp(runtimeRoot, join(targetDir, 'scoped-server-data'), { recursive: true, force: true });
|
|
77
|
+
await cp(scopedRoot, join(targetDir, 'scoped'), { recursive: true, force: true });
|
|
78
|
+
}
|
|
79
|
+
export async function copyHostedPageRuntime(coreOutput, targetDir, options = {}) {
|
|
35
80
|
const serverDir = join(coreOutput, 'server');
|
|
36
81
|
await mkdir(targetDir, { recursive: true });
|
|
37
82
|
for (const name of HOSTED_PAGE_RUNTIME_DIRS) {
|
|
@@ -47,4 +92,24 @@ export async function copyHostedPageRuntime(coreOutput, targetDir) {
|
|
|
47
92
|
const imageServiceSource = await readFile(imageServicePath, 'utf8');
|
|
48
93
|
await writeFile(imageServicePath, imageServiceSource.replace("import sharp from 'sharp';", "import sharp from './sharp-runtime.js';"), 'utf8');
|
|
49
94
|
await writeFile(join(targetDir, 'images', 'sharp-runtime.js'), createSharpRuntimeSource(), 'utf8');
|
|
95
|
+
if (options.includeScopedServerData === true) {
|
|
96
|
+
await copyHostedScopedServerDataRuntime(coreOutput, targetDir);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
export async function copyHostedGlobalMiddlewareRuntime(coreOutput, targetDir) {
|
|
100
|
+
const manifest = await readServerManifest(coreOutput);
|
|
101
|
+
const modulePath = manifest?.global_middleware?.module;
|
|
102
|
+
if (modulePath == null) {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
const normalizedModulePath = normalizeGlobalMiddlewareModulePath(modulePath);
|
|
106
|
+
const serverDir = join(coreOutput, 'server');
|
|
107
|
+
const middlewareRoot = join(serverDir, 'global-middleware');
|
|
108
|
+
await assertPathExists(middlewareRoot, MISSING_GLOBAL_MIDDLEWARE_RUNTIME_ERROR);
|
|
109
|
+
await assertPathExists(join(serverDir, normalizedModulePath), MISSING_GLOBAL_MIDDLEWARE_RUNTIME_ERROR);
|
|
110
|
+
await cp(middlewareRoot, join(targetDir, 'global-middleware'), {
|
|
111
|
+
recursive: true,
|
|
112
|
+
force: true
|
|
113
|
+
});
|
|
114
|
+
return normalizedModulePath;
|
|
50
115
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import type { ResolvedBuildAdapter } from './adapter-types.js';
|
|
2
|
+
type BuildAdapterConfig = {
|
|
3
|
+
target?: unknown;
|
|
4
|
+
adapter?: unknown;
|
|
5
5
|
};
|
|
6
|
+
export declare function resolveBuildAdapter(config?: BuildAdapterConfig): ResolvedBuildAdapter;
|
|
7
|
+
export {};
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
* signal_indices: number[],
|
|
10
10
|
* state_index: number | null,
|
|
11
11
|
* component_instance: string | null,
|
|
12
|
-
* component_binding: string | null
|
|
12
|
+
* component_binding: string | null,
|
|
13
|
+
* scoped_data_key: string | null
|
|
13
14
|
* }>,
|
|
14
15
|
* signals: Array<{ id?: number, kind?: string, state_index?: number }>,
|
|
15
16
|
* stateBindings: Array<{ key?: string, value?: string }>,
|
|
@@ -26,6 +27,7 @@ export function buildComponentExpressionRewrite(compIr: object, rewriteMetrics?:
|
|
|
26
27
|
state_index: number | null;
|
|
27
28
|
component_instance: string | null;
|
|
28
29
|
component_binding: string | null;
|
|
30
|
+
scoped_data_key: string | null;
|
|
29
31
|
}>;
|
|
30
32
|
signals: Array<{
|
|
31
33
|
id?: number;
|
|
@@ -11,7 +11,8 @@ import { rewriteCompilerSignalMapReferences } from './compiler-signal-expression
|
|
|
11
11
|
* signal_indices: number[],
|
|
12
12
|
* state_index: number | null,
|
|
13
13
|
* component_instance: string | null,
|
|
14
|
-
* component_binding: string | null
|
|
14
|
+
* component_binding: string | null,
|
|
15
|
+
* scoped_data_key: string | null
|
|
15
16
|
* }>,
|
|
16
17
|
* signals: Array<{ id?: number, kind?: string, state_index?: number }>,
|
|
17
18
|
* stateBindings: Array<{ key?: string, value?: string }>,
|
|
@@ -60,6 +61,11 @@ export function buildComponentExpressionRewrite(compIr, rewriteMetrics = null) {
|
|
|
60
61
|
component_binding: typeof binding.component_binding === 'string' ? binding.component_binding : null
|
|
61
62
|
}
|
|
62
63
|
: null;
|
|
64
|
+
if (normalizedBinding &&
|
|
65
|
+
typeof binding.scoped_data_key === 'string' &&
|
|
66
|
+
binding.scoped_data_key.length > 0) {
|
|
67
|
+
normalizedBinding.scoped_data_key = binding.scoped_data_key;
|
|
68
|
+
}
|
|
63
69
|
out.sequence.push({ raw, rewritten, binding: normalizedBinding });
|
|
64
70
|
if (!out.ambiguous.has(raw) && normalizedBinding) {
|
|
65
71
|
const existingBinding = out.bindings.get(raw);
|
|
@@ -197,7 +203,10 @@ export function resolveRewrittenBindingMetadata(pageBindingContext, componentRew
|
|
|
197
203
|
signal_indices: [],
|
|
198
204
|
state_index: null,
|
|
199
205
|
component_instance: typeof binding.component_instance === 'string' ? binding.component_instance : null,
|
|
200
|
-
component_binding: typeof binding.component_binding === 'string' ? binding.component_binding : null
|
|
206
|
+
component_binding: typeof binding.component_binding === 'string' ? binding.component_binding : null,
|
|
207
|
+
scoped_data_key: typeof binding.scoped_data_key === 'string' && binding.scoped_data_key.length > 0
|
|
208
|
+
? binding.scoped_data_key
|
|
209
|
+
: null
|
|
201
210
|
};
|
|
202
211
|
if (typeof next.compiled_expr === 'string' && next.compiled_expr.includes('signalMap.get(')) {
|
|
203
212
|
const remapStartedAt = performance.now();
|
|
@@ -334,6 +343,9 @@ function measureBindingSpecificity(binding, raw) {
|
|
|
334
343
|
if (typeof binding.component_binding === 'string' && binding.component_binding.length > 0) {
|
|
335
344
|
score += 1;
|
|
336
345
|
}
|
|
346
|
+
if (typeof binding.scoped_data_key === 'string' && binding.scoped_data_key.length > 0) {
|
|
347
|
+
score += 1;
|
|
348
|
+
}
|
|
337
349
|
return score;
|
|
338
350
|
}
|
|
339
351
|
/**
|
|
@@ -29,6 +29,7 @@ export function buildPageOwnerContext({ componentOccurrences, sourceFile, pageOw
|
|
|
29
29
|
state_index: number | null;
|
|
30
30
|
component_instance: string | null;
|
|
31
31
|
component_binding: string | null;
|
|
32
|
+
scoped_data_key: string | null;
|
|
32
33
|
}>;
|
|
33
34
|
signals: Array<{
|
|
34
35
|
id?: number;
|