@bleedingdev/modern-js-app-tools-extensions 3.9.0-ultramodern.8 → 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 +164 -18
- package/dist/cjs/policy-defaults.js +110 -0
- 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/runtime-package-resolution.js +118 -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 +158 -18
- package/dist/esm/policy-defaults.mjs +51 -0
- 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/runtime-package-resolution.mjs +60 -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 +158 -18
- package/dist/esm-node/policy-defaults.mjs +52 -0
- 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/runtime-package-resolution.mjs +61 -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 +56 -0
- 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/runtime-package-resolution.d.ts +28 -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 +97 -26
- 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 +281 -26
- package/src/policy-defaults.ts +157 -0
- 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/runtime-package-resolution.ts +115 -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
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import node_path from "node:path";
|
|
3
|
+
const REFERENCE_TOPOLOGY_PATH = 'topology/reference-topology.json';
|
|
4
|
+
const DEVELOPMENT_OVERLAY_PATH = 'topology/local-overlays/development.json';
|
|
5
|
+
const normalizeRelativePath = (value)=>value.replace(/\\/gu, '/').replace(/^\.\/+/u, '');
|
|
6
|
+
const distributedSsrFragmentSlug = (expose)=>{
|
|
7
|
+
const slug = expose.replace(/^\.\//u, '').trim().replace(/([a-z0-9])([A-Z])/gu, '$1-$2').replace(/[^a-zA-Z0-9._-]+/gu, '-').replace(/[._]+/gu, '-').toLowerCase().replace(/-+/gu, '-').replace(/^-+|-+$/gu, '');
|
|
8
|
+
if (!slug) throw new Error(`Invalid distributed SSR expose ${expose}.`);
|
|
9
|
+
return slug;
|
|
10
|
+
};
|
|
11
|
+
const distributedSsrFragmentRoute = (expose)=>`/{locale}/_mf/fragment/${distributedSsrFragmentSlug(expose)}`;
|
|
12
|
+
const findWorkspaceRoot = (appDirectory)=>{
|
|
13
|
+
let current = appDirectory;
|
|
14
|
+
while(true){
|
|
15
|
+
if (existsSync(node_path.join(current, REFERENCE_TOPOLOGY_PATH))) return current;
|
|
16
|
+
const parent = node_path.dirname(current);
|
|
17
|
+
if (parent === current) return;
|
|
18
|
+
current = parent;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
export { DEVELOPMENT_OVERLAY_PATH, REFERENCE_TOPOLOGY_PATH, distributedSsrFragmentRoute, distributedSsrFragmentSlug, findWorkspaceRoot, normalizeRelativePath };
|
|
@@ -46,28 +46,34 @@ const createBackendRemoteEntrySource = async (workspaceRoot, app, effectApiPath,
|
|
|
46
46
|
} : {}
|
|
47
47
|
};
|
|
48
48
|
const source = `// Generated by Modern.js backend federation build.
|
|
49
|
-
import
|
|
49
|
+
import { adoptEffectBffShareScope } from '@modern-js/bff-effect/effect-edge';
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
51
|
+
// The expose evaluates lazily so defineEffectBff registers its handler
|
|
52
|
+
// factories with the registry the host shares through init().
|
|
53
|
+
let exposedModule;
|
|
54
|
+
const loadExposedModule = () =>
|
|
55
|
+
(exposedModule ??= import(${JSON.stringify(effectApiSpecifier)}).then(exposedNamespace => ({
|
|
56
|
+
...exposedNamespace,
|
|
57
|
+
backendFederationContract: {
|
|
58
|
+
...(exposedNamespace.backendFederationContract ?? {}),
|
|
59
|
+
compatibility: {
|
|
60
|
+
...(exposedNamespace.backendFederationContract?.compatibility ?? {}),
|
|
61
|
+
...${JSON.stringify(compatibility)},
|
|
62
|
+
},
|
|
63
|
+
name: ${JSON.stringify(app.backendName)},
|
|
64
|
+
role: 'microvertical-server',
|
|
65
|
+
runtimeFramework: 'effect',
|
|
66
|
+
strictEffectApproach: true,
|
|
58
67
|
},
|
|
59
|
-
|
|
60
|
-
role: 'microvertical-server',
|
|
61
|
-
runtimeFramework: 'effect',
|
|
62
|
-
strictEffectApproach: true,
|
|
63
|
-
},
|
|
64
|
-
};
|
|
68
|
+
})));
|
|
65
69
|
const exposedModules = {
|
|
66
|
-
${JSON.stringify(BACKEND_FEDERATION_EFFECT_EXPOSE)}:
|
|
70
|
+
${JSON.stringify(BACKEND_FEDERATION_EFFECT_EXPOSE)}: loadExposedModule,
|
|
67
71
|
};
|
|
68
72
|
const __modernjsBackendFederation = ${JSON.stringify(containerMetadata)};
|
|
69
73
|
|
|
70
|
-
function init() {
|
|
74
|
+
function init(shareScope) {
|
|
75
|
+
return adoptEffectBffShareScope(shareScope);
|
|
76
|
+
}
|
|
71
77
|
|
|
72
78
|
function get(id) {
|
|
73
79
|
const load = exposedModules[id];
|
|
@@ -171,8 +177,13 @@ const createBackendManifest = (workspaceRoot, distDirectory, app, entryIntegrity
|
|
|
171
177
|
source: {
|
|
172
178
|
module: sourceModule
|
|
173
179
|
},
|
|
174
|
-
|
|
175
|
-
|
|
180
|
+
...'rpc' === app.apiProtocol ? {
|
|
181
|
+
rpcPath: app.rpcPath,
|
|
182
|
+
rpcSerialization: 'json'
|
|
183
|
+
} : {
|
|
184
|
+
readinessPath: `${app.apiPrefix}/${app.apiStem}/readiness`,
|
|
185
|
+
openapiPath: `${app.apiPrefix}/openapi.json`
|
|
186
|
+
},
|
|
176
187
|
...app.deliveryUnit ? {
|
|
177
188
|
deliveryUnit: app.deliveryUnit
|
|
178
189
|
} : {},
|
|
@@ -4,8 +4,7 @@ import promises from "node:fs/promises";
|
|
|
4
4
|
import node_path from "node:path";
|
|
5
5
|
import { resolveUltramodernSourceRevision } from "@modern-js/app-tools-extensions/release-identity";
|
|
6
6
|
import { BACKEND_FEDERATION_MANIFEST_FILE, BACKEND_FEDERATION_REMOTE_ENTRY_FILE, DELIVERY_UNIT_DEPLOY_PROFILE, DELIVERY_UNIT_KIND, DELIVERY_UNIT_SCHEMA_VERSION, ULTRAMODERN_BUILD_ARTIFACT_PATH, deliveryUnitContractBlock, isUltramodernBuildArtifact, validateDeliveryUnitRecord, validateUltramodernBuildArtifact } from "@modern-js/backend-federation-contracts";
|
|
7
|
-
|
|
8
|
-
const normalizeRelativePath = (value)=>value.replace(/\\/gu, '/').replace(/^\.\/+/u, '');
|
|
7
|
+
import { DEVELOPMENT_OVERLAY_PATH, REFERENCE_TOPOLOGY_PATH, findWorkspaceRoot, normalizeRelativePath } from "../workspace-topology.mjs";
|
|
9
8
|
const isRecord = (value)=>'object' == typeof value && null !== value;
|
|
10
9
|
const readJsonFile = async (filePath)=>JSON.parse(await promises.readFile(filePath, 'utf8'));
|
|
11
10
|
const buildArtifactPathFor = (appDirectory)=>node_path.join(appDirectory, ULTRAMODERN_BUILD_ARTIFACT_PATH);
|
|
@@ -32,19 +31,20 @@ const readBuildIdentity = async (appDirectory)=>{
|
|
|
32
31
|
const toPascalCase = (value)=>value.split(/[^a-zA-Z0-9]+/u).filter(Boolean).map((part)=>part.charAt(0).toUpperCase() + part.slice(1)).join('');
|
|
33
32
|
const stringValue = (value)=>'string' == typeof value && value.length > 0 ? value : void 0;
|
|
34
33
|
const createBackendName = (app, id)=>{
|
|
35
|
-
const configuredName = stringValue(app.backendFederation?.name) ?? stringValue(app.backendFederation?.executionSurfaces?.node?.remoteName)
|
|
34
|
+
const configuredName = stringValue(app.backendFederation?.name) ?? stringValue(app.backendFederation?.executionSurfaces?.node?.remoteName);
|
|
36
35
|
if (configuredName) return configuredName;
|
|
37
36
|
const mfName = stringValue(app.moduleFederation?.name);
|
|
38
37
|
return mfName ? `${mfName}Backend` : `vertical${toPascalCase(id)}Backend`;
|
|
39
38
|
};
|
|
40
|
-
const
|
|
41
|
-
let
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
current = parent;
|
|
39
|
+
const rebaseDefaultLocalUrl = (value, defaultPort, publicOrigin)=>{
|
|
40
|
+
let url;
|
|
41
|
+
try {
|
|
42
|
+
url = new URL(value);
|
|
43
|
+
} catch {
|
|
44
|
+
return value;
|
|
47
45
|
}
|
|
46
|
+
if ('http:' !== url.protocol || 'localhost' !== url.hostname || Number(url.port) !== defaultPort || url.username || url.password) return value;
|
|
47
|
+
return `${publicOrigin}${url.pathname}${url.search}${url.hash}`;
|
|
48
48
|
};
|
|
49
49
|
const resolveWorkspaceSourceRevision = async (workspaceRoot)=>resolveUltramodernSourceRevision(workspaceRoot);
|
|
50
50
|
const createStampedDeliveryUnit = (input)=>{
|
|
@@ -64,54 +64,90 @@ const createStampedDeliveryUnit = (input)=>{
|
|
|
64
64
|
if (!validation.ok) return;
|
|
65
65
|
return deliveryUnitContractBlock(record);
|
|
66
66
|
};
|
|
67
|
-
const
|
|
68
|
-
const id = stringValue(
|
|
69
|
-
const appPath = stringValue(
|
|
70
|
-
if (!id || 'vertical' !==
|
|
71
|
-
const directory =
|
|
67
|
+
const createAppFromTopology = (workspaceRoot, appDirectory, topologyApp, overlay, packageManifest)=>{
|
|
68
|
+
const id = stringValue(topologyApp.id);
|
|
69
|
+
const appPath = stringValue(topologyApp.path);
|
|
70
|
+
if (!id || !appPath || 'vertical' !== topologyApp.kind || !isRecord(topologyApp.api) || !isRecord(topologyApp.backendFederation)) return;
|
|
71
|
+
const directory = normalizeRelativePath(appPath);
|
|
72
72
|
if (node_path.resolve(workspaceRoot, directory) !== node_path.resolve(appDirectory)) return;
|
|
73
|
-
const
|
|
74
|
-
if (
|
|
75
|
-
const
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
const
|
|
80
|
-
|
|
73
|
+
const defaultPort = overlay.ports?.[id];
|
|
74
|
+
if ('number' != typeof defaultPort || !Number.isInteger(defaultPort) || defaultPort < 1 || defaultPort > 65535) throw new Error(`[backend-federation-build] Invalid development port for ${id}.`);
|
|
75
|
+
const portEnv = stringValue(topologyApp.portEnv) ?? `VERTICAL_${(stringValue(topologyApp.domain) ?? id).replace(/[^a-zA-Z0-9]/gu, '_').toUpperCase()}_PORT`;
|
|
76
|
+
const port = Number(process.env[portEnv] ?? defaultPort);
|
|
77
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) throw new Error(`[backend-federation-build] Invalid ${portEnv} development port for ${id}.`);
|
|
78
|
+
const publicUrlEnv = stringValue(topologyApp.cloudflare?.publicUrlEnv);
|
|
79
|
+
const configuredPublicUrl = publicUrlEnv ? process.env[publicUrlEnv]?.trim() : void 0;
|
|
80
|
+
let publicOrigin = `http://localhost:${port}`;
|
|
81
|
+
if (configuredPublicUrl) {
|
|
82
|
+
let url;
|
|
83
|
+
try {
|
|
84
|
+
url = new URL(configuredPublicUrl);
|
|
85
|
+
} catch {
|
|
86
|
+
throw new Error(`[backend-federation-build] Invalid ${publicUrlEnv} public URL for ${id}.`);
|
|
87
|
+
}
|
|
88
|
+
if (![
|
|
89
|
+
'http:',
|
|
90
|
+
'https:'
|
|
91
|
+
].includes(url.protocol) || url.username || url.password) throw new Error(`[backend-federation-build] Invalid ${publicUrlEnv} public URL for ${id}.`);
|
|
92
|
+
publicOrigin = url.origin;
|
|
93
|
+
}
|
|
94
|
+
const apiPrefix = stringValue(topologyApp.api.bff?.prefix) ?? `/${id}-api`;
|
|
95
|
+
const apiProtocol = topologyApp.api.protocol ?? 'rest';
|
|
96
|
+
if ('rest' !== apiProtocol && 'rpc' !== apiProtocol) throw new Error(`[backend-federation-build] Unsupported API protocol for ${id}.`);
|
|
97
|
+
const rpcPath = 'rpc' === apiProtocol ? stringValue(topologyApp.api.rpcPath) : void 0;
|
|
98
|
+
if ('rpc' === apiProtocol && (!rpcPath || 'json' !== topologyApp.api.rpcSerialization)) throw new Error(`[backend-federation-build] Missing JSON RPC route metadata for ${id}.`);
|
|
99
|
+
const apiStem = stringValue(topologyApp.api.stem) ?? id;
|
|
100
|
+
const backendName = createBackendName(topologyApp, id);
|
|
101
|
+
const nodeOverlay = overlay.serverExecution?.[id]?.node;
|
|
102
|
+
if (!isRecord(nodeOverlay)) throw new Error(`[backend-federation-build] Missing declared Node server execution for ${id}.`);
|
|
103
|
+
const manifestUrl = rebaseDefaultLocalUrl(stringValue(nodeOverlay?.manifestUrl) ?? `http://localhost:${defaultPort}/${BACKEND_FEDERATION_MANIFEST_FILE}`, defaultPort, publicOrigin);
|
|
104
|
+
const containerEntry = rebaseDefaultLocalUrl(stringValue(nodeOverlay?.containerEntry) ?? `http://localhost:${defaultPort}/${BACKEND_FEDERATION_REMOTE_ENTRY_FILE}`, defaultPort, publicOrigin);
|
|
105
|
+
const configuredRemoteType = stringValue(nodeOverlay?.remoteType) ?? stringValue(topologyApp.backendFederation?.executionSurfaces?.node?.remoteType);
|
|
81
106
|
if (void 0 !== configuredRemoteType && 'commonjs-module' !== configuredRemoteType) throw new Error(`[backend-federation-build] Node backend federation remoteType must be "commonjs-module"; received "${configuredRemoteType}" for ${id}.`);
|
|
82
107
|
if (!new URL(containerEntry).pathname.endsWith(`/${BACKEND_FEDERATION_REMOTE_ENTRY_FILE}`)) throw new Error(`[backend-federation-build] Node backend federation containerEntry must end with "/${BACKEND_FEDERATION_REMOTE_ENTRY_FILE}"; received "${containerEntry}" for ${id}.`);
|
|
83
108
|
const remoteType = 'commonjs-module';
|
|
84
|
-
const packageName = stringValue(
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
109
|
+
const packageName = stringValue(packageManifest.name);
|
|
110
|
+
const version = stringValue(packageManifest.version);
|
|
111
|
+
if (stringValue(topologyApp.package) !== packageName || !version) throw new Error(`[backend-federation-build] Topology package identity must match package.json for ${id}.`);
|
|
112
|
+
const declaredUiManifestUrl = stringValue(overlay.manifests?.[id]);
|
|
113
|
+
const uiManifestUrl = declaredUiManifestUrl ? rebaseDefaultLocalUrl(declaredUiManifestUrl, defaultPort, publicOrigin) : void 0;
|
|
114
|
+
const topologyDeliveryUnit = isRecord(topologyApp.deliveryUnit) ? {
|
|
115
|
+
unitId: stringValue(topologyApp.deliveryUnit.unitId),
|
|
116
|
+
buildMarker: stringValue(topologyApp.deliveryUnit.buildMarker),
|
|
117
|
+
sourceRevision: stringValue(topologyApp.deliveryUnit.sourceRevision),
|
|
118
|
+
packageName: stringValue(topologyApp.deliveryUnit.packageName),
|
|
119
|
+
version: stringValue(topologyApp.deliveryUnit.version)
|
|
92
120
|
} : void 0;
|
|
93
121
|
return {
|
|
94
122
|
id,
|
|
95
123
|
directory,
|
|
96
124
|
packageName,
|
|
125
|
+
version,
|
|
97
126
|
port,
|
|
98
127
|
apiPrefix,
|
|
128
|
+
apiProtocol,
|
|
129
|
+
rpcPath,
|
|
99
130
|
apiStem,
|
|
100
131
|
backendName,
|
|
101
132
|
manifestUrl,
|
|
102
133
|
containerEntry,
|
|
103
134
|
remoteType,
|
|
104
135
|
uiManifestUrl,
|
|
105
|
-
|
|
136
|
+
topologyDeliveryUnit
|
|
106
137
|
};
|
|
107
138
|
};
|
|
108
139
|
const findBackendFederationApp = async (workspaceRoot, appDirectory)=>{
|
|
109
|
-
const
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
140
|
+
const topologyPath = node_path.join(workspaceRoot, REFERENCE_TOPOLOGY_PATH);
|
|
141
|
+
const topology = await readJsonFile(topologyPath);
|
|
142
|
+
if (!isRecord(topology) || !Array.isArray(topology.verticals)) throw new Error(`[backend-federation-build] Invalid declared topology at ${topologyPath}.`);
|
|
143
|
+
const overlayPath = node_path.join(workspaceRoot, DEVELOPMENT_OVERLAY_PATH);
|
|
144
|
+
const overlay = await readJsonFile(overlayPath);
|
|
145
|
+
if (!isRecord(overlay) || !isRecord(overlay.ports)) throw new Error(`[backend-federation-build] Invalid development overlay at ${overlayPath}.`);
|
|
146
|
+
const packageManifest = await readJsonFile(node_path.join(appDirectory, 'package.json'));
|
|
147
|
+
for (const app of topology.verticals){
|
|
148
|
+
const resolved = createAppFromTopology(workspaceRoot, appDirectory, app, overlay, packageManifest);
|
|
114
149
|
if (resolved) return resolved;
|
|
115
150
|
}
|
|
151
|
+
throw new Error(`[backend-federation-build] ${appDirectory} is missing from the declared reference topology.`);
|
|
116
152
|
};
|
|
117
|
-
export {
|
|
153
|
+
export { DEVELOPMENT_OVERLAY_PATH, REFERENCE_TOPOLOGY_PATH, buildArtifactPathFor, createAppFromTopology, createStampedDeliveryUnit, findBackendFederationApp, findWorkspaceRoot, normalizeRelativePath, readBuildIdentity, resolveWorkspaceSourceRevision };
|
|
@@ -5,9 +5,10 @@ import node_path from "node:path";
|
|
|
5
5
|
import { resolveUltramodernReleaseIdentity } from "@modern-js/app-tools-extensions/release-identity";
|
|
6
6
|
import { BACKEND_FEDERATION_MANIFEST_FILE, BACKEND_FEDERATION_REMOTE_ENTRY_FILE, ULTRAMODERN_BUILD_ARTIFACT_FILE, stampUltramodernBuildArtifactIdentity } from "@modern-js/backend-federation-contracts";
|
|
7
7
|
import { createBackendFederationEntryIntegrity } from "@modern-js/server-runtime-extensions/backend-federation-security/node";
|
|
8
|
+
import { emitRendererBuildArtifact, stampFinalizedRendererBuildArtifact, validateFinalizedRendererBuild } from "../release-envelope/renderer-output-stamp.mjs";
|
|
8
9
|
import { createBackendManifest, createBackendRemoteEntrySource } from "./codegen.mjs";
|
|
9
|
-
import {
|
|
10
|
-
const emitBackendFederationArtifacts = async (appDirectory, distDirectory)=>{
|
|
10
|
+
import { REFERENCE_TOPOLOGY_PATH, buildArtifactPathFor, createStampedDeliveryUnit, findBackendFederationApp, findWorkspaceRoot, readBuildIdentity, resolveWorkspaceSourceRevision } from "./config.mjs";
|
|
11
|
+
const emitBackendFederationArtifacts = async (appDirectory, distDirectory, options = {})=>{
|
|
11
12
|
const workspaceRoot = findWorkspaceRoot(appDirectory);
|
|
12
13
|
if (!workspaceRoot) return;
|
|
13
14
|
const effectApiPath = node_path.join(appDirectory, 'api/effect-api.ts');
|
|
@@ -16,35 +17,50 @@ const emitBackendFederationArtifacts = async (appDirectory, distDirectory)=>{
|
|
|
16
17
|
const app = await findBackendFederationApp(workspaceRoot, appDirectory);
|
|
17
18
|
if (!app) return;
|
|
18
19
|
const buildIdentity = await readBuildIdentity(appDirectory);
|
|
19
|
-
const
|
|
20
|
-
const
|
|
20
|
+
const topologyDeliveryUnit = app.topologyDeliveryUnit;
|
|
21
|
+
const hasTopologyDeliveryUnit = void 0 !== topologyDeliveryUnit && (void 0 !== topologyDeliveryUnit.unitId || void 0 !== topologyDeliveryUnit.buildMarker || void 0 !== topologyDeliveryUnit.packageName || void 0 !== topologyDeliveryUnit.version);
|
|
21
22
|
const hasBuildIdentity = void 0 !== buildIdentity.unitId || void 0 !== buildIdentity.buildVersion || void 0 !== buildIdentity.packageName || void 0 !== buildIdentity.version;
|
|
22
23
|
if (hasBuildIdentity) {
|
|
23
|
-
const
|
|
24
|
+
const topologyPath = node_path.join(workspaceRoot, REFERENCE_TOPOLOGY_PATH);
|
|
24
25
|
const buildIdentityPath = buildArtifactPathFor(appDirectory);
|
|
25
26
|
const mismatches = [];
|
|
26
27
|
const compare = (label, a, b, leftLabel = 'deliveryUnit')=>{
|
|
27
28
|
if (void 0 !== a && void 0 !== b && a !== b) mismatches.push(`${label}: ${leftLabel}=${a} vs ultramodern-build=${b}`);
|
|
28
29
|
};
|
|
29
30
|
compare('appId', app.id, buildIdentity.appId, 'topology');
|
|
30
|
-
if (
|
|
31
|
-
compare('unitId',
|
|
32
|
-
compare('buildMarker/build',
|
|
33
|
-
compare('packageName',
|
|
34
|
-
compare('version',
|
|
31
|
+
if (hasTopologyDeliveryUnit) {
|
|
32
|
+
compare('unitId', topologyDeliveryUnit?.unitId, buildIdentity.unitId);
|
|
33
|
+
compare('buildMarker/build', topologyDeliveryUnit?.buildMarker, buildIdentity.buildVersion);
|
|
34
|
+
compare('packageName', topologyDeliveryUnit?.packageName, buildIdentity.packageName);
|
|
35
|
+
compare('version', topologyDeliveryUnit?.version, buildIdentity.version);
|
|
35
36
|
}
|
|
36
|
-
|
|
37
|
+
compare('packageName', app.packageName, buildIdentity.packageName, 'package.json');
|
|
38
|
+
compare('packageName', topologyDeliveryUnit?.packageName, app.packageName, 'topology');
|
|
39
|
+
compare('version', app.version, buildIdentity.version, 'package.json');
|
|
40
|
+
compare('version', topologyDeliveryUnit?.version, app.version, 'topology');
|
|
41
|
+
if (mismatches.length > 0) throw new Error(`[backend-federation-build] Delivery-unit identity drift between ${topologyPath}, package.json and ${buildIdentityPath}: ${mismatches.join('; ')}`);
|
|
37
42
|
}
|
|
38
|
-
const unitId =
|
|
39
|
-
const generationBuildMarker =
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
const unitId = topologyDeliveryUnit?.unitId ?? buildIdentity.unitId;
|
|
44
|
+
const generationBuildMarker = topologyDeliveryUnit?.buildMarker ?? buildIdentity.buildVersion;
|
|
45
|
+
let finalizedRendererBuild;
|
|
46
|
+
if (options.resolveRendererBuild && buildIdentity.artifact?.surfaces.ui) {
|
|
47
|
+
if (!options.entrypoints?.length) throw new Error('[backend-federation-build] Renderer output stamping requires the actual finalized application entries.');
|
|
48
|
+
const context = {
|
|
49
|
+
appDirectory,
|
|
50
|
+
distDirectory,
|
|
51
|
+
entrypoints: options.entrypoints
|
|
52
|
+
};
|
|
53
|
+
finalizedRendererBuild = await options.resolveRendererBuild(context);
|
|
54
|
+
validateFinalizedRendererBuild(finalizedRendererBuild, context, app.id);
|
|
55
|
+
}
|
|
56
|
+
const sourceRevision = finalizedRendererBuild?.sourceRevision ?? await resolveWorkspaceSourceRevision(workspaceRoot);
|
|
57
|
+
const buildVersion = finalizedRendererBuild?.buildMarker ?? (generationBuildMarker && unitId ? resolveUltramodernReleaseIdentity({
|
|
42
58
|
generationBuildMarker,
|
|
43
59
|
unitId,
|
|
44
60
|
workspaceRoot
|
|
45
|
-
}).buildMarker : void 0;
|
|
46
|
-
const packageName =
|
|
47
|
-
const version =
|
|
61
|
+
}).buildMarker : void 0);
|
|
62
|
+
const packageName = app.packageName;
|
|
63
|
+
const version = app.version;
|
|
48
64
|
const deliveryUnit = createStampedDeliveryUnit({
|
|
49
65
|
appId: app.id,
|
|
50
66
|
unitId,
|
|
@@ -53,10 +69,15 @@ const emitBackendFederationArtifacts = async (appDirectory, distDirectory)=>{
|
|
|
53
69
|
version,
|
|
54
70
|
sourceRevision
|
|
55
71
|
});
|
|
56
|
-
|
|
72
|
+
let stampedBuildArtifact = buildIdentity.artifact ? stampUltramodernBuildArtifactIdentity(buildIdentity.artifact, {
|
|
57
73
|
buildMarker: buildVersion ?? buildIdentity.artifact.deliveryUnit.buildMarker,
|
|
58
74
|
sourceRevision
|
|
59
75
|
}) : void 0;
|
|
76
|
+
if (finalizedRendererBuild && stampedBuildArtifact?.surfaces.ui) stampedBuildArtifact = stampFinalizedRendererBuildArtifact(stampedBuildArtifact, finalizedRendererBuild, {
|
|
77
|
+
appDirectory,
|
|
78
|
+
distDirectory,
|
|
79
|
+
entrypoints: options.entrypoints
|
|
80
|
+
});
|
|
60
81
|
const resolvedApp = {
|
|
61
82
|
...app,
|
|
62
83
|
packageName,
|
|
@@ -87,14 +108,34 @@ const emitBackendFederationArtifacts = async (appDirectory, distDirectory)=>{
|
|
|
87
108
|
remoteType: resolvedApp.remoteType
|
|
88
109
|
};
|
|
89
110
|
};
|
|
90
|
-
const emit = ()=>
|
|
111
|
+
const emit = (options = {})=>{
|
|
112
|
+
if (options.resolveRendererBuild && !options.rendererBuildPlugin) throw new Error('[backend-federation-build] A finalized renderer resolver requires its owning metadata producer plugin.');
|
|
113
|
+
return {
|
|
91
114
|
name: '@modern-js/backend-federation-build',
|
|
115
|
+
pre: options.resolveRendererBuild ? [
|
|
116
|
+
options.rendererBuildPlugin
|
|
117
|
+
] : [],
|
|
118
|
+
required: options.resolveRendererBuild ? [
|
|
119
|
+
options.rendererBuildPlugin
|
|
120
|
+
] : [],
|
|
92
121
|
setup (api) {
|
|
93
122
|
api.onAfterBuild(async ()=>{
|
|
94
|
-
const { appDirectory, distDirectory } = api.getAppContext();
|
|
95
|
-
|
|
123
|
+
const { appDirectory, distDirectory, entrypoints, apiOnly } = api.getAppContext();
|
|
124
|
+
if (options.resolveRendererBuild && !apiOnly) await emitRendererBuildArtifact({
|
|
125
|
+
appDirectory,
|
|
126
|
+
distDirectory,
|
|
127
|
+
entrypoints: entrypoints ?? []
|
|
128
|
+
}, {
|
|
129
|
+
resolveRendererBuild: options.resolveRendererBuild,
|
|
130
|
+
rendererBuildPlugin: options.rendererBuildPlugin
|
|
131
|
+
});
|
|
132
|
+
await emitBackendFederationArtifacts(appDirectory, distDirectory, {
|
|
133
|
+
...options,
|
|
134
|
+
entrypoints
|
|
135
|
+
});
|
|
96
136
|
});
|
|
97
137
|
}
|
|
98
|
-
}
|
|
138
|
+
};
|
|
139
|
+
};
|
|
99
140
|
export default emit;
|
|
100
141
|
export { emitBackendFederationArtifacts };
|
|
@@ -1,148 +1,29 @@
|
|
|
1
1
|
import "node:module";
|
|
2
|
-
import { execFileSync } from "node:child_process";
|
|
3
2
|
import { createHash } from "node:crypto";
|
|
4
3
|
import { accessSync, chmodSync, constants, lstatSync, mkdirSync, readFileSync, realpathSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
5
|
-
import { createRequire } from "node:module";
|
|
4
|
+
import { createRequire, findPackageJSON } from "node:module";
|
|
6
5
|
import { tmpdir } from "node:os";
|
|
7
|
-
import { basename,
|
|
8
|
-
|
|
9
|
-
const
|
|
6
|
+
import { basename, join } from "node:path";
|
|
7
|
+
import "node:url";
|
|
8
|
+
const owningModuleUrl = import.meta.url;
|
|
9
|
+
const owningManifest = findPackageJSON(owningModuleUrl, owningModuleUrl);
|
|
10
|
+
if (!owningManifest) throw new Error('Cannot find owning build-config package manifest');
|
|
11
|
+
const owningName = JSON.parse(readFileSync(owningManifest, 'utf8')).name;
|
|
12
|
+
if ('string' != typeof owningName || 0 === owningName.length) throw new Error(`Invalid owning build-config package name: ${owningManifest}`);
|
|
13
|
+
const { effectCompilerDiscoveryFailureStage: effectCompilerDiscoveryFailureStage, resolveInstalledEffectCompiler: resolveInstalledEffectCompiler } = createRequire(owningModuleUrl)(`${owningName}/internal-effect-discovery`);
|
|
10
14
|
const EFFECT_TSGO_RESOLUTION_ERROR = 'Unable to resolve the Effect TS-Go compiler. Install "@effect/tsgo" and a native TypeScript backend for this build config, or set EFFECT_TSGO_BIN.';
|
|
11
15
|
const executableEffectTsgoCompilers = new Map();
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
'run',
|
|
17
|
-
'watchRun',
|
|
18
|
-
'afterDone',
|
|
19
|
-
'failed',
|
|
20
|
-
'shutdown',
|
|
21
|
-
'watchClose'
|
|
22
|
-
];
|
|
23
|
-
function restoreEnvironment(name, value) {
|
|
24
|
-
if (void 0 === value) delete process.env[name];
|
|
25
|
-
else process.env[name] = value;
|
|
26
|
-
}
|
|
27
|
-
function createEnvironmentLeaseRegistry() {
|
|
28
|
-
const environmentLeases = new Map();
|
|
29
|
-
return Object.freeze({
|
|
30
|
-
acquire (name, value) {
|
|
31
|
-
let lease = environmentLeases.get(name);
|
|
32
|
-
if (lease) {
|
|
33
|
-
if (lease.value !== value) throw new Error(`Build config environment "${name}" already has an active lease for a different value.`);
|
|
34
|
-
if (process.env[name] !== lease.value) throw new Error(`Build config environment lease for "${name}" lost ownership before another lease was acquired.`);
|
|
35
|
-
} else {
|
|
36
|
-
lease = {
|
|
37
|
-
originalValue: process.env[name],
|
|
38
|
-
owners: new Set(),
|
|
39
|
-
value
|
|
40
|
-
};
|
|
41
|
-
process.env[name] = value;
|
|
42
|
-
environmentLeases.set(name, lease);
|
|
43
|
-
}
|
|
44
|
-
const owner = Symbol(name);
|
|
45
|
-
lease.owners.add(owner);
|
|
46
|
-
let released = false;
|
|
47
|
-
return ()=>{
|
|
48
|
-
if (released) return;
|
|
49
|
-
if (environmentLeases.get(name) !== lease || !lease.owners.has(owner)) throw new Error(`Build config environment lease for "${name}" cannot be restored because its ownership record was lost.`);
|
|
50
|
-
released = true;
|
|
51
|
-
const lostOwnership = process.env[name] !== lease.value;
|
|
52
|
-
lease.owners.delete(owner);
|
|
53
|
-
if (0 === lease.owners.size) {
|
|
54
|
-
environmentLeases.delete(name);
|
|
55
|
-
restoreEnvironment(name, lease.originalValue);
|
|
56
|
-
} else if (lostOwnership) process.env[name] = lease.value;
|
|
57
|
-
if (lostOwnership) throw new Error(`Build config environment lease for "${name}" lost ownership before restoration.`);
|
|
58
|
-
};
|
|
59
|
-
},
|
|
60
|
-
brand: ENVIRONMENT_LEASE_REGISTRY_BRAND
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
function getEnvironmentLeaseRegistry() {
|
|
64
|
-
const descriptor = Object.getOwnPropertyDescriptor(process, ENVIRONMENT_LEASE_REGISTRY_KEY);
|
|
65
|
-
if (descriptor) {
|
|
66
|
-
const registry = descriptor.value;
|
|
67
|
-
if (descriptor.configurable || descriptor.enumerable || descriptor.writable || registry?.brand !== ENVIRONMENT_LEASE_REGISTRY_BRAND || 'function' != typeof registry.acquire) throw new Error('The process-global build config environment lease registry is occupied by an incompatible value.');
|
|
68
|
-
return registry;
|
|
69
|
-
}
|
|
70
|
-
const registry = createEnvironmentLeaseRegistry();
|
|
71
|
-
Object.defineProperty(process, ENVIRONMENT_LEASE_REGISTRY_KEY, {
|
|
72
|
-
configurable: false,
|
|
73
|
-
enumerable: false,
|
|
74
|
-
value: registry,
|
|
75
|
-
writable: false
|
|
16
|
+
function effectTsgoResolutionError(cause, stage, from) {
|
|
17
|
+
const detail = cause instanceof Error ? `${cause.name}: ${cause.message}` : String(cause);
|
|
18
|
+
return new Error(`${EFFECT_TSGO_RESOLUTION_ERROR}\n${stage} failed for ${String(from)}: ${detail}`, {
|
|
19
|
+
cause
|
|
76
20
|
});
|
|
77
|
-
return registry;
|
|
78
|
-
}
|
|
79
|
-
function acquireEnvironmentLease(name, value) {
|
|
80
|
-
return getEnvironmentLeaseRegistry().acquire(name, value);
|
|
81
|
-
}
|
|
82
|
-
function releaseAfterFailure(release, originalError) {
|
|
83
|
-
try {
|
|
84
|
-
release();
|
|
85
|
-
} catch (restorationError) {
|
|
86
|
-
throw new AggregateError([
|
|
87
|
-
originalError,
|
|
88
|
-
restorationError
|
|
89
|
-
], 'Build config environment setup and restoration both failed.');
|
|
90
|
-
}
|
|
91
|
-
throw originalError;
|
|
92
|
-
}
|
|
93
|
-
class BuildConfigEnvironmentLeasePlugin {
|
|
94
|
-
apply(compiler) {
|
|
95
|
-
const hooks = compiler.hooks;
|
|
96
|
-
try {
|
|
97
|
-
const lifecycleHooks = {};
|
|
98
|
-
for (const hookName of LIFECYCLE_HOOK_NAMES){
|
|
99
|
-
const hook = hooks[hookName];
|
|
100
|
-
if (!hook || 'function' != typeof hook.tap) throw new Error(`Rspack does not expose the "${hookName}" lifecycle hook required to restore build config environment leases.`);
|
|
101
|
-
lifecycleHooks[hookName] = hook;
|
|
102
|
-
}
|
|
103
|
-
let mode = 'pending';
|
|
104
|
-
const modeTap = {
|
|
105
|
-
name: BUILD_CONFIG_ENVIRONMENT_PLUGIN,
|
|
106
|
-
stage: Number.MIN_SAFE_INTEGER
|
|
107
|
-
};
|
|
108
|
-
const releaseTap = {
|
|
109
|
-
name: BUILD_CONFIG_ENVIRONMENT_PLUGIN,
|
|
110
|
-
stage: Number.MAX_SAFE_INTEGER
|
|
111
|
-
};
|
|
112
|
-
const releaseAfterOneShot = ()=>{
|
|
113
|
-
if ('watch' !== mode && true !== compiler.watchMode) this.release();
|
|
114
|
-
};
|
|
115
|
-
lifecycleHooks.run.tap(modeTap, ()=>{
|
|
116
|
-
mode = 'run';
|
|
117
|
-
});
|
|
118
|
-
lifecycleHooks.watchRun.tap(modeTap, ()=>{
|
|
119
|
-
mode = 'watch';
|
|
120
|
-
});
|
|
121
|
-
lifecycleHooks.afterDone.tap(releaseTap, releaseAfterOneShot);
|
|
122
|
-
lifecycleHooks.failed.tap(releaseTap, releaseAfterOneShot);
|
|
123
|
-
lifecycleHooks.shutdown.tap(releaseTap, this.release);
|
|
124
|
-
lifecycleHooks.watchClose.tap(releaseTap, this.release);
|
|
125
|
-
} catch (error) {
|
|
126
|
-
releaseAfterFailure(this.release, error);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
constructor(release){
|
|
130
|
-
this.release = release;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
function resolveEffectTsgoCli(from) {
|
|
134
|
-
const projectRequire = createRequire(from);
|
|
135
|
-
const packageJsonPath = projectRequire.resolve(`${EFFECT_TSGO_PACKAGE}/package.json`);
|
|
136
|
-
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
137
|
-
const bin = 'string' == typeof packageJson.bin ? packageJson.bin : packageJson.bin?.[EFFECT_TSGO_BIN];
|
|
138
|
-
if (!bin) throw new Error(EFFECT_TSGO_RESOLUTION_ERROR);
|
|
139
|
-
return resolve(dirname(packageJsonPath), bin);
|
|
140
21
|
}
|
|
141
22
|
function resolveExecutableEffectTsgoCompiler(compilerPath) {
|
|
142
23
|
if ('win32' === process.platform) return compilerPath;
|
|
143
24
|
const sourcePath = realpathSync(compilerPath);
|
|
144
25
|
const source = lstatSync(sourcePath);
|
|
145
|
-
if (!source.isFile()) throw new Error(
|
|
26
|
+
if (!source.isFile()) throw new Error(`Effect TS-Go compiler path is not a regular file: ${sourcePath}`);
|
|
146
27
|
try {
|
|
147
28
|
accessSync(sourcePath, constants.X_OK);
|
|
148
29
|
return compilerPath;
|
|
@@ -189,37 +70,22 @@ function resolveExecutableEffectTsgoCompiler(compilerPath) {
|
|
|
189
70
|
function getBuildConfigEnvironment(name) {
|
|
190
71
|
return process.env[name];
|
|
191
72
|
}
|
|
192
|
-
function withBuildConfigEnvironment(name, value, setup) {
|
|
193
|
-
return async (config, ...args)=>{
|
|
194
|
-
const release = acquireEnvironmentLease(name, value);
|
|
195
|
-
try {
|
|
196
|
-
const configured = await setup(config, ...args) ?? config;
|
|
197
|
-
configured.plugins = [
|
|
198
|
-
...configured.plugins ?? [],
|
|
199
|
-
new BuildConfigEnvironmentLeasePlugin(release)
|
|
200
|
-
];
|
|
201
|
-
return configured;
|
|
202
|
-
} catch (error) {
|
|
203
|
-
releaseAfterFailure(release, error);
|
|
204
|
-
}
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
73
|
function resolveEffectTsgoCompiler(options) {
|
|
208
74
|
const configuredCompiler = getBuildConfigEnvironment('EFFECT_TSGO_BIN')?.trim();
|
|
209
75
|
if (configuredCompiler) try {
|
|
210
76
|
return resolveExecutableEffectTsgoCompiler(configuredCompiler);
|
|
211
|
-
} catch
|
|
212
|
-
throw
|
|
77
|
+
} catch (cause) {
|
|
78
|
+
throw effectTsgoResolutionError(cause, 'Configured compiler validation', options.from);
|
|
213
79
|
}
|
|
80
|
+
let stage = 'Package CLI resolution';
|
|
214
81
|
try {
|
|
215
|
-
const compiler =
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
}
|
|
223
|
-
throw new Error(EFFECT_TSGO_RESOLUTION_ERROR);
|
|
82
|
+
const compiler = resolveInstalledEffectCompiler(options.from).trim();
|
|
83
|
+
stage = 'Compiler backend lookup';
|
|
84
|
+
if (!compiler) throw new Error('Effect TS-Go discovery returned an empty compiler path');
|
|
85
|
+
stage = 'Compiler executable validation';
|
|
86
|
+
return resolveExecutableEffectTsgoCompiler(compiler);
|
|
87
|
+
} catch (cause) {
|
|
88
|
+
throw effectTsgoResolutionError(cause, effectCompilerDiscoveryFailureStage(cause) ?? stage, options.from);
|
|
89
|
+
}
|
|
224
90
|
}
|
|
225
|
-
export { getBuildConfigEnvironment, resolveEffectTsgoCompiler
|
|
91
|
+
export { getBuildConfigEnvironment, resolveEffectTsgoCompiler };
|