@bleedingdev/modern-js-plugin-bff-extensions 3.9.0-ultramodern.17 → 3.9.0-ultramodern.18

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.
Files changed (63) hide show
  1. package/README.md +12 -2
  2. package/dist/cjs/backend-federation/edge.js +1 -1
  3. package/dist/cjs/backend-federation/integrity-plugin.js +112 -0
  4. package/dist/cjs/backend-federation/node-shared.js +85 -0
  5. package/dist/cjs/backend-federation/node.js +8 -3
  6. package/dist/cjs/backend-federation/plugin.js +40 -21
  7. package/dist/cjs/backend-federation/runtime.js +16 -84
  8. package/dist/cjs/backend-federation-manifest/load.js +3 -0
  9. package/dist/cjs/backend-federation-manifest/node.js +5 -3
  10. package/dist/cjs/backend-federation-manifest/remote.js +1 -7
  11. package/dist/cjs/effect-source-loader/loader.js +5 -0
  12. package/dist/esm/backend-federation/edge.mjs +1 -1
  13. package/dist/esm/backend-federation/integrity-plugin.mjs +68 -0
  14. package/dist/esm/backend-federation/node-shared.mjs +41 -0
  15. package/dist/esm/backend-federation/node.mjs +6 -4
  16. package/dist/esm/backend-federation/plugin.mjs +37 -18
  17. package/dist/esm/backend-federation/runtime.mjs +16 -84
  18. package/dist/esm/backend-federation-manifest/load.mjs +3 -0
  19. package/dist/esm/backend-federation-manifest/node.mjs +5 -3
  20. package/dist/esm/backend-federation-manifest/remote.mjs +1 -7
  21. package/dist/esm/effect-source-loader/loader.mjs +5 -0
  22. package/dist/esm-node/backend-federation/edge.mjs +1 -1
  23. package/dist/esm-node/backend-federation/integrity-plugin.mjs +69 -0
  24. package/dist/esm-node/backend-federation/node-shared.mjs +42 -0
  25. package/dist/esm-node/backend-federation/node.mjs +6 -4
  26. package/dist/esm-node/backend-federation/plugin.mjs +37 -18
  27. package/dist/esm-node/backend-federation/runtime.mjs +16 -84
  28. package/dist/esm-node/backend-federation-manifest/load.mjs +3 -0
  29. package/dist/esm-node/backend-federation-manifest/node.mjs +5 -3
  30. package/dist/esm-node/backend-federation-manifest/remote.mjs +1 -7
  31. package/dist/esm-node/effect-source-loader/loader.mjs +5 -0
  32. package/dist/types/backend-federation/edge.d.ts +4 -2
  33. package/dist/types/backend-federation/integrity-plugin.d.ts +13 -0
  34. package/dist/types/backend-federation/node-shared.d.ts +20 -0
  35. package/dist/types/backend-federation/node.d.ts +3 -0
  36. package/dist/types/backend-federation/plugin.d.ts +4 -0
  37. package/dist/types/backend-federation/types.d.ts +2 -7
  38. package/dist/types/backend-federation-manifest/types.d.ts +2 -1
  39. package/package.json +10 -10
  40. package/src/backend-federation/edge.ts +7 -4
  41. package/src/backend-federation/integrity-plugin.ts +157 -0
  42. package/src/backend-federation/load.ts +0 -1
  43. package/src/backend-federation/node-shared.ts +76 -0
  44. package/src/backend-federation/node.ts +9 -4
  45. package/src/backend-federation/plugin.ts +73 -25
  46. package/src/backend-federation/runtime.ts +16 -90
  47. package/src/backend-federation/types.ts +2 -11
  48. package/src/backend-federation-manifest/load.ts +1 -0
  49. package/src/backend-federation-manifest/node.ts +5 -3
  50. package/src/backend-federation-manifest/remote.ts +0 -6
  51. package/src/backend-federation-manifest/types.ts +2 -0
  52. package/src/effect-source-loader/loader.ts +6 -0
  53. package/src/effect-source-loader/rspack-loader.ts +0 -1
  54. package/dist/cjs/backend-federation/entry.js +0 -94
  55. package/dist/cjs/backend-federation/node-evaluator.js +0 -48
  56. package/dist/esm/backend-federation/entry.mjs +0 -56
  57. package/dist/esm/backend-federation/node-evaluator.mjs +0 -7
  58. package/dist/esm-node/backend-federation/entry.mjs +0 -57
  59. package/dist/esm-node/backend-federation/node-evaluator.mjs +0 -8
  60. package/dist/types/backend-federation/entry.d.ts +0 -2
  61. package/dist/types/backend-federation/node-evaluator.d.ts +0 -2
  62. package/src/backend-federation/entry.ts +0 -125
  63. package/src/backend-federation/node-evaluator.ts +0 -13
@@ -1,99 +1,25 @@
1
1
  import { ModuleFederation } from '@module-federation/runtime';
2
2
 
3
- import { loadBackendFederationExpose } from './entry';
4
- import { createBackendFederationLoadEntryPlugin } from './plugin';
3
+ import { createBackendFederationIntegrityPlugin } from './integrity-plugin';
5
4
  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
- }
5
+ import type { BackendFederationRuntimeOptions } from './types';
93
6
 
94
7
  export function createBackendFederationRuntime(
95
8
  options: BackendFederationRuntimeOptions,
96
9
  ): ModuleFederation {
97
10
  const remotes = collectRemotes(options);
98
- return new BackendFederationRuntime(options, remotes);
11
+ return new ModuleFederation({
12
+ name: options.hostName,
13
+ // Remotes use the default share scope, where host shares are registered.
14
+ remotes: remotes.map(({ name, entry, type }) => ({
15
+ name,
16
+ entry,
17
+ ...(type ? { type } : {}),
18
+ })),
19
+ shared: options.shared ?? {},
20
+ plugins: [
21
+ ...(options.plugins ?? []),
22
+ createBackendFederationIntegrityPlugin(options, remotes),
23
+ ],
24
+ });
99
25
  }
@@ -14,8 +14,6 @@ export type BackendFederationRemote = {
14
14
  name: string;
15
15
  entry: string;
16
16
  type?: 'commonjs-module' | 'module' | string;
17
- entryGlobalName?: string;
18
- shareScope?: string | string[];
19
17
  expose?: typeof BACKEND_FEDERATION_EFFECT_EXPOSE;
20
18
  verification?: BackendFederationRemoteEntryVerification;
21
19
  };
@@ -25,6 +23,8 @@ export type BackendFederationRuntimeOptions = {
25
23
  remote?: BackendFederationRemote;
26
24
  remotes?: BackendFederationRemote[];
27
25
  plugins?: ModuleFederationRuntimePlugin[];
26
+ /** Host shares handed to every remote container's `init()`. */
27
+ shared?: ConstructorParameters<typeof ModuleFederation>[0]['shared'];
28
28
  entryPolicy?: BackendFederationRemoteEntryPolicy;
29
29
  };
30
30
 
@@ -86,12 +86,3 @@ export type BackendFederationIdentityLoadOptions =
86
86
  BackendFederationLoadOptions & {
87
87
  expected: BackendFederationExpectedIdentity;
88
88
  };
89
-
90
- export type BackendFederationLoadEntryPlugin = ModuleFederationRuntimePlugin & {
91
- loadEntry?: (args: {
92
- remoteInfo: BackendFederationRemote;
93
- }) =>
94
- | BackendFederationEntryExports
95
- | undefined
96
- | Promise<BackendFederationEntryExports | undefined>;
97
- };
@@ -273,6 +273,7 @@ export async function loadBackendFederatedEffectApiFromManifest(
273
273
  hostName: options.hostName,
274
274
  remote,
275
275
  ...(options.plugins ? { plugins: options.plugins } : {}),
276
+ ...(options.shared ? { shared: options.shared } : {}),
276
277
  entryPolicy: {
277
278
  ...options.entryPolicy,
278
279
  signal: scope.signal,
@@ -1,18 +1,20 @@
1
+ import { evaluateNodeBackendFederationCommonJs } from '@modern-js/server-runtime-extensions/backend-federation-security/node';
1
2
  import type { BackendFederatedEffectApiModule } from '../backend-federation';
2
- import { evaluateEffectBackendFederationCommonJs } from '../backend-federation/node-evaluator';
3
+ import { withEffectBffHostShared } from '../backend-federation/node-shared';
3
4
  import { loadBackendFederatedEffectApiFromManifest as loadUniversalBackendFederatedEffectApiFromManifest } from './load';
4
5
  import type { BackendFederationManifestAdapterOptions } from './types';
5
6
 
6
- export function loadBackendFederatedEffectApiFromManifest(
7
+ export async function loadBackendFederatedEffectApiFromManifest(
7
8
  options: BackendFederationManifestAdapterOptions,
8
9
  ): Promise<BackendFederatedEffectApiModule> {
9
10
  return loadUniversalBackendFederatedEffectApiFromManifest({
10
11
  ...options,
12
+ shared: withEffectBffHostShared(options.shared),
11
13
  entryPolicy: {
12
14
  ...options.entryPolicy,
13
15
  evaluateCommonJs:
14
16
  options.entryPolicy?.evaluateCommonJs ??
15
- evaluateEffectBackendFederationCommonJs,
17
+ evaluateNodeBackendFederationCommonJs,
16
18
  },
17
19
  });
18
20
  }
@@ -91,12 +91,6 @@ export function resolveBackendFederationRemoteFromManifest(
91
91
  entry: remoteEntryUrl,
92
92
  type: remoteType,
93
93
  ...(verification ? { verification } : {}),
94
- ...(remoteOverride.entryGlobalName
95
- ? { entryGlobalName: remoteOverride.entryGlobalName }
96
- : {}),
97
94
  expose,
98
- ...(remoteOverride.shareScope
99
- ? { shareScope: remoteOverride.shareScope }
100
- : {}),
101
95
  };
102
96
  }
@@ -12,6 +12,7 @@ import type {
12
12
  import type {
13
13
  BackendFederatedEffectApiModule,
14
14
  BackendFederationRemote,
15
+ BackendFederationRuntimeOptions,
15
16
  } from '../backend-federation';
16
17
  import type { BackendFederationManifestAdapterError } from './errors';
17
18
 
@@ -68,6 +69,7 @@ export type BackendFederationManifestAdapterOptions = {
68
69
  plugins?: ModuleFederationRuntimePlugin[];
69
70
  remote?: Partial<BackendFederationRemote>;
70
71
  runtime?: ModuleFederation;
72
+ shared?: BackendFederationRuntimeOptions['shared'];
71
73
  signal?: AbortSignal;
72
74
  timeoutMs?: number;
73
75
  };
@@ -79,6 +79,9 @@ const nodeBuiltins = new Set([
79
79
  ...builtinModules.map(name => `node:${name}`),
80
80
  ]);
81
81
  const dependencyResolutionMarker = 'modern-js-effect-dependency-resolution';
82
+ // The BFF server runs lambdas inside these packages' Effect context storage.
83
+ // A bundled copy would own a second storage that the server never enters.
84
+ const BFF_RUNTIME_PACKAGE = /^@modern-js\/(?:bff-effect|plugin-bff)(?:\/|$)/;
82
85
 
83
86
  async function isEsmOnlyFile(filename: string) {
84
87
  const extension = path.extname(filename).toLowerCase();
@@ -136,6 +139,9 @@ function externalizeInstalledDependencies(options: {
136
139
  name: 'modern-js-effect-installed-dependencies',
137
140
  setup(buildApi) {
138
141
  buildApi.onResolve({ filter: /.*/ }, async args => {
142
+ if (BFF_RUNTIME_PACKAGE.test(args.path)) {
143
+ return { external: true, path: args.path };
144
+ }
139
145
  if (
140
146
  !isBareSpecifier(args.path) ||
141
147
  nodeBuiltins.has(args.path) ||
@@ -1,5 +1,4 @@
1
1
  import { realpathSync } from 'node:fs';
2
- import path from 'node:path';
3
2
  import type { Rspack } from '@rsbuild/core';
4
3
  import {
5
4
  bundleEffectWorkerRuntimeSource,
@@ -1,94 +0,0 @@
1
- "use strict";
2
- var __webpack_require__ = {};
3
- (()=>{
4
- __webpack_require__.d = (exports1, getters, values)=>{
5
- var define = (defs, kind)=>{
6
- for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
7
- enumerable: true,
8
- [kind]: defs[key]
9
- });
10
- };
11
- define(getters, "get");
12
- define(values, "value");
13
- };
14
- })();
15
- (()=>{
16
- __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
17
- })();
18
- (()=>{
19
- __webpack_require__.r = (exports1)=>{
20
- if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
21
- value: 'Module'
22
- });
23
- Object.defineProperty(exports1, '__esModule', {
24
- value: true
25
- });
26
- };
27
- })();
28
- var __webpack_exports__ = {};
29
- __webpack_require__.r(__webpack_exports__);
30
- __webpack_require__.d(__webpack_exports__, {
31
- loadBackendFederationExpose: ()=>loadBackendFederationExpose
32
- });
33
- const backend_federation_security_namespaceObject = require("@modern-js/server-runtime-extensions/backend-federation-security");
34
- const external_utils_js_namespaceObject = require("./utils.js");
35
- function decodeDataUrl(url) {
36
- const commaIndex = url.indexOf(',');
37
- if (commaIndex < 0) throw new Error('[BFF][Effect] Invalid backend federation data URL entry.');
38
- return decodeURIComponent(url.slice(commaIndex + 1));
39
- }
40
- async function readCommonJsEntrySource(remote) {
41
- if (remote.entry.startsWith('data:')) return decodeDataUrl(remote.entry);
42
- throw new Error(`[BFF][Effect] Backend federation remote ${remote.name} cannot load CommonJS entry ${remote.entry}.`);
43
- }
44
- async function importModuleEntry(remote) {
45
- const entry = await import(remote.entry);
46
- return entry.default ?? entry;
47
- }
48
- async function resolvePluginEntry(remote, plugins) {
49
- for (const plugin of plugins ?? []){
50
- const loadEntry = plugin.loadEntry;
51
- if ('function' != typeof loadEntry) continue;
52
- const entry = await loadEntry({
53
- remoteInfo: remote
54
- });
55
- if (entry) return entry;
56
- }
57
- }
58
- async function loadBackendFederationEntry(remote, options) {
59
- const requiresVerification = Boolean(remote.verification || options.entryPolicy?.expected);
60
- const isNetworkEntry = /^https?:\/\//iu.test(remote.entry);
61
- if (isNetworkEntry && !requiresVerification) throw new Error(`[BFF][Effect] Backend federation remote ${remote.name} requires verified entry bytes before network execution.`);
62
- if (requiresVerification) return (0, backend_federation_security_namespaceObject.loadVerifiedBackendFederationEntry)({
63
- ...options.entryPolicy,
64
- remote,
65
- ...remote.verification ? {
66
- verification: remote.verification
67
- } : {}
68
- });
69
- const pluginEntry = await resolvePluginEntry(remote, options.plugins);
70
- if (pluginEntry) return pluginEntry;
71
- if (remote.entryGlobalName) {
72
- const globalEntry = globalThis[remote.entryGlobalName];
73
- if ((0, external_utils_js_namespaceObject.isRecord)(globalEntry)) return globalEntry;
74
- }
75
- if ('module' === remote.type || remote.entry.startsWith('file:')) return importModuleEntry(remote);
76
- return (0, backend_federation_security_namespaceObject.evaluateBackendFederationCommonJsEntry)(remote, new TextEncoder().encode(await readCommonJsEntrySource(remote)), options.entryPolicy?.evaluateCommonJs);
77
- }
78
- async function loadBackendFederationExpose(remote, expose, options) {
79
- const entry = await loadBackendFederationEntry(remote, options);
80
- if ('function' == typeof entry.init) await entry.init({
81
- hostName: options.hostName
82
- });
83
- if ('function' != typeof entry.get) throw new Error(`[BFF][Effect] Backend federation remote ${remote.name} entry must expose get().`);
84
- const factory = await entry.get(expose);
85
- if ('function' != typeof factory) throw new Error(`[BFF][Effect] Backend federation expose ${remote.name}/${(0, external_utils_js_namespaceObject.normalizeExpose)(expose)} must load factory function.`);
86
- return factory();
87
- }
88
- exports.loadBackendFederationExpose = __webpack_exports__.loadBackendFederationExpose;
89
- for(var __rspack_i in __webpack_exports__)if (-1 === [
90
- "loadBackendFederationExpose"
91
- ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
92
- Object.defineProperty(exports, '__esModule', {
93
- value: true
94
- });
@@ -1,48 +0,0 @@
1
- "use strict";
2
- const __rslib_import_meta_url__ = /*#__PURE__*/ function() {
3
- return "u" < typeof document ? new (require('url'.replace('', ''))).URL('file:' + __filename).href : document.currentScript && document.currentScript.src || new URL('main.js', document.baseURI).href;
4
- }();
5
- var __webpack_require__ = {};
6
- (()=>{
7
- __webpack_require__.d = (exports1, getters, values)=>{
8
- var define = (defs, kind)=>{
9
- for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
10
- enumerable: true,
11
- [kind]: defs[key]
12
- });
13
- };
14
- define(getters, "get");
15
- define(values, "value");
16
- };
17
- })();
18
- (()=>{
19
- __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
20
- })();
21
- (()=>{
22
- __webpack_require__.r = (exports1)=>{
23
- if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
24
- value: 'Module'
25
- });
26
- Object.defineProperty(exports1, '__esModule', {
27
- value: true
28
- });
29
- };
30
- })();
31
- var __webpack_exports__ = {};
32
- __webpack_require__.r(__webpack_exports__);
33
- __webpack_require__.d(__webpack_exports__, {
34
- evaluateEffectBackendFederationCommonJs: ()=>evaluateEffectBackendFederationCommonJs
35
- });
36
- const external_node_module_namespaceObject = require("node:module");
37
- const node_namespaceObject = require("@modern-js/server-runtime-extensions/backend-federation-security/node");
38
- const fromAdapter = (0, external_node_module_namespaceObject.createRequire)(__rslib_import_meta_url__);
39
- const fromEffectPackage = (0, external_node_module_namespaceObject.createRequire)(fromAdapter.resolve('@modern-js/bff-effect/package.json'));
40
- const privateRegistry = fromEffectPackage("#effect-entry-shape-registry");
41
- const evaluateEffectBackendFederationCommonJs = (source, context)=>(0, node_namespaceObject.evaluateNodeBackendFederationCommonJs)(source, context, privateRegistry);
42
- exports.evaluateEffectBackendFederationCommonJs = __webpack_exports__.evaluateEffectBackendFederationCommonJs;
43
- for(var __rspack_i in __webpack_exports__)if (-1 === [
44
- "evaluateEffectBackendFederationCommonJs"
45
- ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
46
- Object.defineProperty(exports, '__esModule', {
47
- value: true
48
- });
@@ -1,56 +0,0 @@
1
- import { evaluateBackendFederationCommonJsEntry, loadVerifiedBackendFederationEntry } from "@modern-js/server-runtime-extensions/backend-federation-security";
2
- import { isRecord, normalizeExpose } from "./utils.mjs";
3
- function decodeDataUrl(url) {
4
- const commaIndex = url.indexOf(',');
5
- if (commaIndex < 0) throw new Error('[BFF][Effect] Invalid backend federation data URL entry.');
6
- return decodeURIComponent(url.slice(commaIndex + 1));
7
- }
8
- async function readCommonJsEntrySource(remote) {
9
- if (remote.entry.startsWith('data:')) return decodeDataUrl(remote.entry);
10
- throw new Error(`[BFF][Effect] Backend federation remote ${remote.name} cannot load CommonJS entry ${remote.entry}.`);
11
- }
12
- async function importModuleEntry(remote) {
13
- const entry = await import(remote.entry);
14
- return entry.default ?? entry;
15
- }
16
- async function resolvePluginEntry(remote, plugins) {
17
- for (const plugin of plugins ?? []){
18
- const loadEntry = plugin.loadEntry;
19
- if ('function' != typeof loadEntry) continue;
20
- const entry = await loadEntry({
21
- remoteInfo: remote
22
- });
23
- if (entry) return entry;
24
- }
25
- }
26
- async function loadBackendFederationEntry(remote, options) {
27
- const requiresVerification = Boolean(remote.verification || options.entryPolicy?.expected);
28
- const isNetworkEntry = /^https?:\/\//iu.test(remote.entry);
29
- if (isNetworkEntry && !requiresVerification) throw new Error(`[BFF][Effect] Backend federation remote ${remote.name} requires verified entry bytes before network execution.`);
30
- if (requiresVerification) return loadVerifiedBackendFederationEntry({
31
- ...options.entryPolicy,
32
- remote,
33
- ...remote.verification ? {
34
- verification: remote.verification
35
- } : {}
36
- });
37
- const pluginEntry = await resolvePluginEntry(remote, options.plugins);
38
- if (pluginEntry) return pluginEntry;
39
- if (remote.entryGlobalName) {
40
- const globalEntry = globalThis[remote.entryGlobalName];
41
- if (isRecord(globalEntry)) return globalEntry;
42
- }
43
- if ('module' === remote.type || remote.entry.startsWith('file:')) return importModuleEntry(remote);
44
- return evaluateBackendFederationCommonJsEntry(remote, new TextEncoder().encode(await readCommonJsEntrySource(remote)), options.entryPolicy?.evaluateCommonJs);
45
- }
46
- async function loadBackendFederationExpose(remote, expose, options) {
47
- const entry = await loadBackendFederationEntry(remote, options);
48
- if ('function' == typeof entry.init) await entry.init({
49
- hostName: options.hostName
50
- });
51
- if ('function' != typeof entry.get) throw new Error(`[BFF][Effect] Backend federation remote ${remote.name} entry must expose get().`);
52
- const factory = await entry.get(expose);
53
- if ('function' != typeof factory) throw new Error(`[BFF][Effect] Backend federation expose ${remote.name}/${normalizeExpose(expose)} must load factory function.`);
54
- return factory();
55
- }
56
- export { loadBackendFederationExpose };
@@ -1,7 +0,0 @@
1
- import { createRequire } from "node:module";
2
- import { evaluateNodeBackendFederationCommonJs } from "@modern-js/server-runtime-extensions/backend-federation-security/node";
3
- const fromAdapter = createRequire(import.meta.url);
4
- const fromEffectPackage = createRequire(fromAdapter.resolve('@modern-js/bff-effect/package.json'));
5
- const privateRegistry = fromEffectPackage("#effect-entry-shape-registry");
6
- const evaluateEffectBackendFederationCommonJs = (source, context)=>evaluateNodeBackendFederationCommonJs(source, context, privateRegistry);
7
- export { evaluateEffectBackendFederationCommonJs };
@@ -1,57 +0,0 @@
1
- import "node:module";
2
- import { evaluateBackendFederationCommonJsEntry, loadVerifiedBackendFederationEntry } from "@modern-js/server-runtime-extensions/backend-federation-security";
3
- import { isRecord, normalizeExpose } from "./utils.mjs";
4
- function decodeDataUrl(url) {
5
- const commaIndex = url.indexOf(',');
6
- if (commaIndex < 0) throw new Error('[BFF][Effect] Invalid backend federation data URL entry.');
7
- return decodeURIComponent(url.slice(commaIndex + 1));
8
- }
9
- async function readCommonJsEntrySource(remote) {
10
- if (remote.entry.startsWith('data:')) return decodeDataUrl(remote.entry);
11
- throw new Error(`[BFF][Effect] Backend federation remote ${remote.name} cannot load CommonJS entry ${remote.entry}.`);
12
- }
13
- async function importModuleEntry(remote) {
14
- const entry = await import(remote.entry);
15
- return entry.default ?? entry;
16
- }
17
- async function resolvePluginEntry(remote, plugins) {
18
- for (const plugin of plugins ?? []){
19
- const loadEntry = plugin.loadEntry;
20
- if ('function' != typeof loadEntry) continue;
21
- const entry = await loadEntry({
22
- remoteInfo: remote
23
- });
24
- if (entry) return entry;
25
- }
26
- }
27
- async function loadBackendFederationEntry(remote, options) {
28
- const requiresVerification = Boolean(remote.verification || options.entryPolicy?.expected);
29
- const isNetworkEntry = /^https?:\/\//iu.test(remote.entry);
30
- if (isNetworkEntry && !requiresVerification) throw new Error(`[BFF][Effect] Backend federation remote ${remote.name} requires verified entry bytes before network execution.`);
31
- if (requiresVerification) return loadVerifiedBackendFederationEntry({
32
- ...options.entryPolicy,
33
- remote,
34
- ...remote.verification ? {
35
- verification: remote.verification
36
- } : {}
37
- });
38
- const pluginEntry = await resolvePluginEntry(remote, options.plugins);
39
- if (pluginEntry) return pluginEntry;
40
- if (remote.entryGlobalName) {
41
- const globalEntry = globalThis[remote.entryGlobalName];
42
- if (isRecord(globalEntry)) return globalEntry;
43
- }
44
- if ('module' === remote.type || remote.entry.startsWith('file:')) return importModuleEntry(remote);
45
- return evaluateBackendFederationCommonJsEntry(remote, new TextEncoder().encode(await readCommonJsEntrySource(remote)), options.entryPolicy?.evaluateCommonJs);
46
- }
47
- async function loadBackendFederationExpose(remote, expose, options) {
48
- const entry = await loadBackendFederationEntry(remote, options);
49
- if ('function' == typeof entry.init) await entry.init({
50
- hostName: options.hostName
51
- });
52
- if ('function' != typeof entry.get) throw new Error(`[BFF][Effect] Backend federation remote ${remote.name} entry must expose get().`);
53
- const factory = await entry.get(expose);
54
- if ('function' != typeof factory) throw new Error(`[BFF][Effect] Backend federation expose ${remote.name}/${normalizeExpose(expose)} must load factory function.`);
55
- return factory();
56
- }
57
- export { loadBackendFederationExpose };
@@ -1,8 +0,0 @@
1
- import "node:module";
2
- import { createRequire } from "node:module";
3
- import { evaluateNodeBackendFederationCommonJs } from "@modern-js/server-runtime-extensions/backend-federation-security/node";
4
- const fromAdapter = createRequire(import.meta.url);
5
- const fromEffectPackage = createRequire(fromAdapter.resolve('@modern-js/bff-effect/package.json'));
6
- const privateRegistry = fromEffectPackage("#effect-entry-shape-registry");
7
- const evaluateEffectBackendFederationCommonJs = (source, context)=>evaluateNodeBackendFederationCommonJs(source, context, privateRegistry);
8
- export { evaluateEffectBackendFederationCommonJs };
@@ -1,2 +0,0 @@
1
- import type { BackendFederationRemote, BackendFederationRuntimeOptions } from './types.js';
2
- export declare function loadBackendFederationExpose(remote: BackendFederationRemote, expose: string, options: BackendFederationRuntimeOptions): Promise<unknown>;
@@ -1,2 +0,0 @@
1
- import { evaluateNodeBackendFederationCommonJs } from '@modern-js/server-runtime-extensions/backend-federation-security/node';
2
- export declare const evaluateEffectBackendFederationCommonJs: (source: Parameters<typeof evaluateNodeBackendFederationCommonJs>[0], context: Parameters<typeof evaluateNodeBackendFederationCommonJs>[1]) => Record<string, unknown>;
@@ -1,125 +0,0 @@
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
- }
@@ -1,13 +0,0 @@
1
- import { createRequire } from 'node:module';
2
- import { evaluateNodeBackendFederationCommonJs } from '@modern-js/server-runtime-extensions/backend-federation-security/node';
3
-
4
- const fromAdapter = createRequire(import.meta.url);
5
- const fromEffectPackage = createRequire(
6
- fromAdapter.resolve('@modern-js/bff-effect/package.json'),
7
- );
8
- const privateRegistry = fromEffectPackage(`#effect-entry-shape-${'registry'}`);
9
-
10
- export const evaluateEffectBackendFederationCommonJs = (
11
- source: Parameters<typeof evaluateNodeBackendFederationCommonJs>[0],
12
- context: Parameters<typeof evaluateNodeBackendFederationCommonJs>[1],
13
- ) => evaluateNodeBackendFederationCommonJs(source, context, privateRegistry);