@bleedingdev/modern-js-plugin-bff-extensions 3.8.3-ultramodern.2
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/LICENSE +22 -0
- package/README.md +29 -0
- package/dist/cjs/backend-federation/edge-runtime.js +230 -0
- package/dist/cjs/backend-federation/edge.js +80 -0
- package/dist/cjs/backend-federation/entry.js +94 -0
- package/dist/cjs/backend-federation/identity.js +82 -0
- package/dist/cjs/backend-federation/index.js +61 -0
- package/dist/cjs/backend-federation/legacy-warning.js +40 -0
- package/dist/cjs/backend-federation/load.js +72 -0
- package/dist/cjs/backend-federation/node.js +50 -0
- package/dist/cjs/backend-federation/plugin.js +63 -0
- package/dist/cjs/backend-federation/remotes.js +51 -0
- package/dist/cjs/backend-federation/runtime.js +128 -0
- package/dist/cjs/backend-federation/types.js +18 -0
- package/dist/cjs/backend-federation/utils.js +48 -0
- package/dist/cjs/backend-federation/validate-loaded.js +56 -0
- package/dist/cjs/backend-federation-manifest/errors.js +83 -0
- package/dist/cjs/backend-federation-manifest/index.js +48 -0
- package/dist/cjs/backend-federation-manifest/load.js +173 -0
- package/dist/cjs/backend-federation-manifest/metadata.js +101 -0
- package/dist/cjs/backend-federation-manifest/node.js +50 -0
- package/dist/cjs/backend-federation-manifest/reference.js +132 -0
- package/dist/cjs/backend-federation-manifest/remote.js +81 -0
- package/dist/cjs/backend-federation-manifest/types.js +18 -0
- package/dist/cjs/backend-federation-manifest/validation.js +110 -0
- package/dist/cjs/client-generator/built-entry.js +84 -0
- package/dist/cjs/client-generator/generator.js +73 -0
- package/dist/cjs/client-generator/index.js +54 -0
- package/dist/cjs/client-generator/paths.js +62 -0
- package/dist/cjs/client-generator/rendering.js +253 -0
- package/dist/cjs/client-generator/runtime.js +68 -0
- package/dist/cjs/client-generator/types.js +18 -0
- package/dist/cjs/cross-project-generation/index.js +40 -0
- package/dist/cjs/cross-project-generation/render.js +53 -0
- package/dist/cjs/cross-project-policy/evaluation.js +75 -0
- package/dist/cjs/cross-project-policy/index.js +40 -0
- package/dist/cjs/cross-project-policy/node.js +76 -0
- package/dist/cjs/effect-adapter/cross-project-policy.js +64 -0
- package/dist/cjs/effect-adapter/entry.js +98 -0
- package/dist/cjs/effect-adapter/error-response.js +75 -0
- package/dist/cjs/effect-adapter/index.js +187 -0
- package/dist/cjs/effect-source-loader/index.js +51 -0
- package/dist/cjs/effect-source-loader/loader.js +341 -0
- package/dist/cjs/effect-source-loader/worker-runtime-wrapper.js +97 -0
- package/dist/cjs/hono/bind-route-handlers.js +76 -0
- package/dist/cjs/hono/cross-project-policy.js +48 -0
- package/dist/cjs/hono/index.js +40 -0
- package/dist/esm/backend-federation/edge-runtime.mjs +186 -0
- package/dist/esm/backend-federation/edge.mjs +21 -0
- package/dist/esm/backend-federation/entry.mjs +56 -0
- package/dist/esm/backend-federation/identity.mjs +41 -0
- package/dist/esm/backend-federation/index.mjs +4 -0
- package/dist/esm/backend-federation/legacy-warning.mjs +2 -0
- package/dist/esm/backend-federation/load.mjs +34 -0
- package/dist/esm/backend-federation/node.mjs +12 -0
- package/dist/esm/backend-federation/plugin.mjs +25 -0
- package/dist/esm/backend-federation/remotes.mjs +13 -0
- package/dist/esm/backend-federation/runtime.mjs +90 -0
- package/dist/esm/backend-federation/types.mjs +0 -0
- package/dist/esm/backend-federation/utils.mjs +7 -0
- package/dist/esm/backend-federation/validate-loaded.mjs +18 -0
- package/dist/esm/backend-federation-manifest/errors.mjs +32 -0
- package/dist/esm/backend-federation-manifest/index.mjs +3 -0
- package/dist/esm/backend-federation-manifest/load.mjs +135 -0
- package/dist/esm/backend-federation-manifest/metadata.mjs +42 -0
- package/dist/esm/backend-federation-manifest/node.mjs +12 -0
- package/dist/esm/backend-federation-manifest/reference.mjs +88 -0
- package/dist/esm/backend-federation-manifest/remote.mjs +43 -0
- package/dist/esm/backend-federation-manifest/types.mjs +0 -0
- package/dist/esm/backend-federation-manifest/validation.mjs +66 -0
- package/dist/esm/client-generator/built-entry.mjs +40 -0
- package/dist/esm/client-generator/generator.mjs +32 -0
- package/dist/esm/client-generator/index.mjs +3 -0
- package/dist/esm/client-generator/paths.mjs +24 -0
- package/dist/esm/client-generator/rendering.mjs +209 -0
- package/dist/esm/client-generator/runtime.mjs +27 -0
- package/dist/esm/client-generator/types.mjs +0 -0
- package/dist/esm/cross-project-generation/index.mjs +1 -0
- package/dist/esm/cross-project-generation/render.mjs +15 -0
- package/dist/esm/cross-project-policy/evaluation.mjs +34 -0
- package/dist/esm/cross-project-policy/index.mjs +1 -0
- package/dist/esm/cross-project-policy/node.mjs +28 -0
- package/dist/esm/effect-adapter/cross-project-policy.mjs +26 -0
- package/dist/esm/effect-adapter/entry.mjs +50 -0
- package/dist/esm/effect-adapter/error-response.mjs +37 -0
- package/dist/esm/effect-adapter/index.mjs +139 -0
- package/dist/esm/effect-source-loader/index.mjs +3 -0
- package/dist/esm/effect-source-loader/loader.mjs +285 -0
- package/dist/esm/effect-source-loader/worker-runtime-wrapper.mjs +56 -0
- package/dist/esm/hono/bind-route-handlers.mjs +38 -0
- package/dist/esm/hono/cross-project-policy.mjs +10 -0
- package/dist/esm/hono/index.mjs +1 -0
- package/dist/esm-node/backend-federation/edge-runtime.mjs +187 -0
- package/dist/esm-node/backend-federation/edge.mjs +22 -0
- package/dist/esm-node/backend-federation/entry.mjs +57 -0
- package/dist/esm-node/backend-federation/identity.mjs +42 -0
- package/dist/esm-node/backend-federation/index.mjs +5 -0
- package/dist/esm-node/backend-federation/legacy-warning.mjs +3 -0
- package/dist/esm-node/backend-federation/load.mjs +35 -0
- package/dist/esm-node/backend-federation/node.mjs +13 -0
- package/dist/esm-node/backend-federation/plugin.mjs +26 -0
- package/dist/esm-node/backend-federation/remotes.mjs +14 -0
- package/dist/esm-node/backend-federation/runtime.mjs +91 -0
- package/dist/esm-node/backend-federation/types.mjs +1 -0
- package/dist/esm-node/backend-federation/utils.mjs +8 -0
- package/dist/esm-node/backend-federation/validate-loaded.mjs +19 -0
- package/dist/esm-node/backend-federation-manifest/errors.mjs +33 -0
- package/dist/esm-node/backend-federation-manifest/index.mjs +4 -0
- package/dist/esm-node/backend-federation-manifest/load.mjs +136 -0
- package/dist/esm-node/backend-federation-manifest/metadata.mjs +43 -0
- package/dist/esm-node/backend-federation-manifest/node.mjs +13 -0
- package/dist/esm-node/backend-federation-manifest/reference.mjs +89 -0
- package/dist/esm-node/backend-federation-manifest/remote.mjs +44 -0
- package/dist/esm-node/backend-federation-manifest/types.mjs +1 -0
- package/dist/esm-node/backend-federation-manifest/validation.mjs +67 -0
- package/dist/esm-node/client-generator/built-entry.mjs +41 -0
- package/dist/esm-node/client-generator/generator.mjs +33 -0
- package/dist/esm-node/client-generator/index.mjs +4 -0
- package/dist/esm-node/client-generator/paths.mjs +25 -0
- package/dist/esm-node/client-generator/rendering.mjs +210 -0
- package/dist/esm-node/client-generator/runtime.mjs +29 -0
- package/dist/esm-node/client-generator/types.mjs +1 -0
- package/dist/esm-node/cross-project-generation/index.mjs +2 -0
- package/dist/esm-node/cross-project-generation/render.mjs +16 -0
- package/dist/esm-node/cross-project-policy/evaluation.mjs +35 -0
- package/dist/esm-node/cross-project-policy/index.mjs +2 -0
- package/dist/esm-node/cross-project-policy/node.mjs +29 -0
- package/dist/esm-node/effect-adapter/cross-project-policy.mjs +27 -0
- package/dist/esm-node/effect-adapter/entry.mjs +51 -0
- package/dist/esm-node/effect-adapter/error-response.mjs +38 -0
- package/dist/esm-node/effect-adapter/index.mjs +140 -0
- package/dist/esm-node/effect-source-loader/index.mjs +4 -0
- package/dist/esm-node/effect-source-loader/loader.mjs +286 -0
- package/dist/esm-node/effect-source-loader/worker-runtime-wrapper.mjs +57 -0
- package/dist/esm-node/hono/bind-route-handlers.mjs +39 -0
- package/dist/esm-node/hono/cross-project-policy.mjs +11 -0
- package/dist/esm-node/hono/index.mjs +2 -0
- package/dist/types/backend-federation/edge-runtime.d.ts +46 -0
- package/dist/types/backend-federation/edge.d.ts +28 -0
- package/dist/types/backend-federation/entry.d.ts +2 -0
- package/dist/types/backend-federation/identity.d.ts +30 -0
- package/dist/types/backend-federation/index.d.ts +6 -0
- package/dist/types/backend-federation/legacy-warning.d.ts +1 -0
- package/dist/types/backend-federation/load.d.ts +13 -0
- package/dist/types/backend-federation/node.d.ts +4 -0
- package/dist/types/backend-federation/plugin.d.ts +3 -0
- package/dist/types/backend-federation/remotes.d.ts +2 -0
- package/dist/types/backend-federation/runtime.d.ts +3 -0
- package/dist/types/backend-federation/types.d.ts +76 -0
- package/dist/types/backend-federation/utils.d.ts +2 -0
- package/dist/types/backend-federation/validate-loaded.d.ts +8 -0
- package/dist/types/backend-federation-manifest/errors.d.ts +11 -0
- package/dist/types/backend-federation-manifest/index.d.ts +5 -0
- package/dist/types/backend-federation-manifest/load.d.ts +3 -0
- package/dist/types/backend-federation-manifest/metadata.d.ts +18 -0
- package/dist/types/backend-federation-manifest/node.d.ts +3 -0
- package/dist/types/backend-federation-manifest/reference.d.ts +4 -0
- package/dist/types/backend-federation-manifest/remote.d.ts +3 -0
- package/dist/types/backend-federation-manifest/types.d.ts +49 -0
- package/dist/types/backend-federation-manifest/validation.d.ts +5 -0
- package/dist/types/client-generator/built-entry.d.ts +16 -0
- package/dist/types/client-generator/generator.d.ts +3 -0
- package/dist/types/client-generator/index.d.ts +4 -0
- package/dist/types/client-generator/paths.d.ts +5 -0
- package/dist/types/client-generator/rendering.d.ts +24 -0
- package/dist/types/client-generator/runtime.d.ts +12 -0
- package/dist/types/client-generator/types.d.ts +33 -0
- package/dist/types/cross-project-generation/index.d.ts +1 -0
- package/dist/types/cross-project-generation/render.d.ts +1 -0
- package/dist/types/cross-project-policy/evaluation.d.ts +4 -0
- package/dist/types/cross-project-policy/index.d.ts +1 -0
- package/dist/types/cross-project-policy/node.d.ts +4 -0
- package/dist/types/effect-adapter/cross-project-policy.d.ts +4 -0
- package/dist/types/effect-adapter/entry.d.ts +2 -0
- package/dist/types/effect-adapter/error-response.d.ts +2 -0
- package/dist/types/effect-adapter/index.d.ts +19 -0
- package/dist/types/effect-source-loader/index.d.ts +3 -0
- package/dist/types/effect-source-loader/loader.d.ts +17 -0
- package/dist/types/effect-source-loader/worker-runtime-wrapper.d.ts +25 -0
- package/dist/types/hono/bind-route-handlers.d.ts +10 -0
- package/dist/types/hono/cross-project-policy.d.ts +3 -0
- package/dist/types/hono/index.d.ts +1 -0
- package/package.json +213 -0
- package/src/backend-federation/edge-runtime.ts +258 -0
- package/src/backend-federation/edge.ts +128 -0
- package/src/backend-federation/entry.ts +125 -0
- package/src/backend-federation/identity.ts +97 -0
- package/src/backend-federation/index.ts +30 -0
- package/src/backend-federation/legacy-warning.ts +2 -0
- package/src/backend-federation/load.ts +102 -0
- package/src/backend-federation/node.ts +33 -0
- package/src/backend-federation/plugin.ts +35 -0
- package/src/backend-federation/remotes.ts +17 -0
- package/src/backend-federation/runtime.ts +99 -0
- package/src/backend-federation/types.ts +103 -0
- package/src/backend-federation/utils.ts +7 -0
- package/src/backend-federation/validate-loaded.ts +72 -0
- package/src/backend-federation-manifest/errors.ts +85 -0
- package/src/backend-federation-manifest/index.ts +11 -0
- package/src/backend-federation-manifest/load.ts +266 -0
- package/src/backend-federation-manifest/metadata.ts +73 -0
- package/src/backend-federation-manifest/node.ts +19 -0
- package/src/backend-federation-manifest/reference.ts +240 -0
- package/src/backend-federation-manifest/remote.ts +102 -0
- package/src/backend-federation-manifest/types.ts +73 -0
- package/src/backend-federation-manifest/validation.ts +255 -0
- package/src/client-generator/built-entry.ts +70 -0
- package/src/client-generator/generator.ts +52 -0
- package/src/client-generator/index.ts +10 -0
- package/src/client-generator/paths.ts +40 -0
- package/src/client-generator/rendering.ts +307 -0
- package/src/client-generator/runtime.ts +69 -0
- package/src/client-generator/types.ts +35 -0
- package/src/cross-project-generation/index.ts +1 -0
- package/src/cross-project-generation/render.ts +14 -0
- package/src/cross-project-policy/evaluation.ts +70 -0
- package/src/cross-project-policy/index.ts +1 -0
- package/src/cross-project-policy/node.ts +63 -0
- package/src/effect-adapter/cross-project-policy.ts +63 -0
- package/src/effect-adapter/entry.ts +95 -0
- package/src/effect-adapter/error-response.ts +68 -0
- package/src/effect-adapter/index.ts +246 -0
- package/src/effect-source-loader/index.ts +6 -0
- package/src/effect-source-loader/loader.ts +397 -0
- package/src/effect-source-loader/worker-runtime-wrapper.ts +90 -0
- package/src/hono/bind-route-handlers.ts +62 -0
- package/src/hono/cross-project-policy.ts +26 -0
- package/src/hono/index.ts +4 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// @effect-diagnostics asyncFunction:off globalFetch:off strictBooleanExpressions:off
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
evaluateBackendFederationCommonJsEntry,
|
|
5
|
+
loadVerifiedBackendFederationEntry,
|
|
6
|
+
} from '@modern-js/server-runtime-extensions/backend-federation-security';
|
|
7
|
+
import type { ModuleFederationRuntimePlugin } from '@module-federation/runtime';
|
|
8
|
+
|
|
9
|
+
import type {
|
|
10
|
+
BackendFederationEntryExports,
|
|
11
|
+
BackendFederationLoadEntryPlugin,
|
|
12
|
+
BackendFederationRemote,
|
|
13
|
+
BackendFederationRuntimeOptions,
|
|
14
|
+
} from './types';
|
|
15
|
+
import { isRecord, normalizeExpose } from './utils';
|
|
16
|
+
|
|
17
|
+
function decodeDataUrl(url: string) {
|
|
18
|
+
const commaIndex = url.indexOf(',');
|
|
19
|
+
if (commaIndex < 0) {
|
|
20
|
+
throw new Error('[BFF][Effect] Invalid backend federation data URL entry.');
|
|
21
|
+
}
|
|
22
|
+
return decodeURIComponent(url.slice(commaIndex + 1));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function readCommonJsEntrySource(remote: BackendFederationRemote) {
|
|
26
|
+
if (remote.entry.startsWith('data:')) {
|
|
27
|
+
return decodeDataUrl(remote.entry);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
throw new Error(
|
|
31
|
+
`[BFF][Effect] Backend federation remote ${remote.name} cannot load CommonJS entry ${remote.entry}.`,
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function importModuleEntry(remote: BackendFederationRemote) {
|
|
36
|
+
const entry = await import(/* webpackIgnore: true */ remote.entry);
|
|
37
|
+
return (entry.default ?? entry) as BackendFederationEntryExports;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function resolvePluginEntry(
|
|
41
|
+
remote: BackendFederationRemote,
|
|
42
|
+
plugins: ModuleFederationRuntimePlugin[] | undefined,
|
|
43
|
+
) {
|
|
44
|
+
for (const plugin of plugins ?? []) {
|
|
45
|
+
const loadEntry = (plugin as BackendFederationLoadEntryPlugin).loadEntry;
|
|
46
|
+
if (typeof loadEntry !== 'function') {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const entry = await loadEntry({ remoteInfo: remote });
|
|
50
|
+
if (entry) {
|
|
51
|
+
return entry;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function loadBackendFederationEntry(
|
|
57
|
+
remote: BackendFederationRemote,
|
|
58
|
+
options: BackendFederationRuntimeOptions,
|
|
59
|
+
) {
|
|
60
|
+
const requiresVerification = Boolean(
|
|
61
|
+
remote.verification || options.entryPolicy?.expected,
|
|
62
|
+
);
|
|
63
|
+
const isNetworkEntry = /^https?:\/\//iu.test(remote.entry);
|
|
64
|
+
if (isNetworkEntry && !requiresVerification) {
|
|
65
|
+
throw new Error(
|
|
66
|
+
`[BFF][Effect] Backend federation remote ${remote.name} requires verified entry bytes before network execution.`,
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
if (requiresVerification) {
|
|
70
|
+
return loadVerifiedBackendFederationEntry({
|
|
71
|
+
...options.entryPolicy,
|
|
72
|
+
remote,
|
|
73
|
+
...(remote.verification ? { verification: remote.verification } : {}),
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const pluginEntry = await resolvePluginEntry(remote, options.plugins);
|
|
78
|
+
if (pluginEntry) {
|
|
79
|
+
return pluginEntry;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (remote.entryGlobalName) {
|
|
83
|
+
const globalEntry = (globalThis as Record<string, unknown>)[
|
|
84
|
+
remote.entryGlobalName
|
|
85
|
+
];
|
|
86
|
+
if (isRecord(globalEntry)) {
|
|
87
|
+
return globalEntry as unknown as BackendFederationEntryExports;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (remote.type === 'module' || remote.entry.startsWith('file:')) {
|
|
92
|
+
return importModuleEntry(remote);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return evaluateBackendFederationCommonJsEntry(
|
|
96
|
+
remote,
|
|
97
|
+
new TextEncoder().encode(await readCommonJsEntrySource(remote)),
|
|
98
|
+
options.entryPolicy?.evaluateCommonJs,
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export async function loadBackendFederationExpose(
|
|
103
|
+
remote: BackendFederationRemote,
|
|
104
|
+
expose: string,
|
|
105
|
+
options: BackendFederationRuntimeOptions,
|
|
106
|
+
) {
|
|
107
|
+
const entry = await loadBackendFederationEntry(remote, options);
|
|
108
|
+
if (typeof entry.init === 'function') {
|
|
109
|
+
await entry.init({ hostName: options.hostName });
|
|
110
|
+
}
|
|
111
|
+
if (typeof entry.get !== 'function') {
|
|
112
|
+
throw new Error(
|
|
113
|
+
`[BFF][Effect] Backend federation remote ${remote.name} entry must expose get().`,
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
const factory = await entry.get(expose);
|
|
117
|
+
if (typeof factory !== 'function') {
|
|
118
|
+
throw new Error(
|
|
119
|
+
`[BFF][Effect] Backend federation expose ${remote.name}/${normalizeExpose(
|
|
120
|
+
expose,
|
|
121
|
+
)} must load factory function.`,
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
return factory();
|
|
125
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// @effect-diagnostics strictBooleanExpressions:off
|
|
2
|
+
|
|
3
|
+
import { isRecord } from './utils';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Mandatory delivery-unit identity for public backend federation loads
|
|
7
|
+
* (MV-G23, ADR-0019 / RESOLUTION-0001 §2.3): consumers pass the record's
|
|
8
|
+
* `unitId` + `buildMarker` through to identity validation.
|
|
9
|
+
*/
|
|
10
|
+
export type BackendFederationExpectedIdentity = {
|
|
11
|
+
unitId: string;
|
|
12
|
+
buildMarker: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export type BackendFederationIdentityIssue = {
|
|
16
|
+
path: string;
|
|
17
|
+
message: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Shared expected-identity validation for loaded backend federation modules.
|
|
22
|
+
* Compares the expose's `backendFederationContract.compatibility` identity
|
|
23
|
+
* (`unitId`, `build`) against the consumer's expected delivery-unit identity.
|
|
24
|
+
* Missing identity metadata is an error: with an expectation present there is
|
|
25
|
+
* no legacy escape hatch.
|
|
26
|
+
*/
|
|
27
|
+
export function validateExpectedBackendFederationIdentity(
|
|
28
|
+
loaded: unknown,
|
|
29
|
+
expected: BackendFederationExpectedIdentity,
|
|
30
|
+
options: {
|
|
31
|
+
/**
|
|
32
|
+
* Tolerate exposes that declare no identity metadata (legacy modules).
|
|
33
|
+
* Mismatching declared values still fail. Used by the manifest adapter,
|
|
34
|
+
* whose manifest-side identity is already validated against `expected`;
|
|
35
|
+
* the raw identity-aware loader is strict.
|
|
36
|
+
*/
|
|
37
|
+
allowMissingIdentityMetadata?: boolean;
|
|
38
|
+
} = {},
|
|
39
|
+
): BackendFederationIdentityIssue[] {
|
|
40
|
+
const allowMissing = options.allowMissingIdentityMetadata === true;
|
|
41
|
+
const issues: BackendFederationIdentityIssue[] = [];
|
|
42
|
+
const contract = isRecord(loaded)
|
|
43
|
+
? loaded.backendFederationContract
|
|
44
|
+
: undefined;
|
|
45
|
+
const compatibility = isRecord(contract) ? contract.compatibility : undefined;
|
|
46
|
+
|
|
47
|
+
if (!isRecord(compatibility)) {
|
|
48
|
+
if (allowMissing) {
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
return [
|
|
52
|
+
{
|
|
53
|
+
path: 'backendFederationContract.compatibility',
|
|
54
|
+
message:
|
|
55
|
+
'loaded module declares no compatibility metadata; delivery-unit identity cannot be validated',
|
|
56
|
+
},
|
|
57
|
+
];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const unitId = compatibility.unitId;
|
|
61
|
+
if (typeof unitId !== 'string' || unitId.length === 0) {
|
|
62
|
+
if (!allowMissing) {
|
|
63
|
+
issues.push({
|
|
64
|
+
path: 'backendFederationContract.compatibility.unitId',
|
|
65
|
+
message: `missing delivery-unit id; expected ${expected.unitId}`,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
} else if (unitId !== expected.unitId) {
|
|
69
|
+
issues.push({
|
|
70
|
+
path: 'backendFederationContract.compatibility.unitId',
|
|
71
|
+
message: `expected ${expected.unitId}, received ${unitId}`,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const build = compatibility.build;
|
|
76
|
+
if (typeof build !== 'string' || build.length === 0) {
|
|
77
|
+
if (!allowMissing) {
|
|
78
|
+
issues.push({
|
|
79
|
+
path: 'backendFederationContract.compatibility.build',
|
|
80
|
+
message: `missing build marker; expected ${expected.buildMarker}`,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
} else if (build !== expected.buildMarker) {
|
|
84
|
+
issues.push({
|
|
85
|
+
path: 'backendFederationContract.compatibility.build',
|
|
86
|
+
message: `expected ${expected.buildMarker}, received ${build}`,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return issues;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function formatBackendFederationIdentityIssues(
|
|
94
|
+
issues: BackendFederationIdentityIssue[],
|
|
95
|
+
): string {
|
|
96
|
+
return issues.map(issue => `${issue.path}: ${issue.message}`).join('; ');
|
|
97
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// @effect-diagnostics asyncFunction:off globalFetch:off strictBooleanExpressions:off
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
BACKEND_FEDERATION_CONTRACT_VERSION,
|
|
5
|
+
BACKEND_FEDERATION_EFFECT_EXPOSE,
|
|
6
|
+
BACKEND_FEDERATION_MANIFEST_FILE,
|
|
7
|
+
BACKEND_FEDERATION_NODE_ADAPTER_VERSION,
|
|
8
|
+
} from '@modern-js/utils/universal';
|
|
9
|
+
|
|
10
|
+
export {
|
|
11
|
+
type BackendFederationExpectedIdentity,
|
|
12
|
+
type BackendFederationIdentityIssue,
|
|
13
|
+
validateExpectedBackendFederationIdentity,
|
|
14
|
+
} from './identity';
|
|
15
|
+
export { createBackendFederationLoadEntryPlugin } from './plugin';
|
|
16
|
+
export { createBackendFederationRuntime } from './runtime';
|
|
17
|
+
export type {
|
|
18
|
+
BackendFederatedEffectApiModule,
|
|
19
|
+
BackendFederationEntryExports,
|
|
20
|
+
BackendFederationIdentityLoadOptions,
|
|
21
|
+
BackendFederationLoadEntryPluginOptions,
|
|
22
|
+
BackendFederationRemote,
|
|
23
|
+
BackendFederationRuntimeOptions,
|
|
24
|
+
} from './types';
|
|
25
|
+
export {
|
|
26
|
+
BACKEND_FEDERATION_CONTRACT_VERSION,
|
|
27
|
+
BACKEND_FEDERATION_EFFECT_EXPOSE,
|
|
28
|
+
BACKEND_FEDERATION_MANIFEST_FILE,
|
|
29
|
+
BACKEND_FEDERATION_NODE_ADAPTER_VERSION,
|
|
30
|
+
};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export const LEGACY_LOAD_WARNING =
|
|
2
|
+
'[BFF][Effect] loadBackendFederatedEffectApi was called without an expected delivery-unit identity (expected.unitId + expected.buildMarker). Identity-less public backend loads are deprecated (ADR-0019/MV-G23) and will be rejected in a future major.';
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { BACKEND_FEDERATION_EFFECT_EXPOSE } from '@modern-js/utils/universal';
|
|
2
|
+
import * as Effect from 'effect/Effect';
|
|
3
|
+
import * as Logger from 'effect/Logger';
|
|
4
|
+
|
|
5
|
+
import { type BackendFederationExpectedIdentity } from './identity';
|
|
6
|
+
import { LEGACY_LOAD_WARNING } from './legacy-warning';
|
|
7
|
+
import { collectRemotes } from './remotes';
|
|
8
|
+
import { createBackendFederationRuntime } from './runtime';
|
|
9
|
+
import type {
|
|
10
|
+
BackendFederatedEffectApiModule,
|
|
11
|
+
BackendFederationIdentityLoadOptions,
|
|
12
|
+
BackendFederationLoadOptions,
|
|
13
|
+
} from './types';
|
|
14
|
+
import { normalizeExpose } from './utils';
|
|
15
|
+
import { validateLoadedBackendFederatedEffectApi } from './validate-loaded';
|
|
16
|
+
|
|
17
|
+
const legacyWarningLogger = Logger.withLeveledConsole(Logger.formatLogFmt);
|
|
18
|
+
|
|
19
|
+
function warnLegacyLoad() {
|
|
20
|
+
Effect.runSync(
|
|
21
|
+
Effect.provideService(
|
|
22
|
+
Effect.logWarning(LEGACY_LOAD_WARNING),
|
|
23
|
+
Logger.CurrentLoggers,
|
|
24
|
+
new Set([legacyWarningLogger]),
|
|
25
|
+
),
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Load a federated Effect API with mandatory delivery-unit identity
|
|
31
|
+
* validation (MV-G23): the loaded expose's compatibility metadata must match
|
|
32
|
+
* `expected.unitId` + `expected.buildMarker`.
|
|
33
|
+
*/
|
|
34
|
+
export function loadBackendFederatedEffectApi(
|
|
35
|
+
options: BackendFederationIdentityLoadOptions,
|
|
36
|
+
): Promise<BackendFederatedEffectApiModule>;
|
|
37
|
+
/**
|
|
38
|
+
* @deprecated Pass `expected` (delivery-unit `unitId` + `buildMarker`).
|
|
39
|
+
* Loads without an expected identity cannot be validated against a resolved
|
|
40
|
+
* delivery-unit record and emit a runtime warning.
|
|
41
|
+
*/
|
|
42
|
+
export function loadBackendFederatedEffectApi(
|
|
43
|
+
options: BackendFederationLoadOptions,
|
|
44
|
+
): Promise<BackendFederatedEffectApiModule>;
|
|
45
|
+
export function loadBackendFederatedEffectApi(
|
|
46
|
+
options: BackendFederationLoadOptions & {
|
|
47
|
+
expected?: BackendFederationExpectedIdentity;
|
|
48
|
+
allowMissingIdentityMetadata?: boolean;
|
|
49
|
+
},
|
|
50
|
+
): Promise<BackendFederatedEffectApiModule> {
|
|
51
|
+
const remoteName = options.remote?.name ?? options.remoteName;
|
|
52
|
+
if (remoteName === undefined || remoteName.length === 0) {
|
|
53
|
+
return Promise.reject(
|
|
54
|
+
new Error('[BFF][Effect] Missing backend federation remote name.'),
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (options.expected === undefined) {
|
|
59
|
+
warnLegacyLoad();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (options.runtime !== undefined) {
|
|
63
|
+
const configuredRemote = collectRemotes(options).find(
|
|
64
|
+
remote => remote.name === remoteName,
|
|
65
|
+
);
|
|
66
|
+
if (
|
|
67
|
+
configuredRemote === undefined ||
|
|
68
|
+
!/^(?:binding|service|static):/u.test(configuredRemote.entry)
|
|
69
|
+
) {
|
|
70
|
+
return Promise.reject(
|
|
71
|
+
new Error(
|
|
72
|
+
'[BFF][Effect] A custom Module Federation runtime requires a caller-pinned static or service-binding remote and cannot execute network backend federation entries.',
|
|
73
|
+
),
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
if (
|
|
77
|
+
configuredRemote.verification !== undefined ||
|
|
78
|
+
options.entryPolicy?.expected !== undefined
|
|
79
|
+
) {
|
|
80
|
+
return Promise.reject(
|
|
81
|
+
new Error(
|
|
82
|
+
'[BFF][Effect] A custom Module Federation runtime cannot bypass verified backend entry loading.',
|
|
83
|
+
),
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const runtime = options.runtime ?? createBackendFederationRuntime(options);
|
|
89
|
+
const expose =
|
|
90
|
+
options.expose ??
|
|
91
|
+
options.remote?.expose ??
|
|
92
|
+
BACKEND_FEDERATION_EFFECT_EXPOSE;
|
|
93
|
+
const remoteRequest = `${remoteName}/${normalizeExpose(expose)}`;
|
|
94
|
+
return runtime.loadRemote(remoteRequest).then(loaded =>
|
|
95
|
+
validateLoadedBackendFederatedEffectApi(loaded, {
|
|
96
|
+
allowMissingIdentityMetadata: options.allowMissingIdentityMetadata,
|
|
97
|
+
expected: options.expected,
|
|
98
|
+
remoteName,
|
|
99
|
+
remoteRequest,
|
|
100
|
+
}),
|
|
101
|
+
);
|
|
102
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { evaluateNodeBackendFederationCommonJs } from '@modern-js/server-runtime-extensions/backend-federation-security/node';
|
|
2
|
+
|
|
3
|
+
import type { BackendFederationExpectedIdentity } from './identity';
|
|
4
|
+
import { loadBackendFederatedEffectApi as loadUniversalBackendFederatedEffectApi } from './load';
|
|
5
|
+
import type {
|
|
6
|
+
BackendFederatedEffectApiModule,
|
|
7
|
+
BackendFederationIdentityLoadOptions,
|
|
8
|
+
BackendFederationLoadOptions,
|
|
9
|
+
} from './types';
|
|
10
|
+
|
|
11
|
+
export function loadBackendFederatedEffectApi(
|
|
12
|
+
options: BackendFederationIdentityLoadOptions,
|
|
13
|
+
): Promise<BackendFederatedEffectApiModule>;
|
|
14
|
+
/** @deprecated Pass `expected` delivery-unit identity. */
|
|
15
|
+
export function loadBackendFederatedEffectApi(
|
|
16
|
+
options: BackendFederationLoadOptions,
|
|
17
|
+
): Promise<BackendFederatedEffectApiModule>;
|
|
18
|
+
export function loadBackendFederatedEffectApi(
|
|
19
|
+
options: BackendFederationLoadOptions & {
|
|
20
|
+
expected?: BackendFederationExpectedIdentity;
|
|
21
|
+
allowMissingIdentityMetadata?: boolean;
|
|
22
|
+
},
|
|
23
|
+
): Promise<BackendFederatedEffectApiModule> {
|
|
24
|
+
return loadUniversalBackendFederatedEffectApi({
|
|
25
|
+
...options,
|
|
26
|
+
entryPolicy: {
|
|
27
|
+
...options.entryPolicy,
|
|
28
|
+
evaluateCommonJs:
|
|
29
|
+
options.entryPolicy?.evaluateCommonJs ??
|
|
30
|
+
evaluateNodeBackendFederationCommonJs,
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ModuleFederationRuntimePlugin } from '@module-federation/runtime';
|
|
2
|
+
|
|
3
|
+
import type { BackendFederationLoadEntryPluginOptions } from './types';
|
|
4
|
+
|
|
5
|
+
export function createBackendFederationLoadEntryPlugin(
|
|
6
|
+
options: BackendFederationLoadEntryPluginOptions,
|
|
7
|
+
): ModuleFederationRuntimePlugin {
|
|
8
|
+
return {
|
|
9
|
+
name: 'modernjs-backend-federation-load-entry',
|
|
10
|
+
loadEntry({ remoteInfo }) {
|
|
11
|
+
return Promise.resolve(
|
|
12
|
+
options.resolveEntry({
|
|
13
|
+
name: remoteInfo.name,
|
|
14
|
+
entry: remoteInfo.entry,
|
|
15
|
+
type: remoteInfo.type,
|
|
16
|
+
entryGlobalName: remoteInfo.entryGlobalName,
|
|
17
|
+
shareScope: remoteInfo.shareScope,
|
|
18
|
+
}),
|
|
19
|
+
).then(entry => {
|
|
20
|
+
if (entry === undefined) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
get(id: string) {
|
|
25
|
+
return () =>
|
|
26
|
+
Promise.resolve(entry.get(id)).then(factory => factory());
|
|
27
|
+
},
|
|
28
|
+
init(...args: unknown[]) {
|
|
29
|
+
return entry.init?.(...args);
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { BackendFederationRuntimeOptions } from './types';
|
|
2
|
+
|
|
3
|
+
export function collectRemotes(options: BackendFederationRuntimeOptions) {
|
|
4
|
+
const remotes = [...(options.remotes ?? [])];
|
|
5
|
+
const configuredRemote = options.remote;
|
|
6
|
+
if (configuredRemote !== undefined) {
|
|
7
|
+
const existingIndex = remotes.findIndex(
|
|
8
|
+
remote => remote.name === configuredRemote.name,
|
|
9
|
+
);
|
|
10
|
+
if (existingIndex >= 0) {
|
|
11
|
+
remotes[existingIndex] = configuredRemote;
|
|
12
|
+
} else {
|
|
13
|
+
remotes.push(configuredRemote);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return remotes;
|
|
17
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { ModuleFederation } from '@module-federation/runtime';
|
|
2
|
+
|
|
3
|
+
import { loadBackendFederationExpose } from './entry';
|
|
4
|
+
import { createBackendFederationLoadEntryPlugin } from './plugin';
|
|
5
|
+
import { collectRemotes } from './remotes';
|
|
6
|
+
import type {
|
|
7
|
+
BackendFederationRemote,
|
|
8
|
+
BackendFederationRuntimeOptions,
|
|
9
|
+
} from './types';
|
|
10
|
+
|
|
11
|
+
let nextRuntimeId = 0;
|
|
12
|
+
|
|
13
|
+
function parseRemoteRequest(request: string) {
|
|
14
|
+
const [remoteName, ...exposeParts] = request.split('/');
|
|
15
|
+
if (
|
|
16
|
+
remoteName === undefined ||
|
|
17
|
+
remoteName.length === 0 ||
|
|
18
|
+
exposeParts.length === 0
|
|
19
|
+
) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
return remoteName;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function createLocalEntryPlugin(
|
|
26
|
+
options: BackendFederationRuntimeOptions,
|
|
27
|
+
remotes: BackendFederationRemote[],
|
|
28
|
+
) {
|
|
29
|
+
return createBackendFederationLoadEntryPlugin({
|
|
30
|
+
resolveEntry(resolvedRemote) {
|
|
31
|
+
const remote = remotes.find(
|
|
32
|
+
candidate => candidate.name === resolvedRemote.name,
|
|
33
|
+
);
|
|
34
|
+
if (remote === undefined) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
get(expose: string) {
|
|
39
|
+
return () => loadBackendFederationExpose(remote, expose, options);
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function isolateRegisteredRemoteEntries(remotes: BackendFederationRemote[]) {
|
|
47
|
+
const runtimeId = nextRuntimeId;
|
|
48
|
+
nextRuntimeId += 1;
|
|
49
|
+
return remotes.map(remote => ({
|
|
50
|
+
...remote,
|
|
51
|
+
entry: `${remote.entry}#modernjs-backend-runtime-${runtimeId}`,
|
|
52
|
+
}));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
class BackendFederationRuntime extends ModuleFederation {
|
|
56
|
+
readonly #remoteNames: ReadonlySet<string>;
|
|
57
|
+
|
|
58
|
+
constructor(
|
|
59
|
+
options: BackendFederationRuntimeOptions,
|
|
60
|
+
remotes: BackendFederationRemote[],
|
|
61
|
+
) {
|
|
62
|
+
super({
|
|
63
|
+
name: options.hostName,
|
|
64
|
+
remotes: isolateRegisteredRemoteEntries(remotes),
|
|
65
|
+
shared: {},
|
|
66
|
+
plugins: [createLocalEntryPlugin(options, remotes)],
|
|
67
|
+
});
|
|
68
|
+
this.#remoteNames = new Set(remotes.map(remote => remote.name));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
override loadRemote<T>(
|
|
72
|
+
request: string,
|
|
73
|
+
loadOptions?: NonNullable<Parameters<ModuleFederation['loadRemote']>[1]>,
|
|
74
|
+
): Promise<T | null> {
|
|
75
|
+
const remoteName = parseRemoteRequest(request);
|
|
76
|
+
if (remoteName === undefined) {
|
|
77
|
+
return Promise.reject(
|
|
78
|
+
new Error(
|
|
79
|
+
`[BFF][Effect] Invalid backend federation request ${request}.`,
|
|
80
|
+
),
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
if (!this.#remoteNames.has(remoteName)) {
|
|
84
|
+
return Promise.reject(
|
|
85
|
+
new Error(
|
|
86
|
+
`[BFF][Effect] Missing backend federation remote ${remoteName}.`,
|
|
87
|
+
),
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
return super.loadRemote<T>(request, loadOptions);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function createBackendFederationRuntime(
|
|
95
|
+
options: BackendFederationRuntimeOptions,
|
|
96
|
+
): ModuleFederation {
|
|
97
|
+
const remotes = collectRemotes(options);
|
|
98
|
+
return new BackendFederationRuntime(options, remotes);
|
|
99
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { EffectApiModule } from '@modern-js/bff-effect/effect';
|
|
2
|
+
import type {
|
|
3
|
+
BackendFederationRemoteEntryPolicy,
|
|
4
|
+
BackendFederationRemoteEntryVerification,
|
|
5
|
+
} from '@modern-js/server-runtime-extensions/backend-federation-security';
|
|
6
|
+
import type { BACKEND_FEDERATION_EFFECT_EXPOSE } from '@modern-js/utils/universal';
|
|
7
|
+
import type {
|
|
8
|
+
ModuleFederation,
|
|
9
|
+
ModuleFederationRuntimePlugin,
|
|
10
|
+
} from '@module-federation/runtime';
|
|
11
|
+
import type { BackendFederationExpectedIdentity } from './identity';
|
|
12
|
+
|
|
13
|
+
export type BackendFederationRemote = {
|
|
14
|
+
name: string;
|
|
15
|
+
entry: string;
|
|
16
|
+
type?: 'commonjs-module' | 'module' | string;
|
|
17
|
+
entryGlobalName?: string;
|
|
18
|
+
shareScope?: string | string[];
|
|
19
|
+
expose?: typeof BACKEND_FEDERATION_EFFECT_EXPOSE;
|
|
20
|
+
verification?: BackendFederationRemoteEntryVerification;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type BackendFederationRuntimeOptions = {
|
|
24
|
+
hostName: string;
|
|
25
|
+
remote?: BackendFederationRemote;
|
|
26
|
+
remotes?: BackendFederationRemote[];
|
|
27
|
+
plugins?: ModuleFederationRuntimePlugin[];
|
|
28
|
+
entryPolicy?: BackendFederationRemoteEntryPolicy;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type BackendFederationEntryExports = {
|
|
32
|
+
get: (
|
|
33
|
+
id: string,
|
|
34
|
+
) =>
|
|
35
|
+
| (() => Promise<unknown> | unknown)
|
|
36
|
+
| Promise<() => Promise<unknown> | unknown>;
|
|
37
|
+
init?: (...args: unknown[]) => void | Promise<void>;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export type BackendFederatedEffectApiModule = EffectApiModule & {
|
|
41
|
+
backendFederationContract?: {
|
|
42
|
+
compatibility?: {
|
|
43
|
+
build?: unknown;
|
|
44
|
+
contractVersion?: unknown;
|
|
45
|
+
nodeAdapterVersion?: unknown;
|
|
46
|
+
packageName?: unknown;
|
|
47
|
+
/**
|
|
48
|
+
* ADR-0019 delivery-unit identity root, generator-emitted alongside
|
|
49
|
+
* manifest's `versionBoundary.deliveryUnit`. Additive/optional.
|
|
50
|
+
*/
|
|
51
|
+
unitId?: unknown;
|
|
52
|
+
/** ADR-0019 delivery-unit source revision. Additive/optional. */
|
|
53
|
+
sourceRevision?: unknown;
|
|
54
|
+
};
|
|
55
|
+
name?: unknown;
|
|
56
|
+
role?: unknown;
|
|
57
|
+
runtimeFramework?: unknown;
|
|
58
|
+
strictEffectApproach?: unknown;
|
|
59
|
+
};
|
|
60
|
+
contract?: unknown;
|
|
61
|
+
operationContexts?: unknown;
|
|
62
|
+
runtime?: unknown;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export type BackendFederationLoadEntryPluginOptions = {
|
|
66
|
+
resolveEntry: (
|
|
67
|
+
remote: BackendFederationRemote,
|
|
68
|
+
) =>
|
|
69
|
+
| BackendFederationEntryExports
|
|
70
|
+
| undefined
|
|
71
|
+
| Promise<BackendFederationEntryExports | undefined>;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export type BackendFederationLoadOptions = BackendFederationRuntimeOptions & {
|
|
75
|
+
runtime?: ModuleFederation;
|
|
76
|
+
remoteName?: string;
|
|
77
|
+
expose?: string;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Identity-aware public load options (MV-G23): the expected delivery-unit
|
|
82
|
+
* `unitId` + `buildMarker` are mandatory and validated against the loaded
|
|
83
|
+
* expose's compatibility metadata.
|
|
84
|
+
*/
|
|
85
|
+
export type BackendFederationIdentityLoadOptions =
|
|
86
|
+
BackendFederationLoadOptions & {
|
|
87
|
+
expected: BackendFederationExpectedIdentity;
|
|
88
|
+
/**
|
|
89
|
+
* Tolerate legacy exposes without identity metadata (mismatching declared
|
|
90
|
+
* values still fail). Prefer leaving this unset: identity-less exposes
|
|
91
|
+
* cannot be validated against a resolved delivery-unit record.
|
|
92
|
+
*/
|
|
93
|
+
allowMissingIdentityMetadata?: boolean;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export type BackendFederationLoadEntryPlugin = ModuleFederationRuntimePlugin & {
|
|
97
|
+
loadEntry?: (args: {
|
|
98
|
+
remoteInfo: BackendFederationRemote;
|
|
99
|
+
}) =>
|
|
100
|
+
| BackendFederationEntryExports
|
|
101
|
+
| undefined
|
|
102
|
+
| Promise<BackendFederationEntryExports | undefined>;
|
|
103
|
+
};
|