@bleedingdev/modern-js-plugin-bff-extensions 3.9.0-ultramodern.9 → 3.9.3-ultramodern.10

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 (129) hide show
  1. package/README.md +21 -4
  2. package/dist/cjs/backend-federation/edge.js +1 -1
  3. package/dist/cjs/backend-federation/identity.js +23 -22
  4. package/dist/cjs/backend-federation/integrity-plugin.js +112 -0
  5. package/dist/cjs/backend-federation/node-shared.js +85 -0
  6. package/dist/cjs/backend-federation/node.js +6 -1
  7. package/dist/cjs/backend-federation/plugin.js +40 -21
  8. package/dist/cjs/backend-federation/runtime.js +16 -84
  9. package/dist/cjs/backend-federation-manifest/load.js +31 -5
  10. package/dist/cjs/backend-federation-manifest/node.js +3 -1
  11. package/dist/cjs/backend-federation-manifest/remote.js +1 -7
  12. package/dist/cjs/backend-federation-manifest/validation.js +11 -7
  13. package/dist/cjs/cross-project-policy/node.js +8 -28
  14. package/dist/cjs/{effect-adapter → effect-server}/cross-project-policy.js +9 -9
  15. package/dist/cjs/effect-server/entry.js +63 -0
  16. package/dist/cjs/{effect-adapter → effect-server}/error-response.js +4 -4
  17. package/dist/cjs/effect-server/index.js +200 -0
  18. package/dist/cjs/effect-source-loader/built-entry.js +4 -5
  19. package/dist/cjs/effect-source-loader/http-api-runtime.js +4 -4
  20. package/dist/cjs/effect-source-loader/loader.js +10 -2
  21. package/dist/cjs/effect-source-loader/operation-contracts.js +8 -31
  22. package/dist/cjs/effect-source-loader/paths.js +38 -10
  23. package/dist/cjs/server-global-vars/index.js +61 -0
  24. package/dist/esm/backend-federation/edge.mjs +1 -1
  25. package/dist/esm/backend-federation/identity.mjs +18 -23
  26. package/dist/esm/backend-federation/integrity-plugin.mjs +68 -0
  27. package/dist/esm/backend-federation/node-shared.mjs +41 -0
  28. package/dist/esm/backend-federation/node.mjs +4 -2
  29. package/dist/esm/backend-federation/plugin.mjs +37 -18
  30. package/dist/esm/backend-federation/runtime.mjs +16 -84
  31. package/dist/esm/backend-federation-manifest/load.mjs +31 -5
  32. package/dist/esm/backend-federation-manifest/node.mjs +3 -1
  33. package/dist/esm/backend-federation-manifest/remote.mjs +1 -7
  34. package/dist/esm/backend-federation-manifest/validation.mjs +12 -8
  35. package/dist/esm/cross-project-policy/node.mjs +9 -19
  36. package/dist/esm/{effect-adapter → effect-server}/cross-project-policy.mjs +4 -4
  37. package/dist/esm/effect-server/entry.mjs +15 -0
  38. package/dist/esm/{effect-adapter → effect-server}/error-response.mjs +2 -2
  39. package/dist/esm/effect-server/index.mjs +152 -0
  40. package/dist/esm/effect-source-loader/built-entry.mjs +5 -6
  41. package/dist/esm/effect-source-loader/http-api-runtime.mjs +1 -1
  42. package/dist/esm/effect-source-loader/loader.mjs +10 -2
  43. package/dist/esm/effect-source-loader/operation-contracts.mjs +10 -33
  44. package/dist/esm/effect-source-loader/paths.mjs +30 -11
  45. package/dist/esm/server-global-vars/index.mjs +23 -0
  46. package/dist/esm-node/backend-federation/edge.mjs +1 -1
  47. package/dist/esm-node/backend-federation/identity.mjs +18 -23
  48. package/dist/esm-node/backend-federation/integrity-plugin.mjs +69 -0
  49. package/dist/esm-node/backend-federation/node-shared.mjs +42 -0
  50. package/dist/esm-node/backend-federation/node.mjs +4 -2
  51. package/dist/esm-node/backend-federation/plugin.mjs +37 -18
  52. package/dist/esm-node/backend-federation/runtime.mjs +16 -84
  53. package/dist/esm-node/backend-federation-manifest/load.mjs +31 -5
  54. package/dist/esm-node/backend-federation-manifest/node.mjs +3 -1
  55. package/dist/esm-node/backend-federation-manifest/remote.mjs +1 -7
  56. package/dist/esm-node/backend-federation-manifest/validation.mjs +12 -8
  57. package/dist/esm-node/cross-project-policy/node.mjs +9 -19
  58. package/dist/esm-node/{effect-adapter → effect-server}/cross-project-policy.mjs +4 -4
  59. package/dist/esm-node/effect-server/entry.mjs +16 -0
  60. package/dist/esm-node/{effect-adapter → effect-server}/error-response.mjs +2 -2
  61. package/dist/esm-node/effect-server/index.mjs +153 -0
  62. package/dist/esm-node/effect-source-loader/built-entry.mjs +5 -6
  63. package/dist/esm-node/effect-source-loader/http-api-runtime.mjs +1 -1
  64. package/dist/esm-node/effect-source-loader/loader.mjs +10 -2
  65. package/dist/esm-node/effect-source-loader/operation-contracts.mjs +10 -33
  66. package/dist/esm-node/effect-source-loader/paths.mjs +30 -11
  67. package/dist/esm-node/server-global-vars/index.mjs +24 -0
  68. package/dist/types/backend-federation/edge.d.ts +4 -2
  69. package/dist/types/backend-federation/identity.d.ts +3 -6
  70. package/dist/types/backend-federation/integrity-plugin.d.ts +13 -0
  71. package/dist/types/backend-federation/node-shared.d.ts +20 -0
  72. package/dist/types/backend-federation/node.d.ts +3 -0
  73. package/dist/types/backend-federation/plugin.d.ts +4 -0
  74. package/dist/types/backend-federation/types.d.ts +2 -7
  75. package/dist/types/backend-federation-manifest/types.d.ts +2 -1
  76. package/dist/types/cross-project-policy/node.d.ts +2 -2
  77. package/dist/types/effect-server/cross-project-policy.d.ts +5 -0
  78. package/dist/types/{effect-adapter → effect-server}/entry.d.ts +1 -1
  79. package/dist/types/effect-server/error-response.d.ts +2 -0
  80. package/dist/types/effect-server/index.d.ts +4 -0
  81. package/dist/types/effect-source-loader/http-api-runtime.d.ts +2 -0
  82. package/dist/types/effect-source-loader/loader.d.ts +3 -0
  83. package/dist/types/effect-source-loader/operation-contracts.d.ts +2 -0
  84. package/dist/types/effect-source-loader/paths.d.ts +20 -2
  85. package/dist/types/hono/node.d.ts +1 -1
  86. package/dist/types/server-global-vars/index.d.ts +11 -0
  87. package/package.json +47 -33
  88. package/src/backend-federation/edge.ts +7 -4
  89. package/src/backend-federation/identity.ts +39 -47
  90. package/src/backend-federation/integrity-plugin.ts +157 -0
  91. package/src/backend-federation/load.ts +0 -1
  92. package/src/backend-federation/node-shared.ts +76 -0
  93. package/src/backend-federation/node.ts +7 -3
  94. package/src/backend-federation/plugin.ts +73 -25
  95. package/src/backend-federation/runtime.ts +16 -90
  96. package/src/backend-federation/types.ts +2 -11
  97. package/src/backend-federation-manifest/load.ts +76 -27
  98. package/src/backend-federation-manifest/node.ts +3 -2
  99. package/src/backend-federation-manifest/remote.ts +0 -6
  100. package/src/backend-federation-manifest/types.ts +2 -0
  101. package/src/backend-federation-manifest/validation.ts +22 -29
  102. package/src/cross-project-policy/node.ts +7 -38
  103. package/src/{effect-adapter → effect-server}/cross-project-policy.ts +9 -3
  104. package/src/effect-server/entry.ts +18 -0
  105. package/src/{effect-adapter → effect-server}/error-response.ts +1 -1
  106. package/src/effect-server/index.ts +243 -0
  107. package/src/effect-source-loader/built-entry.ts +11 -9
  108. package/src/effect-source-loader/http-api-runtime.ts +3 -1
  109. package/src/effect-source-loader/loader.ts +24 -6
  110. package/src/effect-source-loader/operation-contracts.ts +9 -41
  111. package/src/effect-source-loader/paths.ts +55 -21
  112. package/src/effect-source-loader/rspack-loader.ts +0 -1
  113. package/src/server-global-vars/index.ts +46 -0
  114. package/dist/cjs/backend-federation/entry.js +0 -94
  115. package/dist/cjs/effect-adapter/entry.js +0 -99
  116. package/dist/cjs/effect-adapter/index.js +0 -194
  117. package/dist/esm/backend-federation/entry.mjs +0 -56
  118. package/dist/esm/effect-adapter/entry.mjs +0 -51
  119. package/dist/esm/effect-adapter/index.mjs +0 -143
  120. package/dist/esm-node/backend-federation/entry.mjs +0 -57
  121. package/dist/esm-node/effect-adapter/entry.mjs +0 -52
  122. package/dist/esm-node/effect-adapter/index.mjs +0 -144
  123. package/dist/types/backend-federation/entry.d.ts +0 -2
  124. package/dist/types/effect-adapter/cross-project-policy.d.ts +0 -4
  125. package/dist/types/effect-adapter/error-response.d.ts +0 -2
  126. package/dist/types/effect-adapter/index.d.ts +0 -21
  127. package/src/backend-federation/entry.ts +0 -125
  128. package/src/effect-adapter/entry.ts +0 -96
  129. package/src/effect-adapter/index.ts +0 -251
@@ -5,7 +5,8 @@ import { builtinModules, createRequire } from "node:module";
5
5
  import node_path from "node:path";
6
6
  import { pathToFileURL } from "node:url";
7
7
  import { build, transform } from "esbuild";
8
- const NODE_TARGET = 'node26.7';
8
+ import { serializeServerGlobalVars } from "../server-global-vars/index.mjs";
9
+ const NODE_TARGET = 'node26.10';
9
10
  const SOURCE_LOADERS = new Map([
10
11
  [
11
12
  '.js',
@@ -80,6 +81,7 @@ const nodeBuiltins = new Set([
80
81
  ...builtinModules.map((name)=>`node:${name}`)
81
82
  ]);
82
83
  const dependencyResolutionMarker = 'modern-js-effect-dependency-resolution';
84
+ const BFF_RUNTIME_PACKAGE = /^@modern-js\/(?:bff-effect|plugin-bff)(?:\/|$)/;
83
85
  async function isEsmOnlyFile(filename) {
84
86
  const extension = node_path.extname(filename).toLowerCase();
85
87
  if ('.mjs' === extension || '.mts' === extension) return true;
@@ -108,6 +110,10 @@ function externalizeInstalledDependencies(options) {
108
110
  buildApi.onResolve({
109
111
  filter: /.*/
110
112
  }, async (args)=>{
113
+ if (BFF_RUNTIME_PACKAGE.test(args.path)) return {
114
+ external: true,
115
+ path: args.path
116
+ };
111
117
  if (!isBareSpecifier(args.path) || nodeBuiltins.has(args.path) || args.pluginData?.[dependencyResolutionMarker] === true) return nodeBuiltins.has(args.path) ? {
112
118
  external: true,
113
119
  path: args.path
@@ -131,7 +137,8 @@ function externalizeInstalledDependencies(options) {
131
137
  path: args.path
132
138
  };
133
139
  const realPath = await node_fs.promises.realpath(resolution.path).catch(()=>resolution.path);
134
- if (realPath.includes(`${node_path.sep}node_modules${node_path.sep}`)) {
140
+ const loader = SOURCE_LOADERS.get(node_path.extname(realPath).toLowerCase());
141
+ if (realPath.includes(`${node_path.sep}node_modules${node_path.sep}`) && 'ts' !== loader && 'tsx' !== loader && 'jsx' !== loader) {
135
142
  const runtimeResolution = await buildApi.resolve(args.path, {
136
143
  importer: '',
137
144
  kind: args.kind,
@@ -234,6 +241,7 @@ async function loadEffectSourceModule(options) {
234
241
  js: `import { createRequire as __modernCreateEffectRequire } from 'node:module'; const require = __modernCreateEffectRequire(${JSON.stringify(pathToFileURL(resourcePath).href)});`
235
242
  },
236
243
  bundle: true,
244
+ define: serializeServerGlobalVars(options.globalVars),
237
245
  entryPoints: [
238
246
  resourcePath
239
247
  ],
@@ -1,46 +1,23 @@
1
1
  import "node:module";
2
2
  import { collectEffectEndpoints, toOperationContractSources } from "@modern-js/bff-effect/effect";
3
- import { buildOperationContractMap, deriveOperationVersion } from "@modern-js/server-runtime-extensions/bff-policy/node";
4
- import { fs, upath } from "@modern-js/utils";
3
+ import { buildOperationContractMap, resolveOperationProducer } from "@modern-js/server-runtime-extensions/bff-policy/node";
4
+ import { upath } from "@modern-js/utils";
5
5
  import { getHttpApiRuntime, loadEffectApi } from "./http-api-runtime.mjs";
6
- function getPackageInfo(resourcePath, appDir, onDependency) {
7
- for (const startDir of [
8
- upath.dirname(resourcePath),
9
- appDir
10
- ]){
11
- let current = upath.resolve(startDir);
12
- for(let depth = 0; depth < 32; depth += 1){
13
- const packageJsonPath = upath.join(current, 'package.json');
14
- if (fs.existsSync(packageJsonPath)) {
15
- onDependency?.(packageJsonPath);
16
- try {
17
- const packageJson = fs.readJSONSync(packageJsonPath);
18
- return {
19
- name: packageJson.name,
20
- version: packageJson.version
21
- };
22
- } catch {
23
- return {};
24
- }
25
- }
26
- const parent = upath.dirname(current);
27
- if (parent === current) break;
28
- current = parent;
29
- }
30
- }
31
- return {};
32
- }
33
6
  async function resolveEffectOperationContracts(options) {
34
7
  const api = await loadEffectApi(options);
35
8
  if (null === api) return null;
36
9
  const runtime = await getHttpApiRuntime();
37
10
  const endpoints = collectEffectEndpoints(runtime.reflect, api, options.prefix);
38
- const packageInfo = getPackageInfo(options.resourcePath, options.appDir, options.onDependency);
39
- const requestId = options.requestId?.trim() || packageInfo.name || 'default';
40
11
  return buildOperationContractMap({
41
12
  handlers: toOperationContractSources(endpoints),
42
- requestId,
43
- operationVersion: deriveOperationVersion(packageInfo.version)
13
+ ...resolveOperationProducer({
14
+ directories: [
15
+ upath.dirname(options.resourcePath),
16
+ options.appDir
17
+ ],
18
+ requestId: options.requestId,
19
+ onDependency: options.onDependency
20
+ })
44
21
  });
45
22
  }
46
23
  export { resolveEffectOperationContracts };
@@ -10,16 +10,35 @@ const JS_OR_TS_EXTS = [
10
10
  '.cjs',
11
11
  '.cts'
12
12
  ];
13
- function resolveEffectEntryFile(options) {
14
- const { appDir, apiDir, effectEntry } = options;
15
- const resolveEntry = (entryWithoutExt)=>{
16
- if ('' !== upath.extname(entryWithoutExt)) return fs.existsSync(entryWithoutExt) ? entryWithoutExt : void 0;
17
- return findExists(JS_OR_TS_EXTS.map((ext)=>`${entryWithoutExt}${ext}`)) || void 0;
13
+ const emittedEffectEntry = (entry)=>entry.replace(/\.(?:[cm]?ts|tsx|jsx)$/u, '.js');
14
+ function relativeEffectAppPath(appDir, entry) {
15
+ const relative = upath.relative(appDir, entry);
16
+ return '..' === relative || relative.startsWith('../') || relative.split('/').includes('node_modules') ? void 0 : relative;
17
+ }
18
+ function existingEntry(entry) {
19
+ return upath.extname(entry) ? fs.existsSync(entry) ? entry : void 0 : findExists(JS_OR_TS_EXTS.map((ext)=>`${entry}${ext}`)) || void 0;
20
+ }
21
+ function resolveEffectEntry(options) {
22
+ const { appDir, apiDir, effectEntry, distDir } = options;
23
+ const entry = upath.resolve(appDir, effectEntry || upath.join(apiDir, 'index'));
24
+ if (distDir && void 0 !== relativeEffectAppPath(distDir, entry)) return {
25
+ kind: 'built-output',
26
+ path: existingEntry(emittedEffectEntry(entry))
27
+ };
28
+ const relative = relativeEffectAppPath(appDir, entry);
29
+ if (void 0 === relative) return {
30
+ kind: 'external-sdk',
31
+ path: existingEntry(entry)
18
32
  };
19
- if (void 0 !== effectEntry && '' !== effectEntry) {
20
- const entryWithoutExt = upath.isAbsolute(effectEntry) ? effectEntry : upath.resolve(appDir, effectEntry);
21
- return resolveEntry(entryWithoutExt);
22
- }
23
- return resolveEntry(upath.resolve(apiDir, 'index'));
33
+ return distDir ? {
34
+ kind: 'built-output',
35
+ path: existingEntry(emittedEffectEntry(upath.resolve(distDir, relative)))
36
+ } : {
37
+ kind: 'app-source',
38
+ path: existingEntry(entry)
39
+ };
40
+ }
41
+ function resolveEffectEntryFile(options) {
42
+ return resolveEffectEntry(options).path;
24
43
  }
25
- export { resolveEffectEntryFile };
44
+ export { emittedEffectEntry, relativeEffectAppPath, resolveEffectEntry, resolveEffectEntryFile };
@@ -0,0 +1,24 @@
1
+ import "node:module";
2
+ import { applyOptionsChain } from "@modern-js/utils";
3
+ const serializeServerGlobalVars = (options)=>{
4
+ const globalVars = applyOptionsChain({}, options, {
5
+ env: 'server',
6
+ target: 'node'
7
+ });
8
+ return Object.fromEntries(Object.entries(globalVars).map(([key, value])=>{
9
+ let serialized;
10
+ try {
11
+ serialized = JSON.stringify(value);
12
+ } catch (error) {
13
+ throw new Error(`source.globalVars["${key}"] cannot be serialized exactly for BFF server code.`, {
14
+ cause: error
15
+ });
16
+ }
17
+ if (void 0 === serialized) throw new Error(`source.globalVars["${key}"] cannot be serialized exactly for BFF server code.`);
18
+ return [
19
+ key,
20
+ serialized
21
+ ];
22
+ }));
23
+ };
24
+ export { serializeServerGlobalVars };
@@ -8,19 +8,21 @@ export { BACKEND_FEDERATION_CONTRACT_VERSION, BACKEND_FEDERATION_EFFECT_EXPOSE,
8
8
  export type BackendFederationRemote = BackendFederationEdgeRemote;
9
9
  export type BackendFederationRuntimeOptions = BackendFederationEdgeRuntimeOptions;
10
10
  export type BackendFederationLoadEntryPluginOptions = BackendFederationEdgeLoadEntryPluginOptions;
11
- export type EdgeBackendFederationLoadOptions = Omit<BackendFederationLoadOptions, 'entryPolicy' | 'plugins' | 'remote' | 'remotes' | 'runtime'> & {
11
+ export type EdgeBackendFederationLoadOptions = Omit<BackendFederationLoadOptions, 'entryPolicy' | 'plugins' | 'remote' | 'remotes' | 'runtime' | 'shared'> & {
12
12
  entryPolicy?: never;
13
13
  plugins?: BackendFederationEdgeLoadEntryPlugin[];
14
14
  remote?: BackendFederationEdgeRemote;
15
15
  remotes?: BackendFederationEdgeRemote[];
16
16
  runtime?: never;
17
+ shared?: never;
17
18
  };
18
- export type EdgeBackendFederationIdentityLoadOptions = Omit<UniversalBackendFederationIdentityLoadOptions, 'entryPolicy' | 'plugins' | 'remote' | 'remotes' | 'runtime'> & {
19
+ export type EdgeBackendFederationIdentityLoadOptions = Omit<UniversalBackendFederationIdentityLoadOptions, 'entryPolicy' | 'plugins' | 'remote' | 'remotes' | 'runtime' | 'shared'> & {
19
20
  entryPolicy?: never;
20
21
  plugins?: BackendFederationEdgeLoadEntryPlugin[];
21
22
  remote?: BackendFederationEdgeRemote;
22
23
  remotes?: BackendFederationEdgeRemote[];
23
24
  runtime?: never;
25
+ shared?: never;
24
26
  };
25
27
  export type BackendFederationIdentityLoadOptions = EdgeBackendFederationIdentityLoadOptions;
26
28
  export declare function loadBackendFederatedEffectApi(options: EdgeBackendFederationIdentityLoadOptions): Promise<BackendFederatedEffectApiModule>;
@@ -11,11 +11,8 @@ export type BackendFederationIdentityIssue = {
11
11
  path: string;
12
12
  message: string;
13
13
  };
14
- /**
15
- * Shared expected-identity validation for loaded backend federation modules.
16
- * Compares the expose's `backendFederationContract.compatibility` identity
17
- * (`unitId`, `build`) against the consumer's expected delivery-unit identity.
18
- * Missing identity metadata is an error.
19
- */
14
+ /** Decode independently at each received-manifest / executed-expose boundary. */
15
+ export declare function backendFederationCompatibility(loaded: unknown): Record<string, unknown> | undefined;
16
+ export declare function validateBackendFederationCompatibility(compatibility: Record<string, unknown>, expected: Record<string, string | undefined>): BackendFederationIdentityIssue[];
20
17
  export declare function validateExpectedBackendFederationIdentity(loaded: unknown, expected: BackendFederationExpectedIdentity): BackendFederationIdentityIssue[];
21
18
  export declare function formatBackendFederationIdentityIssues(issues: BackendFederationIdentityIssue[]): string;
@@ -0,0 +1,13 @@
1
+ import { Module, type ModuleFederation, type ModuleFederationRuntimePlugin } from '@module-federation/runtime';
2
+ import type { BackendFederationEntryExports, BackendFederationRemote, BackendFederationRuntimeOptions } from './types.js';
3
+ type RemoteInfo = ConstructorParameters<typeof Module>[0]['remoteInfo'];
4
+ export declare const PROVIDED_ENTRY_SCHEME: RegExp;
5
+ export declare function registerRemoteContainer(origin: ModuleFederation, remoteInfo: RemoteInfo, container: BackendFederationEntryExports): void;
6
+ /**
7
+ * Loads each configured remote once per runtime and registers the resulting
8
+ * container with that runtime only, so Module Federation initializes it with
9
+ * the runtime's own share scope. Registered last, it replaces any container a
10
+ * caller plugin supplied for a scheme it owns.
11
+ */
12
+ export declare function createBackendFederationIntegrityPlugin(options: BackendFederationRuntimeOptions, remotes: readonly BackendFederationRemote[]): ModuleFederationRuntimePlugin;
13
+ export {};
@@ -0,0 +1,20 @@
1
+ import type { BackendFederationRuntimeOptions } from './types.js';
2
+ type HostShared = NonNullable<BackendFederationRuntimeOptions['shared']>;
3
+ /**
4
+ * Shares the package-private Effect handler factory registry and the Effect
5
+ * request storage with every backend container, so factories a remote creates
6
+ * with defineEffectBff are recognized by this host's module resolver and its
7
+ * endpoints read the context this host's dispatcher enters.
8
+ *
9
+ * Loaded on first call, not when this module loads: a CommonJS require() of
10
+ * the Effect ES modules throws while a concurrent import() is still loading
11
+ * them.
12
+ */
13
+ export declare function effectBffHostShared(): HostShared;
14
+ /**
15
+ * Adds the host shares to caller shares. Their names are reserved: a caller
16
+ * replacement would make containers use a registry or a request storage this
17
+ * host never consults.
18
+ */
19
+ export declare function withEffectBffHostShared(shared: BackendFederationRuntimeOptions['shared']): HostShared;
20
+ export {};
@@ -1,2 +1,5 @@
1
+ import { effectBffHostShared } from './node-shared.js';
2
+ /** Call for the `shared` option when building a custom runtime for Node hosts. */
3
+ export { effectBffHostShared };
1
4
  import type { BackendFederatedEffectApiModule, BackendFederationIdentityLoadOptions } from './types.js';
2
5
  export declare function loadBackendFederatedEffectApi(options: BackendFederationIdentityLoadOptions): Promise<BackendFederatedEffectApiModule>;
@@ -1,3 +1,7 @@
1
1
  import type { ModuleFederationRuntimePlugin } from '@module-federation/runtime';
2
2
  import type { BackendFederationLoadEntryPluginOptions } from './types.js';
3
+ /**
4
+ * Serves binding:, service: and static: entries. The provider resolves each
5
+ * remote once per runtime and registers the container with that runtime only.
6
+ */
3
7
  export declare function createBackendFederationLoadEntryPlugin(options: BackendFederationLoadEntryPluginOptions): ModuleFederationRuntimePlugin;
@@ -7,8 +7,6 @@ export type BackendFederationRemote = {
7
7
  name: string;
8
8
  entry: string;
9
9
  type?: 'commonjs-module' | 'module' | string;
10
- entryGlobalName?: string;
11
- shareScope?: string | string[];
12
10
  expose?: typeof BACKEND_FEDERATION_EFFECT_EXPOSE;
13
11
  verification?: BackendFederationRemoteEntryVerification;
14
12
  };
@@ -17,6 +15,8 @@ export type BackendFederationRuntimeOptions = {
17
15
  remote?: BackendFederationRemote;
18
16
  remotes?: BackendFederationRemote[];
19
17
  plugins?: ModuleFederationRuntimePlugin[];
18
+ /** Host shares handed to every remote container's `init()`. */
19
+ shared?: ConstructorParameters<typeof ModuleFederation>[0]['shared'];
20
20
  entryPolicy?: BackendFederationRemoteEntryPolicy;
21
21
  };
22
22
  export type BackendFederationEntryExports = {
@@ -63,8 +63,3 @@ export type BackendFederationLoadOptions = BackendFederationRuntimeOptions & {
63
63
  export type BackendFederationIdentityLoadOptions = BackendFederationLoadOptions & {
64
64
  expected: BackendFederationExpectedIdentity;
65
65
  };
66
- export type BackendFederationLoadEntryPlugin = ModuleFederationRuntimePlugin & {
67
- loadEntry?: (args: {
68
- remoteInfo: BackendFederationRemote;
69
- }) => BackendFederationEntryExports | undefined | Promise<BackendFederationEntryExports | undefined>;
70
- };
@@ -1,6 +1,6 @@
1
1
  import type { BackendFederationRemoteEntryPolicy, BackendFederationResourcePolicy, BackendFederationResourceResponse } from '@modern-js/server-runtime-extensions/backend-federation-security';
2
2
  import type { ModuleFederation, ModuleFederationRuntimePlugin } from '@module-federation/runtime';
3
- import type { BackendFederatedEffectApiModule, BackendFederationRemote } from '../backend-federation/index.js';
3
+ import type { BackendFederatedEffectApiModule, BackendFederationRemote, BackendFederationRuntimeOptions } from '../backend-federation/index.js';
4
4
  import type { BackendFederationManifestAdapterError } from './errors.js';
5
5
  export type BackendFederationManifest = Record<string, unknown>;
6
6
  export type BackendFederationVersionBoundaryExpectation = {
@@ -44,6 +44,7 @@ export type BackendFederationManifestAdapterOptions = {
44
44
  plugins?: ModuleFederationRuntimePlugin[];
45
45
  remote?: Partial<BackendFederationRemote>;
46
46
  runtime?: ModuleFederation;
47
+ shared?: BackendFederationRuntimeOptions['shared'];
47
48
  signal?: AbortSignal;
48
49
  timeoutMs?: number;
49
50
  };
@@ -1,5 +1,5 @@
1
1
  import '@modern-js/server-runtime-extensions/server-config';
2
2
  import type { ServerPluginAPI } from '@modern-js/server-core';
3
- import { type OperationContractSource } from '@modern-js/server-runtime-extensions/bff-policy/node';
3
+ import { type OperationContractSource, resolveOperationProducer } from '@modern-js/server-runtime-extensions/bff-policy/node';
4
4
  import type { ResolvedCrossProjectPolicy } from './evaluation.js';
5
- export declare const resolveAdapterCrossProjectPolicy: (api: ServerPluginAPI, handlers: OperationContractSource[]) => ResolvedCrossProjectPolicy | undefined;
5
+ export declare const resolveAdapterCrossProjectPolicy: (api: ServerPluginAPI, handlers: OperationContractSource[], producer?: ReturnType<typeof resolveOperationProducer>) => ResolvedCrossProjectPolicy | undefined;
@@ -0,0 +1,5 @@
1
+ import { type EffectApiModule } from '@modern-js/bff-effect/effect';
2
+ import type { ServerPluginAPI } from '@modern-js/server-core';
3
+ import type { resolveOperationProducer } from '@modern-js/server-runtime-extensions/bff-policy/node';
4
+ import type { ResolvedCrossProjectPolicy } from '../cross-project-policy/evaluation.js';
5
+ export declare function resolveEffectServerCrossProjectPolicy(api: ServerPluginAPI, prefix: string, mod: EffectApiModule | null, producer?: ReturnType<typeof resolveOperationProducer>): Promise<ResolvedCrossProjectPolicy | undefined>;
@@ -1,3 +1,3 @@
1
1
  import '@modern-js/server-runtime-extensions/server-config';
2
2
  import type { ServerPluginAPI } from '@modern-js/server-core';
3
- export declare function resolveEffectAdapterEntryFile(api: ServerPluginAPI): string | undefined;
3
+ export declare function resolveEffectServerEntryFile(api: ServerPluginAPI): string | undefined;
@@ -0,0 +1,2 @@
1
+ import type { Context, ServerPluginAPI } from '@modern-js/server-core';
2
+ export declare function createEffectServerRuntimeErrorResponse(api: ServerPluginAPI, error: unknown, context: Context): Promise<Response>;
@@ -0,0 +1,4 @@
1
+ import '@modern-js/server-runtime-extensions/server-config';
2
+ import type { ServerPlugin } from '@modern-js/server-core';
3
+ export default _default;
4
+ declare function _default(): ServerPlugin;
@@ -1,4 +1,5 @@
1
1
  import { type HttpApiLike, type HttpApiReflect } from '@modern-js/bff-effect/effect';
2
+ import type { ServerGlobalVarsOptions } from '../server-global-vars/index.js';
2
3
  type HttpApiRuntime = {
3
4
  isHttpApi: (value: unknown) => boolean;
4
5
  reflect: HttpApiReflect;
@@ -7,6 +8,7 @@ export declare function getHttpApiRuntime(): Promise<HttpApiRuntime>;
7
8
  export declare function loadEffectApi(options: {
8
9
  appDir: string;
9
10
  resourcePath: string;
11
+ globalVars?: ServerGlobalVarsOptions;
10
12
  onDependency?: (dependency: string) => void;
11
13
  }): Promise<HttpApiLike | null>;
12
14
  export {};
@@ -1,6 +1,9 @@
1
+ import { type ServerGlobalVarsOptions } from '../server-global-vars/index.js';
1
2
  export type EffectSourceLoaderOptions = {
2
3
  resourcePath: string;
3
4
  appDir?: string;
5
+ /** `source.globalVars`, replaced in the loaded source graph. */
6
+ globalVars?: ServerGlobalVarsOptions;
4
7
  onDependency?: (dependency: string) => void;
5
8
  };
6
9
  export declare function bundleEffectEntryForNode(options: {
@@ -1,8 +1,10 @@
1
+ import type { ServerGlobalVarsOptions } from '../server-global-vars/index.js';
1
2
  /** Derives server policy metadata without emitting or typing a client. */
2
3
  export declare function resolveEffectOperationContracts(options: {
3
4
  appDir: string;
4
5
  resourcePath: string;
5
6
  prefix: string;
6
7
  requestId?: string;
8
+ globalVars?: ServerGlobalVarsOptions;
7
9
  onDependency?: (dependency: string) => void;
8
10
  }): Promise<import("@modern-js/server-runtime-extensions/bff-policy/node").OperationContractMap | null>;
@@ -1,5 +1,23 @@
1
- export declare function resolveEffectEntryFile(options: {
1
+ export declare const emittedEffectEntry: (entry: string) => string;
2
+ export declare function relativeEffectAppPath(appDir: string, entry: string): string | undefined;
3
+ type EffectEntryOptions = {
2
4
  appDir: string;
3
5
  apiDir: string;
4
6
  effectEntry?: string;
5
- }): string | undefined;
7
+ };
8
+ export type EffectEntry = {
9
+ kind: 'app-source';
10
+ path: string | undefined;
11
+ } | {
12
+ kind: 'built-output';
13
+ path: string | undefined;
14
+ } | {
15
+ kind: 'external-sdk';
16
+ path: string | undefined;
17
+ };
18
+ /** Classify ownership before resolving files: production works without source. */
19
+ export declare function resolveEffectEntry(options: EffectEntryOptions & {
20
+ distDir?: string;
21
+ }): EffectEntry;
22
+ export declare function resolveEffectEntryFile(options: EffectEntryOptions): string | undefined;
23
+ export {};
@@ -1,4 +1,4 @@
1
1
  import type { ServerPluginAPI } from '@modern-js/server-core';
2
2
  import type { OperationContractSource } from '@modern-js/server-runtime-extensions/bff-policy/node';
3
3
  import { type BindHonoRouteHandlersOptions } from './bind-route-handlers.js';
4
- export declare const createHonoRouteBinder: (api: ServerPluginAPI, handlers: OperationContractSource[]) => (options: Pick<BindHonoRouteHandlersOptions, 'handler' | 'routePath'>) => import("hono").MiddlewareHandler[] | import("hono").MiddlewareHandler;
4
+ export declare const createHonoRouteBinder: (api: ServerPluginAPI, handlers: OperationContractSource[]) => (options: Pick<BindHonoRouteHandlersOptions, 'handler' | 'routePath'>) => import("@modern-js/server-core").MiddlewareHandler[] | import("@modern-js/server-core").MiddlewareHandler;
@@ -0,0 +1,11 @@
1
+ import type { ServerSourceConfigExtension } from '@modern-js/runtime-extensions/server-config';
2
+ export type ServerGlobalVarsOptions = ServerSourceConfigExtension['globalVars'];
3
+ /** Each global name mapped to the JSON source text that replaces it. */
4
+ export type SerializedServerGlobalVars = Record<string, string>;
5
+ /**
6
+ * Resolves `source.globalVars` for BFF server code and serializes every value
7
+ * to the JSON text that replaces it. Dev source loading and build output use
8
+ * this one function, so both see the same values. A value without an exact
9
+ * JSON form (such as `undefined`, a function or a BigInt) is rejected.
10
+ */
11
+ export declare const serializeServerGlobalVars: (options: ServerGlobalVarsOptions) => SerializedServerGlobalVars;
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@bleedingdev/modern-js-plugin-bff-extensions",
3
3
  "description": "Fork-owned UltraModern.js BFF adapters, generation, policy, and backend federation extensions.",
4
- "homepage": "https://github.com/BleedingDev/ultramodern.js#readme",
4
+ "homepage": "https://github.com/ultramodernjs/ultramodern.js#readme",
5
5
  "bugs": {
6
- "url": "https://github.com/BleedingDev/ultramodern.js/issues"
6
+ "url": "https://github.com/ultramodernjs/ultramodern.js/issues"
7
7
  },
8
8
  "repository": {
9
9
  "type": "git",
10
- "url": "git+https://github.com/BleedingDev/ultramodern.js.git",
10
+ "url": "git+https://github.com/ultramodernjs/ultramodern.js.git",
11
11
  "directory": "packages/cli/plugin-bff-extensions"
12
12
  },
13
13
  "license": "MIT",
@@ -18,7 +18,7 @@
18
18
  "modern.js",
19
19
  "ultramodern.js"
20
20
  ],
21
- "version": "3.9.0-ultramodern.9",
21
+ "version": "3.9.3-ultramodern.10",
22
22
  "files": [
23
23
  "dist",
24
24
  "src"
@@ -50,13 +50,13 @@
50
50
  },
51
51
  "default": "./dist/cjs/cross-project-generation/index.js"
52
52
  },
53
- "./effect-adapter": {
54
- "types": "./dist/types/effect-adapter/index.d.ts",
53
+ "./effect-server": {
54
+ "types": "./dist/types/effect-server/index.d.ts",
55
55
  "node": {
56
- "import": "./dist/esm-node/effect-adapter/index.mjs",
57
- "require": "./dist/cjs/effect-adapter/index.js"
56
+ "import": "./dist/esm-node/effect-server/index.mjs",
57
+ "require": "./dist/cjs/effect-server/index.js"
58
58
  },
59
- "default": "./dist/cjs/effect-adapter/index.js"
59
+ "default": "./dist/cjs/effect-server/index.js"
60
60
  },
61
61
  "./effect-source-loader": {
62
62
  "types": "./dist/types/effect-source-loader/index.d.ts",
@@ -66,6 +66,14 @@
66
66
  },
67
67
  "default": "./dist/cjs/effect-source-loader/index.js"
68
68
  },
69
+ "./server-global-vars": {
70
+ "types": "./dist/types/server-global-vars/index.d.ts",
71
+ "node": {
72
+ "import": "./dist/esm-node/server-global-vars/index.mjs",
73
+ "require": "./dist/cjs/server-global-vars/index.js"
74
+ },
75
+ "default": "./dist/cjs/server-global-vars/index.js"
76
+ },
69
77
  "./backend-federation": {
70
78
  "types": "./dist/types/backend-federation/index.d.ts",
71
79
  "node": {
@@ -147,14 +155,18 @@
147
155
  "./dist/types/cross-project-generation/index.d.ts",
148
156
  "./src/cross-project-generation/index.ts"
149
157
  ],
150
- "effect-adapter": [
151
- "./dist/types/effect-adapter/index.d.ts",
152
- "./src/effect-adapter/index.ts"
158
+ "effect-server": [
159
+ "./dist/types/effect-server/index.d.ts",
160
+ "./src/effect-server/index.ts"
153
161
  ],
154
162
  "effect-source-loader": [
155
163
  "./dist/types/effect-source-loader/index.d.ts",
156
164
  "./src/effect-source-loader/index.ts"
157
165
  ],
166
+ "server-global-vars": [
167
+ "./dist/types/server-global-vars/index.d.ts",
168
+ "./src/server-global-vars/index.ts"
169
+ ],
158
170
  "backend-federation": [
159
171
  "./dist/types/backend-federation/index.d.ts",
160
172
  "./src/backend-federation/index.ts"
@@ -190,24 +202,24 @@
190
202
  }
191
203
  },
192
204
  "engines": {
193
- "node": ">=26.7.0"
205
+ "node": ">=26.12.0"
194
206
  },
195
207
  "dependencies": {
196
- "@modern-js/backend-federation-contracts": "npm:@bleedingdev/modern-js-backend-federation-contracts@3.9.0-ultramodern.9",
197
- "@modern-js/bff-core": "npm:@bleedingdev/modern-js-bff-core@3.9.0-ultramodern.9",
198
- "@modern-js/bff-effect": "npm:@bleedingdev/modern-js-bff-effect@3.9.0-ultramodern.9",
199
- "@modern-js/runtime-extensions": "npm:@bleedingdev/modern-js-runtime-extensions@3.9.0-ultramodern.9",
200
- "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.9.0-ultramodern.9",
201
- "@modern-js/server-runtime-extensions": "npm:@bleedingdev/modern-js-server-runtime-extensions@3.9.0-ultramodern.9",
202
- "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.9.0-ultramodern.9",
203
- "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.9.0-ultramodern.9",
204
- "@module-federation/runtime": "2.9.0",
205
- "@swc/core": "1.16.2",
208
+ "@modern-js/backend-federation-contracts": "npm:@bleedingdev/modern-js-backend-federation-contracts@3.9.3-ultramodern.10",
209
+ "@modern-js/bff-core": "npm:@bleedingdev/modern-js-bff-core@3.9.3-ultramodern.10",
210
+ "@modern-js/bff-effect": "npm:@bleedingdev/modern-js-bff-effect@3.9.3-ultramodern.10",
211
+ "@modern-js/runtime-extensions": "npm:@bleedingdev/modern-js-runtime-extensions@3.9.3-ultramodern.10",
212
+ "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.9.3-ultramodern.10",
213
+ "@modern-js/server-runtime-extensions": "npm:@bleedingdev/modern-js-server-runtime-extensions@3.9.3-ultramodern.10",
214
+ "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.9.3-ultramodern.10",
215
+ "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.9.3-ultramodern.10",
216
+ "@module-federation/runtime": "2.9.2",
217
+ "@swc/core": "1.16.18",
206
218
  "esbuild": "^0.28.2"
207
219
  },
208
220
  "peerDependencies": {
209
- "@effect/opentelemetry": "4.0.0-rc.112",
210
- "effect": "4.0.0-rc.112"
221
+ "@effect/opentelemetry": "4.0.5",
222
+ "effect": "4.0.5"
211
223
  },
212
224
  "peerDependenciesMeta": {
213
225
  "@effect/opentelemetry": {
@@ -218,15 +230,14 @@
218
230
  }
219
231
  },
220
232
  "devDependencies": {
221
- "@effect/opentelemetry": "4.0.0-rc.112",
222
- "@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.9.0-ultramodern.9",
223
- "@rsbuild/core": "2.2.3",
224
- "@rslib/core": "1.0.0",
233
+ "@effect/opentelemetry": "4.0.5",
234
+ "@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.9.3-ultramodern.10",
235
+ "@rsbuild/core": "2.2.13",
236
+ "@rslib/core": "1.0.3",
225
237
  "@scripts/rstest-config": "2.66.0",
226
- "@types/node": "^26.4.1",
227
- "@types/react": "^19.2.18",
228
- "@typescript/native-preview": "7.0.0-dev.20260707.2",
229
- "effect": "4.0.0-rc.112"
238
+ "@types/node": "^26.6.5",
239
+ "@types/react": "^19.3.0",
240
+ "effect": "4.0.5"
230
241
  },
231
242
  "sideEffects": false,
232
243
  "publishConfig": {
@@ -237,5 +248,8 @@
237
248
  "dev": "rslib build --watch",
238
249
  "build": "rslib build",
239
250
  "test": "rstest"
251
+ },
252
+ "ultramodern": {
253
+ "sourceName": "@modern-js/plugin-bff-extensions"
240
254
  }
241
255
  }
@@ -52,24 +52,26 @@ export type BackendFederationLoadEntryPluginOptions =
52
52
 
53
53
  export type EdgeBackendFederationLoadOptions = Omit<
54
54
  BackendFederationLoadOptions,
55
- 'entryPolicy' | 'plugins' | 'remote' | 'remotes' | 'runtime'
55
+ 'entryPolicy' | 'plugins' | 'remote' | 'remotes' | 'runtime' | 'shared'
56
56
  > & {
57
57
  entryPolicy?: never;
58
58
  plugins?: BackendFederationEdgeLoadEntryPlugin[];
59
59
  remote?: BackendFederationEdgeRemote;
60
60
  remotes?: BackendFederationEdgeRemote[];
61
61
  runtime?: never;
62
+ shared?: never;
62
63
  };
63
64
 
64
65
  export type EdgeBackendFederationIdentityLoadOptions = Omit<
65
66
  UniversalBackendFederationIdentityLoadOptions,
66
- 'entryPolicy' | 'plugins' | 'remote' | 'remotes' | 'runtime'
67
+ 'entryPolicy' | 'plugins' | 'remote' | 'remotes' | 'runtime' | 'shared'
67
68
  > & {
68
69
  entryPolicy?: never;
69
70
  plugins?: BackendFederationEdgeLoadEntryPlugin[];
70
71
  remote?: BackendFederationEdgeRemote;
71
72
  remotes?: BackendFederationEdgeRemote[];
72
73
  runtime?: never;
74
+ shared?: never;
73
75
  };
74
76
 
75
77
  export type BackendFederationIdentityLoadOptions =
@@ -80,11 +82,12 @@ export function loadBackendFederatedEffectApi(
80
82
  ): Promise<BackendFederatedEffectApiModule> {
81
83
  if (
82
84
  (options as BackendFederationLoadOptions).runtime !== undefined ||
83
- (options as BackendFederationLoadOptions).entryPolicy !== undefined
85
+ (options as BackendFederationLoadOptions).entryPolicy !== undefined ||
86
+ (options as BackendFederationLoadOptions).shared !== undefined
84
87
  ) {
85
88
  return Promise.reject(
86
89
  new Error(
87
- '[BFF][Effect] Edge backend federation does not execute custom runtimes or entry evaluators. Register a static or service-binding entry provider.',
90
+ '[BFF][Effect] Edge backend federation does not execute custom runtimes, entry evaluators or host shares. Register a static or service-binding entry provider.',
88
91
  ),
89
92
  );
90
93
  }