@bleedingdev/modern-js-app-tools-extensions 3.9.0-ultramodern.9 → 3.9.3-ultramodern.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -0
- package/dist/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 +25 -162
- package/dist/cjs/build-config/internal-effect-discovery.js +143 -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 +130 -13
- 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 +8 -5
- package/dist/cjs/renderer-build-identity.js +134 -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 +530 -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 +26 -160
- package/dist/esm/build-config/internal-effect-discovery.mjs +102 -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 +124 -13
- 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 +8 -5
- package/dist/esm/renderer-build-identity.mjs +82 -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 +530 -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 +26 -160
- package/dist/esm-node/build-config/internal-effect-discovery.mjs +103 -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 +124 -13
- 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 +8 -5
- package/dist/esm-node/renderer-build-identity.mjs +83 -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 +530 -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 +1 -9
- package/dist/types/build-config/internal-effect-discovery.d.ts +4 -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 +17 -2
- 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 +98 -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 +26 -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 +3 -2
- package/dist/types/renderer-build-identity.d.ts +30 -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 +59 -285
- package/src/build-config/internal-effect-discovery.ts +239 -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 +108 -10
- 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 +101 -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 +233 -20
- 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 +19 -2
- package/src/renderer-build-identity.ts +168 -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 +530 -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
|
@@ -1,14 +1,34 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import promises from "node:fs/promises";
|
|
3
3
|
import node_path from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { isDeepStrictEqual } from "node:util";
|
|
5
|
+
import { BACKEND_FEDERATION_MANIFEST_FILE, BACKEND_FEDERATION_REMOTE_ENTRY_FILE, ULTRAMODERN_BUILD_ARTIFACT_FILE, ULTRAMODERN_BUILD_ARTIFACT_PATH, assertRendererProfileCompatibility, isUltramodernBuildArtifact } from "@modern-js/backend-federation-contracts";
|
|
6
|
+
import { readBuildIdentity } from "../backend-federation-build/config.mjs";
|
|
7
|
+
import { resolveTopologyDeliveryUnit, resolveTopologyReleaseRole, resolveWorkerDeliveryUnitStamp } from "../cloudflare/delivery-unit.mjs";
|
|
5
8
|
import { canonicalSerializeMicroVerticalReleaseEnvelope, createMicroVerticalReleaseEnvelope, verifyMicroVerticalReleaseEnvelope } from "./index.mjs";
|
|
9
|
+
import { SHELL_RELEASE_ENVELOPE_KIND } from "./types.mjs";
|
|
6
10
|
const MICROVERTICAL_RELEASE_ENVELOPE_PATH = 'release/microvertical-release-envelope.json';
|
|
7
11
|
const MICROVERTICAL_RELEASE_IDENTITY_CARRIERS_PATH = 'release/microvertical-release-identity-carriers.json';
|
|
8
12
|
const MICROVERTICAL_RELEASE_IDENTITY_CARRIERS_KIND = 'ultramodern-release-identity-carriers';
|
|
9
13
|
const MICROVERTICAL_RELEASE_IDENTITY_CARRIERS_SCHEMA_VERSION = 1;
|
|
10
14
|
const COMPILED_MODULE_PATTERN = /\.(?:c|m)?js$/u;
|
|
11
15
|
const EFFECT_BFF_WORKER_PATTERN = /^worker\/__modern_bff_effect\.(?:c|m)?js$/u;
|
|
16
|
+
const EFFECT_BFF_WORKER_SUPPORT_PATTERN = /^worker\/__modern_worker_(?:runtime|shared)_*\.(?:c|m)?js$/u;
|
|
17
|
+
const isEffectBffWorkerArtifact = (logicalPath)=>EFFECT_BFF_WORKER_PATTERN.test(logicalPath) || EFFECT_BFF_WORKER_SUPPORT_PATTERN.test(logicalPath);
|
|
18
|
+
const effectBffWorkerArtifacts = (files)=>files.some((logicalPath)=>EFFECT_BFF_WORKER_PATTERN.test(logicalPath)) ? files.filter(isEffectBffWorkerArtifact) : [];
|
|
19
|
+
const CRAWLER_POLICY_PATH = 'public/robots.txt';
|
|
20
|
+
const isPublicMetadataPath = (logicalPath)=>'public/_headers' === logicalPath || /^public\/\.well-known\/[^/]+\.json$/u.test(logicalPath);
|
|
21
|
+
const PUBLIC_BUILD_ARTIFACT_PATH = `public/${ULTRAMODERN_BUILD_ARTIFACT_FILE}`;
|
|
22
|
+
const DECLARED_PUBLIC_ASSET_RUNTIME = 'public-asset';
|
|
23
|
+
const resolveDeclaredPublicAssets = (files, declaredPublicAssets, target)=>{
|
|
24
|
+
const staged = new Set(files);
|
|
25
|
+
const declared = new Set();
|
|
26
|
+
for (const logicalPath of declaredPublicAssets){
|
|
27
|
+
if (!logicalPath.startsWith('public/') || !staged.has(logicalPath)) throw new Error(`[ultramodern-release-envelope] final ${target} staging has no declared public asset file ${JSON.stringify(logicalPath)}.`);
|
|
28
|
+
declared.add(logicalPath);
|
|
29
|
+
}
|
|
30
|
+
return declared;
|
|
31
|
+
};
|
|
12
32
|
const isRecord = (value)=>'object' == typeof value && null !== value && !Array.isArray(value);
|
|
13
33
|
const flattenStrings = (value)=>'string' == typeof value ? [
|
|
14
34
|
value
|
|
@@ -22,7 +42,12 @@ const collectNestedStrings = (value, key)=>{
|
|
|
22
42
|
]);
|
|
23
43
|
};
|
|
24
44
|
const emptyProducerRouteModules = async (distDirectory, files, manifest, manifestLogicalPath)=>{
|
|
25
|
-
if (!isRecord(manifest) || !Array.isArray(manifest.exposes) || 0 !== manifest.exposes.length || !Array.isArray(manifest.remotes) ||
|
|
45
|
+
if (!isRecord(manifest) || !Array.isArray(manifest.exposes) || 0 !== manifest.exposes.length || !Array.isArray(manifest.remotes) || manifest.remotes.some((remote)=>!isRecord(remote) || [
|
|
46
|
+
'federationContainerName',
|
|
47
|
+
'moduleName',
|
|
48
|
+
'alias',
|
|
49
|
+
'entry'
|
|
50
|
+
].some((key)=>'string' != typeof remote[key] || 0 === remote[key].trim().length)) || !isRecord(manifest.metaData) || !isRecord(manifest.metaData.remoteEntry) || '' !== manifest.metaData.remoteEntry.name || '' !== manifest.metaData.remoteEntry.path || 'global' !== manifest.metaData.remoteEntry.type) return [];
|
|
26
51
|
const publicPath = manifest.metaData.publicPath;
|
|
27
52
|
const safeReference = (value)=>'string' == typeof value && value.length > 0 && !/[\\\\%?#\s]/u.test(value) && !value.split('/').some((segment)=>'.' === segment || '..' === segment);
|
|
28
53
|
if (!safeReference(publicPath)) return [];
|
|
@@ -123,11 +148,14 @@ const writeReleaseEnvelope = async (artifactRoot, envelope)=>{
|
|
|
123
148
|
if (!envelopePath) throw new Error('[ultramodern-release-envelope] could not resolve release envelope path.');
|
|
124
149
|
await promises.writeFile(envelopePath, `${canonicalSerializeMicroVerticalReleaseEnvelope(envelope)}\n`);
|
|
125
150
|
};
|
|
126
|
-
const readBuildArtifact = async (distDirectory)=>{
|
|
151
|
+
const readBuildArtifact = async (distDirectory, requirePromotable = true)=>{
|
|
127
152
|
const artifactPath = node_path.join(distDirectory, ULTRAMODERN_BUILD_ARTIFACT_FILE);
|
|
128
153
|
const artifact = await readJson(artifactPath);
|
|
129
154
|
if (!isUltramodernBuildArtifact(artifact)) throw new Error(`[ultramodern-release-envelope] ${ULTRAMODERN_BUILD_ARTIFACT_FILE} is missing or invalid.`);
|
|
130
|
-
if ('workspace' === artifact.deliveryUnit.sourceRevision)
|
|
155
|
+
if ('workspace' === artifact.deliveryUnit.sourceRevision) {
|
|
156
|
+
if (!requirePromotable) return;
|
|
157
|
+
throw new Error('[ultramodern-release-envelope] sourceRevision "workspace" cannot produce a promotable envelope.');
|
|
158
|
+
}
|
|
131
159
|
return artifact;
|
|
132
160
|
};
|
|
133
161
|
const assertIdentityBlock = (value, identity, location, includeReleaseVersion)=>{
|
|
@@ -196,7 +224,7 @@ const releaseArtifact = (logicalPath, runtime)=>({
|
|
|
196
224
|
const writeReleaseIdentityCarrierMetadata = async (artifactRoot, identity, carrierPaths)=>{
|
|
197
225
|
const surfacesByPath = new Map();
|
|
198
226
|
for (const [surface, logicalPaths] of Object.entries(carrierPaths)){
|
|
199
|
-
if (0 === logicalPaths.length) throw new Error(`[ultramodern-release-envelope] ${surface} has no declared release-identity carrier artifact.`);
|
|
227
|
+
if (0 === logicalPaths.length && 'ssr' !== surface && 'uiClient' !== surface) throw new Error(`[ultramodern-release-envelope] ${surface} has no declared release-identity carrier artifact.`);
|
|
200
228
|
for (const logicalPath of logicalPaths){
|
|
201
229
|
const surfaces = surfacesByPath.get(logicalPath) ?? new Set();
|
|
202
230
|
surfaces.add(surface);
|
|
@@ -236,12 +264,14 @@ const writeReleaseIdentityCarrierMetadata = async (artifactRoot, identity, carri
|
|
|
236
264
|
}, null, 2)}\n`);
|
|
237
265
|
return releaseArtifact(MICROVERTICAL_RELEASE_IDENTITY_CARRIERS_PATH, 'release-identity-metadata');
|
|
238
266
|
};
|
|
239
|
-
const createReleaseArtifactInputs = async (distDirectory, identity, target)=>{
|
|
267
|
+
const createReleaseArtifactInputs = async (distDirectory, identity, target, apiOnly, uiOnly, shellConsumer)=>{
|
|
268
|
+
const backendProducer = !uiOnly && !shellConsumer;
|
|
240
269
|
const files = await collectFiles(distDirectory);
|
|
241
|
-
|
|
270
|
+
const effectWorkerPaths = effectBffWorkerArtifacts(files);
|
|
271
|
+
if ('node' === target && files.some(isEffectBffWorkerArtifact)) throw new Error('[ultramodern-release-envelope] Node target conflicts with a Cloudflare Effect API/BFF worker artifact; resolve the canonical deploy target instead of emitting a Node envelope for Cloudflare output.');
|
|
242
272
|
const uiClientPaths = files.filter((logicalPath)=>{
|
|
243
273
|
const topLevel = logicalPath.split('/')[0];
|
|
244
|
-
return 'static' === topLevel || 'html' === topLevel || 'public' === topLevel || [
|
|
274
|
+
return 'static' === topLevel || 'html' === topLevel || 'public' === topLevel && logicalPath !== CRAWLER_POLICY_PATH && logicalPath !== PUBLIC_BUILD_ARTIFACT_PATH && !isPublicMetadataPath(logicalPath) || [
|
|
245
275
|
'index.html',
|
|
246
276
|
'mf-manifest.json',
|
|
247
277
|
'mf-stats.json',
|
|
@@ -250,16 +280,19 @@ const createReleaseArtifactInputs = async (distDirectory, identity, target)=>{
|
|
|
250
280
|
'loadable-stats.json'
|
|
251
281
|
].includes(logicalPath);
|
|
252
282
|
});
|
|
253
|
-
const ssrPaths = 'node' === target ? files.filter((logicalPath)=>logicalPath.startsWith('bundles/') && COMPILED_MODULE_PATTERN.test(logicalPath)) : files.filter((logicalPath)=>logicalPath.startsWith('worker/') && COMPILED_MODULE_PATTERN.test(logicalPath) && !
|
|
283
|
+
const ssrPaths = 'node' === target ? files.filter((logicalPath)=>logicalPath.startsWith('bundles/') && COMPILED_MODULE_PATTERN.test(logicalPath)) : files.filter((logicalPath)=>logicalPath.startsWith('worker/') && COMPILED_MODULE_PATTERN.test(logicalPath) && !effectWorkerPaths.includes(logicalPath));
|
|
254
284
|
const nodeApiEntryPaths = files.filter((logicalPath)=>logicalPath.startsWith('api/') && COMPILED_MODULE_PATTERN.test(logicalPath));
|
|
255
|
-
const apiBackendPaths = 'node' === target ? files.filter((logicalPath)=>(logicalPath.startsWith('api/') || logicalPath.startsWith('shared/')) && COMPILED_MODULE_PATTERN.test(logicalPath)) :
|
|
256
|
-
if (0 ===
|
|
257
|
-
if (0
|
|
258
|
-
if (
|
|
259
|
-
|
|
260
|
-
if (0
|
|
261
|
-
|
|
262
|
-
|
|
285
|
+
const apiBackendPaths = 'node' === target ? files.filter((logicalPath)=>(logicalPath.startsWith('api/') || logicalPath.startsWith('shared/')) && COMPILED_MODULE_PATTERN.test(logicalPath)) : effectWorkerPaths;
|
|
286
|
+
if (backendProducer && 'cloudflare' === target && 0 === effectWorkerPaths.length) throw new Error('[ultramodern-release-envelope] cloudflare MicroVertical has no actual Effect API/BFF worker artifact.');
|
|
287
|
+
if (apiOnly && (uiClientPaths.length > 0 || ssrPaths.length > 0)) throw new Error('[ultramodern-release-envelope] API-only MicroVertical emitted an undeclared UI/client or SSR surface.');
|
|
288
|
+
if (!apiOnly && 0 === uiClientPaths.length) throw new Error(`[ultramodern-release-envelope] ${target} full-stack MicroVertical has no UI/client artifacts.`);
|
|
289
|
+
if (!apiOnly && 0 === ssrPaths.length) throw new Error(`[ultramodern-release-envelope] ${target} full-stack MicroVertical has no ${'node' === target ? 'Node' : 'workerd'} SSR artifacts.`);
|
|
290
|
+
if (uiOnly && (apiBackendPaths.length > 0 || nodeApiEntryPaths.length > 0)) throw new Error('[ultramodern-release-envelope] UI-only application emitted an undeclared API/backend artifact.');
|
|
291
|
+
if (backendProducer && ('node' === target && 0 === nodeApiEntryPaths.length || 0 === apiBackendPaths.length)) throw new Error(`[ultramodern-release-envelope] ${target} MicroVertical has no actual ${'node' === target ? 'compiled Node Effect API artifact' : 'Effect API/BFF worker artifact'}.`);
|
|
292
|
+
const clientExecutionPaths = apiOnly ? [] : await manifestReferencedClientModules(distDirectory, files);
|
|
293
|
+
if (!apiOnly && 0 === clientExecutionPaths.length) throw new Error('[ultramodern-release-envelope] UI/client manifest references no compiled execution module.');
|
|
294
|
+
const ssrExecutionPaths = apiOnly ? [] : await routeReferencedSsrModules(distDirectory, files, target);
|
|
295
|
+
if (!apiOnly && 0 === ssrExecutionPaths.length) throw new Error(`[ultramodern-release-envelope] route manifest references no emitted ${'node' === target ? 'Node' : 'Cloudflare'} SSR execution module.`);
|
|
263
296
|
const runtimeByPath = new Map();
|
|
264
297
|
const add = (paths, runtime)=>{
|
|
265
298
|
for (const logicalPath of paths){
|
|
@@ -269,14 +302,25 @@ const createReleaseArtifactInputs = async (distDirectory, identity, target)=>{
|
|
|
269
302
|
}
|
|
270
303
|
};
|
|
271
304
|
add(uiClientPaths, 'browser');
|
|
305
|
+
add(files.filter((logicalPath)=>logicalPath === CRAWLER_POLICY_PATH), 'crawler-policy');
|
|
306
|
+
add(files.filter(isPublicMetadataPath), 'public-metadata');
|
|
272
307
|
add(ssrPaths, 'node' === target ? 'nodejs' : 'workerd');
|
|
273
308
|
add(apiBackendPaths, 'node' === target ? 'nodejs' : 'workerd-effect');
|
|
274
309
|
add([
|
|
275
|
-
|
|
276
|
-
], '
|
|
277
|
-
add(
|
|
278
|
-
|
|
279
|
-
|
|
310
|
+
ULTRAMODERN_BUILD_ARTIFACT_FILE
|
|
311
|
+
], 'release-identity-metadata');
|
|
312
|
+
add(files.filter((logicalPath)=>logicalPath === PUBLIC_BUILD_ARTIFACT_PATH), 'release-identity-metadata');
|
|
313
|
+
if (backendProducer) {
|
|
314
|
+
add([
|
|
315
|
+
BACKEND_FEDERATION_MANIFEST_FILE
|
|
316
|
+
], 'module-federation-manifest');
|
|
317
|
+
add([
|
|
318
|
+
BACKEND_FEDERATION_REMOTE_ENTRY_FILE
|
|
319
|
+
], 'node' === target ? 'nodejs' : 'commonjs-module');
|
|
320
|
+
}
|
|
321
|
+
if (shellConsumer) {
|
|
322
|
+
for (const logicalPath of files)if (!runtimeByPath.has(logicalPath)) runtimeByPath.set(logicalPath, `${target}-deployment`);
|
|
323
|
+
}
|
|
280
324
|
const surfaces = {
|
|
281
325
|
uiClient: [
|
|
282
326
|
...uiClientPaths
|
|
@@ -287,20 +331,26 @@ const createReleaseArtifactInputs = async (distDirectory, identity, target)=>{
|
|
|
287
331
|
apiBackend: [
|
|
288
332
|
...apiBackendPaths
|
|
289
333
|
].sort((left, right)=>left.localeCompare(right)),
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
334
|
+
...backendProducer ? {
|
|
335
|
+
backendFederation: {
|
|
336
|
+
manifest: BACKEND_FEDERATION_MANIFEST_FILE,
|
|
337
|
+
container: BACKEND_FEDERATION_REMOTE_ENTRY_FILE
|
|
338
|
+
}
|
|
339
|
+
} : {}
|
|
294
340
|
};
|
|
295
341
|
const artifacts = [
|
|
296
342
|
...runtimeByPath
|
|
297
343
|
].map(([logicalPath, runtime])=>releaseArtifact(logicalPath, runtime)).sort((left, right)=>left.logicalPath.localeCompare(right.logicalPath));
|
|
298
344
|
const identityCarrierMetadata = await writeReleaseIdentityCarrierMetadata(distDirectory, identity, {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
345
|
+
...apiBackendPaths.length > 0 ? {
|
|
346
|
+
apiBackend: apiBackendPaths
|
|
347
|
+
} : {},
|
|
348
|
+
...backendProducer ? {
|
|
349
|
+
backendFederation: [
|
|
350
|
+
BACKEND_FEDERATION_MANIFEST_FILE,
|
|
351
|
+
BACKEND_FEDERATION_REMOTE_ENTRY_FILE
|
|
352
|
+
]
|
|
353
|
+
} : {},
|
|
304
354
|
ssr: [
|
|
305
355
|
...new Set([
|
|
306
356
|
...ssrExecutionPaths,
|
|
@@ -317,6 +367,25 @@ const createReleaseArtifactInputs = async (distDirectory, identity, target)=>{
|
|
|
317
367
|
surfaces
|
|
318
368
|
};
|
|
319
369
|
};
|
|
370
|
+
const releaseEnvelopeSurfaces = (surfaces, shellConsumer)=>{
|
|
371
|
+
if (!shellConsumer) return {
|
|
372
|
+
surfaces
|
|
373
|
+
};
|
|
374
|
+
const { uiClient, ssr, apiBackend } = surfaces;
|
|
375
|
+
return {
|
|
376
|
+
kind: SHELL_RELEASE_ENVELOPE_KIND,
|
|
377
|
+
surfaces: {
|
|
378
|
+
uiClient,
|
|
379
|
+
ssr,
|
|
380
|
+
apiBackend
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
};
|
|
384
|
+
const assertShellBuildIdentity = async (appDirectory, distDirectory)=>{
|
|
385
|
+
const source = await readBuildIdentity(appDirectory);
|
|
386
|
+
const finalized = await pathExists(node_path.join(distDirectory, ULTRAMODERN_BUILD_ARTIFACT_FILE)) ? await resolveWorkerDeliveryUnitStamp(appDirectory, distDirectory) : void 0;
|
|
387
|
+
if (!source.artifact || !finalized || finalized.unitId !== source.unitId) throw new Error('[ultramodern-release-envelope] Shell is missing its native compiled delivery-unit identity.');
|
|
388
|
+
};
|
|
320
389
|
const pathExists = async (filePath)=>{
|
|
321
390
|
try {
|
|
322
391
|
await promises.access(filePath);
|
|
@@ -325,36 +394,79 @@ const pathExists = async (filePath)=>{
|
|
|
325
394
|
return false;
|
|
326
395
|
}
|
|
327
396
|
};
|
|
328
|
-
const emitFrameworkMicroVerticalReleaseEnvelope = async ({ apiOnly, distDirectory, target })=>{
|
|
329
|
-
|
|
397
|
+
const emitFrameworkMicroVerticalReleaseEnvelope = async ({ apiOnly, appDirectory, distDirectory, requirePromotable = true, expectedRendererProfile, role, target })=>{
|
|
398
|
+
const declaredRole = appDirectory ? await resolveTopologyReleaseRole(appDirectory) : void 0;
|
|
399
|
+
if (void 0 !== role && void 0 !== declaredRole && role !== declaredRole) throw new Error('[ultramodern-release-envelope] Configured release role disagrees with the declared topology app.');
|
|
400
|
+
const shellConsumer = (declaredRole ?? role ?? 'microvertical') === 'shell';
|
|
330
401
|
const backendManifestPath = node_path.join(distDirectory, BACKEND_FEDERATION_MANIFEST_FILE);
|
|
331
402
|
const backendContainerPath = node_path.join(distDirectory, BACKEND_FEDERATION_REMOTE_ENTRY_FILE);
|
|
332
403
|
const [hasBackendManifest, hasBackendContainer] = await Promise.all([
|
|
333
404
|
pathExists(backendManifestPath),
|
|
334
405
|
pathExists(backendContainerPath)
|
|
335
406
|
]);
|
|
336
|
-
if (
|
|
337
|
-
|
|
338
|
-
|
|
407
|
+
if (shellConsumer) {
|
|
408
|
+
if (apiOnly || hasBackendManifest || hasBackendContainer || !appDirectory) throw new Error('[ultramodern-release-envelope] Shell requires a full-stack application source and cannot declare a backend federation producer.');
|
|
409
|
+
await assertShellBuildIdentity(appDirectory, distDirectory);
|
|
410
|
+
} else if (!apiOnly && !hasBackendManifest && !hasBackendContainer) {
|
|
411
|
+
const source = appDirectory ? node_path.join(appDirectory, ULTRAMODERN_BUILD_ARTIFACT_PATH) : void 0;
|
|
412
|
+
const participationPaths = [
|
|
413
|
+
node_path.join(distDirectory, ULTRAMODERN_BUILD_ARTIFACT_FILE),
|
|
414
|
+
backendManifestPath,
|
|
415
|
+
backendContainerPath,
|
|
416
|
+
...source ? [
|
|
417
|
+
source,
|
|
418
|
+
source.replace(/\.json$/u, '.ts')
|
|
419
|
+
] : []
|
|
420
|
+
];
|
|
421
|
+
const hasParticipationEntry = (await Promise.all(participationPaths.map(async (filePath)=>{
|
|
422
|
+
try {
|
|
423
|
+
await promises.lstat(filePath);
|
|
424
|
+
return true;
|
|
425
|
+
} catch (error) {
|
|
426
|
+
if (isMissingPathError(error)) return false;
|
|
427
|
+
throw error;
|
|
428
|
+
}
|
|
429
|
+
}))).some(Boolean);
|
|
430
|
+
if (!hasParticipationEntry && (!appDirectory || !await resolveTopologyDeliveryUnit(appDirectory))) return;
|
|
431
|
+
}
|
|
432
|
+
const buildArtifact = await readBuildArtifact(distDirectory, requirePromotable);
|
|
433
|
+
const declared = appDirectory && buildArtifact ? await resolveWorkerDeliveryUnitStamp(appDirectory, distDirectory) : void 0;
|
|
434
|
+
const uiOnly = Boolean(declared?.surfaces.ui && !declared.surfaces.api);
|
|
435
|
+
if (uiOnly && (apiOnly || hasBackendManifest || hasBackendContainer)) throw new Error('[ultramodern-release-envelope] UI-only application cannot declare API-only configuration or backend federation output.');
|
|
436
|
+
if (!hasBackendManifest && !hasBackendContainer && !apiOnly && !buildArtifact) return;
|
|
437
|
+
if (!shellConsumer && !uiOnly && (!hasBackendManifest || !hasBackendContainer)) throw new Error('[ultramodern-release-envelope] MicroVertical backend federation manifest and container must be emitted together.');
|
|
438
|
+
if (!buildArtifact) return;
|
|
439
|
+
const builtUi = buildArtifact.surfaces.ui;
|
|
440
|
+
if (Boolean(builtUi) === apiOnly) throw new Error('[ultramodern-release-envelope] build artifact UI surface must match the configured application surface.');
|
|
441
|
+
if (void 0 !== expectedRendererProfile) assertRendererProfileCompatibility(expectedRendererProfile, builtUi?.rendererProfile);
|
|
442
|
+
const ui = builtUi ? {
|
|
443
|
+
rendererIdentity: builtUi.rendererIdentity,
|
|
444
|
+
rendererProfile: builtUi.rendererProfile,
|
|
445
|
+
routerBindings: builtUi.routerBindings
|
|
446
|
+
} : void 0;
|
|
339
447
|
const identity = {
|
|
340
448
|
unitId: buildArtifact.deliveryUnit.unitId,
|
|
341
449
|
buildMarker: buildArtifact.deliveryUnit.buildMarker,
|
|
342
450
|
sourceRevision: buildArtifact.deliveryUnit.sourceRevision,
|
|
343
451
|
releaseVersion: buildArtifact.deliveryUnit.version
|
|
344
452
|
};
|
|
345
|
-
await readBackendManifest(distDirectory, identity);
|
|
346
|
-
const { artifacts, surfaces } = await createReleaseArtifactInputs(distDirectory, identity, target);
|
|
453
|
+
if (!shellConsumer && !uiOnly) await readBackendManifest(distDirectory, identity);
|
|
454
|
+
const { artifacts, surfaces } = await createReleaseArtifactInputs(distDirectory, identity, target, apiOnly, uiOnly, shellConsumer);
|
|
347
455
|
const envelope = await createMicroVerticalReleaseEnvelope({
|
|
348
456
|
artifactRoot: distDirectory,
|
|
349
457
|
target,
|
|
350
458
|
identity,
|
|
459
|
+
...ui ? {
|
|
460
|
+
ui
|
|
461
|
+
} : {},
|
|
351
462
|
artifacts,
|
|
352
|
-
surfaces
|
|
463
|
+
...releaseEnvelopeSurfaces(surfaces, shellConsumer)
|
|
353
464
|
});
|
|
465
|
+
await verifyBuildArtifactCarriers(distDirectory, envelope);
|
|
354
466
|
await writeReleaseEnvelope(distDirectory, envelope);
|
|
355
467
|
return envelope;
|
|
356
468
|
};
|
|
357
|
-
const readFrameworkMicroVerticalReleaseEnvelope = async ({ artifactRoot, expectedTarget, logicalPathForArtifact, required = false })=>{
|
|
469
|
+
const readFrameworkMicroVerticalReleaseEnvelope = async ({ artifactRoot, expectedTarget, logicalPathForArtifact, expectedRendererProfile, required = false })=>{
|
|
358
470
|
const envelopePath = await resolveSafeReleaseEnvelopePath({
|
|
359
471
|
artifactRoot,
|
|
360
472
|
createDirectory: false
|
|
@@ -363,30 +475,55 @@ const readFrameworkMicroVerticalReleaseEnvelope = async ({ artifactRoot, expecte
|
|
|
363
475
|
if (required) throw new Error(`[ultramodern-release-envelope] required envelope is missing at ${MICROVERTICAL_RELEASE_ENVELOPE_PATH}.`);
|
|
364
476
|
return;
|
|
365
477
|
}
|
|
366
|
-
|
|
478
|
+
const envelope = await verifyMicroVerticalReleaseEnvelope(await readJson(envelopePath), {
|
|
367
479
|
artifactRoot,
|
|
368
480
|
...expectedTarget ? {
|
|
369
481
|
expectedTarget
|
|
370
482
|
} : {},
|
|
371
483
|
...logicalPathForArtifact ? {
|
|
372
484
|
logicalPathForArtifact
|
|
485
|
+
} : {},
|
|
486
|
+
...expectedRendererProfile ? {
|
|
487
|
+
expectedRendererProfile
|
|
373
488
|
} : {}
|
|
374
489
|
});
|
|
490
|
+
await verifyBuildArtifactCarriers(artifactRoot, envelope, logicalPathForArtifact);
|
|
491
|
+
return envelope;
|
|
492
|
+
};
|
|
493
|
+
const verifyBuildArtifactCarriers = async (artifactRoot, envelope, logicalPathForArtifact)=>{
|
|
494
|
+
const carriers = envelope.artifacts.filter((artifact)=>artifact.logicalPath === ULTRAMODERN_BUILD_ARTIFACT_FILE || artifact.logicalPath === PUBLIC_BUILD_ARTIFACT_PATH);
|
|
495
|
+
if (0 === carriers.length) throw new Error('[ultramodern-release-envelope] immutable build artifact must be bound to the release envelope.');
|
|
496
|
+
for (const artifact of carriers){
|
|
497
|
+
if ('file' !== artifact.kind || 'release-identity-metadata' !== artifact.runtime) throw new Error('[ultramodern-release-envelope] immutable build artifact must be a real file with runtime "release-identity-metadata".');
|
|
498
|
+
const logicalPath = logicalPathForArtifact?.(artifact) ?? artifact.logicalPath;
|
|
499
|
+
const built = await readJson(node_path.join(artifactRoot, logicalPath));
|
|
500
|
+
if (!isUltramodernBuildArtifact(built)) throw new Error('[ultramodern-release-envelope] bound build artifact is invalid.');
|
|
501
|
+
assertIdentityBlock(built.deliveryUnit, envelope.identity, 'buildArtifact.deliveryUnit', true);
|
|
502
|
+
if (Boolean(built.surfaces.ui) !== Boolean(envelope.ui)) throw new Error('[ultramodern-release-envelope] bound build artifact UI surface differs from the release envelope.');
|
|
503
|
+
if (envelope.ui && built.surfaces.ui) {
|
|
504
|
+
if (!isDeepStrictEqual(envelope.ui.routerBindings, built.surfaces.ui.routerBindings)) throw new Error('[ultramodern-release-envelope] buildArtifact.ui.routerBindings differ from the release envelope.');
|
|
505
|
+
assertRendererProfileCompatibility(envelope.ui.rendererProfile, built.surfaces.ui.rendererProfile);
|
|
506
|
+
for (const field of [
|
|
507
|
+
'renderer',
|
|
508
|
+
'protocolVersion',
|
|
509
|
+
'appId',
|
|
510
|
+
'entryName',
|
|
511
|
+
'buildId'
|
|
512
|
+
])if (envelope.ui.rendererIdentity[field] !== built.surfaces.ui.rendererIdentity[field]) throw new Error(`[ultramodern-release-envelope] buildArtifact.ui.rendererIdentity.${field} differs from the release envelope.`);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
375
515
|
};
|
|
376
516
|
const verifyBuildOutputReleaseEnvelope = async (distDirectory, expectedTarget)=>{
|
|
377
|
-
const [hasEnvelope, hasBuildArtifact
|
|
517
|
+
const [hasEnvelope, hasBuildArtifact] = await Promise.all([
|
|
378
518
|
pathExists(node_path.join(distDirectory, MICROVERTICAL_RELEASE_ENVELOPE_PATH)),
|
|
379
|
-
pathExists(node_path.join(distDirectory, ULTRAMODERN_BUILD_ARTIFACT_FILE))
|
|
380
|
-
pathExists(node_path.join(distDirectory, BACKEND_FEDERATION_MANIFEST_FILE)),
|
|
381
|
-
pathExists(node_path.join(distDirectory, BACKEND_FEDERATION_REMOTE_ENTRY_FILE))
|
|
519
|
+
pathExists(node_path.join(distDirectory, ULTRAMODERN_BUILD_ARTIFACT_FILE))
|
|
382
520
|
]);
|
|
383
|
-
const isFullStackMicroVertical = hasBuildArtifact && (hasBackendManifest || hasBackendEntry);
|
|
384
521
|
return readFrameworkMicroVerticalReleaseEnvelope({
|
|
385
522
|
artifactRoot: distDirectory,
|
|
386
523
|
...expectedTarget ? {
|
|
387
524
|
expectedTarget
|
|
388
525
|
} : {},
|
|
389
|
-
required: hasEnvelope ||
|
|
526
|
+
required: hasEnvelope || hasBuildArtifact
|
|
390
527
|
});
|
|
391
528
|
};
|
|
392
529
|
const verifyNodeReleaseEnvelopeStaging = async ({ outputDirectory })=>readFrameworkMicroVerticalReleaseEnvelope({
|
|
@@ -394,21 +531,26 @@ const verifyNodeReleaseEnvelopeStaging = async ({ outputDirectory })=>readFramew
|
|
|
394
531
|
expectedTarget: 'node',
|
|
395
532
|
required: true
|
|
396
533
|
});
|
|
397
|
-
const createNodeStagedReleaseArtifactInputs = async (outputDirectory, identity)=>{
|
|
534
|
+
const createNodeStagedReleaseArtifactInputs = async (outputDirectory, identity, apiOnly, uiOnly, declaredPublicAssets, shellConsumer)=>{
|
|
535
|
+
const backendProducer = !uiOnly && !shellConsumer;
|
|
398
536
|
const files = await collectFiles(outputDirectory);
|
|
537
|
+
const declaredPublicAssetPaths = resolveDeclaredPublicAssets(files, declaredPublicAssets, 'Node');
|
|
399
538
|
for (const requiredPath of [
|
|
400
539
|
'index.js',
|
|
401
540
|
'package.json',
|
|
402
|
-
|
|
403
|
-
|
|
541
|
+
...backendProducer ? [
|
|
542
|
+
BACKEND_FEDERATION_MANIFEST_FILE,
|
|
543
|
+
BACKEND_FEDERATION_REMOTE_ENTRY_FILE
|
|
544
|
+
] : []
|
|
404
545
|
])if (!files.includes(requiredPath)) throw new Error(`[ultramodern-release-envelope] final Node staging is missing ${requiredPath}.`);
|
|
405
546
|
const backendFederationPaths = new Set([
|
|
406
547
|
BACKEND_FEDERATION_MANIFEST_FILE,
|
|
407
548
|
BACKEND_FEDERATION_REMOTE_ENTRY_FILE
|
|
408
549
|
]);
|
|
550
|
+
if (shellConsumer && files.some((logicalPath)=>backendFederationPaths.has(logicalPath))) throw new Error('[ultramodern-release-envelope] final Shell Node staging cannot contain a backend federation producer artifact.');
|
|
409
551
|
const uiClientPaths = files.filter((logicalPath)=>{
|
|
410
552
|
const topLevel = logicalPath.split('/')[0];
|
|
411
|
-
return 'static' === topLevel || 'html' === topLevel || 'public' === topLevel || [
|
|
553
|
+
return 'static' === topLevel || 'html' === topLevel || 'public' === topLevel && logicalPath !== CRAWLER_POLICY_PATH && logicalPath !== PUBLIC_BUILD_ARTIFACT_PATH && !isPublicMetadataPath(logicalPath) && !declaredPublicAssetPaths.has(logicalPath) || [
|
|
412
554
|
'index.html',
|
|
413
555
|
'mf-manifest.json',
|
|
414
556
|
'mf-stats.json',
|
|
@@ -419,6 +561,8 @@ const createNodeStagedReleaseArtifactInputs = async (outputDirectory, identity)=
|
|
|
419
561
|
});
|
|
420
562
|
const ssrPaths = files.filter((logicalPath)=>'index.js' === logicalPath || logicalPath.startsWith('bundles/') && COMPILED_MODULE_PATTERN.test(logicalPath));
|
|
421
563
|
const apiBackendPaths = files.filter((logicalPath)=>(logicalPath.startsWith('api/') || logicalPath.startsWith('shared/')) && COMPILED_MODULE_PATTERN.test(logicalPath));
|
|
564
|
+
if (uiOnly && (apiBackendPaths.length > 0 || files.some((logicalPath)=>backendFederationPaths.has(logicalPath)))) throw new Error('[ultramodern-release-envelope] final UI-only Node staging contains an undeclared API/backend or backend federation artifact.');
|
|
565
|
+
if (apiOnly && (uiClientPaths.length > 0 || ssrPaths.some((path)=>'index.js' !== path))) throw new Error('[ultramodern-release-envelope] final API-only Node staging contains an undeclared UI/client or SSR surface.');
|
|
422
566
|
for (const [surface, paths] of [
|
|
423
567
|
[
|
|
424
568
|
'UI/client',
|
|
@@ -426,32 +570,45 @@ const createNodeStagedReleaseArtifactInputs = async (outputDirectory, identity)=
|
|
|
426
570
|
],
|
|
427
571
|
[
|
|
428
572
|
'Node SSR',
|
|
429
|
-
ssrPaths
|
|
573
|
+
apiOnly ? [] : ssrPaths
|
|
430
574
|
],
|
|
431
575
|
[
|
|
432
576
|
'Node API/backend',
|
|
433
577
|
apiBackendPaths
|
|
434
578
|
]
|
|
435
|
-
])if (0 === paths.length) throw new Error(`[ultramodern-release-envelope] final Node staging has no ${surface} artifacts.`);
|
|
436
|
-
const clientExecutionPaths = await manifestReferencedClientModules(outputDirectory, files);
|
|
437
|
-
const ssrExecutionPaths = await routeReferencedSsrModules(outputDirectory, files, 'node');
|
|
438
|
-
if (0 === clientExecutionPaths.length || 0 === ssrExecutionPaths.length) throw new Error('[ultramodern-release-envelope] final Node manifests must reference emitted UI/client and SSR execution modules.');
|
|
579
|
+
])if (0 === paths.length && ('Node API/backend' === surface ? backendProducer : !apiOnly)) throw new Error(`[ultramodern-release-envelope] final Node staging has no ${surface} artifacts.`);
|
|
580
|
+
const clientExecutionPaths = apiOnly ? [] : await manifestReferencedClientModules(outputDirectory, files);
|
|
581
|
+
const ssrExecutionPaths = apiOnly ? [] : await routeReferencedSsrModules(outputDirectory, files, 'node');
|
|
582
|
+
if (!apiOnly && (0 === clientExecutionPaths.length || 0 === ssrExecutionPaths.length)) throw new Error('[ultramodern-release-envelope] final Node manifests must reference emitted UI/client and SSR execution modules.');
|
|
439
583
|
const runtimeByPath = new Map(files.filter((logicalPath)=>!backendFederationPaths.has(logicalPath)).map((logicalPath)=>[
|
|
440
584
|
logicalPath,
|
|
441
585
|
'nodejs-deployment'
|
|
442
586
|
]));
|
|
443
587
|
for (const logicalPath of uiClientPaths)runtimeByPath.set(logicalPath, 'browser');
|
|
444
|
-
for (const logicalPath of
|
|
588
|
+
for (const logicalPath of declaredPublicAssetPaths)runtimeByPath.set(logicalPath, DECLARED_PUBLIC_ASSET_RUNTIME);
|
|
589
|
+
if (files.includes(CRAWLER_POLICY_PATH)) runtimeByPath.set(CRAWLER_POLICY_PATH, 'crawler-policy');
|
|
590
|
+
for (const logicalPath of files.filter(isPublicMetadataPath))runtimeByPath.set(logicalPath, 'public-metadata');
|
|
591
|
+
for (const logicalPath of apiOnly ? [] : ssrPaths)runtimeByPath.set(logicalPath, 'nodejs');
|
|
445
592
|
for (const logicalPath of apiBackendPaths)runtimeByPath.set(logicalPath, 'nodejs');
|
|
446
|
-
|
|
447
|
-
|
|
593
|
+
if (backendProducer) {
|
|
594
|
+
runtimeByPath.set(BACKEND_FEDERATION_MANIFEST_FILE, 'module-federation-manifest');
|
|
595
|
+
runtimeByPath.set(BACKEND_FEDERATION_REMOTE_ENTRY_FILE, 'nodejs');
|
|
596
|
+
}
|
|
597
|
+
for (const logicalPath of [
|
|
598
|
+
ULTRAMODERN_BUILD_ARTIFACT_FILE,
|
|
599
|
+
PUBLIC_BUILD_ARTIFACT_PATH
|
|
600
|
+
])if (files.includes(logicalPath)) runtimeByPath.set(logicalPath, 'release-identity-metadata');
|
|
448
601
|
const identityCarrierMetadata = await writeReleaseIdentityCarrierMetadata(outputDirectory, identity, {
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
602
|
+
...apiBackendPaths.length > 0 ? {
|
|
603
|
+
apiBackend: apiBackendPaths
|
|
604
|
+
} : {},
|
|
605
|
+
...backendProducer ? {
|
|
606
|
+
backendFederation: [
|
|
607
|
+
BACKEND_FEDERATION_MANIFEST_FILE,
|
|
608
|
+
BACKEND_FEDERATION_REMOTE_ENTRY_FILE
|
|
609
|
+
]
|
|
610
|
+
} : {},
|
|
611
|
+
ssr: apiOnly ? [] : [
|
|
455
612
|
...new Set([
|
|
456
613
|
...ssrExecutionPaths,
|
|
457
614
|
...ssrPaths.filter((logicalPath)=>'index.js' !== logicalPath)
|
|
@@ -470,30 +627,37 @@ const createNodeStagedReleaseArtifactInputs = async (outputDirectory, identity)=
|
|
|
470
627
|
uiClient: [
|
|
471
628
|
...uiClientPaths
|
|
472
629
|
].sort((left, right)=>left.localeCompare(right)),
|
|
473
|
-
ssr: [
|
|
630
|
+
ssr: apiOnly ? [] : [
|
|
474
631
|
...ssrPaths
|
|
475
632
|
].sort((left, right)=>left.localeCompare(right)),
|
|
476
633
|
apiBackend: [
|
|
477
634
|
...apiBackendPaths
|
|
478
635
|
].sort((left, right)=>left.localeCompare(right)),
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
636
|
+
...backendProducer ? {
|
|
637
|
+
backendFederation: {
|
|
638
|
+
manifest: BACKEND_FEDERATION_MANIFEST_FILE,
|
|
639
|
+
container: BACKEND_FEDERATION_REMOTE_ENTRY_FILE
|
|
640
|
+
}
|
|
641
|
+
} : {}
|
|
483
642
|
}
|
|
484
643
|
};
|
|
485
644
|
};
|
|
486
|
-
const emitNodeStagedReleaseEnvelope = async ({ distDirectory, outputDirectory })=>{
|
|
645
|
+
const emitNodeStagedReleaseEnvelope = async ({ declaredPublicAssets = [], distDirectory, outputDirectory })=>{
|
|
487
646
|
const source = await verifyBuildOutputReleaseEnvelope(distDirectory, 'node');
|
|
488
647
|
if (!source) return;
|
|
489
|
-
const
|
|
648
|
+
const shellConsumer = source.kind === SHELL_RELEASE_ENVELOPE_KIND;
|
|
649
|
+
const { artifacts, surfaces } = await createNodeStagedReleaseArtifactInputs(outputDirectory, source.identity, 0 === source.surfaces.uiClient.length, 0 === source.surfaces.apiBackend.length, declaredPublicAssets, shellConsumer);
|
|
490
650
|
const staged = await createMicroVerticalReleaseEnvelope({
|
|
491
651
|
artifactRoot: outputDirectory,
|
|
492
652
|
target: 'node',
|
|
493
653
|
identity: source.identity,
|
|
654
|
+
...source.ui ? {
|
|
655
|
+
ui: source.ui
|
|
656
|
+
} : {},
|
|
494
657
|
artifacts,
|
|
495
|
-
surfaces
|
|
658
|
+
...releaseEnvelopeSurfaces(surfaces, shellConsumer)
|
|
496
659
|
});
|
|
660
|
+
await verifyBuildArtifactCarriers(outputDirectory, staged);
|
|
497
661
|
await writeReleaseEnvelope(outputDirectory, staged);
|
|
498
662
|
return staged;
|
|
499
663
|
};
|
|
@@ -504,21 +668,29 @@ const stageCloudflareReleaseEnvelope = async ({ distDirectory, outputDirectory }
|
|
|
504
668
|
if (await pathExists(stagedEnvelopePath)) throw new Error('[ultramodern-release-envelope] Cloudflare staging contains a stale envelope before final output generation.');
|
|
505
669
|
return source;
|
|
506
670
|
};
|
|
507
|
-
const createCloudflareStagedReleaseArtifactInputs = async (outputDirectory, identity)=>{
|
|
671
|
+
const createCloudflareStagedReleaseArtifactInputs = async (outputDirectory, identity, apiOnly, uiOnly, declaredPublicAssets, shellConsumer)=>{
|
|
672
|
+
const backendProducer = !uiOnly && !shellConsumer;
|
|
508
673
|
const files = await collectFiles(outputDirectory);
|
|
674
|
+
const declaredPublicAssetPaths = resolveDeclaredPublicAssets(files, declaredPublicAssets, 'Cloudflare');
|
|
509
675
|
for (const requiredPath of [
|
|
510
676
|
'server/index.mjs',
|
|
511
677
|
'server/modern-worker-manifest.json',
|
|
512
678
|
'wrangler.json',
|
|
513
679
|
'package.json',
|
|
514
|
-
|
|
680
|
+
...apiOnly ? [] : [
|
|
681
|
+
'worker/package.json'
|
|
682
|
+
]
|
|
515
683
|
])if (!files.includes(requiredPath)) throw new Error(`[ultramodern-release-envelope] final Cloudflare staging is missing ${requiredPath}.`);
|
|
516
684
|
if (files.some((logicalPath)=>'public/release' === logicalPath || logicalPath.startsWith('public/release/'))) throw new Error('[ultramodern-release-envelope] final Cloudflare envelope must remain private and cannot be staged under public/release.');
|
|
517
685
|
const backendManifestPath = `public/${BACKEND_FEDERATION_MANIFEST_FILE}`;
|
|
518
686
|
const backendContainerPath = `public/${BACKEND_FEDERATION_REMOTE_ENTRY_FILE}`;
|
|
519
|
-
const apiBackendPaths = files
|
|
520
|
-
|
|
521
|
-
const
|
|
687
|
+
const apiBackendPaths = effectBffWorkerArtifacts(files);
|
|
688
|
+
if (backendProducer && !files.some((logicalPath)=>EFFECT_BFF_WORKER_PATTERN.test(logicalPath))) throw new Error('[ultramodern-release-envelope] final Cloudflare staging has no actual Effect API/BFF worker artifact.');
|
|
689
|
+
const ssrPaths = files.filter((logicalPath)=>(logicalPath.startsWith('server/') || logicalPath.startsWith('worker/')) && COMPILED_MODULE_PATTERN.test(logicalPath) && !apiBackendPaths.includes(logicalPath));
|
|
690
|
+
const uiClientPaths = files.filter((logicalPath)=>logicalPath.startsWith('public/') && logicalPath !== CRAWLER_POLICY_PATH && !isPublicMetadataPath(logicalPath) && !declaredPublicAssetPaths.has(logicalPath) && logicalPath !== PUBLIC_BUILD_ARTIFACT_PATH && logicalPath !== backendManifestPath && logicalPath !== backendContainerPath);
|
|
691
|
+
if (shellConsumer && files.some((logicalPath)=>logicalPath === backendManifestPath || logicalPath === backendContainerPath)) throw new Error('[ultramodern-release-envelope] final Shell Cloudflare staging cannot contain a backend federation producer artifact.');
|
|
692
|
+
if (uiOnly && (apiBackendPaths.length > 0 || files.some((logicalPath)=>logicalPath === backendManifestPath || logicalPath === backendContainerPath || logicalPath.startsWith('api/') && COMPILED_MODULE_PATTERN.test(logicalPath)))) throw new Error('[ultramodern-release-envelope] final UI-only Cloudflare staging contains an undeclared API/backend or backend federation artifact.');
|
|
693
|
+
if (apiOnly && (uiClientPaths.length > 0 || ssrPaths.some((path)=>'server/index.mjs' !== path))) throw new Error('[ultramodern-release-envelope] final API-only Cloudflare staging contains an undeclared UI/client or SSR surface.');
|
|
522
694
|
for (const [surface, paths] of [
|
|
523
695
|
[
|
|
524
696
|
'UI/client',
|
|
@@ -526,41 +698,53 @@ const createCloudflareStagedReleaseArtifactInputs = async (outputDirectory, iden
|
|
|
526
698
|
],
|
|
527
699
|
[
|
|
528
700
|
'Cloudflare SSR',
|
|
529
|
-
ssrPaths
|
|
701
|
+
apiOnly ? [] : ssrPaths
|
|
530
702
|
],
|
|
531
703
|
[
|
|
532
704
|
'Cloudflare API/backend',
|
|
533
705
|
apiBackendPaths
|
|
534
706
|
]
|
|
535
|
-
])if (0 === paths.length) throw new Error(`[ultramodern-release-envelope] final Cloudflare staging has no ${surface} artifacts.`);
|
|
536
|
-
for (const logicalPath of [
|
|
707
|
+
])if (0 === paths.length && ('Cloudflare API/backend' === surface ? backendProducer : !apiOnly)) throw new Error(`[ultramodern-release-envelope] final Cloudflare staging has no ${surface} artifacts.`);
|
|
708
|
+
for (const logicalPath of backendProducer ? [
|
|
537
709
|
backendManifestPath,
|
|
538
710
|
backendContainerPath
|
|
539
|
-
])if (!files.includes(logicalPath)) throw new Error(`[ultramodern-release-envelope] final Cloudflare staging is missing ${logicalPath}.`);
|
|
540
|
-
const clientExecutionPaths = await manifestReferencedClientModules(outputDirectory, files, 'public/mf-manifest.json');
|
|
541
|
-
const ssrExecutionPaths = await routeReferencedSsrModules(outputDirectory, files, 'cloudflare', 'server/route.json');
|
|
542
|
-
if (0 === clientExecutionPaths.length || 0 === ssrExecutionPaths.length) throw new Error('[ultramodern-release-envelope] final Cloudflare manifests must reference emitted UI/client and SSR execution modules.');
|
|
711
|
+
] : [])if (!files.includes(logicalPath)) throw new Error(`[ultramodern-release-envelope] final Cloudflare staging is missing ${logicalPath}.`);
|
|
712
|
+
const clientExecutionPaths = apiOnly ? [] : await manifestReferencedClientModules(outputDirectory, files, 'public/mf-manifest.json');
|
|
713
|
+
const ssrExecutionPaths = apiOnly ? [] : await routeReferencedSsrModules(outputDirectory, files, 'cloudflare', 'server/route.json');
|
|
714
|
+
if (!apiOnly && (0 === clientExecutionPaths.length || 0 === ssrExecutionPaths.length)) throw new Error('[ultramodern-release-envelope] final Cloudflare manifests must reference emitted UI/client and SSR execution modules.');
|
|
543
715
|
const runtimeByPath = new Map();
|
|
544
716
|
for (const logicalPath of files)runtimeByPath.set(logicalPath, 'cloudflare-deployment');
|
|
545
717
|
const add = (paths, runtime)=>{
|
|
546
718
|
for (const logicalPath of paths)runtimeByPath.set(logicalPath, runtime);
|
|
547
719
|
};
|
|
548
720
|
add(uiClientPaths, 'browser');
|
|
549
|
-
add(ssrPaths, 'workerd');
|
|
550
|
-
add(apiBackendPaths, 'workerd-effect');
|
|
551
721
|
add([
|
|
552
|
-
|
|
553
|
-
],
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
], '
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
backendManifestPath
|
|
722
|
+
...declaredPublicAssetPaths
|
|
723
|
+
], DECLARED_PUBLIC_ASSET_RUNTIME);
|
|
724
|
+
if (files.includes(CRAWLER_POLICY_PATH)) runtimeByPath.set(CRAWLER_POLICY_PATH, 'crawler-policy');
|
|
725
|
+
add(files.filter(isPublicMetadataPath), 'public-metadata');
|
|
726
|
+
add(apiOnly ? [] : ssrPaths, 'workerd');
|
|
727
|
+
add(apiBackendPaths, 'workerd-effect');
|
|
728
|
+
if (backendProducer) {
|
|
729
|
+
add([
|
|
730
|
+
backendManifestPath
|
|
731
|
+
], 'module-federation-manifest');
|
|
732
|
+
add([
|
|
561
733
|
backendContainerPath
|
|
562
|
-
],
|
|
563
|
-
|
|
734
|
+
], 'commonjs-module');
|
|
735
|
+
}
|
|
736
|
+
add(files.filter((logicalPath)=>logicalPath === ULTRAMODERN_BUILD_ARTIFACT_FILE || logicalPath === PUBLIC_BUILD_ARTIFACT_PATH), 'release-identity-metadata');
|
|
737
|
+
const identityCarrierMetadata = await writeReleaseIdentityCarrierMetadata(outputDirectory, identity, {
|
|
738
|
+
...apiBackendPaths.length > 0 ? {
|
|
739
|
+
apiBackend: apiBackendPaths
|
|
740
|
+
} : {},
|
|
741
|
+
...backendProducer ? {
|
|
742
|
+
backendFederation: [
|
|
743
|
+
backendManifestPath,
|
|
744
|
+
backendContainerPath
|
|
745
|
+
]
|
|
746
|
+
} : {},
|
|
747
|
+
ssr: apiOnly ? [] : [
|
|
564
748
|
...new Set([
|
|
565
749
|
...ssrExecutionPaths,
|
|
566
750
|
...ssrPaths.filter((logicalPath)=>logicalPath.startsWith('worker/'))
|
|
@@ -579,30 +763,37 @@ const createCloudflareStagedReleaseArtifactInputs = async (outputDirectory, iden
|
|
|
579
763
|
uiClient: [
|
|
580
764
|
...uiClientPaths
|
|
581
765
|
].sort((left, right)=>left.localeCompare(right)),
|
|
582
|
-
ssr: [
|
|
766
|
+
ssr: apiOnly ? [] : [
|
|
583
767
|
...ssrPaths
|
|
584
768
|
].sort((left, right)=>left.localeCompare(right)),
|
|
585
769
|
apiBackend: [
|
|
586
770
|
...apiBackendPaths
|
|
587
771
|
].sort((left, right)=>left.localeCompare(right)),
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
772
|
+
...backendProducer ? {
|
|
773
|
+
backendFederation: {
|
|
774
|
+
manifest: backendManifestPath,
|
|
775
|
+
container: backendContainerPath
|
|
776
|
+
}
|
|
777
|
+
} : {}
|
|
592
778
|
}
|
|
593
779
|
};
|
|
594
780
|
};
|
|
595
|
-
const emitCloudflareStagedReleaseEnvelope = async ({ distDirectory, outputDirectory })=>{
|
|
781
|
+
const emitCloudflareStagedReleaseEnvelope = async ({ declaredPublicAssets = [], distDirectory, outputDirectory })=>{
|
|
596
782
|
const source = await verifyBuildOutputReleaseEnvelope(distDirectory, 'cloudflare');
|
|
597
783
|
if (!source) return;
|
|
598
|
-
const
|
|
784
|
+
const shellConsumer = source.kind === SHELL_RELEASE_ENVELOPE_KIND;
|
|
785
|
+
const { artifacts, surfaces } = await createCloudflareStagedReleaseArtifactInputs(outputDirectory, source.identity, 0 === source.surfaces.uiClient.length, 0 === source.surfaces.apiBackend.length, declaredPublicAssets, shellConsumer);
|
|
599
786
|
const staged = await createMicroVerticalReleaseEnvelope({
|
|
600
787
|
artifactRoot: outputDirectory,
|
|
601
788
|
target: 'cloudflare',
|
|
602
789
|
identity: source.identity,
|
|
790
|
+
...source.ui ? {
|
|
791
|
+
ui: source.ui
|
|
792
|
+
} : {},
|
|
603
793
|
artifacts,
|
|
604
|
-
surfaces
|
|
794
|
+
...releaseEnvelopeSurfaces(surfaces, shellConsumer)
|
|
605
795
|
});
|
|
796
|
+
await verifyBuildArtifactCarriers(outputDirectory, staged);
|
|
606
797
|
await writeReleaseEnvelope(outputDirectory, staged);
|
|
607
798
|
return staged;
|
|
608
799
|
};
|