@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,6 +1,14 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import fs from 'node:fs/promises';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
+
import {
|
|
5
|
+
formatBackendFederationValidationErrors,
|
|
6
|
+
immutableRendererRouterBindings,
|
|
7
|
+
validateRendererIdentity,
|
|
8
|
+
validateRendererProfile,
|
|
9
|
+
validateRendererProfileCompatibility,
|
|
10
|
+
validateRendererRouterBindings,
|
|
11
|
+
} from '@modern-js/backend-federation-contracts';
|
|
4
12
|
import {
|
|
5
13
|
canonicalSerializeMicroVerticalReleaseEnvelope,
|
|
6
14
|
digestMicroVerticalReleaseEnvelopePayload,
|
|
@@ -16,8 +24,15 @@ import {
|
|
|
16
24
|
type MicroVerticalReleaseEnvelope,
|
|
17
25
|
type MicroVerticalReleaseEnvelopePayload,
|
|
18
26
|
type MicroVerticalReleaseIdentity,
|
|
19
|
-
type MicroVerticalReleaseSurfaces,
|
|
20
27
|
type MicroVerticalReleaseTarget,
|
|
28
|
+
type MicroVerticalReleaseUi,
|
|
29
|
+
type ReleaseEnvelope,
|
|
30
|
+
type ReleaseEnvelopeKind,
|
|
31
|
+
type ReleaseEnvelopePayload,
|
|
32
|
+
type ReleaseSurfaces,
|
|
33
|
+
SHELL_RELEASE_ENVELOPE_KIND,
|
|
34
|
+
type ShellReleaseEnvelope,
|
|
35
|
+
type ShellReleaseEnvelopePayload,
|
|
21
36
|
type VerifyMicroVerticalReleaseEnvelopeOptions,
|
|
22
37
|
} from './types';
|
|
23
38
|
|
|
@@ -33,6 +48,14 @@ export type {
|
|
|
33
48
|
MicroVerticalReleaseSurfaces,
|
|
34
49
|
MicroVerticalReleaseSymbolicLinkArtifact,
|
|
35
50
|
MicroVerticalReleaseTarget,
|
|
51
|
+
MicroVerticalReleaseUi,
|
|
52
|
+
ReleaseEnvelope,
|
|
53
|
+
ReleaseEnvelopeKind,
|
|
54
|
+
ReleaseEnvelopePayload,
|
|
55
|
+
ReleaseSurfaces,
|
|
56
|
+
ShellReleaseEnvelope,
|
|
57
|
+
ShellReleaseEnvelopePayload,
|
|
58
|
+
ShellReleaseSurfaces,
|
|
36
59
|
VerifyMicroVerticalReleaseEnvelopeOptions,
|
|
37
60
|
} from './types';
|
|
38
61
|
export {
|
|
@@ -40,6 +63,7 @@ export {
|
|
|
40
63
|
MICROVERTICAL_RELEASE_ENVELOPE_KIND,
|
|
41
64
|
MICROVERTICAL_RELEASE_ENVELOPE_SCHEMA_VERSION,
|
|
42
65
|
MICROVERTICAL_RELEASE_TARGETS,
|
|
66
|
+
SHELL_RELEASE_ENVELOPE_KIND,
|
|
43
67
|
};
|
|
44
68
|
|
|
45
69
|
const SHA256_PATTERN = /^[a-f0-9]{64}$/u;
|
|
@@ -100,6 +124,18 @@ const assertTarget = (
|
|
|
100
124
|
return target as MicroVerticalReleaseTarget;
|
|
101
125
|
};
|
|
102
126
|
|
|
127
|
+
const assertEnvelopeKind = (value: unknown): ReleaseEnvelopeKind => {
|
|
128
|
+
if (
|
|
129
|
+
value !== MICROVERTICAL_RELEASE_ENVELOPE_KIND &&
|
|
130
|
+
value !== SHELL_RELEASE_ENVELOPE_KIND
|
|
131
|
+
) {
|
|
132
|
+
throw new Error(
|
|
133
|
+
`envelope.kind must be "${MICROVERTICAL_RELEASE_ENVELOPE_KIND}" or "${SHELL_RELEASE_ENVELOPE_KIND}".`,
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
return value;
|
|
137
|
+
};
|
|
138
|
+
|
|
103
139
|
const assertReleaseIdentity = (
|
|
104
140
|
value: unknown,
|
|
105
141
|
location = 'identity',
|
|
@@ -381,8 +417,8 @@ const assertUniqueSortedArtifacts = (
|
|
|
381
417
|
};
|
|
382
418
|
|
|
383
419
|
const assertSurfacePaths = (value: unknown, location: string): string[] => {
|
|
384
|
-
if (!Array.isArray(value)
|
|
385
|
-
throw new Error(`${location} must
|
|
420
|
+
if (!Array.isArray(value)) {
|
|
421
|
+
throw new Error(`${location} must be an array of artifact paths.`);
|
|
386
422
|
}
|
|
387
423
|
const paths = value.map((item, index) =>
|
|
388
424
|
assertNormalizedLogicalPath(item, `${location}[${index}]`),
|
|
@@ -397,42 +433,97 @@ const assertSurfacePaths = (value: unknown, location: string): string[] => {
|
|
|
397
433
|
return paths;
|
|
398
434
|
};
|
|
399
435
|
|
|
400
|
-
const assertSurfaces = (
|
|
436
|
+
const assertSurfaces = (
|
|
437
|
+
value: unknown,
|
|
438
|
+
kind: ReleaseEnvelopeKind,
|
|
439
|
+
):
|
|
440
|
+
| Pick<MicroVerticalReleaseEnvelopePayload, 'kind' | 'surfaces'>
|
|
441
|
+
| Pick<ShellReleaseEnvelopePayload, 'kind' | 'surfaces'> => {
|
|
401
442
|
const surfaces = assertRecord(value, 'surfaces');
|
|
402
443
|
assertExactKeys(
|
|
403
444
|
surfaces,
|
|
404
|
-
[
|
|
445
|
+
[
|
|
446
|
+
'uiClient',
|
|
447
|
+
'ssr',
|
|
448
|
+
'apiBackend',
|
|
449
|
+
// A Shell consumes remotes and never publishes a backend federation pair.
|
|
450
|
+
// A UI-only MicroVertical (cold deploy) has no backend surface to pair.
|
|
451
|
+
...(kind !== SHELL_RELEASE_ENVELOPE_KIND &&
|
|
452
|
+
Object.hasOwn(surfaces, 'backendFederation')
|
|
453
|
+
? ['backendFederation']
|
|
454
|
+
: []),
|
|
455
|
+
],
|
|
405
456
|
'surfaces',
|
|
406
457
|
);
|
|
407
|
-
const backendFederation =
|
|
408
|
-
surfaces.backendFederation,
|
|
409
|
-
|
|
410
|
-
)
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
458
|
+
const backendFederation = Object.hasOwn(surfaces, 'backendFederation')
|
|
459
|
+
? assertRecord(surfaces.backendFederation, 'surfaces.backendFederation')
|
|
460
|
+
: undefined;
|
|
461
|
+
if (backendFederation)
|
|
462
|
+
assertExactKeys(
|
|
463
|
+
backendFederation,
|
|
464
|
+
['manifest', 'container'],
|
|
465
|
+
'surfaces.backendFederation',
|
|
466
|
+
);
|
|
467
|
+
const uiClient = assertSurfacePaths(surfaces.uiClient, 'surfaces.uiClient');
|
|
468
|
+
const ssr = assertSurfacePaths(surfaces.ssr, 'surfaces.ssr');
|
|
469
|
+
const apiBackend = assertSurfacePaths(
|
|
470
|
+
surfaces.apiBackend,
|
|
471
|
+
'surfaces.apiBackend',
|
|
415
472
|
);
|
|
473
|
+
if (uiClient.length > 0 && ssr.length === 0) {
|
|
474
|
+
throw new Error(
|
|
475
|
+
'surfaces.ssr must contain at least one artifact path when UI/client is declared.',
|
|
476
|
+
);
|
|
477
|
+
}
|
|
478
|
+
if (ssr.length > 0 && uiClient.length === 0) {
|
|
479
|
+
throw new Error(
|
|
480
|
+
'surfaces.uiClient must contain at least one artifact path when SSR is declared.',
|
|
481
|
+
);
|
|
482
|
+
}
|
|
483
|
+
if (apiBackend.length === 0 && (backendFederation || uiClient.length === 0)) {
|
|
484
|
+
throw new Error(
|
|
485
|
+
'surfaces.apiBackend must contain at least one artifact path.',
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
if (kind === SHELL_RELEASE_ENVELOPE_KIND) {
|
|
489
|
+
if (uiClient.length === 0 || ssr.length === 0) {
|
|
490
|
+
throw new Error(
|
|
491
|
+
'Shell surfaces.uiClient and surfaces.ssr must each contain at least one artifact path.',
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
return { kind, surfaces: { uiClient, ssr, apiBackend } };
|
|
495
|
+
}
|
|
496
|
+
if (apiBackend.length > 0 && !backendFederation)
|
|
497
|
+
throw new Error(
|
|
498
|
+
'surfaces.backendFederation is required when API/backend is declared.',
|
|
499
|
+
);
|
|
416
500
|
return {
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
501
|
+
kind,
|
|
502
|
+
surfaces: {
|
|
503
|
+
uiClient,
|
|
504
|
+
ssr,
|
|
505
|
+
apiBackend,
|
|
506
|
+
...(backendFederation
|
|
507
|
+
? {
|
|
508
|
+
backendFederation: {
|
|
509
|
+
manifest: assertNormalizedLogicalPath(
|
|
510
|
+
backendFederation.manifest,
|
|
511
|
+
'surfaces.backendFederation.manifest',
|
|
512
|
+
),
|
|
513
|
+
container: assertNormalizedLogicalPath(
|
|
514
|
+
backendFederation.container,
|
|
515
|
+
'surfaces.backendFederation.container',
|
|
516
|
+
),
|
|
517
|
+
},
|
|
518
|
+
}
|
|
519
|
+
: {}),
|
|
429
520
|
},
|
|
430
521
|
};
|
|
431
522
|
};
|
|
432
523
|
|
|
433
524
|
const assertSurfaceReferences = (
|
|
434
525
|
artifacts: readonly MicroVerticalReleaseArtifactInput[],
|
|
435
|
-
surfaces:
|
|
526
|
+
surfaces: ReleaseSurfaces,
|
|
436
527
|
) => {
|
|
437
528
|
const artifactPaths = new Set(
|
|
438
529
|
artifacts.map(artifact => artifact.logicalPath),
|
|
@@ -441,8 +532,12 @@ const assertSurfaceReferences = (
|
|
|
441
532
|
uiClient: surfaces.uiClient,
|
|
442
533
|
ssr: surfaces.ssr,
|
|
443
534
|
apiBackend: surfaces.apiBackend,
|
|
444
|
-
'backendFederation
|
|
445
|
-
|
|
535
|
+
...('backendFederation' in surfaces && surfaces.backendFederation
|
|
536
|
+
? {
|
|
537
|
+
'backendFederation.manifest': [surfaces.backendFederation.manifest],
|
|
538
|
+
'backendFederation.container': [surfaces.backendFederation.container],
|
|
539
|
+
}
|
|
540
|
+
: {}),
|
|
446
541
|
})) {
|
|
447
542
|
for (const logicalPath of paths) {
|
|
448
543
|
if (!artifactPaths.has(logicalPath)) {
|
|
@@ -457,7 +552,7 @@ const assertSurfaceReferences = (
|
|
|
457
552
|
const assertTargetSurfaceContract = (
|
|
458
553
|
target: MicroVerticalReleaseTarget,
|
|
459
554
|
artifacts: readonly MicroVerticalReleaseArtifactInput[],
|
|
460
|
-
surfaces:
|
|
555
|
+
surfaces: ReleaseSurfaces,
|
|
461
556
|
) => {
|
|
462
557
|
const byPath = new Map(
|
|
463
558
|
artifacts.map(artifact => [artifact.logicalPath, artifact]),
|
|
@@ -489,16 +584,18 @@ const assertTargetSurfaceContract = (
|
|
|
489
584
|
target === 'node' ? 'nodejs' : 'workerd-effect',
|
|
490
585
|
'API/backend',
|
|
491
586
|
);
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
587
|
+
if ('backendFederation' in surfaces && surfaces.backendFederation) {
|
|
588
|
+
assertRuntime(
|
|
589
|
+
[surfaces.backendFederation.manifest],
|
|
590
|
+
'module-federation-manifest',
|
|
591
|
+
'backend federation manifest',
|
|
592
|
+
);
|
|
593
|
+
assertRuntime(
|
|
594
|
+
[surfaces.backendFederation.container],
|
|
595
|
+
target === 'node' ? 'nodejs' : 'commonjs-module',
|
|
596
|
+
'backend federation container',
|
|
597
|
+
);
|
|
598
|
+
}
|
|
502
599
|
};
|
|
503
600
|
|
|
504
601
|
const deepFreeze = <T>(value: T): T => {
|
|
@@ -511,7 +608,81 @@ const deepFreeze = <T>(value: T): T => {
|
|
|
511
608
|
return value;
|
|
512
609
|
};
|
|
513
610
|
|
|
514
|
-
const
|
|
611
|
+
const assertReleaseUi = (
|
|
612
|
+
value: unknown,
|
|
613
|
+
identity: MicroVerticalReleaseIdentity,
|
|
614
|
+
surfaces: ReleaseSurfaces,
|
|
615
|
+
): MicroVerticalReleaseUi | undefined => {
|
|
616
|
+
if (surfaces.uiClient.length === 0) {
|
|
617
|
+
if (value !== undefined) {
|
|
618
|
+
throw new Error('envelope.ui is forbidden for an API-only release.');
|
|
619
|
+
}
|
|
620
|
+
return undefined;
|
|
621
|
+
}
|
|
622
|
+
const ui = assertRecord(value, 'envelope.ui');
|
|
623
|
+
assertExactKeys(
|
|
624
|
+
ui,
|
|
625
|
+
['rendererIdentity', 'rendererProfile', 'routerBindings'],
|
|
626
|
+
'envelope.ui',
|
|
627
|
+
);
|
|
628
|
+
const routerBindings = assertRecord(
|
|
629
|
+
ui.routerBindings,
|
|
630
|
+
'envelope.ui.routerBindings',
|
|
631
|
+
);
|
|
632
|
+
const errors = [
|
|
633
|
+
...validateRendererIdentity(
|
|
634
|
+
ui.rendererIdentity,
|
|
635
|
+
'envelope.ui.rendererIdentity',
|
|
636
|
+
).errors,
|
|
637
|
+
...validateRendererProfile(
|
|
638
|
+
ui.rendererProfile,
|
|
639
|
+
'envelope.ui.rendererProfile',
|
|
640
|
+
).errors,
|
|
641
|
+
...validateRendererRouterBindings(
|
|
642
|
+
routerBindings,
|
|
643
|
+
Object.keys(routerBindings),
|
|
644
|
+
'envelope.ui.routerBindings',
|
|
645
|
+
).errors,
|
|
646
|
+
];
|
|
647
|
+
if (errors.length > 0) {
|
|
648
|
+
throw new Error(formatBackendFederationValidationErrors(errors));
|
|
649
|
+
}
|
|
650
|
+
const rendererIdentity =
|
|
651
|
+
ui.rendererIdentity as MicroVerticalReleaseUi['rendererIdentity'];
|
|
652
|
+
const rendererProfile =
|
|
653
|
+
ui.rendererProfile as MicroVerticalReleaseUi['rendererProfile'];
|
|
654
|
+
if (!Object.hasOwn(routerBindings, rendererIdentity.entryName)) {
|
|
655
|
+
throw new Error(
|
|
656
|
+
'envelope.ui.routerBindings must include the primary rendererIdentity.entryName.',
|
|
657
|
+
);
|
|
658
|
+
}
|
|
659
|
+
if (rendererIdentity.buildId !== identity.buildMarker) {
|
|
660
|
+
throw new Error(
|
|
661
|
+
'envelope.ui.rendererIdentity.buildId must match identity.buildMarker.',
|
|
662
|
+
);
|
|
663
|
+
}
|
|
664
|
+
for (const field of ['renderer', 'protocolVersion'] as const) {
|
|
665
|
+
if (rendererIdentity[field] !== rendererProfile[field]) {
|
|
666
|
+
throw new Error(
|
|
667
|
+
`envelope.ui.rendererProfile.${field} must match rendererIdentity.${field}.`,
|
|
668
|
+
);
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
return {
|
|
672
|
+
rendererIdentity: { ...rendererIdentity },
|
|
673
|
+
rendererProfile: {
|
|
674
|
+
...rendererProfile,
|
|
675
|
+
compiler: { ...rendererProfile.compiler },
|
|
676
|
+
hydration: { ...rendererProfile.hydration },
|
|
677
|
+
router: { ...rendererProfile.router },
|
|
678
|
+
},
|
|
679
|
+
routerBindings: immutableRendererRouterBindings(
|
|
680
|
+
routerBindings as MicroVerticalReleaseUi['routerBindings'],
|
|
681
|
+
),
|
|
682
|
+
};
|
|
683
|
+
};
|
|
684
|
+
|
|
685
|
+
const assertEnvelope = (value: unknown): ReleaseEnvelope => {
|
|
515
686
|
const envelope = assertRecord(value, 'envelope');
|
|
516
687
|
assertExactKeys(
|
|
517
688
|
envelope,
|
|
@@ -520,6 +691,7 @@ const assertEnvelope = (value: unknown): MicroVerticalReleaseEnvelope => {
|
|
|
520
691
|
'kind',
|
|
521
692
|
'target',
|
|
522
693
|
'identity',
|
|
694
|
+
...(Object.hasOwn(envelope, 'ui') ? ['ui'] : []),
|
|
523
695
|
'artifacts',
|
|
524
696
|
'surfaces',
|
|
525
697
|
'envelopeDigest',
|
|
@@ -533,11 +705,7 @@ const assertEnvelope = (value: unknown): MicroVerticalReleaseEnvelope => {
|
|
|
533
705
|
`envelope.schemaVersion must be ${MICROVERTICAL_RELEASE_ENVELOPE_SCHEMA_VERSION}.`,
|
|
534
706
|
);
|
|
535
707
|
}
|
|
536
|
-
|
|
537
|
-
throw new Error(
|
|
538
|
-
`envelope.kind must be "${MICROVERTICAL_RELEASE_ENVELOPE_KIND}".`,
|
|
539
|
-
);
|
|
540
|
-
}
|
|
708
|
+
const kind = assertEnvelopeKind(envelope.kind);
|
|
541
709
|
if (!Array.isArray(envelope.artifacts) || envelope.artifacts.length === 0) {
|
|
542
710
|
throw new Error('envelope.artifacts must contain at least one artifact.');
|
|
543
711
|
}
|
|
@@ -546,16 +714,25 @@ const assertEnvelope = (value: unknown): MicroVerticalReleaseEnvelope => {
|
|
|
546
714
|
);
|
|
547
715
|
assertUniqueSortedArtifacts(artifacts, 'envelope.artifacts');
|
|
548
716
|
const target = assertTarget(envelope.target, 'envelope.target');
|
|
549
|
-
const
|
|
717
|
+
const releaseSurfaces = assertSurfaces(envelope.surfaces, kind);
|
|
718
|
+
const { surfaces } = releaseSurfaces;
|
|
719
|
+
if (surfaces.uiClient.length === 0 && Object.hasOwn(envelope, 'ui')) {
|
|
720
|
+
throw new Error('envelope.ui is forbidden for an API-only release.');
|
|
721
|
+
}
|
|
550
722
|
assertSurfaceReferences(artifacts, surfaces);
|
|
551
723
|
assertTargetSurfaceContract(target, artifacts, surfaces);
|
|
552
|
-
const
|
|
724
|
+
const identity = assertReleaseIdentity(
|
|
725
|
+
envelope.identity,
|
|
726
|
+
'envelope.identity',
|
|
727
|
+
);
|
|
728
|
+
const ui = assertReleaseUi(envelope.ui, identity, surfaces);
|
|
729
|
+
const parsed: ReleaseEnvelope = {
|
|
730
|
+
...releaseSurfaces,
|
|
553
731
|
schemaVersion: MICROVERTICAL_RELEASE_ENVELOPE_SCHEMA_VERSION,
|
|
554
|
-
kind: MICROVERTICAL_RELEASE_ENVELOPE_KIND,
|
|
555
732
|
target,
|
|
556
|
-
identity
|
|
733
|
+
identity,
|
|
734
|
+
...(ui ? { ui } : {}),
|
|
557
735
|
artifacts,
|
|
558
|
-
surfaces,
|
|
559
736
|
envelopeDigest: assertNonEmptyString(
|
|
560
737
|
envelope.envelopeDigest,
|
|
561
738
|
'envelope.envelopeDigest',
|
|
@@ -577,12 +754,28 @@ const assertEnvelope = (value: unknown): MicroVerticalReleaseEnvelope => {
|
|
|
577
754
|
return parsed;
|
|
578
755
|
};
|
|
579
756
|
|
|
580
|
-
export
|
|
757
|
+
export function createMicroVerticalReleaseEnvelope(
|
|
758
|
+
input: CreateMicroVerticalReleaseEnvelopeInput & {
|
|
759
|
+
kind: typeof SHELL_RELEASE_ENVELOPE_KIND;
|
|
760
|
+
},
|
|
761
|
+
): Promise<ShellReleaseEnvelope>;
|
|
762
|
+
export function createMicroVerticalReleaseEnvelope(
|
|
763
|
+
input: CreateMicroVerticalReleaseEnvelopeInput & {
|
|
764
|
+
kind?: typeof MICROVERTICAL_RELEASE_ENVELOPE_KIND;
|
|
765
|
+
},
|
|
766
|
+
): Promise<MicroVerticalReleaseEnvelope>;
|
|
767
|
+
export function createMicroVerticalReleaseEnvelope(
|
|
768
|
+
input: CreateMicroVerticalReleaseEnvelopeInput,
|
|
769
|
+
): Promise<ReleaseEnvelope>;
|
|
770
|
+
export async function createMicroVerticalReleaseEnvelope(
|
|
581
771
|
input: CreateMicroVerticalReleaseEnvelopeInput,
|
|
582
|
-
): Promise<
|
|
772
|
+
): Promise<ReleaseEnvelope> {
|
|
583
773
|
const artifactRoot = await fs.realpath(path.resolve(input.artifactRoot));
|
|
584
774
|
const target = assertTarget(input.target);
|
|
585
775
|
const identity = assertReleaseIdentity(input.identity);
|
|
776
|
+
const kind = assertEnvelopeKind(
|
|
777
|
+
input.kind === undefined ? MICROVERTICAL_RELEASE_ENVELOPE_KIND : input.kind,
|
|
778
|
+
);
|
|
586
779
|
if (!Array.isArray(input.artifacts) || input.artifacts.length === 0) {
|
|
587
780
|
throw new Error('artifacts must contain at least one artifact.');
|
|
588
781
|
}
|
|
@@ -593,32 +786,94 @@ export const createMicroVerticalReleaseEnvelope = async (
|
|
|
593
786
|
left.logicalPath.localeCompare(right.logicalPath),
|
|
594
787
|
);
|
|
595
788
|
assertUniqueSortedArtifacts(sortedInputs, 'artifacts');
|
|
596
|
-
const
|
|
789
|
+
const releaseSurfaces = assertSurfaces(input.surfaces, kind);
|
|
790
|
+
const { surfaces } = releaseSurfaces;
|
|
791
|
+
if (surfaces.uiClient.length === 0 && Object.hasOwn(input, 'ui')) {
|
|
792
|
+
throw new Error('envelope.ui is forbidden for an API-only release.');
|
|
793
|
+
}
|
|
597
794
|
assertSurfaceReferences(sortedInputs, surfaces);
|
|
598
795
|
assertTargetSurfaceContract(target, sortedInputs, surfaces);
|
|
796
|
+
const ui = assertReleaseUi(input.ui, identity, surfaces);
|
|
599
797
|
const artifacts = await Promise.all(
|
|
600
798
|
sortedInputs.map(artifact => readFinalArtifact(artifactRoot, artifact)),
|
|
601
799
|
);
|
|
602
800
|
assertTargetSurfaceContract(target, artifacts, surfaces);
|
|
603
|
-
const payload:
|
|
801
|
+
const payload: ReleaseEnvelopePayload = {
|
|
802
|
+
...releaseSurfaces,
|
|
604
803
|
schemaVersion: MICROVERTICAL_RELEASE_ENVELOPE_SCHEMA_VERSION,
|
|
605
|
-
kind: MICROVERTICAL_RELEASE_ENVELOPE_KIND,
|
|
606
804
|
target,
|
|
607
805
|
identity,
|
|
806
|
+
...(ui ? { ui } : {}),
|
|
608
807
|
artifacts,
|
|
609
|
-
surfaces,
|
|
610
808
|
};
|
|
611
809
|
return deepFreeze({
|
|
612
810
|
...payload,
|
|
613
811
|
envelopeDigest: digestMicroVerticalReleaseEnvelopePayload(payload),
|
|
614
812
|
});
|
|
615
|
-
}
|
|
813
|
+
}
|
|
616
814
|
|
|
617
|
-
export
|
|
815
|
+
export function verifyMicroVerticalReleaseEnvelope(
|
|
816
|
+
value: unknown,
|
|
817
|
+
options: VerifyMicroVerticalReleaseEnvelopeOptions & {
|
|
818
|
+
expectedKind: typeof SHELL_RELEASE_ENVELOPE_KIND;
|
|
819
|
+
},
|
|
820
|
+
): Promise<ShellReleaseEnvelope>;
|
|
821
|
+
export function verifyMicroVerticalReleaseEnvelope(
|
|
822
|
+
value: unknown,
|
|
823
|
+
options: VerifyMicroVerticalReleaseEnvelopeOptions & {
|
|
824
|
+
expectedKind: typeof MICROVERTICAL_RELEASE_ENVELOPE_KIND;
|
|
825
|
+
},
|
|
826
|
+
): Promise<MicroVerticalReleaseEnvelope>;
|
|
827
|
+
export function verifyMicroVerticalReleaseEnvelope(
|
|
618
828
|
value: unknown,
|
|
619
829
|
options: VerifyMicroVerticalReleaseEnvelopeOptions,
|
|
620
|
-
): Promise<
|
|
830
|
+
): Promise<ReleaseEnvelope>;
|
|
831
|
+
export async function verifyMicroVerticalReleaseEnvelope(
|
|
832
|
+
value: unknown,
|
|
833
|
+
options: VerifyMicroVerticalReleaseEnvelopeOptions,
|
|
834
|
+
): Promise<ReleaseEnvelope> {
|
|
621
835
|
const envelope = assertEnvelope(value);
|
|
836
|
+
if (options.expectedRendererProfile !== undefined) {
|
|
837
|
+
const result = validateRendererProfileCompatibility(
|
|
838
|
+
options.expectedRendererProfile,
|
|
839
|
+
envelope.ui?.rendererProfile,
|
|
840
|
+
'envelope.ui.rendererProfile',
|
|
841
|
+
);
|
|
842
|
+
if (!result.ok) {
|
|
843
|
+
throw new Error(formatBackendFederationValidationErrors(result.errors));
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
if (options.expectedRendererIdentity !== undefined) {
|
|
847
|
+
const expected = options.expectedRendererIdentity;
|
|
848
|
+
const result = validateRendererIdentity(
|
|
849
|
+
expected,
|
|
850
|
+
'expectedRendererIdentity',
|
|
851
|
+
);
|
|
852
|
+
if (!result.ok) {
|
|
853
|
+
throw new Error(formatBackendFederationValidationErrors(result.errors));
|
|
854
|
+
}
|
|
855
|
+
for (const field of [
|
|
856
|
+
'renderer',
|
|
857
|
+
'protocolVersion',
|
|
858
|
+
'appId',
|
|
859
|
+
'entryName',
|
|
860
|
+
'buildId',
|
|
861
|
+
] as const) {
|
|
862
|
+
if (envelope.ui?.rendererIdentity[field] !== expected[field]) {
|
|
863
|
+
throw new Error(
|
|
864
|
+
`envelope.ui.rendererIdentity.${field} must match the consuming renderer identity.`,
|
|
865
|
+
);
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
if (
|
|
870
|
+
options.expectedKind !== undefined &&
|
|
871
|
+
envelope.kind !== options.expectedKind
|
|
872
|
+
) {
|
|
873
|
+
throw new Error(
|
|
874
|
+
`envelope.kind must be "${options.expectedKind}" for this release owner; received "${envelope.kind}".`,
|
|
875
|
+
);
|
|
876
|
+
}
|
|
622
877
|
if (
|
|
623
878
|
options.expectedTarget !== undefined &&
|
|
624
879
|
envelope.target !== options.expectedTarget
|
|
@@ -653,4 +908,4 @@ export const verifyMicroVerticalReleaseEnvelope = async (
|
|
|
653
908
|
}
|
|
654
909
|
}
|
|
655
910
|
return deepFreeze(envelope);
|
|
656
|
-
}
|
|
911
|
+
}
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
+
import type { RendererProfile } from '@modern-js/backend-federation-contracts';
|
|
3
|
+
import type { NodePublicAssetConfig } from '../config';
|
|
4
|
+
import {
|
|
5
|
+
NODE_PUBLIC_ASSET_SCOPE,
|
|
6
|
+
normalizeDeclaredPublicAssets,
|
|
7
|
+
resolveAddedDeclaredPublicAssetPaths,
|
|
8
|
+
} from '../deploy-output/public-assets';
|
|
9
|
+
import {
|
|
10
|
+
getDeployingTarget,
|
|
11
|
+
type ResolvedDeployTarget,
|
|
12
|
+
} from '../deploy-output/target';
|
|
2
13
|
import {
|
|
3
14
|
emitFrameworkMicroVerticalReleaseEnvelope,
|
|
4
15
|
emitNodeStagedReleaseEnvelope,
|
|
@@ -6,10 +17,11 @@ import {
|
|
|
6
17
|
verifyNodeReleaseEnvelopeStaging,
|
|
7
18
|
} from './framework-output';
|
|
8
19
|
|
|
9
|
-
type ReleaseEnvelopeTarget = 'cloudflare' | 'node' | string;
|
|
10
|
-
|
|
11
20
|
export interface ReleaseEnvelopeConfig {
|
|
12
|
-
deploy?: {
|
|
21
|
+
deploy?: {
|
|
22
|
+
releaseEnvelopeRole?: 'microvertical' | 'shell';
|
|
23
|
+
node?: { publicAssets?: NodePublicAssetConfig[] };
|
|
24
|
+
};
|
|
13
25
|
}
|
|
14
26
|
|
|
15
27
|
export interface ReleaseEnvelopeAppContext {
|
|
@@ -17,6 +29,7 @@ export interface ReleaseEnvelopeAppContext {
|
|
|
17
29
|
appDirectory: string;
|
|
18
30
|
distDirectory: string;
|
|
19
31
|
metaName: string;
|
|
32
|
+
deployTarget?: ResolvedDeployTarget;
|
|
20
33
|
}
|
|
21
34
|
|
|
22
35
|
export interface ReleaseEnvelopePluginApi<
|
|
@@ -38,64 +51,59 @@ export interface ReleaseEnvelopePlugin<
|
|
|
38
51
|
setup(api: ReleaseEnvelopePluginApi<Config>): void;
|
|
39
52
|
}
|
|
40
53
|
|
|
41
|
-
export type ResolveDeployTarget<
|
|
42
|
-
Config extends ReleaseEnvelopeConfig = ReleaseEnvelopeConfig,
|
|
43
|
-
> = (config: Config) => ReleaseEnvelopeTarget;
|
|
44
|
-
|
|
45
|
-
const resolveActiveDeployTarget = <Config extends ReleaseEnvelopeConfig>(
|
|
46
|
-
api: ReleaseEnvelopePluginApi<Config>,
|
|
47
|
-
resolveDeployTarget: ResolveDeployTarget<Config>,
|
|
48
|
-
) => {
|
|
49
|
-
const { metaName } = api.getAppContext();
|
|
50
|
-
const config = api.getNormalizedConfig();
|
|
51
|
-
if (
|
|
52
|
-
metaName !== 'modern-js' &&
|
|
53
|
-
!config.deploy?.target &&
|
|
54
|
-
!process.env.MODERNJS_DEPLOY
|
|
55
|
-
) {
|
|
56
|
-
return undefined;
|
|
57
|
-
}
|
|
58
|
-
return resolveDeployTarget(config);
|
|
59
|
-
};
|
|
60
|
-
|
|
61
54
|
export const createUltramodernReleaseEnvelopePlugin = <
|
|
62
55
|
Config extends ReleaseEnvelopeConfig,
|
|
63
56
|
>({
|
|
64
|
-
|
|
57
|
+
resolveRendererProfile,
|
|
65
58
|
}: {
|
|
66
|
-
|
|
67
|
-
}): ReleaseEnvelopePlugin<Config> => {
|
|
59
|
+
resolveRendererProfile?: (config: Config) => RendererProfile;
|
|
60
|
+
} = {}): ReleaseEnvelopePlugin<Config> => {
|
|
68
61
|
return {
|
|
69
62
|
name: '@modern-js/ultramodern-release-envelope',
|
|
70
63
|
pre: [
|
|
71
64
|
'@modern-js/backend-federation-build',
|
|
72
65
|
'@modern-js/plugin-bff',
|
|
73
66
|
'@modern-js/deploy-output-aliases',
|
|
67
|
+
'@modern-js/deploy-output-public-assets',
|
|
74
68
|
],
|
|
75
69
|
post: ['@modern-js/plugin-deploy'],
|
|
76
70
|
setup(api) {
|
|
77
|
-
const emitBuildEnvelope = async (
|
|
78
|
-
|
|
71
|
+
const emitBuildEnvelope = async (
|
|
72
|
+
target: 'node' | 'cloudflare',
|
|
73
|
+
requirePromotable = true,
|
|
74
|
+
) => {
|
|
75
|
+
const { apiOnly, appDirectory, distDirectory } = api.getAppContext();
|
|
79
76
|
await emitFrameworkMicroVerticalReleaseEnvelope({
|
|
80
77
|
apiOnly,
|
|
78
|
+
appDirectory,
|
|
81
79
|
distDirectory,
|
|
80
|
+
role: api.getNormalizedConfig().deploy?.releaseEnvelopeRole,
|
|
81
|
+
requirePromotable,
|
|
82
82
|
target,
|
|
83
|
+
...(!apiOnly && resolveRendererProfile
|
|
84
|
+
? {
|
|
85
|
+
expectedRendererProfile: resolveRendererProfile(
|
|
86
|
+
api.getNormalizedConfig(),
|
|
87
|
+
),
|
|
88
|
+
}
|
|
89
|
+
: {}),
|
|
83
90
|
});
|
|
84
91
|
};
|
|
85
92
|
|
|
86
93
|
api.onAfterBuild(async () => {
|
|
87
|
-
const configuredTarget =
|
|
94
|
+
const configuredTarget = api.getAppContext().deployTarget?.target;
|
|
88
95
|
if (configuredTarget !== 'node' && configuredTarget !== 'cloudflare') {
|
|
89
96
|
return;
|
|
90
97
|
}
|
|
91
|
-
|
|
98
|
+
// A plain `modern build` is the development path: a dirty or non-Git
|
|
99
|
+
// checkout resolves to the `workspace` source revision, which is not
|
|
100
|
+
// promotable but must still build. Deploy re-emits the envelope and
|
|
101
|
+
// verifies it, so the release gate keeps its teeth there.
|
|
102
|
+
await emitBuildEnvelope(configuredTarget, false);
|
|
92
103
|
});
|
|
93
104
|
|
|
94
105
|
api.onBeforeDeploy(async () => {
|
|
95
|
-
const configuredTarget =
|
|
96
|
-
api,
|
|
97
|
-
resolveDeployTarget,
|
|
98
|
-
);
|
|
106
|
+
const configuredTarget = getDeployingTarget(api.getAppContext());
|
|
99
107
|
if (configuredTarget !== 'node') {
|
|
100
108
|
return;
|
|
101
109
|
}
|
|
@@ -105,16 +113,24 @@ export const createUltramodernReleaseEnvelopePlugin = <
|
|
|
105
113
|
});
|
|
106
114
|
|
|
107
115
|
api.onAfterDeploy(async () => {
|
|
108
|
-
const configuredTarget =
|
|
109
|
-
api,
|
|
110
|
-
resolveDeployTarget,
|
|
111
|
-
);
|
|
116
|
+
const configuredTarget = getDeployingTarget(api.getAppContext());
|
|
112
117
|
if (configuredTarget !== 'node') {
|
|
113
118
|
return;
|
|
114
119
|
}
|
|
115
120
|
const { appDirectory, distDirectory } = api.getAppContext();
|
|
116
121
|
const outputDirectory = path.join(appDirectory, '.output');
|
|
117
122
|
const releaseEnvelope = await emitNodeStagedReleaseEnvelope({
|
|
123
|
+
// The Node deploy output is a copy of dist, so a declared file
|
|
124
|
+
// added output exactly when dist has no file at its path.
|
|
125
|
+
declaredPublicAssets: await resolveAddedDeclaredPublicAssetPaths({
|
|
126
|
+
appDirectory,
|
|
127
|
+
assets: normalizeDeclaredPublicAssets(
|
|
128
|
+
api.getNormalizedConfig().deploy?.node?.publicAssets,
|
|
129
|
+
NODE_PUBLIC_ASSET_SCOPE,
|
|
130
|
+
),
|
|
131
|
+
generatedRoot: distDirectory,
|
|
132
|
+
scope: NODE_PUBLIC_ASSET_SCOPE,
|
|
133
|
+
}),
|
|
118
134
|
distDirectory,
|
|
119
135
|
outputDirectory,
|
|
120
136
|
});
|