@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.
Files changed (228) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +29 -0
  3. package/dist/cjs/backend-federation/edge-runtime.js +230 -0
  4. package/dist/cjs/backend-federation/edge.js +80 -0
  5. package/dist/cjs/backend-federation/entry.js +94 -0
  6. package/dist/cjs/backend-federation/identity.js +82 -0
  7. package/dist/cjs/backend-federation/index.js +61 -0
  8. package/dist/cjs/backend-federation/legacy-warning.js +40 -0
  9. package/dist/cjs/backend-federation/load.js +72 -0
  10. package/dist/cjs/backend-federation/node.js +50 -0
  11. package/dist/cjs/backend-federation/plugin.js +63 -0
  12. package/dist/cjs/backend-federation/remotes.js +51 -0
  13. package/dist/cjs/backend-federation/runtime.js +128 -0
  14. package/dist/cjs/backend-federation/types.js +18 -0
  15. package/dist/cjs/backend-federation/utils.js +48 -0
  16. package/dist/cjs/backend-federation/validate-loaded.js +56 -0
  17. package/dist/cjs/backend-federation-manifest/errors.js +83 -0
  18. package/dist/cjs/backend-federation-manifest/index.js +48 -0
  19. package/dist/cjs/backend-federation-manifest/load.js +173 -0
  20. package/dist/cjs/backend-federation-manifest/metadata.js +101 -0
  21. package/dist/cjs/backend-federation-manifest/node.js +50 -0
  22. package/dist/cjs/backend-federation-manifest/reference.js +132 -0
  23. package/dist/cjs/backend-federation-manifest/remote.js +81 -0
  24. package/dist/cjs/backend-federation-manifest/types.js +18 -0
  25. package/dist/cjs/backend-federation-manifest/validation.js +110 -0
  26. package/dist/cjs/client-generator/built-entry.js +84 -0
  27. package/dist/cjs/client-generator/generator.js +73 -0
  28. package/dist/cjs/client-generator/index.js +54 -0
  29. package/dist/cjs/client-generator/paths.js +62 -0
  30. package/dist/cjs/client-generator/rendering.js +253 -0
  31. package/dist/cjs/client-generator/runtime.js +68 -0
  32. package/dist/cjs/client-generator/types.js +18 -0
  33. package/dist/cjs/cross-project-generation/index.js +40 -0
  34. package/dist/cjs/cross-project-generation/render.js +53 -0
  35. package/dist/cjs/cross-project-policy/evaluation.js +75 -0
  36. package/dist/cjs/cross-project-policy/index.js +40 -0
  37. package/dist/cjs/cross-project-policy/node.js +76 -0
  38. package/dist/cjs/effect-adapter/cross-project-policy.js +64 -0
  39. package/dist/cjs/effect-adapter/entry.js +98 -0
  40. package/dist/cjs/effect-adapter/error-response.js +75 -0
  41. package/dist/cjs/effect-adapter/index.js +187 -0
  42. package/dist/cjs/effect-source-loader/index.js +51 -0
  43. package/dist/cjs/effect-source-loader/loader.js +341 -0
  44. package/dist/cjs/effect-source-loader/worker-runtime-wrapper.js +97 -0
  45. package/dist/cjs/hono/bind-route-handlers.js +76 -0
  46. package/dist/cjs/hono/cross-project-policy.js +48 -0
  47. package/dist/cjs/hono/index.js +40 -0
  48. package/dist/esm/backend-federation/edge-runtime.mjs +186 -0
  49. package/dist/esm/backend-federation/edge.mjs +21 -0
  50. package/dist/esm/backend-federation/entry.mjs +56 -0
  51. package/dist/esm/backend-federation/identity.mjs +41 -0
  52. package/dist/esm/backend-federation/index.mjs +4 -0
  53. package/dist/esm/backend-federation/legacy-warning.mjs +2 -0
  54. package/dist/esm/backend-federation/load.mjs +34 -0
  55. package/dist/esm/backend-federation/node.mjs +12 -0
  56. package/dist/esm/backend-federation/plugin.mjs +25 -0
  57. package/dist/esm/backend-federation/remotes.mjs +13 -0
  58. package/dist/esm/backend-federation/runtime.mjs +90 -0
  59. package/dist/esm/backend-federation/types.mjs +0 -0
  60. package/dist/esm/backend-federation/utils.mjs +7 -0
  61. package/dist/esm/backend-federation/validate-loaded.mjs +18 -0
  62. package/dist/esm/backend-federation-manifest/errors.mjs +32 -0
  63. package/dist/esm/backend-federation-manifest/index.mjs +3 -0
  64. package/dist/esm/backend-federation-manifest/load.mjs +135 -0
  65. package/dist/esm/backend-federation-manifest/metadata.mjs +42 -0
  66. package/dist/esm/backend-federation-manifest/node.mjs +12 -0
  67. package/dist/esm/backend-federation-manifest/reference.mjs +88 -0
  68. package/dist/esm/backend-federation-manifest/remote.mjs +43 -0
  69. package/dist/esm/backend-federation-manifest/types.mjs +0 -0
  70. package/dist/esm/backend-federation-manifest/validation.mjs +66 -0
  71. package/dist/esm/client-generator/built-entry.mjs +40 -0
  72. package/dist/esm/client-generator/generator.mjs +32 -0
  73. package/dist/esm/client-generator/index.mjs +3 -0
  74. package/dist/esm/client-generator/paths.mjs +24 -0
  75. package/dist/esm/client-generator/rendering.mjs +209 -0
  76. package/dist/esm/client-generator/runtime.mjs +27 -0
  77. package/dist/esm/client-generator/types.mjs +0 -0
  78. package/dist/esm/cross-project-generation/index.mjs +1 -0
  79. package/dist/esm/cross-project-generation/render.mjs +15 -0
  80. package/dist/esm/cross-project-policy/evaluation.mjs +34 -0
  81. package/dist/esm/cross-project-policy/index.mjs +1 -0
  82. package/dist/esm/cross-project-policy/node.mjs +28 -0
  83. package/dist/esm/effect-adapter/cross-project-policy.mjs +26 -0
  84. package/dist/esm/effect-adapter/entry.mjs +50 -0
  85. package/dist/esm/effect-adapter/error-response.mjs +37 -0
  86. package/dist/esm/effect-adapter/index.mjs +139 -0
  87. package/dist/esm/effect-source-loader/index.mjs +3 -0
  88. package/dist/esm/effect-source-loader/loader.mjs +285 -0
  89. package/dist/esm/effect-source-loader/worker-runtime-wrapper.mjs +56 -0
  90. package/dist/esm/hono/bind-route-handlers.mjs +38 -0
  91. package/dist/esm/hono/cross-project-policy.mjs +10 -0
  92. package/dist/esm/hono/index.mjs +1 -0
  93. package/dist/esm-node/backend-federation/edge-runtime.mjs +187 -0
  94. package/dist/esm-node/backend-federation/edge.mjs +22 -0
  95. package/dist/esm-node/backend-federation/entry.mjs +57 -0
  96. package/dist/esm-node/backend-federation/identity.mjs +42 -0
  97. package/dist/esm-node/backend-federation/index.mjs +5 -0
  98. package/dist/esm-node/backend-federation/legacy-warning.mjs +3 -0
  99. package/dist/esm-node/backend-federation/load.mjs +35 -0
  100. package/dist/esm-node/backend-federation/node.mjs +13 -0
  101. package/dist/esm-node/backend-federation/plugin.mjs +26 -0
  102. package/dist/esm-node/backend-federation/remotes.mjs +14 -0
  103. package/dist/esm-node/backend-federation/runtime.mjs +91 -0
  104. package/dist/esm-node/backend-federation/types.mjs +1 -0
  105. package/dist/esm-node/backend-federation/utils.mjs +8 -0
  106. package/dist/esm-node/backend-federation/validate-loaded.mjs +19 -0
  107. package/dist/esm-node/backend-federation-manifest/errors.mjs +33 -0
  108. package/dist/esm-node/backend-federation-manifest/index.mjs +4 -0
  109. package/dist/esm-node/backend-federation-manifest/load.mjs +136 -0
  110. package/dist/esm-node/backend-federation-manifest/metadata.mjs +43 -0
  111. package/dist/esm-node/backend-federation-manifest/node.mjs +13 -0
  112. package/dist/esm-node/backend-federation-manifest/reference.mjs +89 -0
  113. package/dist/esm-node/backend-federation-manifest/remote.mjs +44 -0
  114. package/dist/esm-node/backend-federation-manifest/types.mjs +1 -0
  115. package/dist/esm-node/backend-federation-manifest/validation.mjs +67 -0
  116. package/dist/esm-node/client-generator/built-entry.mjs +41 -0
  117. package/dist/esm-node/client-generator/generator.mjs +33 -0
  118. package/dist/esm-node/client-generator/index.mjs +4 -0
  119. package/dist/esm-node/client-generator/paths.mjs +25 -0
  120. package/dist/esm-node/client-generator/rendering.mjs +210 -0
  121. package/dist/esm-node/client-generator/runtime.mjs +29 -0
  122. package/dist/esm-node/client-generator/types.mjs +1 -0
  123. package/dist/esm-node/cross-project-generation/index.mjs +2 -0
  124. package/dist/esm-node/cross-project-generation/render.mjs +16 -0
  125. package/dist/esm-node/cross-project-policy/evaluation.mjs +35 -0
  126. package/dist/esm-node/cross-project-policy/index.mjs +2 -0
  127. package/dist/esm-node/cross-project-policy/node.mjs +29 -0
  128. package/dist/esm-node/effect-adapter/cross-project-policy.mjs +27 -0
  129. package/dist/esm-node/effect-adapter/entry.mjs +51 -0
  130. package/dist/esm-node/effect-adapter/error-response.mjs +38 -0
  131. package/dist/esm-node/effect-adapter/index.mjs +140 -0
  132. package/dist/esm-node/effect-source-loader/index.mjs +4 -0
  133. package/dist/esm-node/effect-source-loader/loader.mjs +286 -0
  134. package/dist/esm-node/effect-source-loader/worker-runtime-wrapper.mjs +57 -0
  135. package/dist/esm-node/hono/bind-route-handlers.mjs +39 -0
  136. package/dist/esm-node/hono/cross-project-policy.mjs +11 -0
  137. package/dist/esm-node/hono/index.mjs +2 -0
  138. package/dist/types/backend-federation/edge-runtime.d.ts +46 -0
  139. package/dist/types/backend-federation/edge.d.ts +28 -0
  140. package/dist/types/backend-federation/entry.d.ts +2 -0
  141. package/dist/types/backend-federation/identity.d.ts +30 -0
  142. package/dist/types/backend-federation/index.d.ts +6 -0
  143. package/dist/types/backend-federation/legacy-warning.d.ts +1 -0
  144. package/dist/types/backend-federation/load.d.ts +13 -0
  145. package/dist/types/backend-federation/node.d.ts +4 -0
  146. package/dist/types/backend-federation/plugin.d.ts +3 -0
  147. package/dist/types/backend-federation/remotes.d.ts +2 -0
  148. package/dist/types/backend-federation/runtime.d.ts +3 -0
  149. package/dist/types/backend-federation/types.d.ts +76 -0
  150. package/dist/types/backend-federation/utils.d.ts +2 -0
  151. package/dist/types/backend-federation/validate-loaded.d.ts +8 -0
  152. package/dist/types/backend-federation-manifest/errors.d.ts +11 -0
  153. package/dist/types/backend-federation-manifest/index.d.ts +5 -0
  154. package/dist/types/backend-federation-manifest/load.d.ts +3 -0
  155. package/dist/types/backend-federation-manifest/metadata.d.ts +18 -0
  156. package/dist/types/backend-federation-manifest/node.d.ts +3 -0
  157. package/dist/types/backend-federation-manifest/reference.d.ts +4 -0
  158. package/dist/types/backend-federation-manifest/remote.d.ts +3 -0
  159. package/dist/types/backend-federation-manifest/types.d.ts +49 -0
  160. package/dist/types/backend-federation-manifest/validation.d.ts +5 -0
  161. package/dist/types/client-generator/built-entry.d.ts +16 -0
  162. package/dist/types/client-generator/generator.d.ts +3 -0
  163. package/dist/types/client-generator/index.d.ts +4 -0
  164. package/dist/types/client-generator/paths.d.ts +5 -0
  165. package/dist/types/client-generator/rendering.d.ts +24 -0
  166. package/dist/types/client-generator/runtime.d.ts +12 -0
  167. package/dist/types/client-generator/types.d.ts +33 -0
  168. package/dist/types/cross-project-generation/index.d.ts +1 -0
  169. package/dist/types/cross-project-generation/render.d.ts +1 -0
  170. package/dist/types/cross-project-policy/evaluation.d.ts +4 -0
  171. package/dist/types/cross-project-policy/index.d.ts +1 -0
  172. package/dist/types/cross-project-policy/node.d.ts +4 -0
  173. package/dist/types/effect-adapter/cross-project-policy.d.ts +4 -0
  174. package/dist/types/effect-adapter/entry.d.ts +2 -0
  175. package/dist/types/effect-adapter/error-response.d.ts +2 -0
  176. package/dist/types/effect-adapter/index.d.ts +19 -0
  177. package/dist/types/effect-source-loader/index.d.ts +3 -0
  178. package/dist/types/effect-source-loader/loader.d.ts +17 -0
  179. package/dist/types/effect-source-loader/worker-runtime-wrapper.d.ts +25 -0
  180. package/dist/types/hono/bind-route-handlers.d.ts +10 -0
  181. package/dist/types/hono/cross-project-policy.d.ts +3 -0
  182. package/dist/types/hono/index.d.ts +1 -0
  183. package/package.json +213 -0
  184. package/src/backend-federation/edge-runtime.ts +258 -0
  185. package/src/backend-federation/edge.ts +128 -0
  186. package/src/backend-federation/entry.ts +125 -0
  187. package/src/backend-federation/identity.ts +97 -0
  188. package/src/backend-federation/index.ts +30 -0
  189. package/src/backend-federation/legacy-warning.ts +2 -0
  190. package/src/backend-federation/load.ts +102 -0
  191. package/src/backend-federation/node.ts +33 -0
  192. package/src/backend-federation/plugin.ts +35 -0
  193. package/src/backend-federation/remotes.ts +17 -0
  194. package/src/backend-federation/runtime.ts +99 -0
  195. package/src/backend-federation/types.ts +103 -0
  196. package/src/backend-federation/utils.ts +7 -0
  197. package/src/backend-federation/validate-loaded.ts +72 -0
  198. package/src/backend-federation-manifest/errors.ts +85 -0
  199. package/src/backend-federation-manifest/index.ts +11 -0
  200. package/src/backend-federation-manifest/load.ts +266 -0
  201. package/src/backend-federation-manifest/metadata.ts +73 -0
  202. package/src/backend-federation-manifest/node.ts +19 -0
  203. package/src/backend-federation-manifest/reference.ts +240 -0
  204. package/src/backend-federation-manifest/remote.ts +102 -0
  205. package/src/backend-federation-manifest/types.ts +73 -0
  206. package/src/backend-federation-manifest/validation.ts +255 -0
  207. package/src/client-generator/built-entry.ts +70 -0
  208. package/src/client-generator/generator.ts +52 -0
  209. package/src/client-generator/index.ts +10 -0
  210. package/src/client-generator/paths.ts +40 -0
  211. package/src/client-generator/rendering.ts +307 -0
  212. package/src/client-generator/runtime.ts +69 -0
  213. package/src/client-generator/types.ts +35 -0
  214. package/src/cross-project-generation/index.ts +1 -0
  215. package/src/cross-project-generation/render.ts +14 -0
  216. package/src/cross-project-policy/evaluation.ts +70 -0
  217. package/src/cross-project-policy/index.ts +1 -0
  218. package/src/cross-project-policy/node.ts +63 -0
  219. package/src/effect-adapter/cross-project-policy.ts +63 -0
  220. package/src/effect-adapter/entry.ts +95 -0
  221. package/src/effect-adapter/error-response.ts +68 -0
  222. package/src/effect-adapter/index.ts +246 -0
  223. package/src/effect-source-loader/index.ts +6 -0
  224. package/src/effect-source-loader/loader.ts +397 -0
  225. package/src/effect-source-loader/worker-runtime-wrapper.ts +90 -0
  226. package/src/hono/bind-route-handlers.ts +62 -0
  227. package/src/hono/cross-project-policy.ts +26 -0
  228. package/src/hono/index.ts +4 -0
@@ -0,0 +1,7 @@
1
+ function normalizeExpose(expose) {
2
+ return expose.replace(/^\.\//u, '');
3
+ }
4
+ function isRecord(value) {
5
+ return 'object' == typeof value && null !== value;
6
+ }
7
+ export { isRecord, normalizeExpose };
@@ -0,0 +1,18 @@
1
+ import { formatBackendFederationIdentityIssues, validateExpectedBackendFederationIdentity } from "./identity.mjs";
2
+ import { isRecord } from "./utils.mjs";
3
+ function validateLoadedBackendFederatedEffectApi(loaded, options) {
4
+ if (!isRecord(loaded)) throw new Error(`[BFF][Effect] Backend federation expose ${options.remoteRequest} must load an object module.`);
5
+ const backendContract = loaded.backendFederationContract;
6
+ if (!isRecord(backendContract) || true !== backendContract.strictEffectApproach) throw new Error(`[BFF][Effect] Backend federation expose ${options.remoteRequest} must expose strict Effect metadata (strictEffectApproach: true).`);
7
+ if ('effect' !== backendContract.runtimeFramework) throw new Error(`[BFF][Effect] Backend federation expose ${options.remoteRequest} must expose strict Effect metadata (runtimeFramework: "effect").`);
8
+ if ('string' == typeof backendContract.name && backendContract.name !== options.remoteName) throw new Error(`[BFF][Effect] Backend federation expose ${options.remoteRequest} metadata name mismatch: expected ${options.remoteName}, received ${backendContract.name}.`);
9
+ if (!('runtime' in loaded)) throw new Error(`[BFF][Effect] Backend federation expose ${options.remoteRequest} must expose runtime.`);
10
+ if (void 0 !== options.expected) {
11
+ const issues = validateExpectedBackendFederationIdentity(loaded, options.expected, {
12
+ allowMissingIdentityMetadata: true === options.allowMissingIdentityMetadata
13
+ });
14
+ if (issues.length > 0) throw new Error(`[BFF][Effect] Backend federation expose ${options.remoteRequest} delivery-unit identity mismatch: ${formatBackendFederationIdentityIssues(issues)}.`);
15
+ }
16
+ return loaded;
17
+ }
18
+ export { validateLoadedBackendFederatedEffectApi };
@@ -0,0 +1,32 @@
1
+ const BACKEND_FEDERATION_MANIFEST_ADAPTER_FAILURE_EVENT = 'modernjs:microvertical-server-fallback';
2
+ class BackendFederationManifestAdapterError extends Error {
3
+ constructor(code, message, cause, details){
4
+ super(message), this.failureEvent = BACKEND_FEDERATION_MANIFEST_ADAPTER_FAILURE_EVENT;
5
+ this.name = 'BackendFederationManifestAdapterError';
6
+ this.code = code;
7
+ if (details) this.details = details;
8
+ if (void 0 !== cause) this.cause = cause;
9
+ }
10
+ }
11
+ function assertManifestAdapter(condition, code, message) {
12
+ if (!condition) throw new BackendFederationManifestAdapterError(code, message);
13
+ }
14
+ function assertVersionValue(actual, expected, label, details) {
15
+ if (void 0 === expected) return;
16
+ if (actual !== expected) throw new BackendFederationManifestAdapterError('version_mismatch', `[BFF][Effect] Backend federation ${label} mismatch: expected ${expected}, received ${actual ?? 'undefined'}.`, void 0, {
17
+ label,
18
+ expected,
19
+ received: actual,
20
+ ...details
21
+ });
22
+ }
23
+ function assertConsistentValue(left, right, label, details) {
24
+ if (void 0 === left || void 0 === right || left === right) return;
25
+ throw new BackendFederationManifestAdapterError('version_mismatch', `[BFF][Effect] Backend federation ${label} mismatch: expected ${left}, received ${right}.`, void 0, {
26
+ label,
27
+ expected: left,
28
+ received: right,
29
+ ...details
30
+ });
31
+ }
32
+ export { BACKEND_FEDERATION_MANIFEST_ADAPTER_FAILURE_EVENT, BackendFederationManifestAdapterError, assertConsistentValue, assertManifestAdapter, assertVersionValue };
@@ -0,0 +1,3 @@
1
+ export { BackendFederationManifestAdapterError } from "./errors.mjs";
2
+ export { loadBackendFederationManifest } from "./reference.mjs";
3
+ export { resolveBackendFederationRemoteFromManifest } from "./remote.mjs";
@@ -0,0 +1,135 @@
1
+ import { BACKEND_FEDERATION_EFFECT_EXPOSE } from "../backend-federation/index.mjs";
2
+ import { loadBackendFederatedEffectApi } from "../backend-federation/load.mjs";
3
+ import { BackendFederationManifestAdapterError } from "./errors.mjs";
4
+ import { loadBackendFederationManifest } from "./reference.mjs";
5
+ import { resolveBackendFederationRemoteFromManifest } from "./remote.mjs";
6
+ import { classifyLoadError, validateBackendFederationManifest, validateLoadedBackendFederationContract } from "./validation.mjs";
7
+ function createManifestLoadScope(options) {
8
+ const controller = new AbortController();
9
+ const policyTimeouts = [
10
+ options.manifestPolicy?.timeoutMs,
11
+ options.entryPolicy?.timeoutMs
12
+ ].filter((timeout)=>void 0 !== timeout);
13
+ const configuredTimeouts = [
14
+ options.timeoutMs,
15
+ ...policyTimeouts
16
+ ].filter((timeout)=>void 0 !== timeout);
17
+ for (const timeout of configuredTimeouts)if (!Number.isSafeInteger(timeout) || timeout < 0) throw new BackendFederationManifestAdapterError('manifest_invalid', '[BFF][Effect] Backend federation timeoutMs must be a non-negative safe integer.');
18
+ const timeoutMs = options.timeoutMs ?? (policyTimeouts.length > 0 ? Math.min(...policyTimeouts) : 0);
19
+ const inputSignals = [
20
+ options.signal,
21
+ options.manifestPolicy?.signal,
22
+ options.entryPolicy?.signal
23
+ ].filter((signal)=>void 0 !== signal);
24
+ const abortListeners = [];
25
+ let timedOut = false;
26
+ const forwardAbort = (signal)=>{
27
+ controller.abort(signal.reason);
28
+ };
29
+ for (const signal of inputSignals){
30
+ if (signal.aborted) {
31
+ forwardAbort(signal);
32
+ break;
33
+ }
34
+ const listener = ()=>forwardAbort(signal);
35
+ abortListeners.push([
36
+ signal,
37
+ listener
38
+ ]);
39
+ signal.addEventListener('abort', listener, {
40
+ once: true
41
+ });
42
+ }
43
+ const timeout = timeoutMs > 0 ? setTimeout(()=>{
44
+ if (controller.signal.aborted) return;
45
+ timedOut = true;
46
+ controller.abort(new BackendFederationManifestAdapterError('timeout', `[BFF][Effect] Backend federation load timed out after ${timeoutMs}ms.`));
47
+ }, timeoutMs) : void 0;
48
+ return {
49
+ cleanup () {
50
+ if (timeout) clearTimeout(timeout);
51
+ for (const [signal, listener] of abortListeners)signal.removeEventListener('abort', listener);
52
+ },
53
+ signal: controller.signal,
54
+ timedOut: ()=>timedOut,
55
+ timeoutMs
56
+ };
57
+ }
58
+ function isRemoteManifestReference(options) {
59
+ if (void 0 !== options.manifest || options.manifestPath) return false;
60
+ return Boolean(options.manifestUrl || options.manifestEnv);
61
+ }
62
+ function hasPinnedRemoteEntryExpectation(options) {
63
+ const expected = options.entryPolicy?.expected;
64
+ return 'number' == typeof expected?.byteLength && 'string' == typeof expected.entryUrl && 'string' == typeof expected.remoteName && 'string' == typeof expected.sha256;
65
+ }
66
+ function isCallerPinnedStaticRemote(options, remote) {
67
+ return options.remote?.entry === remote.entry && options.remote?.name === remote.name && /^(?:binding|service|static):/u.test(remote.entry);
68
+ }
69
+ function throwIfManifestLoadAborted(signal) {
70
+ if (signal.aborted) throw new BackendFederationManifestAdapterError('remote_unavailable', '[BFF][Effect] Backend federation load was aborted before remote execution.', signal.reason);
71
+ }
72
+ async function loadBackendFederatedEffectApiFromManifest(options) {
73
+ let manifest;
74
+ let remote;
75
+ let scope;
76
+ try {
77
+ scope = createManifestLoadScope(options);
78
+ throwIfManifestLoadAborted(scope.signal);
79
+ manifest = await loadBackendFederationManifest({
80
+ ...options,
81
+ manifestPolicy: {
82
+ ...options.manifestPolicy,
83
+ signal: scope.signal,
84
+ timeoutMs: 0
85
+ },
86
+ signal: scope.signal,
87
+ timeoutMs: 0
88
+ });
89
+ validateBackendFederationManifest(manifest, options.expected);
90
+ remote = resolveBackendFederationRemoteFromManifest(manifest, options.remote);
91
+ throwIfManifestLoadAborted(scope.signal);
92
+ const remoteManifest = isRemoteManifestReference(options);
93
+ if (remoteManifest && void 0 !== options.runtime) throw new BackendFederationManifestAdapterError('manifest_invalid', `[BFF][Effect] Backend federation remote ${remote.name} cannot use a custom runtime selected by a network manifest.`);
94
+ if (remoteManifest && !/^https?:\/\//iu.test(remote.entry) && !isCallerPinnedStaticRemote(options, remote)) throw new BackendFederationManifestAdapterError('manifest_invalid', `[BFF][Effect] Backend federation network manifests cannot select local, global, or plugin entry ${remote.entry}. Pin a static/service binding in caller configuration or use a verified HTTP(S) entry.`);
95
+ if (remoteManifest && /^https?:\/\//iu.test(remote.entry) && !hasPinnedRemoteEntryExpectation(options)) throw new BackendFederationManifestAdapterError('manifest_invalid', `[BFF][Effect] Backend federation remote ${remote.name} from a network manifest requires caller-pinned entryUrl, remoteName, sha256, and byteLength values.`);
96
+ if (/^https?:\/\//iu.test(remote.entry) && void 0 === remote.verification && options.entryPolicy?.expected === void 0) throw new BackendFederationManifestAdapterError('manifest_invalid', `[BFF][Effect] Backend federation remote ${remote.name} requires entry.sha256 and entry.byteLength before network execution.`);
97
+ if (/^https?:\/\//iu.test(remote.entry) && void 0 !== options.runtime) throw new BackendFederationManifestAdapterError('manifest_invalid', `[BFF][Effect] Backend federation remote ${remote.name} cannot use a custom runtime for network entry execution.`);
98
+ const loaded = await loadBackendFederatedEffectApi({
99
+ hostName: options.hostName,
100
+ remote,
101
+ ...options.plugins ? {
102
+ plugins: options.plugins
103
+ } : {},
104
+ entryPolicy: {
105
+ ...options.entryPolicy,
106
+ signal: scope.signal,
107
+ timeoutMs: 0
108
+ },
109
+ ...options.runtime ? {
110
+ runtime: options.runtime
111
+ } : {},
112
+ ...options.expected?.unitId && options.expected.buildMarker ? {
113
+ expected: {
114
+ unitId: options.expected.unitId,
115
+ buildMarker: options.expected.buildMarker
116
+ },
117
+ allowMissingIdentityMetadata: true
118
+ } : {}
119
+ }).catch((error)=>{
120
+ throw new BackendFederationManifestAdapterError(scope?.timedOut() === true ? 'timeout' : classifyLoadError(error), `[BFF][Effect] Backend federation remote ${remote?.name ?? 'unknown'} could not load ${remote?.expose ?? BACKEND_FEDERATION_EFFECT_EXPOSE}.`, error);
121
+ });
122
+ validateLoadedBackendFederationContract(loaded, manifest, remote);
123
+ return loaded;
124
+ } catch (error) {
125
+ const adapterError = scope?.timedOut() === true ? new BackendFederationManifestAdapterError('timeout', `[BFF][Effect] Backend federation load timed out after ${scope.timeoutMs}ms.`, error) : error instanceof BackendFederationManifestAdapterError ? error : new BackendFederationManifestAdapterError('remote_unavailable', '[BFF][Effect] Backend federation manifest adapter failed.', error);
126
+ if (options.fallback) return options.fallback(adapterError, {
127
+ manifest,
128
+ remote
129
+ });
130
+ throw adapterError;
131
+ } finally{
132
+ scope?.cleanup();
133
+ }
134
+ }
135
+ export { loadBackendFederatedEffectApiFromManifest };
@@ -0,0 +1,42 @@
1
+ import { backendFederationMetadata, backendFederationVersionBoundary } from "@modern-js/utils/universal";
2
+ function stringValue(value) {
3
+ return 'string' == typeof value && value.length > 0 ? value : void 0;
4
+ }
5
+ function isRecord(value) {
6
+ return 'object' == typeof value && null !== value;
7
+ }
8
+ function recordField(value, field) {
9
+ const fieldValue = value?.[field];
10
+ return isRecord(fieldValue) ? fieldValue : void 0;
11
+ }
12
+ function resolveRemoteEntryFromMetadata(manifest) {
13
+ const metaData = recordField(manifest, 'metaData');
14
+ const remoteEntry = recordField(metaData, 'remoteEntry');
15
+ const publicPath = stringValue(metaData?.publicPath) ?? stringValue(metaData?.ssrPublicPath);
16
+ const entryName = stringValue(remoteEntry?.name);
17
+ if (!publicPath || !entryName) return;
18
+ const entryPath = stringValue(remoteEntry?.path) ?? '';
19
+ const normalizedBase = publicPath.replace(/\/+$/u, '');
20
+ const normalizedPath = entryPath.replace(/^\/+|\/+$/gu, '');
21
+ return [
22
+ normalizedBase,
23
+ normalizedPath,
24
+ entryName
25
+ ].filter(Boolean).join('/');
26
+ }
27
+ function metadata_backendFederationMetadata(manifest) {
28
+ return backendFederationMetadata(manifest);
29
+ }
30
+ function versionBoundaryMetadata(manifest) {
31
+ return backendFederationVersionBoundary(manifest);
32
+ }
33
+ function deliveryUnitMetadata(record) {
34
+ return recordField(record, 'deliveryUnit');
35
+ }
36
+ function manifestDeliveryUnit(backendFederation, boundary) {
37
+ return {
38
+ boundary: deliveryUnitMetadata(boundary),
39
+ top: deliveryUnitMetadata(backendFederation)
40
+ };
41
+ }
42
+ export { deliveryUnitMetadata, isRecord, manifestDeliveryUnit, metadata_backendFederationMetadata as backendFederationMetadata, recordField, resolveRemoteEntryFromMetadata, stringValue, versionBoundaryMetadata };
@@ -0,0 +1,12 @@
1
+ import { evaluateNodeBackendFederationCommonJs } from "@modern-js/server-runtime-extensions/backend-federation-security/node";
2
+ import { loadBackendFederatedEffectApiFromManifest } from "./load.mjs";
3
+ function node_loadBackendFederatedEffectApiFromManifest(options) {
4
+ return loadBackendFederatedEffectApiFromManifest({
5
+ ...options,
6
+ entryPolicy: {
7
+ ...options.entryPolicy,
8
+ evaluateCommonJs: options.entryPolicy?.evaluateCommonJs ?? evaluateNodeBackendFederationCommonJs
9
+ }
10
+ });
11
+ }
12
+ export { node_loadBackendFederatedEffectApiFromManifest as loadBackendFederatedEffectApiFromManifest };
@@ -0,0 +1,88 @@
1
+ import { BackendFederationRemoteEntryError, loadBoundedBackendFederationResource, redactBackendFederationUrl } from "@modern-js/server-runtime-extensions/backend-federation-security";
2
+ import { BACKEND_FEDERATION_MANIFEST_FILE } from "../backend-federation/index.mjs";
3
+ import { BackendFederationManifestAdapterError, assertManifestAdapter } from "./errors.mjs";
4
+ import { isRecord } from "./metadata.mjs";
5
+ function getProcessEnv() {
6
+ return "u" > typeof process ? process.env : void 0;
7
+ }
8
+ function resolveManifestReferenceSource(options) {
9
+ if (options.manifestPath) return 'path';
10
+ if (options.manifestUrl) return 'url';
11
+ if (options.manifestEnv) return 'env';
12
+ }
13
+ function resolveBackendFederationManifestReference(options) {
14
+ if (options.manifestPath) return options.manifestPath;
15
+ if (options.manifestUrl) return options.manifestUrl;
16
+ if (!options.manifestEnv) return;
17
+ return options.env?.[options.manifestEnv] ?? getProcessEnv()?.[options.manifestEnv];
18
+ }
19
+ function assertExpectedIdentityForReference(options, source) {
20
+ if (void 0 === source || 'path' === source) return;
21
+ if (options.expected?.unitId && options.expected.buildMarker) return;
22
+ throw new BackendFederationManifestAdapterError('version_mismatch', `[BFF][Effect] Backend federation ${source} manifest references require expected.unitId and expected.buildMarker.`, void 0, {
23
+ label: 'expected.deliveryUnit',
24
+ expected: 'unitId + buildMarker',
25
+ received: options.expected,
26
+ referenceSource: source
27
+ });
28
+ }
29
+ function isHttpUrl(value) {
30
+ return /^https?:\/\//iu.test(value);
31
+ }
32
+ function referenceForDiagnostics(reference) {
33
+ return isHttpUrl(reference) ? redactBackendFederationUrl(reference) : '[local manifest]';
34
+ }
35
+ async function readFileReference(reference) {
36
+ const [{ fileURLToPath }, fs] = await Promise.all([
37
+ import("node:url"),
38
+ import("node:fs/promises")
39
+ ]);
40
+ const filePath = reference.startsWith('file:') ? fileURLToPath(reference) : reference;
41
+ return fs.readFile(filePath, 'utf8');
42
+ }
43
+ async function withTimeout(promise, timeoutMs, label) {
44
+ if (!timeoutMs || timeoutMs <= 0) return promise;
45
+ let timeout;
46
+ try {
47
+ return await Promise.race([
48
+ promise,
49
+ new Promise((_, reject)=>{
50
+ timeout = setTimeout(()=>{
51
+ reject(new BackendFederationManifestAdapterError('timeout', `[BFF][Effect] ${label} timed out after ${timeoutMs}ms.`));
52
+ }, timeoutMs);
53
+ })
54
+ ]);
55
+ } finally{
56
+ if (timeout) clearTimeout(timeout);
57
+ }
58
+ }
59
+ async function loadBackendFederationManifest(options) {
60
+ if (options.manifest) return options.manifest;
61
+ const reference = resolveBackendFederationManifestReference(options);
62
+ if (!reference) throw new BackendFederationManifestAdapterError('manifest_unavailable', `[BFF][Effect] Backend federation manifest reference is missing. Pass manifest, manifestPath, manifestUrl, or manifestEnv for ${BACKEND_FEDERATION_MANIFEST_FILE}.`);
63
+ assertExpectedIdentityForReference(options, resolveManifestReferenceSource(options));
64
+ const referenceSource = resolveManifestReferenceSource(options);
65
+ if ('path' === referenceSource && isHttpUrl(reference)) throw new BackendFederationManifestAdapterError('manifest_unavailable', '[BFF][Effect] Backend federation manifestPath must identify an explicit local file. Use manifestUrl for HTTP(S) manifests.');
66
+ if (('url' === referenceSource || 'env' === referenceSource) && !isHttpUrl(reference)) throw new BackendFederationManifestAdapterError('manifest_unavailable', `[BFF][Effect] Backend federation ${referenceSource} manifest references must use HTTP(S). Use manifestPath for an explicit local file.`);
67
+ try {
68
+ const diagnosticReference = referenceForDiagnostics(reference);
69
+ const source = isHttpUrl(reference) ? new TextDecoder('utf-8', {
70
+ fatal: true
71
+ }).decode(await loadBoundedBackendFederationResource(reference, {
72
+ allowInsecureHttp: options.manifestPolicy?.allowInsecureHttp === true,
73
+ fetch: options.fetch,
74
+ kind: 'manifest',
75
+ maxBytes: options.manifestPolicy?.maxBytes,
76
+ signal: options.manifestPolicy?.signal ?? options.signal,
77
+ timeoutMs: options.manifestPolicy?.timeoutMs ?? options.timeoutMs
78
+ })) : await withTimeout(readFileReference(reference), options.manifestPolicy?.timeoutMs ?? options.timeoutMs, 'Backend federation local manifest');
79
+ const manifest = JSON.parse(source);
80
+ assertManifestAdapter(isRecord(manifest), 'manifest_invalid', `[BFF][Effect] Backend federation manifest ${diagnosticReference} must be a JSON object.`);
81
+ return manifest;
82
+ } catch (error) {
83
+ if (error instanceof BackendFederationManifestAdapterError) throw error;
84
+ if (error instanceof BackendFederationRemoteEntryError) throw new BackendFederationManifestAdapterError('timeout' === error.code ? 'timeout' : 'manifest_unavailable', `[BFF][Effect] ${error.message}`, error, error.details);
85
+ throw new BackendFederationManifestAdapterError('manifest_unavailable', `[BFF][Effect] Backend federation manifest ${referenceForDiagnostics(reference)} could not be loaded.`, error);
86
+ }
87
+ }
88
+ export { loadBackendFederationManifest, resolveBackendFederationManifestReference, withTimeout };
@@ -0,0 +1,43 @@
1
+ import { BackendFederationRemoteEntryError, resolveBackendFederationRemoteEntryVerification } from "@modern-js/server-runtime-extensions/backend-federation-security";
2
+ import { backendFederationExposeNames } from "@modern-js/utils/universal";
3
+ import { BACKEND_FEDERATION_EFFECT_EXPOSE } from "../backend-federation/index.mjs";
4
+ import { BackendFederationManifestAdapterError, assertManifestAdapter } from "./errors.mjs";
5
+ import { backendFederationMetadata, recordField, resolveRemoteEntryFromMetadata, stringValue } from "./metadata.mjs";
6
+ function resolveBackendFederationRemoteFromManifest(manifest, remoteOverride = {}) {
7
+ const backendFederation = backendFederationMetadata(manifest);
8
+ const entry = recordField(manifest, 'entry');
9
+ const metaData = recordField(manifest, 'metaData');
10
+ const remoteEntry = recordField(metaData, 'remoteEntry');
11
+ const remoteName = remoteOverride.name ?? stringValue(backendFederation?.name) ?? stringValue(manifest.name) ?? stringValue(manifest.id);
12
+ const manifestEntryUrl = stringValue(backendFederation?.containerEntry) ?? stringValue(entry?.url) ?? resolveRemoteEntryFromMetadata(manifest);
13
+ const remoteEntryUrl = remoteOverride.entry ?? manifestEntryUrl;
14
+ const remoteType = remoteOverride.type ?? stringValue(backendFederation?.remoteType) ?? stringValue(entry?.type) ?? stringValue(remoteEntry?.type) ?? 'module';
15
+ const expose = remoteOverride.expose ?? backendFederationExposeNames(backendFederation)[0] ?? BACKEND_FEDERATION_EFFECT_EXPOSE;
16
+ let verification;
17
+ try {
18
+ const manifestVerification = resolveBackendFederationRemoteEntryVerification(manifest);
19
+ verification = remoteOverride.verification ?? (remoteEntryUrl === manifestEntryUrl ? manifestVerification : void 0);
20
+ } catch (cause) {
21
+ if (cause instanceof BackendFederationRemoteEntryError) throw new BackendFederationManifestAdapterError('identity_mismatch' === cause.code ? 'version_mismatch' : 'manifest_invalid', `[BFF][Effect] ${cause.message}`, cause, cause.details);
22
+ throw cause;
23
+ }
24
+ assertManifestAdapter(remoteName, 'manifest_invalid', '[BFF][Effect] Backend federation manifest must declare a remote name.');
25
+ assertManifestAdapter(remoteEntryUrl, 'manifest_invalid', '[BFF][Effect] Backend federation manifest must declare a backend remote entry URL.');
26
+ assertManifestAdapter(expose === BACKEND_FEDERATION_EFFECT_EXPOSE, 'manifest_invalid', `[BFF][Effect] Backend federation manifest expose must be ${BACKEND_FEDERATION_EFFECT_EXPOSE}.`);
27
+ return {
28
+ name: remoteName,
29
+ entry: remoteEntryUrl,
30
+ type: remoteType,
31
+ ...verification ? {
32
+ verification
33
+ } : {},
34
+ ...remoteOverride.entryGlobalName ? {
35
+ entryGlobalName: remoteOverride.entryGlobalName
36
+ } : {},
37
+ expose,
38
+ ...remoteOverride.shareScope ? {
39
+ shareScope: remoteOverride.shareScope
40
+ } : {}
41
+ };
42
+ }
43
+ export { resolveBackendFederationRemoteFromManifest };
File without changes
@@ -0,0 +1,66 @@
1
+ import { formatBackendFederationValidationErrors, validateBackendFederationManifest } from "@modern-js/utils/universal";
2
+ import { BACKEND_FEDERATION_CONTRACT_VERSION, BACKEND_FEDERATION_NODE_ADAPTER_VERSION } from "../backend-federation/index.mjs";
3
+ import { BackendFederationManifestAdapterError, assertConsistentValue, assertManifestAdapter, assertVersionValue } from "./errors.mjs";
4
+ import { backendFederationMetadata, manifestDeliveryUnit, recordField, stringValue, versionBoundaryMetadata } from "./metadata.mjs";
5
+ function resolveExpectedBuildMarker(expected) {
6
+ if (void 0 !== expected.buildVersion && void 0 !== expected.buildMarker && expected.buildVersion !== expected.buildMarker) throw new BackendFederationManifestAdapterError('version_mismatch', `[BFF][Effect] Backend federation expected buildVersion/buildMarker mismatch: buildVersion ${expected.buildVersion}, buildMarker ${expected.buildMarker}.`, void 0, {
7
+ label: 'expected.buildVersion/buildMarker',
8
+ expected: expected.buildVersion,
9
+ received: expected.buildMarker
10
+ });
11
+ return expected.buildMarker;
12
+ }
13
+ function validation_validateBackendFederationManifest(manifest, expected = {}) {
14
+ const expectedBuildMarker = resolveExpectedBuildMarker(expected);
15
+ const backendFederation = backendFederationMetadata(manifest);
16
+ assertManifestAdapter(backendFederation, 'manifest_invalid', '[BFF][Effect] Backend federation manifest must declare backendFederation metadata.');
17
+ const manifestShape = validateBackendFederationManifest(manifest, {
18
+ expectedContractVersion: false,
19
+ expectedNodeAdapterVersion: false,
20
+ validateDeliveryUnit: false
21
+ });
22
+ assertManifestAdapter(manifestShape.ok, 'manifest_invalid', `[BFF][Effect] Backend federation manifest schema invalid: ${formatBackendFederationValidationErrors(manifestShape.errors)}.`);
23
+ assertManifestAdapter('effect' === backendFederation.runtimeFramework, 'strict_effect_required', '[BFF][Effect] Backend federation manifest must declare runtimeFramework: "effect".');
24
+ assertManifestAdapter(true === backendFederation.strictEffectApproach, 'strict_effect_required', '[BFF][Effect] Backend federation manifest must declare strictEffectApproach: true.');
25
+ assertVersionValue(stringValue(backendFederation.contractVersion), expected.contractVersion ?? BACKEND_FEDERATION_CONTRACT_VERSION, 'manifest contractVersion');
26
+ assertVersionValue(stringValue(backendFederation.nodeAdapterVersion), expected.nodeAdapterVersion ?? BACKEND_FEDERATION_NODE_ADAPTER_VERSION, 'manifest nodeAdapterVersion');
27
+ const boundary = versionBoundaryMetadata(manifest);
28
+ assertVersionValue(stringValue(backendFederation.name) ?? stringValue(manifest.name) ?? stringValue(manifest.id), expected.remoteName, 'manifest remoteName');
29
+ assertVersionValue(stringValue(boundary?.packageName), expected.packageName, 'versionBoundary.packageName');
30
+ assertVersionValue(stringValue(boundary?.version), expected.version, 'versionBoundary.version');
31
+ assertVersionValue(stringValue(boundary?.buildVersion), expected.buildVersion, 'versionBoundary.buildVersion');
32
+ assertConsistentValue(stringValue(manifest.version), stringValue(boundary?.version), 'manifest versionBoundary.version');
33
+ assertConsistentValue(stringValue(manifest.buildVersion), stringValue(boundary?.buildVersion), 'manifest versionBoundary.buildVersion');
34
+ const deliveryUnit = manifestDeliveryUnit(backendFederation, boundary);
35
+ assertConsistentValue(stringValue(deliveryUnit.boundary?.buildMarker), stringValue(boundary?.buildVersion), 'versionBoundary.deliveryUnit.buildMarker vs versionBoundary.buildVersion');
36
+ assertConsistentValue(stringValue(deliveryUnit.top?.unitId), stringValue(deliveryUnit.boundary?.unitId), 'backendFederation.deliveryUnit.unitId vs versionBoundary.deliveryUnit.unitId');
37
+ const manifestUnitId = stringValue(deliveryUnit.boundary?.unitId) ?? stringValue(deliveryUnit.top?.unitId);
38
+ assertVersionValue(manifestUnitId, expected.unitId, 'deliveryUnit.unitId');
39
+ assertVersionValue(stringValue(deliveryUnit.boundary?.buildMarker), expectedBuildMarker, 'deliveryUnit.buildMarker');
40
+ }
41
+ function validateLoadedBackendFederationContract(loaded, manifest, remote) {
42
+ const loadedContract = loaded.backendFederationContract;
43
+ const backendFederation = backendFederationMetadata(manifest);
44
+ const boundary = versionBoundaryMetadata(manifest);
45
+ const compatibility = recordField(loadedContract, 'compatibility');
46
+ assertManifestAdapter(compatibility, 'version_mismatch', `[BFF][Effect] Backend federation expose ${remote.name}/${remote.expose?.replace(/^\.\//u, '')} must declare compatibility metadata.`);
47
+ assertVersionValue(stringValue(loadedContract?.role), 'microvertical-server', 'expose role');
48
+ assertVersionValue(stringValue(loadedContract?.name), remote.name, 'expose name');
49
+ assertVersionValue(stringValue(compatibility.contractVersion), stringValue(backendFederation?.contractVersion), 'expose contractVersion');
50
+ assertVersionValue(stringValue(compatibility.nodeAdapterVersion), stringValue(backendFederation?.nodeAdapterVersion), 'expose nodeAdapterVersion');
51
+ assertVersionValue(stringValue(compatibility.packageName), stringValue(boundary?.packageName), 'expose packageName');
52
+ assertVersionValue(stringValue(compatibility.build), stringValue(boundary?.buildVersion), 'expose buildVersion');
53
+ const deliveryUnit = manifestDeliveryUnit(backendFederation, boundary);
54
+ const manifestUnitId = stringValue(deliveryUnit.boundary?.unitId) ?? stringValue(deliveryUnit.top?.unitId);
55
+ const manifestBuildMarker = stringValue(deliveryUnit.boundary?.buildMarker);
56
+ assertConsistentValue(manifestUnitId, stringValue(compatibility.unitId), 'deliveryUnit.unitId vs expose compatibility.unitId');
57
+ assertConsistentValue(manifestBuildMarker, stringValue(compatibility.build), 'deliveryUnit.buildMarker vs expose compatibility.build');
58
+ }
59
+ function classifyLoadError(error) {
60
+ const message = error instanceof Error ? error.message : String(error);
61
+ if ('object' == typeof error && null !== error && 'code' in error && 'timeout' === error.code || /timed out/iu.test(message)) return 'timeout';
62
+ if (message.includes('delivery-unit identity mismatch')) return 'version_mismatch';
63
+ if (message.includes('strictEffectApproach') || message.includes('runtimeFramework')) return 'strict_effect_required';
64
+ return 'remote_unavailable';
65
+ }
66
+ export { classifyLoadError, validateLoadedBackendFederationContract, validation_validateBackendFederationManifest as validateBackendFederationManifest };
@@ -0,0 +1,40 @@
1
+ import { fs, upath } from "@modern-js/utils";
2
+ import { resolveEffectEntryFile } from "./paths.mjs";
3
+ const BUILT_ENTRY_EXT = /\.(?:[cm]?ts|tsx|jsx)$/u;
4
+ function resolveBuiltEffectEntry(appDirectory, distDirectory, sourceEntry) {
5
+ if (void 0 === sourceEntry || 0 === sourceEntry.length) return;
6
+ const relativeEntry = upath.relative(appDirectory, sourceEntry);
7
+ if ('..' === relativeEntry || relativeEntry.startsWith(`..${upath.sep}`)) throw new Error(`Effect BFF entry must be inside the application directory: ${sourceEntry}`);
8
+ const builtEntry = upath.resolve(distDirectory, relativeEntry).replace(BUILT_ENTRY_EXT, '.js');
9
+ return fs.existsSync(builtEntry) ? builtEntry : void 0;
10
+ }
11
+ async function bundleBuiltEffectEntryForNode(options) {
12
+ const { appDir, apiDir, distDir, effectEntry, format } = options;
13
+ const sourceEntry = resolveEffectEntryFile({
14
+ appDir,
15
+ apiDir,
16
+ effectEntry
17
+ });
18
+ const builtEntry = resolveBuiltEffectEntry(appDir, distDir, sourceEntry);
19
+ if (void 0 === builtEntry || 0 === builtEntry.length) throw new Error(`Effect BFF entry was not emitted into ${distDir}: ${sourceEntry ?? upath.resolve(apiDir, 'index')}`);
20
+ const { bundleEffectEntryForNode } = await import("../effect-source-loader/loader.mjs");
21
+ return bundleEffectEntryForNode({
22
+ appDir,
23
+ entryPath: builtEntry,
24
+ format
25
+ });
26
+ }
27
+ function resolveEffectEntryPaths(options) {
28
+ const { appDir, apiDir, effectEntry } = options;
29
+ const sourceEffectEntry = resolveEffectEntryFile({
30
+ appDir,
31
+ apiDir,
32
+ effectEntry
33
+ });
34
+ const relativeEffectEntry = void 0 !== sourceEffectEntry && sourceEffectEntry.length > 0 ? upath.relative(appDir, sourceEffectEntry).replace(BUILT_ENTRY_EXT, '.js') : '';
35
+ return {
36
+ sourceEffectEntry,
37
+ relativeEffectEntry
38
+ };
39
+ }
40
+ export { bundleBuiltEffectEntryForNode, resolveBuiltEffectEntry, resolveEffectEntryPaths };
@@ -0,0 +1,32 @@
1
+ import { collectEffectEndpoints } from "@modern-js/bff-effect/effect";
2
+ import { logger } from "@modern-js/utils";
3
+ import { createEffectClientGeneration, renderEffectClientCode, renderEffectClientDeclaration } from "./rendering.mjs";
4
+ import { getHttpApiRuntime, loadEffectApi } from "./runtime.mjs";
5
+ function generateEffectClient(options) {
6
+ return loadEffectApi({
7
+ appDir: options.appDir,
8
+ resourcePath: options.resourcePath,
9
+ onDependency: options.onDependency
10
+ }).then((api)=>{
11
+ if (null === api) {
12
+ logger.warn(`[BFF][Effect] Failed to generate client for ${options.resourcePath}: unable to resolve exported HttpApi.`);
13
+ return null;
14
+ }
15
+ return getHttpApiRuntime().then((httpApiRuntime)=>{
16
+ const endpoints = collectEffectEndpoints(httpApiRuntime.reflect, api, options.prefix);
17
+ const generation = createEffectClientGeneration(endpoints, options);
18
+ return {
19
+ code: renderEffectClientCode(generation),
20
+ declaration: renderEffectClientDeclaration(endpoints),
21
+ endpoints,
22
+ operationContracts: generation.operationContracts,
23
+ operationVersion: generation.operationVersion,
24
+ requestId: generation.requestId
25
+ };
26
+ });
27
+ });
28
+ }
29
+ function generateEffectClientCode(options) {
30
+ return generateEffectClient(options).then((artifacts)=>null === artifacts ? null : artifacts.code);
31
+ }
32
+ export { generateEffectClient, generateEffectClientCode };
@@ -0,0 +1,3 @@
1
+ export { bundleBuiltEffectEntryForNode, resolveEffectEntryPaths } from "./built-entry.mjs";
2
+ export { generateEffectClient, generateEffectClientCode } from "./generator.mjs";
3
+ export { resolveEffectEntryFile } from "./paths.mjs";
@@ -0,0 +1,24 @@
1
+ import { findExists, fs, upath } from "@modern-js/utils";
2
+ const JS_OR_TS_EXTS = [
3
+ '.js',
4
+ '.jsx',
5
+ '.ts',
6
+ '.tsx',
7
+ '.mjs',
8
+ '.mts',
9
+ '.cjs',
10
+ '.cts'
11
+ ];
12
+ function resolveEffectEntryFile(options) {
13
+ const { appDir, apiDir, effectEntry } = options;
14
+ const resolveEntry = (entryWithoutExt)=>{
15
+ if ('' !== upath.extname(entryWithoutExt)) return fs.existsSync(entryWithoutExt) ? entryWithoutExt : void 0;
16
+ return findExists(JS_OR_TS_EXTS.map((ext)=>`${entryWithoutExt}${ext}`)) || void 0;
17
+ };
18
+ if (void 0 !== effectEntry && '' !== effectEntry) {
19
+ const entryWithoutExt = upath.isAbsolute(effectEntry) ? effectEntry : upath.resolve(appDir, effectEntry);
20
+ return resolveEntry(entryWithoutExt);
21
+ }
22
+ return resolveEntry(upath.resolve(apiDir, 'index'));
23
+ }
24
+ export { resolveEffectEntryFile };