@bleedingdev/modern-js-plugin-bff-extensions 3.9.0-ultramodern.3 → 3.9.0-ultramodern.5

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 (92) hide show
  1. package/dist/cjs/backend-federation/edge.js +6 -6
  2. package/dist/cjs/backend-federation/index.js +5 -5
  3. package/dist/cjs/backend-federation/load.js +2 -2
  4. package/dist/cjs/backend-federation-manifest/metadata.js +3 -3
  5. package/dist/cjs/backend-federation-manifest/remote.js +2 -2
  6. package/dist/cjs/backend-federation-manifest/validation.js +3 -3
  7. package/dist/cjs/client-generator/rendering.js +4 -4
  8. package/dist/cjs/cross-project-policy/evaluation.js +3 -3
  9. package/dist/cjs/cross-project-policy/node.js +4 -3
  10. package/dist/cjs/cross-project-policy/producer-runtime.js +58 -0
  11. package/dist/cjs/effect-adapter/entry.js +1 -0
  12. package/dist/cjs/effect-adapter/index.js +9 -2
  13. package/dist/cjs/effect-source-loader/index.js +4 -0
  14. package/dist/cjs/effect-source-loader/loader.js +6 -4
  15. package/dist/cjs/effect-source-loader/rspack-loader.js +89 -0
  16. package/dist/cjs/effect-source-loader/worker-runtime-source.js +71 -0
  17. package/dist/cjs/effect-source-loader/worker-runtime-wrapper.js +2 -30
  18. package/dist/cjs/hono/cross-project-policy.js +2 -1
  19. package/dist/cjs/hono/node.js +51 -0
  20. package/dist/esm/backend-federation/edge.mjs +1 -1
  21. package/dist/esm/backend-federation/index.mjs +1 -1
  22. package/dist/esm/backend-federation/load.mjs +1 -1
  23. package/dist/esm/backend-federation-manifest/metadata.mjs +1 -1
  24. package/dist/esm/backend-federation-manifest/remote.mjs +1 -1
  25. package/dist/esm/backend-federation-manifest/validation.mjs +1 -1
  26. package/dist/esm/client-generator/rendering.mjs +2 -2
  27. package/dist/esm/cross-project-policy/evaluation.mjs +1 -1
  28. package/dist/esm/cross-project-policy/node.mjs +2 -1
  29. package/dist/esm/cross-project-policy/producer-runtime.mjs +20 -0
  30. package/dist/esm/effect-adapter/entry.mjs +1 -0
  31. package/dist/esm/effect-adapter/index.mjs +5 -1
  32. package/dist/esm/effect-source-loader/index.mjs +1 -0
  33. package/dist/esm/effect-source-loader/loader.mjs +6 -4
  34. package/dist/esm/effect-source-loader/rspack-loader.mjs +51 -0
  35. package/dist/esm/effect-source-loader/worker-runtime-source.mjs +23 -0
  36. package/dist/esm/effect-source-loader/worker-runtime-wrapper.mjs +2 -30
  37. package/dist/esm/hono/cross-project-policy.mjs +2 -1
  38. package/dist/esm-node/backend-federation/edge.mjs +1 -1
  39. package/dist/esm-node/backend-federation/index.mjs +1 -1
  40. package/dist/esm-node/backend-federation/load.mjs +1 -1
  41. package/dist/esm-node/backend-federation-manifest/metadata.mjs +1 -1
  42. package/dist/esm-node/backend-federation-manifest/remote.mjs +1 -1
  43. package/dist/esm-node/backend-federation-manifest/validation.mjs +1 -1
  44. package/dist/esm-node/client-generator/rendering.mjs +2 -2
  45. package/dist/esm-node/cross-project-policy/evaluation.mjs +1 -1
  46. package/dist/esm-node/cross-project-policy/node.mjs +2 -1
  47. package/dist/esm-node/cross-project-policy/producer-runtime.mjs +21 -0
  48. package/dist/esm-node/effect-adapter/entry.mjs +1 -0
  49. package/dist/esm-node/effect-adapter/index.mjs +5 -1
  50. package/dist/esm-node/effect-source-loader/index.mjs +1 -0
  51. package/dist/esm-node/effect-source-loader/loader.mjs +6 -4
  52. package/dist/esm-node/effect-source-loader/rspack-loader.mjs +53 -0
  53. package/dist/esm-node/effect-source-loader/worker-runtime-source.mjs +24 -0
  54. package/dist/esm-node/effect-source-loader/worker-runtime-wrapper.mjs +2 -30
  55. package/dist/esm-node/hono/cross-project-policy.mjs +2 -1
  56. package/dist/esm-node/hono/node.mjs +14 -0
  57. package/dist/types/backend-federation/edge.d.ts +1 -1
  58. package/dist/types/backend-federation/index.d.ts +1 -1
  59. package/dist/types/backend-federation/types.d.ts +1 -1
  60. package/dist/types/client-generator/rendering.d.ts +1 -1
  61. package/dist/types/client-generator/types.d.ts +1 -1
  62. package/dist/types/cross-project-policy/evaluation.d.ts +1 -1
  63. package/dist/types/cross-project-policy/node.d.ts +2 -1
  64. package/dist/types/cross-project-policy/producer-runtime.d.ts +20 -0
  65. package/dist/types/effect-adapter/entry.d.ts +1 -0
  66. package/dist/types/effect-adapter/index.d.ts +2 -0
  67. package/dist/types/effect-source-loader/index.d.ts +1 -0
  68. package/dist/types/effect-source-loader/rspack-loader.d.ts +23 -0
  69. package/dist/types/effect-source-loader/worker-runtime-source.d.ts +4 -0
  70. package/dist/types/hono/node.d.ts +4 -0
  71. package/package.json +48 -8
  72. package/src/backend-federation/edge.ts +1 -1
  73. package/src/backend-federation/index.ts +1 -1
  74. package/src/backend-federation/load.ts +1 -1
  75. package/src/backend-federation/types.ts +1 -1
  76. package/src/backend-federation-manifest/metadata.ts +1 -1
  77. package/src/backend-federation-manifest/remote.ts +1 -1
  78. package/src/backend-federation-manifest/validation.ts +1 -1
  79. package/src/client-generator/rendering.ts +6 -6
  80. package/src/client-generator/types.ts +1 -1
  81. package/src/cross-project-policy/evaluation.ts +1 -1
  82. package/src/cross-project-policy/node.ts +3 -3
  83. package/src/cross-project-policy/producer-runtime.ts +43 -0
  84. package/src/effect-adapter/entry.ts +1 -0
  85. package/src/effect-adapter/index.ts +5 -0
  86. package/src/effect-source-loader/index.ts +1 -0
  87. package/src/effect-source-loader/loader.ts +29 -23
  88. package/src/effect-source-loader/rspack-loader.ts +102 -0
  89. package/src/effect-source-loader/worker-runtime-source.ts +34 -0
  90. package/src/effect-source-loader/worker-runtime-wrapper.ts +2 -30
  91. package/src/hono/cross-project-policy.ts +2 -1
  92. package/src/hono/node.ts +24 -0
@@ -1,4 +1,4 @@
1
- import { type CrossProjectRequestObservation, type NormalizedCrossProjectPolicy } from '@modern-js/bff-core/security/cross-project-policy';
1
+ import { type CrossProjectRequestObservation, type NormalizedCrossProjectPolicy } from '@modern-js/server-runtime-extensions/bff-policy';
2
2
  export type ResolvedCrossProjectPolicy = NormalizedCrossProjectPolicy;
3
3
  export declare const checkCrossProjectPolicyResponse: (headers: Record<string, unknown>, policy: ResolvedCrossProjectPolicy | undefined, observedRequest?: CrossProjectRequestObservation) => Response | null;
4
4
  export declare const checkCrossProjectPolicyForRequest: (request: Request, policy: ResolvedCrossProjectPolicy | undefined) => Response | null;
@@ -1,4 +1,5 @@
1
- import { type OperationContractSource } from '@modern-js/bff-core';
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
4
  import type { ResolvedCrossProjectPolicy } from './evaluation.js';
4
5
  export declare const resolveAdapterCrossProjectPolicy: (api: ServerPluginAPI, handlers: OperationContractSource[]) => ResolvedCrossProjectPolicy | undefined;
@@ -0,0 +1,20 @@
1
+ interface ProducerClientOptions {
2
+ requestId?: string;
3
+ requireEnvelope?: boolean;
4
+ identityBinding?: {
5
+ enabled?: boolean;
6
+ strict?: boolean;
7
+ protectedHeaders?: string[];
8
+ };
9
+ operationContract?: {
10
+ enabled?: boolean;
11
+ strict?: boolean;
12
+ requireSchemaHash?: boolean;
13
+ requireOperationVersion?: boolean;
14
+ };
15
+ }
16
+ /** Bind producer defaults once while preserving every per-call nested override. */
17
+ export declare function createProducerClient<Options extends ProducerClientOptions, Result>(configure: (options: Options) => Result, { requestId }: {
18
+ requestId: string;
19
+ }): (options?: Options) => Result;
20
+ export {};
@@ -1,2 +1,3 @@
1
+ import '@modern-js/server-runtime-extensions/server-config';
1
2
  import type { ServerPluginAPI } from '@modern-js/server-core';
2
3
  export declare function resolveEffectAdapterEntryFile(api: ServerPluginAPI): string | undefined;
@@ -1,3 +1,4 @@
1
+ import '@modern-js/server-runtime-extensions/server-config';
1
2
  import type { ServerPluginAPI } from '@modern-js/server-core';
2
3
  interface EffectAdapterMiddlewareOptions {
3
4
  prefix: string | readonly string[];
@@ -16,4 +17,5 @@ export declare class EffectAdapter {
16
17
  dispose: () => Promise<void>;
17
18
  private loadHandler;
18
19
  }
20
+ export declare const createRuntimeAdapters: (api: ServerPluginAPI) => EffectAdapter[];
19
21
  export {};
@@ -1,3 +1,4 @@
1
1
  export { resolveEffectEntryFile } from '../client-generator/paths.js';
2
2
  export { bundleEffectEntryForNode } from './loader.js';
3
+ export { bundleEffectWorkerRuntimeSource } from './worker-runtime-source.js';
3
4
  export { generateEffectClientCode, generateEffectWorkerRuntimeWrapper, } from './worker-runtime-wrapper.js';
@@ -0,0 +1,23 @@
1
+ import type { HttpMethodDecider } from '@modern-js/types';
2
+ import type { Rspack } from '@rsbuild/core';
3
+ export interface EffectBffLoaderOptions {
4
+ prefix: string;
5
+ appDir: string;
6
+ apiDir: string;
7
+ effectEntry: string;
8
+ port: number;
9
+ target: string;
10
+ requestCreator?: string;
11
+ requestId?: string;
12
+ httpMethodDecider?: HttpMethodDecider;
13
+ effectDataPlatformBatch?: {
14
+ enabled?: boolean;
15
+ endpoint?: string;
16
+ flushIntervalMs?: number;
17
+ maxBatchSize?: number;
18
+ maxBatchBytes?: number;
19
+ requestTimeoutMs?: number;
20
+ allowedMethods?: string[];
21
+ };
22
+ }
23
+ export default function loader(this: Rspack.LoaderContext<EffectBffLoaderOptions>, source: string): Promise<void>;
@@ -0,0 +1,4 @@
1
+ /** Keep the worker implementation graph out of the API-to-client loader. */
2
+ export declare function bundleEffectWorkerRuntimeSource(source: string, resourcePath: string, loader: {
3
+ addDependency: (dependency: string) => void;
4
+ }): Promise<string>;
@@ -0,0 +1,4 @@
1
+ import type { ServerPluginAPI } from '@modern-js/server-core';
2
+ import type { OperationContractSource } from '@modern-js/server-runtime-extensions/bff-policy/node';
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;
package/package.json CHANGED
@@ -18,7 +18,7 @@
18
18
  "modern.js",
19
19
  "ultramodern.js"
20
20
  ],
21
- "version": "3.9.0-ultramodern.3",
21
+ "version": "3.9.0-ultramodern.5",
22
22
  "files": [
23
23
  "dist",
24
24
  "src"
@@ -115,6 +115,30 @@
115
115
  "require": "./dist/cjs/backend-federation-manifest/node.js"
116
116
  },
117
117
  "default": "./dist/cjs/backend-federation-manifest/node.js"
118
+ },
119
+ "./effect-source-loader/rspack-loader": {
120
+ "types": "./dist/types/effect-source-loader/rspack-loader.d.ts",
121
+ "node": {
122
+ "import": "./dist/esm-node/effect-source-loader/rspack-loader.mjs",
123
+ "require": "./dist/cjs/effect-source-loader/rspack-loader.js"
124
+ },
125
+ "default": "./dist/cjs/effect-source-loader/rspack-loader.js"
126
+ },
127
+ "./producer-runtime": {
128
+ "types": "./dist/types/cross-project-policy/producer-runtime.d.ts",
129
+ "node": {
130
+ "import": "./dist/esm-node/cross-project-policy/producer-runtime.mjs",
131
+ "require": "./dist/cjs/cross-project-policy/producer-runtime.js"
132
+ },
133
+ "import": "./dist/esm/cross-project-policy/producer-runtime.mjs",
134
+ "default": "./dist/esm/cross-project-policy/producer-runtime.mjs"
135
+ },
136
+ "./hono/node": {
137
+ "types": "./dist/types/hono/node.d.ts",
138
+ "node": {
139
+ "import": "./dist/esm-node/hono/node.mjs",
140
+ "require": "./dist/cjs/hono/node.js"
141
+ }
118
142
  }
119
143
  },
120
144
  "typesVersions": {
@@ -162,6 +186,18 @@
162
186
  "backend-federation-manifest/node": [
163
187
  "./dist/types/backend-federation-manifest/node.d.ts",
164
188
  "./src/backend-federation-manifest/node.ts"
189
+ ],
190
+ "effect-source-loader/rspack-loader": [
191
+ "./dist/types/effect-source-loader/rspack-loader.d.ts",
192
+ "./src/effect-source-loader/rspack-loader.ts"
193
+ ],
194
+ "producer-runtime": [
195
+ "./dist/types/cross-project-policy/producer-runtime.d.ts",
196
+ "./src/cross-project-policy/producer-runtime.ts"
197
+ ],
198
+ "hono/node": [
199
+ "./dist/types/hono/node.d.ts",
200
+ "./src/hono/node.ts"
165
201
  ]
166
202
  }
167
203
  },
@@ -169,14 +205,16 @@
169
205
  "node": ">=26.7.0"
170
206
  },
171
207
  "dependencies": {
172
- "@modern-js/bff-core": "npm:@bleedingdev/modern-js-bff-core@3.9.0-ultramodern.3",
173
- "@modern-js/bff-effect": "npm:@bleedingdev/modern-js-bff-effect@3.9.0-ultramodern.3",
174
- "@modern-js/runtime-extensions": "npm:@bleedingdev/modern-js-runtime-extensions@3.9.0-ultramodern.3",
175
- "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.9.0-ultramodern.3",
176
- "@modern-js/server-runtime-extensions": "npm:@bleedingdev/modern-js-server-runtime-extensions@3.9.0-ultramodern.3",
177
- "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.9.0-ultramodern.3",
178
- "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.9.0-ultramodern.3",
208
+ "@modern-js/backend-federation-contracts": "npm:@bleedingdev/modern-js-backend-federation-contracts@3.9.0-ultramodern.5",
209
+ "@modern-js/bff-core": "npm:@bleedingdev/modern-js-bff-core@3.9.0-ultramodern.5",
210
+ "@modern-js/bff-effect": "npm:@bleedingdev/modern-js-bff-effect@3.9.0-ultramodern.5",
211
+ "@modern-js/runtime-extensions": "npm:@bleedingdev/modern-js-runtime-extensions@3.9.0-ultramodern.5",
212
+ "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.9.0-ultramodern.5",
213
+ "@modern-js/server-runtime-extensions": "npm:@bleedingdev/modern-js-server-runtime-extensions@3.9.0-ultramodern.5",
214
+ "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.9.0-ultramodern.5",
215
+ "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.9.0-ultramodern.5",
179
216
  "@module-federation/runtime": "2.9.0",
217
+ "@swc/core": "1.16.2",
180
218
  "esbuild": "^0.28.2"
181
219
  },
182
220
  "peerDependencies": {
@@ -193,6 +231,8 @@
193
231
  },
194
232
  "devDependencies": {
195
233
  "@effect/opentelemetry": "4.0.0-rc.112",
234
+ "@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.9.0-ultramodern.5",
235
+ "@rsbuild/core": "2.2.3",
196
236
  "@rslib/core": "1.0.0",
197
237
  "@scripts/rstest-config": "2.66.0",
198
238
  "@types/node": "^26.4.1",
@@ -3,7 +3,7 @@ import {
3
3
  BACKEND_FEDERATION_EFFECT_EXPOSE,
4
4
  BACKEND_FEDERATION_MANIFEST_FILE,
5
5
  BACKEND_FEDERATION_NODE_ADAPTER_VERSION,
6
- } from '@modern-js/utils/universal';
6
+ } from '@modern-js/backend-federation-contracts';
7
7
  import {
8
8
  type BackendFederationEdgeLoadEntryPlugin,
9
9
  type BackendFederationEdgeLoadEntryPluginOptions,
@@ -5,7 +5,7 @@ import {
5
5
  BACKEND_FEDERATION_EFFECT_EXPOSE,
6
6
  BACKEND_FEDERATION_MANIFEST_FILE,
7
7
  BACKEND_FEDERATION_NODE_ADAPTER_VERSION,
8
- } from '@modern-js/utils/universal';
8
+ } from '@modern-js/backend-federation-contracts';
9
9
 
10
10
  export {
11
11
  type BackendFederationExpectedIdentity,
@@ -1,4 +1,4 @@
1
- import { BACKEND_FEDERATION_EFFECT_EXPOSE } from '@modern-js/utils/universal';
1
+ import { BACKEND_FEDERATION_EFFECT_EXPOSE } from '@modern-js/backend-federation-contracts';
2
2
  import * as Effect from 'effect/Effect';
3
3
  import * as Logger from 'effect/Logger';
4
4
 
@@ -1,9 +1,9 @@
1
+ import type { BACKEND_FEDERATION_EFFECT_EXPOSE } from '@modern-js/backend-federation-contracts';
1
2
  import type { EffectApiModule } from '@modern-js/bff-effect/effect';
2
3
  import type {
3
4
  BackendFederationRemoteEntryPolicy,
4
5
  BackendFederationRemoteEntryVerification,
5
6
  } from '@modern-js/server-runtime-extensions/backend-federation-security';
6
- import type { BACKEND_FEDERATION_EFFECT_EXPOSE } from '@modern-js/utils/universal';
7
7
  import type {
8
8
  ModuleFederation,
9
9
  ModuleFederationRuntimePlugin,
@@ -3,7 +3,7 @@
3
3
  import {
4
4
  backendFederationMetadata as sharedBackendFederationMetadata,
5
5
  backendFederationVersionBoundary as sharedBackendFederationVersionBoundary,
6
- } from '@modern-js/utils/universal';
6
+ } from '@modern-js/backend-federation-contracts';
7
7
  import type { BackendFederationManifest } from './types';
8
8
 
9
9
  export function stringValue(value: unknown) {
@@ -1,10 +1,10 @@
1
1
  // @effect-diagnostics asyncFunction:off extendsNativeError:off globalTimers:off newPromise:off strictBooleanExpressions:off
2
2
 
3
+ import { backendFederationExposeNames } from '@modern-js/backend-federation-contracts';
3
4
  import {
4
5
  BackendFederationRemoteEntryError,
5
6
  resolveBackendFederationRemoteEntryVerification,
6
7
  } from '@modern-js/server-runtime-extensions/backend-federation-security';
7
- import { backendFederationExposeNames } from '@modern-js/utils/universal';
8
8
  import {
9
9
  BACKEND_FEDERATION_EFFECT_EXPOSE,
10
10
  type BackendFederationRemote,
@@ -3,7 +3,7 @@
3
3
  import {
4
4
  formatBackendFederationValidationErrors,
5
5
  validateBackendFederationManifest as validateBackendFederationManifestContract,
6
- } from '@modern-js/utils/universal';
6
+ } from '@modern-js/backend-federation-contracts';
7
7
  import {
8
8
  BACKEND_FEDERATION_CONTRACT_VERSION,
9
9
  BACKEND_FEDERATION_NODE_ADAPTER_VERSION,
@@ -1,8 +1,3 @@
1
- import {
2
- buildOperationContractMap,
3
- deriveOperationVersion,
4
- type OperationContractMap,
5
- } from '@modern-js/bff-core';
6
1
  import {
7
2
  createEffectEndpointContractHash,
8
3
  type EffectEndpointMeta,
@@ -10,12 +5,17 @@ import {
10
5
  normalizeEffectPrefix,
11
6
  toOperationContractSources,
12
7
  } from '@modern-js/bff-effect/effect';
8
+ import {
9
+ buildOperationContractMap,
10
+ deriveOperationVersion,
11
+ type OperationContractMap,
12
+ } from '@modern-js/server-runtime-extensions/bff-policy/node';
13
13
  import { fs, upath as path } from '@modern-js/utils';
14
14
  import type { EffectClientCodegenOptions } from './types';
15
15
 
16
16
  const DEFAULT_REQUEST_CREATOR = '@modern-js/plugin-bff/client';
17
17
  const EFFECT_CLIENT_RUNTIME_IMPORT =
18
- '@modern-js/plugin-bff/effect-client-runtime';
18
+ '@modern-js/bff-effect/effect-client-runtime';
19
19
 
20
20
  function isAbsoluteUrl(value: string) {
21
21
  try {
@@ -1,5 +1,5 @@
1
- import type { OperationContractMap } from '@modern-js/bff-core';
2
1
  import type { EffectEndpointMeta } from '@modern-js/bff-effect/effect';
2
+ import type { OperationContractMap } from '@modern-js/server-runtime-extensions/bff-policy/node';
3
3
  import type { HttpMethodDecider } from '@modern-js/types';
4
4
 
5
5
  export type EffectClientCodegenOptions = {
@@ -3,7 +3,7 @@ import {
3
3
  evaluateCrossProjectPolicy,
4
4
  type NormalizedCrossProjectPolicy,
5
5
  resolveCrossProjectRequestObservation,
6
- } from '@modern-js/bff-core/security/cross-project-policy';
6
+ } from '@modern-js/server-runtime-extensions/bff-policy';
7
7
 
8
8
  export type ResolvedCrossProjectPolicy = NormalizedCrossProjectPolicy;
9
9
 
@@ -1,12 +1,12 @@
1
1
  import { readFileSync } from 'node:fs';
2
2
  import path from 'node:path';
3
-
3
+ import '@modern-js/server-runtime-extensions/server-config';
4
+ import type { ServerPluginAPI } from '@modern-js/server-core';
4
5
  import {
5
6
  deriveOperationVersion,
6
7
  type OperationContractSource,
7
8
  resolveCrossProjectPolicy,
8
- } from '@modern-js/bff-core';
9
- import type { ServerPluginAPI } from '@modern-js/server-core';
9
+ } from '@modern-js/server-runtime-extensions/bff-policy/node';
10
10
 
11
11
  import type { ResolvedCrossProjectPolicy } from './evaluation';
12
12
 
@@ -0,0 +1,43 @@
1
+ interface ProducerClientOptions {
2
+ requestId?: string;
3
+ requireEnvelope?: boolean;
4
+ identityBinding?: {
5
+ enabled?: boolean;
6
+ strict?: boolean;
7
+ protectedHeaders?: string[];
8
+ };
9
+ operationContract?: {
10
+ enabled?: boolean;
11
+ strict?: boolean;
12
+ requireSchemaHash?: boolean;
13
+ requireOperationVersion?: boolean;
14
+ };
15
+ }
16
+
17
+ /** Bind producer defaults once while preserving every per-call nested override. */
18
+ export function createProducerClient<
19
+ Options extends ProducerClientOptions,
20
+ Result,
21
+ >(
22
+ configure: (options: Options) => Result,
23
+ { requestId }: { requestId: string },
24
+ ) {
25
+ return (options?: Options): Result =>
26
+ configure({
27
+ requestId,
28
+ requireEnvelope: true,
29
+ ...options,
30
+ identityBinding: {
31
+ enabled: true,
32
+ strict: true,
33
+ ...options?.identityBinding,
34
+ },
35
+ operationContract: {
36
+ enabled: true,
37
+ strict: true,
38
+ requireSchemaHash: true,
39
+ requireOperationVersion: true,
40
+ ...options?.operationContract,
41
+ },
42
+ } as Options);
43
+ }
@@ -1,6 +1,7 @@
1
1
  // @effect-diagnostics nodeBuiltinImport:off strictBooleanExpressions:off
2
2
 
3
3
  import path from 'node:path';
4
+ import '@modern-js/server-runtime-extensions/server-config';
4
5
  import type { ServerPluginAPI } from '@modern-js/server-core';
5
6
  import { API_DIR, findExists, fs, isProd } from '@modern-js/utils';
6
7
 
@@ -1,6 +1,7 @@
1
1
  // @effect-diagnostics anyUnknownInErrorContext:off asyncFunction:off nodeBuiltinImport:off strictBooleanExpressions:off
2
2
 
3
3
  import path from 'node:path';
4
+ import '@modern-js/server-runtime-extensions/server-config';
4
5
  import {
5
6
  dispatchEffectBffRequest,
6
7
  type EffectApiModule,
@@ -244,3 +245,7 @@ export class EffectAdapter {
244
245
  this.handler = candidate;
245
246
  }
246
247
  }
248
+
249
+ export const createRuntimeAdapters = (api: ServerPluginAPI) => [
250
+ new EffectAdapter(api),
251
+ ];
@@ -1,5 +1,6 @@
1
1
  export { resolveEffectEntryFile } from '../client-generator/paths';
2
2
  export { bundleEffectEntryForNode } from './loader';
3
+ export { bundleEffectWorkerRuntimeSource } from './worker-runtime-source';
3
4
  export {
4
5
  generateEffectClientCode,
5
6
  generateEffectWorkerRuntimeWrapper,
@@ -39,31 +39,37 @@ function preserveSourceModuleSemantics(): Plugin {
39
39
  return {
40
40
  name: 'modern-js-effect-source-semantics',
41
41
  setup(buildApi) {
42
- buildApi.onLoad({ filter: /\.[cm]?[jt]sx?$/ }, async args => {
43
- const loader = sourceLoader(args);
44
- if (!loader) {
45
- return undefined;
46
- }
42
+ buildApi.onLoad(
43
+ { filter: /\.[cm]?[jt]sx?$/, namespace: 'file' },
44
+ async args => {
45
+ const loader = sourceLoader(args);
46
+ if (!loader) {
47
+ return undefined;
48
+ }
47
49
 
48
- const source = await fs.promises.readFile(args.path, 'utf8');
49
- const compiled = await transform(source, {
50
- define: {
51
- __dirname: JSON.stringify(path.dirname(args.path)),
52
- __filename: JSON.stringify(args.path),
53
- 'import.meta.url': JSON.stringify(pathToFileURL(args.path).href),
54
- },
55
- jsx: 'automatic',
56
- loader,
57
- sourcefile: args.path,
58
- target: NODE_TARGET,
59
- });
50
+ const source = await fs.promises.readFile(args.path, 'utf8');
51
+ const canonicalSourcePath = await fs.promises.realpath(args.path);
52
+ const compiled = await transform(source, {
53
+ define: {
54
+ __dirname: JSON.stringify(path.dirname(canonicalSourcePath)),
55
+ __filename: JSON.stringify(canonicalSourcePath),
56
+ 'import.meta.url': JSON.stringify(
57
+ pathToFileURL(canonicalSourcePath).href,
58
+ ),
59
+ },
60
+ jsx: 'automatic',
61
+ loader,
62
+ sourcefile: args.path,
63
+ target: NODE_TARGET,
64
+ });
60
65
 
61
- return {
62
- contents: compiled.code,
63
- loader: 'js',
64
- resolveDir: path.dirname(args.path),
65
- };
66
- });
66
+ return {
67
+ contents: compiled.code,
68
+ loader: 'js',
69
+ resolveDir: path.dirname(args.path),
70
+ };
71
+ },
72
+ );
67
73
  },
68
74
  };
69
75
  }
@@ -0,0 +1,102 @@
1
+ import { realpathSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ import type { HttpMethodDecider } from '@modern-js/types';
4
+ import type { Rspack } from '@rsbuild/core';
5
+ import {
6
+ bundleEffectWorkerRuntimeSource,
7
+ generateEffectClientCode,
8
+ generateEffectWorkerRuntimeWrapper,
9
+ resolveEffectEntryFile,
10
+ } from './index';
11
+
12
+ export interface EffectBffLoaderOptions {
13
+ prefix: string;
14
+ appDir: string;
15
+ apiDir: string;
16
+ effectEntry: string;
17
+ port: number;
18
+ target: string;
19
+ requestCreator?: string;
20
+ requestId?: string;
21
+ httpMethodDecider?: HttpMethodDecider;
22
+ effectDataPlatformBatch?: {
23
+ enabled?: boolean;
24
+ endpoint?: string;
25
+ flushIntervalMs?: number;
26
+ maxBatchSize?: number;
27
+ maxBatchBytes?: number;
28
+ requestTimeoutMs?: number;
29
+ allowedMethods?: string[];
30
+ };
31
+ }
32
+
33
+ export default async function loader(
34
+ this: Rspack.LoaderContext<EffectBffLoaderOptions>,
35
+ source: string,
36
+ ) {
37
+ this.cacheable();
38
+ delete require.cache[this.resourcePath];
39
+ const callback = this.async();
40
+ try {
41
+ const options = this.getOptions();
42
+ const entry = resolveEffectEntryFile(options);
43
+ if (!entry || realpathSync(entry) !== realpathSync(this.resourcePath))
44
+ throw new Error(
45
+ `Unexpected Effect BFF loader resource: ${this.resourcePath}`,
46
+ );
47
+ const query = new URLSearchParams(this.resourceQuery);
48
+ if (query.has('modern-bff-runtime-source')) {
49
+ const { transform } = await import('@swc/core');
50
+ const transformed = await transform(source, {
51
+ filename: this.resourcePath,
52
+ sourceMaps: false,
53
+ jsc: {
54
+ parser: {
55
+ syntax: 'typescript',
56
+ tsx: /\.[jt]sx$/.test(this.resourcePath),
57
+ },
58
+ target: 'es2024',
59
+ },
60
+ module: { type: 'es6' },
61
+ });
62
+ callback(
63
+ undefined,
64
+ await bundleEffectWorkerRuntimeSource(
65
+ transformed.code,
66
+ this.resourcePath,
67
+ this,
68
+ ),
69
+ );
70
+ } else if (query.has('modern-bff-runtime')) {
71
+ callback(
72
+ undefined,
73
+ await generateEffectWorkerRuntimeWrapper(
74
+ this,
75
+ options,
76
+ this.resourcePath,
77
+ ),
78
+ );
79
+ } else {
80
+ const code = await generateEffectClientCode({
81
+ appDir: options.appDir,
82
+ apiDir: options.apiDir,
83
+ resourcePath: this.resourcePath,
84
+ prefix: options.prefix,
85
+ port: Number(options.port),
86
+ target: options.target,
87
+ requestId: options.requestId,
88
+ requestCreator: options.requestCreator,
89
+ httpMethodDecider: options.httpMethodDecider,
90
+ dataPlatformBatch: options.effectDataPlatformBatch,
91
+ onDependency: dependency => this.addDependency(dependency),
92
+ });
93
+ if (code === null)
94
+ throw new Error(
95
+ `Failed to generate Effect client for ${this.resourcePath}`,
96
+ );
97
+ callback(undefined, code);
98
+ }
99
+ } catch (error) {
100
+ callback(error instanceof Error ? error : new Error(String(error)));
101
+ }
102
+ }
@@ -0,0 +1,34 @@
1
+ import path from 'node:path';
2
+ import { build } from 'esbuild';
3
+
4
+ /** Keep the worker implementation graph out of the API-to-client loader. */
5
+ export async function bundleEffectWorkerRuntimeSource(
6
+ source: string,
7
+ resourcePath: string,
8
+ loader: { addDependency: (dependency: string) => void },
9
+ ) {
10
+ const result = await build({
11
+ absWorkingDir: path.dirname(resourcePath),
12
+ bundle: true,
13
+ format: 'esm',
14
+ metafile: true,
15
+ packages: 'external',
16
+ platform: 'neutral',
17
+ stdin: {
18
+ contents: source,
19
+ loader: 'js',
20
+ resolveDir: path.dirname(resourcePath),
21
+ sourcefile: resourcePath,
22
+ },
23
+ target: 'es2024',
24
+ write: false,
25
+ });
26
+ for (const dependency of Object.keys(result.metafile.inputs)) {
27
+ if (dependency !== '<stdin>') {
28
+ loader.addDependency(
29
+ path.resolve(path.dirname(resourcePath), dependency),
30
+ );
31
+ }
32
+ }
33
+ return result.outputFiles[0].text;
34
+ }
@@ -46,36 +46,8 @@ export async function generateEffectWorkerRuntimeWrapper(
46
46
  const operationContracts = artifacts?.operationContracts ?? {};
47
47
 
48
48
  return `import * as effectBffModule from ${JSON.stringify(sourceRequest)};
49
- import { createEffectBffEdgeDispatcher } from '@modern-js/plugin-bff/effect-edge/dispatcher';
50
-
51
- const __generatedOperationContracts = ${JSON.stringify(operationContracts)};
52
-
53
- const __mergeGeneratedOperationContracts = policy => {
54
- if (
55
- !policy ||
56
- !policy.expectedOperationContracts ||
57
- typeof policy.expectedOperationContracts !== 'object' ||
58
- Array.isArray(policy.expectedOperationContracts)
59
- ) {
60
- return policy;
61
- }
62
- return {
63
- ...policy,
64
- expectedOperationContracts: {
65
- ...policy.expectedOperationContracts,
66
- ...__generatedOperationContracts,
67
- },
68
- };
69
- };
70
-
71
- export const __modern_create_effect_bff_dispatcher = options =>
72
- createEffectBffEdgeDispatcher({
73
- ...options,
74
- crossProjectPolicy: __mergeGeneratedOperationContracts(
75
- options?.crossProjectPolicy,
76
- ),
77
- module: effectBffModule,
78
- });
49
+ import { createEffectBffEdgeDispatcherFactory } from '@modern-js/bff-effect/effect-edge';
50
+ export const __modern_create_effect_bff_dispatcher = createEffectBffEdgeDispatcherFactory(effectBffModule, ${JSON.stringify(operationContracts)});
79
51
  `;
80
52
  }
81
53
 
@@ -22,5 +22,6 @@ export const createHonoCrossProjectPolicyMiddleware = (
22
22
  return denial;
23
23
  }
24
24
 
25
- return next();
25
+ const result: unknown = await next();
26
+ return result instanceof Response ? result : undefined;
26
27
  };