@bleedingdev/modern-js-app-tools-extensions 3.9.0-ultramodern.9 → 3.9.3-ultramodern.10
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/cjs/backend-federation-build/codegen.js +29 -18
- package/dist/cjs/backend-federation-build/config.js +84 -45
- package/dist/cjs/backend-federation-build/emit.js +63 -22
- package/dist/cjs/build-config/build-environment.js +30 -165
- package/dist/cjs/build-config/internal-effect-discovery.js +231 -0
- package/dist/cjs/build-config/public.js +2 -5
- package/dist/cjs/build-config/remote-address.js +58 -0
- package/dist/cjs/cloudflare/artifacts.js +8 -19
- package/dist/cjs/cloudflare/delivery-unit.js +125 -43
- package/dist/cjs/cloudflare/index.js +14 -4
- package/dist/cjs/cloudflare/native-renderer.js +100 -0
- package/dist/cjs/cloudflare/renderer-identity.js +106 -0
- package/dist/cjs/cloudflare/worker-manifest.js +54 -13
- package/dist/cjs/cloudflare/worker-options.js +48 -0
- package/dist/cjs/cloudflare/wrangler-config.js +210 -13
- package/dist/cjs/cloudflare-builder.js +307 -89
- package/dist/cjs/cloudflare-output-contract.js +36 -4
- package/dist/cjs/cloudflare-output-verifier/identity.js +112 -23
- package/dist/cjs/cloudflare-output-verifier/index.js +10 -0
- package/dist/cjs/cloudflare-output-verifier/manifest.js +46 -0
- package/dist/cjs/cloudflare-output-verifier/mutation-policy.js +7 -1
- package/dist/cjs/cloudflare-output-verifier/worker-bundles.js +10 -5
- package/dist/cjs/config.js +10 -5
- package/dist/cjs/deploy-output/npmAliases.js +92 -6
- package/dist/cjs/deploy-output/plugin.js +27 -6
- package/dist/cjs/deploy-output/public-assets.js +146 -0
- package/dist/cjs/deploy-output/target.js +57 -1
- package/dist/cjs/deploy-output/trace-files.js +99 -0
- package/dist/cjs/module-federation-config/exposes.js +70 -0
- package/dist/cjs/module-federation-config/index.js +73 -0
- package/dist/cjs/module-federation-config/inspect.js +103 -0
- package/dist/cjs/module-federation-config/object-literal.js +87 -0
- package/dist/cjs/module-federation-config/syntax.js +151 -0
- package/dist/cjs/module-federation-config/types.js +18 -0
- package/dist/cjs/native-type-checker.js +180 -17
- package/dist/cjs/policy-defaults.js +38 -29
- package/dist/cjs/release-envelope/canonical.js +2 -9
- package/dist/cjs/release-envelope/contract.js +68 -0
- package/dist/cjs/release-envelope/framework-output.js +296 -105
- package/dist/cjs/release-envelope/index.js +150 -36
- package/dist/cjs/release-envelope/plugin.js +24 -15
- package/dist/cjs/release-envelope/renderer-output-stamp.js +170 -0
- package/dist/cjs/release-envelope/types.js +10 -8
- package/dist/cjs/release-identity.js +9 -6
- package/dist/cjs/renderer-build-identity.js +144 -0
- package/dist/cjs/templates/cloudflare-entry.001-bootstrap-security.mjs +14 -6
- package/dist/cjs/templates/cloudflare-entry.002-assets-routes.mjs +10 -2
- package/dist/cjs/templates/cloudflare-entry.004-rendering-css.mjs +403 -96
- package/dist/cjs/templates/cloudflare-entry.005-worker-dispatch.mjs +547 -103
- package/dist/cjs/templates/cloudflare-entry.006-fetch-handler.mjs +26 -7
- package/dist/cjs/templates/cloudflare-worker-route-data.mjs +1069 -0
- package/dist/cjs/workspace-topology.js +84 -0
- package/dist/esm/backend-federation-build/codegen.mjs +29 -18
- package/dist/esm/backend-federation-build/config.mjs +74 -38
- package/dist/esm/backend-federation-build/emit.mjs +64 -23
- package/dist/esm/build-config/build-environment.mjs +31 -163
- package/dist/esm/build-config/internal-effect-discovery.mjs +187 -0
- package/dist/esm/build-config/public.mjs +1 -1
- package/dist/esm/build-config/remote-address.mjs +20 -0
- package/dist/esm/cloudflare/artifacts.mjs +8 -19
- package/dist/esm/cloudflare/delivery-unit.mjs +124 -45
- package/dist/esm/cloudflare/index.mjs +15 -5
- package/dist/esm/cloudflare/native-renderer.mjs +48 -0
- package/dist/esm/cloudflare/renderer-identity.mjs +57 -0
- package/dist/esm/cloudflare/worker-manifest.mjs +55 -14
- package/dist/esm/cloudflare/worker-options.mjs +10 -0
- package/dist/esm/cloudflare/wrangler-config.mjs +203 -12
- package/dist/esm/cloudflare-builder.mjs +301 -89
- package/dist/esm/cloudflare-output-contract.mjs +29 -3
- package/dist/esm/cloudflare-output-verifier/identity.mjs +113 -24
- package/dist/esm/cloudflare-output-verifier/index.mjs +10 -0
- package/dist/esm/cloudflare-output-verifier/manifest.mjs +46 -0
- package/dist/esm/cloudflare-output-verifier/mutation-policy.mjs +7 -1
- package/dist/esm/cloudflare-output-verifier/worker-bundles.mjs +11 -6
- package/dist/esm/config.mjs +3 -1
- package/dist/esm/deploy-output/npmAliases.mjs +92 -6
- package/dist/esm/deploy-output/plugin.mjs +24 -6
- package/dist/esm/deploy-output/public-assets.mjs +82 -0
- package/dist/esm/deploy-output/target.mjs +50 -3
- package/dist/esm/deploy-output/trace-files.mjs +47 -0
- package/dist/esm/module-federation-config/exposes.mjs +18 -0
- package/dist/esm/module-federation-config/index.mjs +4 -0
- package/dist/esm/module-federation-config/inspect.mjs +65 -0
- package/dist/esm/module-federation-config/object-literal.mjs +43 -0
- package/dist/esm/module-federation-config/syntax.mjs +101 -0
- package/dist/esm/module-federation-config/types.mjs +0 -0
- package/dist/esm/native-type-checker.mjs +175 -18
- package/dist/esm/policy-defaults.mjs +36 -30
- package/dist/esm/release-envelope/canonical.mjs +2 -9
- package/dist/esm/release-envelope/contract.mjs +21 -0
- package/dist/esm/release-envelope/framework-output.mjs +297 -106
- package/dist/esm/release-envelope/index.mjs +149 -38
- package/dist/esm/release-envelope/plugin.mjs +24 -15
- package/dist/esm/release-envelope/renderer-output-stamp.mjs +112 -0
- package/dist/esm/release-envelope/types.mjs +2 -3
- package/dist/esm/release-identity.mjs +9 -6
- package/dist/esm/renderer-build-identity.mjs +92 -0
- package/dist/esm/templates/cloudflare-entry.001-bootstrap-security.mjs +14 -6
- package/dist/esm/templates/cloudflare-entry.002-assets-routes.mjs +10 -2
- package/dist/esm/templates/cloudflare-entry.004-rendering-css.mjs +403 -96
- package/dist/esm/templates/cloudflare-entry.005-worker-dispatch.mjs +547 -103
- package/dist/esm/templates/cloudflare-entry.006-fetch-handler.mjs +26 -7
- package/dist/esm/templates/cloudflare-worker-route-data.mjs +1069 -0
- package/dist/esm/workspace-topology.mjs +21 -0
- package/dist/esm-node/backend-federation-build/codegen.mjs +29 -18
- package/dist/esm-node/backend-federation-build/config.mjs +74 -38
- package/dist/esm-node/backend-federation-build/emit.mjs +64 -23
- package/dist/esm-node/build-config/build-environment.mjs +31 -163
- package/dist/esm-node/build-config/internal-effect-discovery.mjs +188 -0
- package/dist/esm-node/build-config/public.mjs +1 -1
- package/dist/esm-node/build-config/remote-address.mjs +21 -0
- package/dist/esm-node/cloudflare/artifacts.mjs +8 -19
- package/dist/esm-node/cloudflare/delivery-unit.mjs +124 -45
- package/dist/esm-node/cloudflare/index.mjs +15 -5
- package/dist/esm-node/cloudflare/native-renderer.mjs +49 -0
- package/dist/esm-node/cloudflare/renderer-identity.mjs +58 -0
- package/dist/esm-node/cloudflare/worker-manifest.mjs +55 -14
- package/dist/esm-node/cloudflare/worker-options.mjs +11 -0
- package/dist/esm-node/cloudflare/wrangler-config.mjs +203 -12
- package/dist/esm-node/cloudflare-builder.mjs +301 -89
- package/dist/esm-node/cloudflare-output-contract.mjs +29 -3
- package/dist/esm-node/cloudflare-output-verifier/identity.mjs +113 -24
- package/dist/esm-node/cloudflare-output-verifier/index.mjs +10 -0
- package/dist/esm-node/cloudflare-output-verifier/manifest.mjs +46 -0
- package/dist/esm-node/cloudflare-output-verifier/mutation-policy.mjs +7 -1
- package/dist/esm-node/cloudflare-output-verifier/worker-bundles.mjs +11 -6
- package/dist/esm-node/config.mjs +3 -1
- package/dist/esm-node/deploy-output/npmAliases.mjs +92 -6
- package/dist/esm-node/deploy-output/plugin.mjs +24 -6
- package/dist/esm-node/deploy-output/public-assets.mjs +83 -0
- package/dist/esm-node/deploy-output/target.mjs +50 -3
- package/dist/esm-node/deploy-output/trace-files.mjs +48 -0
- package/dist/esm-node/module-federation-config/exposes.mjs +19 -0
- package/dist/esm-node/module-federation-config/index.mjs +5 -0
- package/dist/esm-node/module-federation-config/inspect.mjs +66 -0
- package/dist/esm-node/module-federation-config/object-literal.mjs +44 -0
- package/dist/esm-node/module-federation-config/syntax.mjs +102 -0
- package/dist/esm-node/module-federation-config/types.mjs +1 -0
- package/dist/esm-node/native-type-checker.mjs +175 -18
- package/dist/esm-node/policy-defaults.mjs +36 -30
- package/dist/esm-node/release-envelope/canonical.mjs +2 -9
- package/dist/esm-node/release-envelope/contract.mjs +22 -0
- package/dist/esm-node/release-envelope/framework-output.mjs +297 -106
- package/dist/esm-node/release-envelope/index.mjs +149 -38
- package/dist/esm-node/release-envelope/plugin.mjs +24 -15
- package/dist/esm-node/release-envelope/renderer-output-stamp.mjs +113 -0
- package/dist/esm-node/release-envelope/types.mjs +2 -3
- package/dist/esm-node/release-identity.mjs +9 -6
- package/dist/esm-node/renderer-build-identity.mjs +93 -0
- package/dist/esm-node/templates/cloudflare-entry.001-bootstrap-security.mjs +14 -6
- package/dist/esm-node/templates/cloudflare-entry.002-assets-routes.mjs +10 -2
- package/dist/esm-node/templates/cloudflare-entry.004-rendering-css.mjs +403 -96
- package/dist/esm-node/templates/cloudflare-entry.005-worker-dispatch.mjs +547 -103
- package/dist/esm-node/templates/cloudflare-entry.006-fetch-handler.mjs +26 -7
- package/dist/esm-node/templates/cloudflare-worker-route-data.mjs +1069 -0
- package/dist/esm-node/workspace-topology.mjs +22 -0
- package/dist/types/backend-federation-build/codegen.d.ts +30 -0
- package/dist/types/backend-federation-build/config.d.ts +10 -57
- package/dist/types/backend-federation-build/emit.d.ts +12 -2
- package/dist/types/backend-federation-build/index.d.ts +1 -1
- package/dist/types/build-config/build-environment.d.ts +4 -10
- package/dist/types/build-config/internal-effect-discovery.d.ts +6 -0
- package/dist/types/build-config/public.d.ts +1 -1
- package/dist/types/build-config/remote-address.d.ts +3 -0
- package/dist/types/cloudflare/artifacts.d.ts +7 -6
- package/dist/types/cloudflare/constants.d.ts +1 -1
- package/dist/types/cloudflare/delivery-unit.d.ts +38 -7
- package/dist/types/cloudflare/native-renderer.d.ts +30 -0
- package/dist/types/cloudflare/renderer-identity.d.ts +25 -0
- package/dist/types/cloudflare/worker-manifest.d.ts +20 -4
- package/dist/types/cloudflare/worker-options.d.ts +20 -0
- package/dist/types/cloudflare/wrangler-config.d.ts +55 -2
- package/dist/types/cloudflare-builder.d.ts +51 -8
- package/dist/types/cloudflare-output-contract.d.ts +5 -3
- package/dist/types/cloudflare-output-verifier/identity.d.ts +7 -3
- package/dist/types/cloudflare-output-verifier/worker-bundles.d.ts +2 -2
- package/dist/types/config.d.ts +102 -13
- package/dist/types/deploy-output/plugin.d.ts +29 -9
- package/dist/types/deploy-output/public-assets.d.ts +51 -0
- package/dist/types/deploy-output/target.d.ts +28 -5
- package/dist/types/deploy-output/trace-files.d.ts +17 -0
- package/dist/types/module-federation-config/exposes.d.ts +11 -0
- package/dist/types/module-federation-config/index.d.ts +5 -0
- package/dist/types/module-federation-config/inspect.d.ts +2 -0
- package/dist/types/module-federation-config/object-literal.d.ts +4 -0
- package/dist/types/module-federation-config/syntax.d.ts +7 -0
- package/dist/types/module-federation-config/types.d.ts +20 -0
- package/dist/types/native-type-checker.d.ts +28 -3
- package/dist/types/policy-defaults.d.ts +12 -2
- package/dist/types/release-envelope/canonical.d.ts +5 -5
- package/dist/types/release-envelope/contract.d.mts +8 -0
- package/dist/types/release-envelope/framework-output.d.ts +23 -13
- package/dist/types/release-envelope/index.d.ts +17 -5
- package/dist/types/release-envelope/plugin.d.ts +10 -6
- package/dist/types/release-envelope/renderer-output-stamp.d.ts +34 -0
- package/dist/types/release-envelope/types.d.ts +42 -4
- package/dist/types/release-identity.d.ts +13 -2
- package/dist/types/renderer-build-identity.d.ts +41 -0
- package/dist/types/templates/cloudflare-worker-route-data.d.mts +14 -0
- package/dist/types/workspace-topology.d.ts +91 -0
- package/package.json +87 -27
- package/src/backend-federation-build/codegen.ts +28 -19
- package/src/backend-federation-build/config.ts +189 -123
- package/src/backend-federation-build/emit.ts +119 -38
- package/src/backend-federation-build/index.ts +4 -1
- package/src/build-config/build-environment.ts +69 -293
- package/src/build-config/internal-effect-discovery.ts +458 -0
- package/src/build-config/public.ts +0 -1
- package/src/build-config/remote-address.ts +33 -0
- package/src/cloudflare/artifacts.ts +22 -43
- package/src/cloudflare/delivery-unit.ts +283 -60
- package/src/cloudflare/index.ts +35 -19
- package/src/cloudflare/native-renderer.ts +117 -0
- package/src/cloudflare/renderer-identity.ts +171 -0
- package/src/cloudflare/worker-manifest.ts +115 -13
- package/src/cloudflare/worker-options.ts +60 -0
- package/src/cloudflare/wrangler-config.ts +390 -14
- package/src/cloudflare-builder.ts +543 -170
- package/src/cloudflare-output-contract.ts +45 -2
- package/src/cloudflare-output-verifier/identity.ts +138 -7
- package/src/cloudflare-output-verifier/index.ts +20 -0
- package/src/cloudflare-output-verifier/manifest.ts +77 -0
- package/src/cloudflare-output-verifier/mutation-policy.ts +11 -1
- package/src/cloudflare-output-verifier/worker-bundles.ts +27 -11
- package/src/config.ts +105 -19
- package/src/deploy-output/npmAliases.ts +141 -4
- package/src/deploy-output/plugin.ts +55 -18
- package/src/deploy-output/public-assets.ts +224 -0
- package/src/deploy-output/target.ts +97 -14
- package/src/deploy-output/trace-files.ts +80 -0
- package/src/module-federation-config/exposes.ts +46 -0
- package/src/module-federation-config/index.ts +22 -0
- package/src/module-federation-config/inspect.ts +157 -0
- package/src/module-federation-config/object-literal.ts +76 -0
- package/src/module-federation-config/syntax.ts +212 -0
- package/src/module-federation-config/types.ts +22 -0
- package/src/native-type-checker.ts +284 -27
- package/src/policy-defaults.ts +47 -17
- package/src/release-envelope/canonical.ts +6 -18
- package/src/release-envelope/contract.mjs +28 -0
- package/src/release-envelope/framework-output.ts +681 -156
- package/src/release-envelope/index.ts +315 -60
- package/src/release-envelope/plugin.ts +54 -38
- package/src/release-envelope/renderer-output-stamp.ts +210 -0
- package/src/release-envelope/types.ts +75 -6
- package/src/release-identity.ts +30 -4
- package/src/renderer-build-identity.ts +208 -0
- package/src/templates/cloudflare-entry.001-bootstrap-security.mjs +14 -6
- package/src/templates/cloudflare-entry.002-assets-routes.mjs +10 -2
- package/src/templates/cloudflare-entry.004-rendering-css.mjs +403 -96
- package/src/templates/cloudflare-entry.005-worker-dispatch.mjs +547 -103
- package/src/templates/cloudflare-entry.006-fetch-handler.mjs +26 -7
- package/src/templates/cloudflare-worker-route-data.mjs +1069 -0
- package/src/workspace-topology.ts +125 -0
- package/dist/cjs/templates/cloudflare-worker-fs-promises.mjs +0 -11
- package/dist/cjs/templates/cloudflare-worker-loadable-server.mjs +0 -281
- package/dist/cjs/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
- package/dist/cjs/templates/cloudflare-worker-path.mjs +0 -98
- package/dist/esm/templates/cloudflare-worker-fs-promises.mjs +0 -11
- package/dist/esm/templates/cloudflare-worker-loadable-server.mjs +0 -281
- package/dist/esm/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
- package/dist/esm/templates/cloudflare-worker-path.mjs +0 -98
- package/dist/esm-node/templates/cloudflare-worker-fs-promises.mjs +0 -11
- package/dist/esm-node/templates/cloudflare-worker-loadable-server.mjs +0 -281
- package/dist/esm-node/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
- package/dist/esm-node/templates/cloudflare-worker-path.mjs +0 -98
- package/dist/types/templates/cloudflare-worker-fs-promises.d.mts +0 -5
- package/dist/types/templates/cloudflare-worker-loadable-server.d.mts +0 -48
- package/dist/types/templates/cloudflare-worker-mf-ssr-runtime-plugin.d.mts +0 -13
- package/dist/types/templates/cloudflare-worker-path.d.mts +0 -21
- package/src/templates/cloudflare-worker-fs-promises.mjs +0 -11
- package/src/templates/cloudflare-worker-loadable-server.mjs +0 -281
- package/src/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
- package/src/templates/cloudflare-worker-path.mjs +0 -98
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
4
|
+
import {
|
|
5
|
+
formatBackendFederationValidationErrors,
|
|
6
|
+
type RendererIdentity,
|
|
7
|
+
validateRendererIdentity,
|
|
8
|
+
validateRendererProfile,
|
|
9
|
+
} from '@modern-js/backend-federation-contracts';
|
|
10
|
+
import type { DeliveryUnitStamp } from './delivery-unit';
|
|
11
|
+
import { isRecord } from './utils';
|
|
12
|
+
|
|
13
|
+
export type WorkerRendererIdentities = Readonly<
|
|
14
|
+
Record<string, RendererIdentity>
|
|
15
|
+
>;
|
|
16
|
+
|
|
17
|
+
/** The built renderer and how its adapter serves worker documents. */
|
|
18
|
+
export interface WorkerRenderer {
|
|
19
|
+
readonly name: string;
|
|
20
|
+
/** Documents come only from the renderer's native server handler. */
|
|
21
|
+
readonly nativeDocuments: boolean;
|
|
22
|
+
readonly rsc: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface WorkerRendererBuild {
|
|
26
|
+
readonly renderer: WorkerRenderer;
|
|
27
|
+
readonly identities: WorkerRendererIdentities;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Bind response metadata to the finalized build and its generated entries. */
|
|
31
|
+
export async function readWorkerRendererBuild(
|
|
32
|
+
distDirectory: string,
|
|
33
|
+
routes: readonly {
|
|
34
|
+
entryName?: unknown;
|
|
35
|
+
entryPath?: unknown;
|
|
36
|
+
isApi?: unknown;
|
|
37
|
+
isSSR?: unknown;
|
|
38
|
+
worker?: unknown;
|
|
39
|
+
bundle?: unknown;
|
|
40
|
+
isRSC?: unknown;
|
|
41
|
+
isStream?: unknown;
|
|
42
|
+
}[],
|
|
43
|
+
deliveryUnit?: DeliveryUnitStamp,
|
|
44
|
+
): Promise<WorkerRendererBuild | undefined> {
|
|
45
|
+
let bytes: string;
|
|
46
|
+
try {
|
|
47
|
+
bytes = await fs.readFile(
|
|
48
|
+
path.join(distDirectory, 'renderer-build.json'),
|
|
49
|
+
'utf8',
|
|
50
|
+
);
|
|
51
|
+
} catch (error) {
|
|
52
|
+
if (error instanceof Error && 'code' in error && error.code === 'ENOENT')
|
|
53
|
+
return undefined;
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
const build: unknown = JSON.parse(bytes);
|
|
57
|
+
if (
|
|
58
|
+
!isRecord(build) ||
|
|
59
|
+
build.schema !== 'ultramodern-renderer-build' ||
|
|
60
|
+
build.version !== 2 ||
|
|
61
|
+
typeof build.buildId !== 'string' ||
|
|
62
|
+
!/^[a-f0-9]{64}$/u.test(build.buildId) ||
|
|
63
|
+
!isRecord(build.profile) ||
|
|
64
|
+
build.renderer !== build.profile.renderer ||
|
|
65
|
+
!isRecord(build.worker) ||
|
|
66
|
+
typeof build.worker.nativeDocuments !== 'boolean' ||
|
|
67
|
+
typeof build.worker.rsc !== 'boolean' ||
|
|
68
|
+
!isRecord(build.entries) ||
|
|
69
|
+
!Object.keys(build.entries).length
|
|
70
|
+
)
|
|
71
|
+
throw new Error(
|
|
72
|
+
'Invalid or outdated renderer-build.json for the Cloudflare worker; rebuild the application.',
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
// The SDK profile also carries compiler configuration. Only the neutral
|
|
76
|
+
// renderer protocol fields belong to the worker response binding.
|
|
77
|
+
const { renderer, protocolVersion, compiler, hydration, router } =
|
|
78
|
+
build.profile;
|
|
79
|
+
const validation = validateRendererProfile({
|
|
80
|
+
renderer,
|
|
81
|
+
protocolVersion,
|
|
82
|
+
compiler,
|
|
83
|
+
hydration,
|
|
84
|
+
router,
|
|
85
|
+
});
|
|
86
|
+
if (!validation.ok)
|
|
87
|
+
throw new Error(formatBackendFederationValidationErrors(validation.errors));
|
|
88
|
+
|
|
89
|
+
const identities: Record<string, RendererIdentity> = {};
|
|
90
|
+
let appId: string | undefined;
|
|
91
|
+
for (const [entryName, value] of Object.entries(build.entries)) {
|
|
92
|
+
const validation = validateRendererIdentity(value);
|
|
93
|
+
if (!validation.ok)
|
|
94
|
+
throw new Error(
|
|
95
|
+
formatBackendFederationValidationErrors(validation.errors),
|
|
96
|
+
);
|
|
97
|
+
const identity = value as RendererIdentity;
|
|
98
|
+
if (
|
|
99
|
+
entryName === '__proto__' ||
|
|
100
|
+
identity.entryName !== entryName ||
|
|
101
|
+
identity.renderer !== renderer ||
|
|
102
|
+
identity.protocolVersion !== protocolVersion ||
|
|
103
|
+
identity.buildId !== build.buildId ||
|
|
104
|
+
(appId !== undefined && identity.appId !== appId)
|
|
105
|
+
)
|
|
106
|
+
throw new Error(
|
|
107
|
+
'Cloudflare renderer entry identity conflicts with its built manifest',
|
|
108
|
+
);
|
|
109
|
+
appId = identity.appId;
|
|
110
|
+
identities[entryName] = Object.freeze({ ...identity });
|
|
111
|
+
}
|
|
112
|
+
for (const route of routes) {
|
|
113
|
+
// Native public routes name a copied file rather than a renderer entry.
|
|
114
|
+
// Classify the original route shape so application dispatch markers cannot
|
|
115
|
+
// be erased by the worker manifest's normalization.
|
|
116
|
+
if (
|
|
117
|
+
route.isSSR === false &&
|
|
118
|
+
route.entryName === undefined &&
|
|
119
|
+
route.worker === undefined &&
|
|
120
|
+
route.bundle === undefined &&
|
|
121
|
+
(route.isRSC === undefined || route.isRSC === false) &&
|
|
122
|
+
(route.isStream === undefined || route.isStream === false) &&
|
|
123
|
+
typeof route.entryPath === 'string' &&
|
|
124
|
+
route.entryPath.startsWith('public/') &&
|
|
125
|
+
!route.entryPath.includes('\\') &&
|
|
126
|
+
path.posix.normalize(route.entryPath) === route.entryPath
|
|
127
|
+
) {
|
|
128
|
+
const asset = await fs.stat(path.join(distDirectory, route.entryPath));
|
|
129
|
+
if (asset.isFile()) continue;
|
|
130
|
+
}
|
|
131
|
+
// The BFF prefix route is served by the API worker, never a renderer
|
|
132
|
+
// entry; it carries no document, bundle or dispatch marker.
|
|
133
|
+
if (
|
|
134
|
+
route.isApi === true &&
|
|
135
|
+
route.isSSR === false &&
|
|
136
|
+
route.entryName === undefined &&
|
|
137
|
+
route.entryPath === '' &&
|
|
138
|
+
route.worker === undefined &&
|
|
139
|
+
route.bundle === undefined &&
|
|
140
|
+
(route.isRSC === undefined || route.isRSC === false) &&
|
|
141
|
+
(route.isStream === undefined || route.isStream === false)
|
|
142
|
+
)
|
|
143
|
+
continue;
|
|
144
|
+
if (
|
|
145
|
+
typeof route.entryName !== 'string' ||
|
|
146
|
+
!Object.hasOwn(identities, route.entryName)
|
|
147
|
+
)
|
|
148
|
+
throw new Error(
|
|
149
|
+
`Cloudflare generated route has no built renderer identity for ${String(route.entryName)}`,
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
const ui = deliveryUnit?.surfaces.ui;
|
|
153
|
+
if (
|
|
154
|
+
ui &&
|
|
155
|
+
!isDeepStrictEqual(
|
|
156
|
+
identities[ui.rendererIdentity.entryName],
|
|
157
|
+
ui.rendererIdentity,
|
|
158
|
+
)
|
|
159
|
+
)
|
|
160
|
+
throw new Error(
|
|
161
|
+
'Cloudflare built renderer identity conflicts with its finalized delivery unit',
|
|
162
|
+
);
|
|
163
|
+
return Object.freeze({
|
|
164
|
+
renderer: Object.freeze({
|
|
165
|
+
name: renderer as string,
|
|
166
|
+
nativeDocuments: build.worker.nativeDocuments,
|
|
167
|
+
rsc: build.worker.rsc,
|
|
168
|
+
}),
|
|
169
|
+
identities: Object.freeze(identities),
|
|
170
|
+
});
|
|
171
|
+
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
BffEffectDataPlatformUserConfig,
|
|
4
|
+
BffEffectOpenApiUserConfig,
|
|
5
|
+
} from '@modern-js/server-runtime-extensions/server-config';
|
|
3
6
|
import { fs as fse } from '@modern-js/utils';
|
|
7
|
+
import { getCloudflareWorkerRouteDataEntryName } from '../cloudflare-output-contract';
|
|
4
8
|
import { readRouteSpec } from './artifacts';
|
|
5
9
|
import {
|
|
6
10
|
ASSETS_BINDING,
|
|
@@ -21,12 +25,16 @@ import {
|
|
|
21
25
|
} from './constants';
|
|
22
26
|
import type { DeliveryUnitStamp } from './delivery-unit';
|
|
23
27
|
import { createI18nWorkerManifest } from './i18n-worker';
|
|
28
|
+
import { readNativeRendererWorkerResources } from './native-renderer';
|
|
29
|
+
import { readWorkerRendererBuild } from './renderer-identity';
|
|
24
30
|
import { createCloudflareWorkerSecurityPolicy } from './security-policies';
|
|
25
31
|
import type { CloudflareAppContext, CloudflareModernConfig } from './types';
|
|
26
32
|
import { isRecord, normalizeRelativePath } from './utils';
|
|
27
33
|
import {
|
|
28
34
|
createWorkerManifestServiceBindings,
|
|
29
35
|
createWorkerServiceBindings,
|
|
36
|
+
createWorkerVpcServiceBindings,
|
|
37
|
+
getWorkerEffectBffPrefix,
|
|
30
38
|
} from './wrangler-config';
|
|
31
39
|
|
|
32
40
|
const createMissingEffectBffWorkerError = (
|
|
@@ -66,8 +74,9 @@ const createEffectBffWorkerManifest = (
|
|
|
66
74
|
},
|
|
67
75
|
};
|
|
68
76
|
|
|
69
|
-
const openapi = bff?.effect?.openapi;
|
|
70
|
-
const dataPlatform =
|
|
77
|
+
const openapi: BffEffectOpenApiUserConfig | undefined = bff?.effect?.openapi;
|
|
78
|
+
const dataPlatform: BffEffectDataPlatformUserConfig | undefined =
|
|
79
|
+
bff?.effect?.dataPlatform;
|
|
71
80
|
|
|
72
81
|
return {
|
|
73
82
|
...(openapi === undefined ? {} : { openapi }),
|
|
@@ -118,7 +127,38 @@ const createModuleFederationWorkerManifest = async (
|
|
|
118
127
|
];
|
|
119
128
|
});
|
|
120
129
|
|
|
121
|
-
|
|
130
|
+
if (!name || exposes.length === 0) return undefined;
|
|
131
|
+
|
|
132
|
+
// A fragment is rendered by this app's own route, so it depends on the
|
|
133
|
+
// route stylesheets too (for example a global Tailwind sheet no exposed
|
|
134
|
+
// component imports). Bundle them so the worker reports them to the
|
|
135
|
+
// composing shell without reading assets at request time.
|
|
136
|
+
const routeManifestPath = path.join(
|
|
137
|
+
outputDirectory,
|
|
138
|
+
PUBLIC_ASSETS_DIRECTORY,
|
|
139
|
+
ROUTE_MANIFEST_FILE,
|
|
140
|
+
);
|
|
141
|
+
const routeManifest = (await fse.pathExists(routeManifestPath))
|
|
142
|
+
? ((await fse.readJson(routeManifestPath)) as unknown)
|
|
143
|
+
: undefined;
|
|
144
|
+
const routeAssets =
|
|
145
|
+
isRecord(routeManifest) && isRecord(routeManifest.routeAssets)
|
|
146
|
+
? Object.values(routeManifest.routeAssets).filter(isRecord)
|
|
147
|
+
: [];
|
|
148
|
+
const routeCss = [
|
|
149
|
+
...new Set(
|
|
150
|
+
routeAssets.flatMap(routeAsset =>
|
|
151
|
+
[routeAsset.referenceCssAssets, routeAsset.assets]
|
|
152
|
+
.flatMap(value => (Array.isArray(value) ? value : []))
|
|
153
|
+
.filter(
|
|
154
|
+
(asset): asset is string =>
|
|
155
|
+
typeof asset === 'string' && asset.endsWith('.css'),
|
|
156
|
+
),
|
|
157
|
+
),
|
|
158
|
+
),
|
|
159
|
+
];
|
|
160
|
+
|
|
161
|
+
return { name, exposes, routeCss };
|
|
122
162
|
};
|
|
123
163
|
|
|
124
164
|
export const createWorkerManifest = async (
|
|
@@ -132,6 +172,15 @@ export const createWorkerManifest = async (
|
|
|
132
172
|
routeSpec.routes.map(async (route: Record<string, any>) => {
|
|
133
173
|
const worker =
|
|
134
174
|
typeof route.worker === 'string' ? route.worker : undefined;
|
|
175
|
+
const routeDataWorker =
|
|
176
|
+
route.isSSR && typeof route.entryName === 'string'
|
|
177
|
+
? `${WORKER_BUNDLE_DIRECTORY}/${getCloudflareWorkerRouteDataEntryName(
|
|
178
|
+
route.entryName,
|
|
179
|
+
)}.js`
|
|
180
|
+
: undefined;
|
|
181
|
+
const hasRouteDataWorker = routeDataWorker
|
|
182
|
+
? await fse.pathExists(path.join(outputDirectory, routeDataWorker))
|
|
183
|
+
: false;
|
|
135
184
|
|
|
136
185
|
return {
|
|
137
186
|
urlPath: route.urlPath,
|
|
@@ -142,24 +191,68 @@ export const createWorkerManifest = async (
|
|
|
142
191
|
workerExists: worker
|
|
143
192
|
? await fse.pathExists(path.join(outputDirectory, worker))
|
|
144
193
|
: false,
|
|
194
|
+
...(hasRouteDataWorker ? { routeDataWorker } : {}),
|
|
195
|
+
// Native workers apply configured route headers as the Node host does.
|
|
196
|
+
...(route.responseHeaders && typeof route.responseHeaders === 'object'
|
|
197
|
+
? { responseHeaders: route.responseHeaders }
|
|
198
|
+
: {}),
|
|
145
199
|
};
|
|
146
200
|
}),
|
|
147
201
|
);
|
|
202
|
+
const rendererBuild = await readWorkerRendererBuild(
|
|
203
|
+
appContext.distDirectory,
|
|
204
|
+
routeSpec.routes,
|
|
205
|
+
deliveryUnitStamp,
|
|
206
|
+
);
|
|
207
|
+
const rendererIdentities = rendererBuild?.identities;
|
|
208
|
+
const nativeRenderer = await readNativeRendererWorkerResources(
|
|
209
|
+
appContext.distDirectory,
|
|
210
|
+
rendererBuild,
|
|
211
|
+
);
|
|
212
|
+
// Native-document renderers serve pages only through their native server
|
|
213
|
+
// handler. Fail deploy before emitting an entry that could only reject.
|
|
214
|
+
for (const route of routes) {
|
|
215
|
+
const renderer =
|
|
216
|
+
typeof route.entryName === 'string' &&
|
|
217
|
+
rendererIdentities &&
|
|
218
|
+
Object.hasOwn(rendererIdentities, route.entryName)
|
|
219
|
+
? rendererIdentities[route.entryName].renderer
|
|
220
|
+
: undefined;
|
|
221
|
+
if (
|
|
222
|
+
renderer !== undefined &&
|
|
223
|
+
rendererBuild?.renderer.nativeDocuments &&
|
|
224
|
+
(nativeRenderer?.renderer !== renderer || !route.workerExists)
|
|
225
|
+
)
|
|
226
|
+
throw new Error(
|
|
227
|
+
`Cloudflare worker deploy of the ${renderer} renderer requires its native worker build for entry ${route.entryName}. Set deploy.worker.ssr: true and rebuild with the Cloudflare deploy target.`,
|
|
228
|
+
);
|
|
229
|
+
}
|
|
148
230
|
|
|
149
|
-
const bffPrefix = modernConfig.bff?.prefix;
|
|
150
|
-
const primaryBffPrefix = Array.isArray(bffPrefix) ? bffPrefix[0] : bffPrefix;
|
|
151
231
|
const isEffectApi =
|
|
152
232
|
Boolean(modernConfig.bff) && modernConfig.bff?.runtimeFramework !== 'hono';
|
|
233
|
+
const effectBffPrefix = getWorkerEffectBffPrefix(modernConfig);
|
|
153
234
|
const effectApiWorkerExists = await fse.pathExists(
|
|
154
235
|
path.join(outputDirectory, BFF_EFFECT_WORKER_ENTRY),
|
|
155
236
|
);
|
|
237
|
+
const typedServiceBindings = createWorkerServiceBindings(
|
|
238
|
+
modernConfig,
|
|
239
|
+
undefined,
|
|
240
|
+
);
|
|
156
241
|
const serviceBindings = createWorkerManifestServiceBindings(
|
|
157
|
-
|
|
242
|
+
typedServiceBindings,
|
|
243
|
+
// The wrangler config checks VPC names against every Worker binding; the
|
|
244
|
+
// manifest only needs the framework-owned assets binding reserved.
|
|
245
|
+
createWorkerVpcServiceBindings(
|
|
246
|
+
modernConfig,
|
|
247
|
+
undefined,
|
|
248
|
+
typedServiceBindings,
|
|
249
|
+
new Set([ASSETS_BINDING]),
|
|
250
|
+
),
|
|
158
251
|
);
|
|
159
252
|
const moduleFederation =
|
|
160
253
|
await createModuleFederationWorkerManifest(outputDirectory);
|
|
161
254
|
|
|
162
|
-
if (
|
|
255
|
+
if (effectBffPrefix !== undefined && !effectApiWorkerExists) {
|
|
163
256
|
throw createMissingEffectBffWorkerError(
|
|
164
257
|
outputDirectory,
|
|
165
258
|
BFF_EFFECT_WORKER_ENTRY,
|
|
@@ -199,13 +292,17 @@ export const createWorkerManifest = async (
|
|
|
199
292
|
security: createCloudflareWorkerSecurityPolicy(modernConfig),
|
|
200
293
|
...(moduleFederation === undefined ? {} : { moduleFederation }),
|
|
201
294
|
...(deliveryUnitStamp ? { deliveryUnit: deliveryUnitStamp } : {}),
|
|
295
|
+
...(rendererBuild
|
|
296
|
+
? { renderer: rendererBuild.renderer, rendererIdentities }
|
|
297
|
+
: {}),
|
|
298
|
+
...(nativeRenderer ? { nativeRenderer } : {}),
|
|
202
299
|
i18n: createI18nWorkerManifest(routeSpec, appContext),
|
|
203
300
|
bff:
|
|
204
|
-
|
|
301
|
+
effectBffPrefix !== undefined && effectApiWorkerExists
|
|
205
302
|
? {
|
|
206
303
|
dispatcherExport: BFF_EFFECT_WORKER_DISPATCHER_EXPORT,
|
|
207
304
|
runtimeFramework: 'effect',
|
|
208
|
-
prefix:
|
|
305
|
+
prefix: effectBffPrefix,
|
|
209
306
|
worker: BFF_EFFECT_WORKER_ENTRY,
|
|
210
307
|
effect: effectBffManifest,
|
|
211
308
|
}
|
|
@@ -218,9 +315,14 @@ export const createWorkerModuleLoaders = (manifest: any) => {
|
|
|
218
315
|
const imports = new Map<string, string>();
|
|
219
316
|
|
|
220
317
|
for (const route of manifest.routeSpec.routes) {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
318
|
+
for (const worker of [
|
|
319
|
+
route.workerExists ? route.worker : undefined,
|
|
320
|
+
route.routeDataWorker,
|
|
321
|
+
]) {
|
|
322
|
+
if (worker) {
|
|
323
|
+
const importPath = `../${String(worker).replace(/^\/+/u, '')}`;
|
|
324
|
+
imports.set(worker, `() => import(${JSON.stringify(importPath)})`);
|
|
325
|
+
}
|
|
224
326
|
}
|
|
225
327
|
}
|
|
226
328
|
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { RequestHandlerOptions } from '@modern-js/server-core';
|
|
2
|
+
|
|
3
|
+
/** The native context supplied to a Cloudflare module worker's fetch method. */
|
|
4
|
+
export interface CloudflareExecutionContext {
|
|
5
|
+
waitUntil(promise: Promise<unknown>): void;
|
|
6
|
+
passThroughOnException(): void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** Worker request bindings follow the shared RequestPlatform kind/bindings shape. */
|
|
10
|
+
export interface CloudflareWorkerPlatform<Bindings extends object = object> {
|
|
11
|
+
readonly kind: 'worker';
|
|
12
|
+
/** The original env object. Direct worker invocations may omit it. */
|
|
13
|
+
readonly bindings: Bindings | undefined;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Request-owned options for manifest HTML and Flight worker handlers. */
|
|
17
|
+
export interface CloudflareWorkerRequestHandlerOptions<
|
|
18
|
+
Bindings extends object = object,
|
|
19
|
+
> extends RequestHandlerOptions {
|
|
20
|
+
readonly platform: CloudflareWorkerPlatform<Bindings>;
|
|
21
|
+
/** The original context, including its native method receivers. */
|
|
22
|
+
readonly executionContext: CloudflareExecutionContext | undefined;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Narrow native handler options without replacing their worker references. */
|
|
26
|
+
export function isCloudflareWorkerRequestHandlerOptions(
|
|
27
|
+
options: RequestHandlerOptions,
|
|
28
|
+
): options is CloudflareWorkerRequestHandlerOptions {
|
|
29
|
+
if (!('platform' in options) || !('executionContext' in options))
|
|
30
|
+
return false;
|
|
31
|
+
const platform = options.platform;
|
|
32
|
+
if (
|
|
33
|
+
platform === null ||
|
|
34
|
+
typeof platform !== 'object' ||
|
|
35
|
+
!('kind' in platform) ||
|
|
36
|
+
platform.kind !== 'worker' ||
|
|
37
|
+
!('bindings' in platform)
|
|
38
|
+
) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
const bindings = platform.bindings;
|
|
42
|
+
if (
|
|
43
|
+
bindings !== undefined &&
|
|
44
|
+
(bindings === null ||
|
|
45
|
+
typeof bindings !== 'object' ||
|
|
46
|
+
Array.isArray(bindings))
|
|
47
|
+
) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
const context = options.executionContext;
|
|
51
|
+
return (
|
|
52
|
+
context === undefined ||
|
|
53
|
+
(context !== null &&
|
|
54
|
+
typeof context === 'object' &&
|
|
55
|
+
'waitUntil' in context &&
|
|
56
|
+
typeof context.waitUntil === 'function' &&
|
|
57
|
+
'passThroughOnException' in context &&
|
|
58
|
+
typeof context.passThroughOnException === 'function')
|
|
59
|
+
);
|
|
60
|
+
}
|