@bleedingdev/modern-js-plugin-bff 3.5.0-ultramodern.28 → 3.5.0-ultramodern.29

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 (39) hide show
  1. package/dist/cjs/runtime/effect/adapter.js +9 -40
  2. package/dist/cjs/runtime/effect/backend-federation-manifest.js +287 -0
  3. package/dist/cjs/runtime/effect/backend-federation.js +189 -0
  4. package/dist/cjs/runtime/effect/dispatch.js +116 -0
  5. package/dist/cjs/runtime/effect/edge.js +58 -69
  6. package/dist/cjs/runtime/effect/endpoint-contracts.js +7 -12
  7. package/dist/cjs/runtime/effect/entry-shape.js +87 -0
  8. package/dist/cjs/runtime/effect/handler.js +15 -16
  9. package/dist/cjs/runtime/effect/index.js +91 -15
  10. package/dist/cjs/runtime/effect/module.js +23 -80
  11. package/dist/esm/runtime/effect/adapter.mjs +10 -41
  12. package/dist/esm/runtime/effect/backend-federation-manifest.mjs +237 -0
  13. package/dist/esm/runtime/effect/backend-federation.mjs +132 -0
  14. package/dist/esm/runtime/effect/dispatch.mjs +63 -0
  15. package/dist/esm/runtime/effect/edge.mjs +17 -63
  16. package/dist/esm/runtime/effect/endpoint-contracts.mjs +7 -12
  17. package/dist/esm/runtime/effect/entry-shape.mjs +36 -0
  18. package/dist/esm/runtime/effect/handler.mjs +1 -4
  19. package/dist/esm/runtime/effect/index.mjs +3 -0
  20. package/dist/esm/runtime/effect/module.mjs +23 -80
  21. package/dist/esm-node/runtime/effect/adapter.mjs +10 -41
  22. package/dist/esm-node/runtime/effect/backend-federation-manifest.mjs +238 -0
  23. package/dist/esm-node/runtime/effect/backend-federation.mjs +133 -0
  24. package/dist/esm-node/runtime/effect/dispatch.mjs +64 -0
  25. package/dist/esm-node/runtime/effect/edge.mjs +17 -63
  26. package/dist/esm-node/runtime/effect/endpoint-contracts.mjs +7 -12
  27. package/dist/esm-node/runtime/effect/entry-shape.mjs +37 -0
  28. package/dist/esm-node/runtime/effect/handler.mjs +1 -4
  29. package/dist/esm-node/runtime/effect/index.mjs +3 -0
  30. package/dist/esm-node/runtime/effect/module.mjs +23 -80
  31. package/dist/types/runtime/effect/backend-federation-manifest.d.ts +60 -0
  32. package/dist/types/runtime/effect/backend-federation.d.ts +60 -0
  33. package/dist/types/runtime/effect/dispatch.d.ts +17 -0
  34. package/dist/types/runtime/effect/edge.d.ts +9 -8
  35. package/dist/types/runtime/effect/endpoint-contracts.d.ts +2 -2
  36. package/dist/types/runtime/effect/entry-shape.d.ts +31 -0
  37. package/dist/types/runtime/effect/handler.d.ts +1 -17
  38. package/dist/types/runtime/effect/index.d.ts +3 -0
  39. package/package.json +25 -13
@@ -0,0 +1,60 @@
1
+ import type { ModuleFederation, ModuleFederationRuntimePlugin } from '@module-federation/runtime';
2
+ import type { EffectApiModule } from './module';
3
+ export declare const BACKEND_FEDERATION_EFFECT_EXPOSE = "./effect-api";
4
+ export declare const BACKEND_FEDERATION_MANIFEST_FILE = "backend-mf-manifest.json";
5
+ export declare const BACKEND_FEDERATION_CONTRACT_VERSION = "microvertical-server-effect-v1";
6
+ export declare const BACKEND_FEDERATION_NODE_ADAPTER_VERSION = "backend-mf-effect-v1";
7
+ export type BackendFederationRemote = {
8
+ name: string;
9
+ entry: string;
10
+ type?: 'commonjs-module' | 'module' | string;
11
+ entryGlobalName?: string;
12
+ shareScope?: string | string[];
13
+ expose?: typeof BACKEND_FEDERATION_EFFECT_EXPOSE;
14
+ };
15
+ export type BackendFederationRuntimeOptions = {
16
+ hostName: string;
17
+ remote?: BackendFederationRemote;
18
+ remotes?: BackendFederationRemote[];
19
+ plugins?: ModuleFederationRuntimePlugin[];
20
+ };
21
+ export type BackendFederationEntryExports = {
22
+ get: (id: string) => (() => Promise<unknown> | unknown) | Promise<() => Promise<unknown> | unknown>;
23
+ init?: (...args: unknown[]) => void | Promise<void>;
24
+ };
25
+ export type BackendFederatedEffectApiModule = EffectApiModule & {
26
+ backendFederationContract?: {
27
+ compatibility?: {
28
+ build?: unknown;
29
+ contractVersion?: unknown;
30
+ nodeAdapterVersion?: unknown;
31
+ packageName?: unknown;
32
+ /**
33
+ * ADR-0019 delivery-unit identity root, generator-emitted alongside
34
+ * the manifest's `versionBoundary.deliveryUnit`. Additive/optional.
35
+ */
36
+ unitId?: unknown;
37
+ /** ADR-0019 delivery-unit source revision. Additive/optional. */
38
+ sourceRevision?: unknown;
39
+ };
40
+ name?: unknown;
41
+ role?: unknown;
42
+ runtimeFramework?: unknown;
43
+ strictEffectApproach?: unknown;
44
+ };
45
+ contract?: unknown;
46
+ operationContexts?: unknown;
47
+ runtime?: unknown;
48
+ };
49
+ export type BackendFederationLoadEntryPluginOptions = {
50
+ resolveEntry: (remote: BackendFederationRemote) => BackendFederationEntryExports | undefined | Promise<BackendFederationEntryExports | undefined>;
51
+ };
52
+ type BackendFederationLoadOptions = BackendFederationRuntimeOptions & {
53
+ runtime?: ModuleFederation;
54
+ remoteName?: string;
55
+ expose?: string;
56
+ };
57
+ export declare function createBackendFederationRuntime(options: BackendFederationRuntimeOptions): ModuleFederation;
58
+ export declare function createBackendFederationLoadEntryPlugin(options: BackendFederationLoadEntryPluginOptions): ModuleFederationRuntimePlugin;
59
+ export declare function loadBackendFederatedEffectApi(options: BackendFederationLoadOptions): Promise<BackendFederatedEffectApiModule>;
60
+ export {};
@@ -0,0 +1,17 @@
1
+ import type { EffectBffRequestHandler } from './module';
2
+ import { type EffectContext } from './operation-context';
3
+ export type EffectDispatchContextRunner = <T>(context: EffectContext, cb: () => T) => T;
4
+ export type DispatchEffectBffRequestOptions = {
5
+ prefix?: string;
6
+ env?: Record<string, unknown>;
7
+ path?: string;
8
+ method?: string;
9
+ runWithEffectContext: EffectDispatchContextRunner;
10
+ onError?: (error: unknown, context: EffectContext) => Promise<Response> | Response;
11
+ };
12
+ export declare function normalizeEffectBffPrefix(prefix: string | undefined): string;
13
+ export declare function removeEffectBffPrefixFromPath(pathname: string, prefix: string | undefined): string;
14
+ export declare function matchesEffectBffPrefix(pathname: string, prefix: string | undefined): boolean;
15
+ export declare function createEffectBffMountedRequest(req: Request, prefix: string | undefined): Request;
16
+ export declare function createEffectBffDispatchContext(originalRequest: Request, mountedRequest: Request, options: Omit<DispatchEffectBffRequestOptions, 'runWithEffectContext'>): EffectContext;
17
+ export declare function dispatchEffectBffRequestWithContext(handler: EffectBffRequestHandler, request: Request, options: DispatchEffectBffRequestOptions): Promise<Response>;
@@ -1,16 +1,12 @@
1
+ import { type DispatchEffectBffRequestOptions } from './dispatch';
1
2
  import type { EffectBffOpenApiConfig, EffectDataPlatformValidationOptions } from './handler';
2
3
  import { type EffectApiModule, type EffectBffRequestHandler } from './module';
3
- import { type EffectContext } from './operation-context';
4
+ import type { EffectContext } from './operation-context';
5
+ export { BACKEND_FEDERATION_CONTRACT_VERSION, BACKEND_FEDERATION_EFFECT_EXPOSE, BACKEND_FEDERATION_MANIFEST_FILE, BACKEND_FEDERATION_NODE_ADAPTER_VERSION, type BackendFederatedEffectApiModule, type BackendFederationEntryExports, type BackendFederationLoadEntryPluginOptions, type BackendFederationRemote, type BackendFederationRuntimeOptions, createBackendFederationLoadEntryPlugin, createBackendFederationRuntime, loadBackendFederatedEffectApi, } from './backend-federation';
4
6
  export { runWithEffectContext, useEffectContext, useOperationContext, } from './edge-context';
5
7
  export * from './handler';
6
8
  export { type CreateEffectOperationContextOptions, createEffectOperationContext, type EffectContext, } from './operation-context';
7
- export type EffectBffEdgeDispatchOptions = {
8
- prefix?: string;
9
- env?: Record<string, unknown>;
10
- path?: string;
11
- method?: string;
12
- onError?: (error: unknown, context: EffectContext) => Promise<Response> | Response;
13
- };
9
+ export type EffectBffEdgeDispatchOptions = Omit<DispatchEffectBffRequestOptions, 'runWithEffectContext'>;
14
10
  export type EffectBffEdgeHandlerOptions = {
15
11
  module: EffectApiModule;
16
12
  prefix?: string;
@@ -19,7 +15,12 @@ export type EffectBffEdgeHandlerOptions = {
19
15
  onError?: (error: unknown, context: EffectContext) => Promise<Response> | Response;
20
16
  onWarning?: (message: string) => void;
21
17
  };
18
+ export type EffectBffEdgeRequestDispatcher = (request: Request, dispatchOptions?: Omit<EffectBffEdgeDispatchOptions, 'prefix' | 'onError'>) => Promise<Response>;
22
19
  export declare function dispatchEffectBffRequest(handler: EffectBffRequestHandler, request: Request, options?: EffectBffEdgeDispatchOptions): Promise<Response>;
20
+ export declare function createEffectBffEdgeDispatcher(options: EffectBffEdgeHandlerOptions): Promise<{
21
+ dispatch: (request: Request, dispatchOptions?: Omit<EffectBffEdgeDispatchOptions, 'prefix' | 'onError'>) => Promise<Response>;
22
+ dispose: () => Promise<void>;
23
+ }>;
23
24
  export declare const createEffectBffTestHandler: typeof createEffectBffEdgeHandler;
24
25
  export declare function createEffectBffEdgeHandler(options: EffectBffEdgeHandlerOptions): Promise<{
25
26
  handler: (request: Request, dispatchOptions?: Omit<EffectBffEdgeDispatchOptions, 'prefix' | 'onError'>) => Promise<Response>;
@@ -51,8 +51,8 @@ export declare function toOperationContractSources(endpoints: EffectEndpointMeta
51
51
  export declare function createEffectOperationContractSource(endpoint: EffectEndpointMeta): OperationContractSource;
52
52
  /**
53
53
  * Extracts the HttpApi instance from a loaded effect entry module. Mirrors
54
- * the module shapes accepted by `resolveEffectBffModuleHandler`:
55
- * `{ api }`, `{ default: { api } }` and zero-arg default factories.
54
+ * the shared entry-shape policy accepted by `resolveEffectBffModuleHandler`,
55
+ * without executing factories during contract extraction.
56
56
  */
57
57
  export declare function extractHttpApiFromModule(mod: unknown, isHttpApi: (value: unknown) => boolean): Promise<HttpApiLike | null>;
58
58
  /**
@@ -0,0 +1,31 @@
1
+ export type EffectBffEntryModule = {
2
+ api?: unknown;
3
+ layer?: unknown;
4
+ handler?: unknown;
5
+ createHandler?: unknown;
6
+ default?: unknown;
7
+ };
8
+ export type LegacyEffectBffEntryShape = '`handler` export' | 'default request handler';
9
+ export type EffectBffEntryShapeFacts = {
10
+ module: EffectBffEntryModule;
11
+ legacyShape?: LegacyEffectBffEntryShape;
12
+ createHandler?: unknown;
13
+ createHandlerValidatorAware: boolean;
14
+ api?: unknown;
15
+ layer?: unknown;
16
+ hasRuntimeLayer: boolean;
17
+ };
18
+ export type EffectBffEntryShapePredicates = {
19
+ isRequestHandler: (value: unknown) => boolean;
20
+ isValidatorAwareHandlerFactory: (value: unknown) => boolean;
21
+ isHttpApi: (value: unknown) => boolean;
22
+ };
23
+ export declare const EFFECT_VALIDATOR_AWARE_FACTORY: symbol;
24
+ /**
25
+ * True when a custom createHandler factory is produced by defineEffectBff and
26
+ * therefore forwards strict cross-project validation into createHttpApiHandler.
27
+ */
28
+ export declare function isValidatorAwareHandlerFactory(factory: unknown): boolean;
29
+ export declare const strictEffectApproachMessage = "[BFF][Effect] strictEffectApproach is enforced: Effect API entries export defineEffectBff(...) or { api, layer } HttpApi module. Raw handler exports, default request handlers, unbranded custom createHandler factories not valid Effect API entries.";
30
+ export declare function isEffectEntryRecord(value: unknown): value is Record<string, unknown>;
31
+ export declare function classifyEffectBffEntryModule(value: unknown, predicates: EffectBffEntryShapePredicates): EffectBffEntryShapeFacts | null;
@@ -15,6 +15,7 @@ export { HttpTraceContext } from 'effect/unstable/http';
15
15
  export * from 'effect/unstable/httpapi';
16
16
  export { HttpApiBuilder } from 'effect/unstable/httpapi';
17
17
  export * from 'effect/unstable/rpc';
18
+ export { EFFECT_VALIDATOR_AWARE_FACTORY, isValidatorAwareHandlerFactory, } from './entry-shape';
18
19
  export type EffectRuntimeRequirements = Etag.Generator | FileSystem.FileSystem | HttpPlatform.HttpPlatform | HttpRouter.HttpRouter | HttpRouter.Request<'Error', unknown> | HttpRouter.Request<'GlobalError', unknown> | HttpRouter.Request<'GlobalRequires', unknown> | HttpRouter.Request<'Requires', unknown> | Path.Path;
19
20
  export type EffectRuntimeLayer = Layer.Layer<never, never, EffectRuntimeRequirements>;
20
21
  export type EffectRpcSerialization = 'json' | 'ndjson' | 'jsonRpc' | 'ndJsonRpc' | 'msgPack';
@@ -138,23 +139,6 @@ export type EffectDataPlatformValidationOptions = {
138
139
  * cannot bypass it.
139
140
  */
140
141
  export type EffectRequestValidator = (request: Request) => Response | null | undefined;
141
- /**
142
- * Brand stamped on `createHandler` factories that are guaranteed to forward
143
- * `options.validateRequest` into `createHttpApiHandler` — i.e. the policy
144
- * seam runs inside the produced handler, including per batched item.
145
- *
146
- * `defineEffectBff` brands its factory automatically. Hand-written factories
147
- * are NOT assumed to honor `validateRequest`, so strict module resolution
148
- * rejects unbranded factories instead of silently skipping the policy.
149
- *
150
- * Registered via `Symbol.for` so independently loaded runtime copies agree.
151
- */
152
- export declare const EFFECT_VALIDATOR_AWARE_FACTORY: symbol;
153
- /**
154
- * True when `factory` is branded as validator-aware (see
155
- * {@link EFFECT_VALIDATOR_AWARE_FACTORY}).
156
- */
157
- export declare function isValidatorAwareHandlerFactory(factory: unknown): boolean;
158
142
  export type EffectBffHandlerFactory<TApi extends HttpApi.AnyWithProps = HttpApi.AnyWithProps, TLayer extends EffectRuntimeLayer = EffectRuntimeLayer> = (options?: {
159
143
  openapi?: EffectBffOpenApiConfig;
160
144
  rpc?: Partial<EffectRpcBffHandlerOptions>;
@@ -1,4 +1,7 @@
1
1
  export * as OpenTelemetry from '@effect/opentelemetry';
2
+ export * from './backend-federation';
3
+ export { BACKEND_FEDERATION_CONTRACT_VERSION, BACKEND_FEDERATION_EFFECT_EXPOSE, BACKEND_FEDERATION_MANIFEST_FILE, BACKEND_FEDERATION_NODE_ADAPTER_VERSION, type BackendFederatedEffectApiModule, type BackendFederationEntryExports, type BackendFederationLoadEntryPluginOptions, type BackendFederationRemote, type BackendFederationRuntimeOptions, createBackendFederationLoadEntryPlugin, createBackendFederationRuntime, loadBackendFederatedEffectApi, } from './backend-federation';
4
+ export { type BackendFederationManifest, BackendFederationManifestAdapterError, type BackendFederationManifestAdapterErrorCode, type BackendFederationManifestAdapterFallback, type BackendFederationManifestAdapterOptions, type BackendFederationManifestFetchResponse, type BackendFederationVersionBoundaryExpectation, loadBackendFederatedEffectApiFromManifest, loadBackendFederationManifest, resolveBackendFederationRemoteFromManifest, } from './backend-federation-manifest';
2
5
  export { type CreateEffectOperationContextOptions, createEffectOperationContext, type EffectContext, runWithEffectContext, useEffectContext, useOperationContext, } from './context';
3
6
  export { createEffectBffEdgeHandler, createEffectBffTestHandler, dispatchEffectBffRequest, } from './edge';
4
7
  export * from './handler';
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "modern",
18
18
  "modern.js"
19
19
  ],
20
- "version": "3.5.0-ultramodern.28",
20
+ "version": "3.5.0-ultramodern.29",
21
21
  "types": "./dist/types/cli.d.ts",
22
22
  "main": "./dist/cjs/cli.js",
23
23
  "exports": {
@@ -69,6 +69,14 @@
69
69
  },
70
70
  "default": "./dist/cjs/runtime/effect/index.js"
71
71
  },
72
+ "./effect": {
73
+ "types": "./dist/types/runtime/effect/index.d.ts",
74
+ "node": {
75
+ "import": "./dist/esm-node/runtime/effect/index.mjs",
76
+ "require": "./dist/cjs/runtime/effect/index.js"
77
+ },
78
+ "default": "./dist/cjs/runtime/effect/index.js"
79
+ },
72
80
  "./effect-edge": {
73
81
  "types": "./dist/types/runtime/effect/edge.d.ts",
74
82
  "import": "./dist/esm/runtime/effect/edge.mjs",
@@ -124,6 +132,9 @@
124
132
  "effect-server": [
125
133
  "./dist/types/runtime/effect/index.d.ts"
126
134
  ],
135
+ "effect": [
136
+ "./dist/types/runtime/effect/index.d.ts"
137
+ ],
127
138
  "effect-edge": [
128
139
  "./dist/types/runtime/effect/edge.d.ts"
129
140
  ],
@@ -143,6 +154,7 @@
143
154
  },
144
155
  "dependencies": {
145
156
  "@effect/opentelemetry": "4.0.0-beta.92",
157
+ "@module-federation/runtime": "2.6.0",
146
158
  "@opentelemetry/api": "1.9.1",
147
159
  "@opentelemetry/api-logs": "0.219.0",
148
160
  "@opentelemetry/resources": "2.8.0",
@@ -157,12 +169,12 @@
157
169
  "effect": "4.0.0-beta.92",
158
170
  "qs": "^6.15.3",
159
171
  "type-is": "^2.1.0",
160
- "@modern-js/bff-core": "npm:@bleedingdev/modern-js-bff-core@3.5.0-ultramodern.28",
161
- "@modern-js/builder": "npm:@bleedingdev/modern-js-builder@3.5.0-ultramodern.28",
162
- "@modern-js/server-utils": "npm:@bleedingdev/modern-js-server-utils@3.5.0-ultramodern.28",
163
- "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.5.0-ultramodern.28",
164
- "@modern-js/create-request": "npm:@bleedingdev/modern-js-create-request@3.5.0-ultramodern.28",
165
- "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.5.0-ultramodern.28"
172
+ "@modern-js/bff-core": "npm:@bleedingdev/modern-js-bff-core@3.5.0-ultramodern.29",
173
+ "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.5.0-ultramodern.29",
174
+ "@modern-js/create-request": "npm:@bleedingdev/modern-js-create-request@3.5.0-ultramodern.29",
175
+ "@modern-js/server-utils": "npm:@bleedingdev/modern-js-server-utils@3.5.0-ultramodern.29",
176
+ "@modern-js/builder": "npm:@bleedingdev/modern-js-builder@3.5.0-ultramodern.29",
177
+ "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.5.0-ultramodern.29"
166
178
  },
167
179
  "devDependencies": {
168
180
  "@rsbuild/core": "2.1.1",
@@ -174,12 +186,12 @@
174
186
  "memfs": "^4.57.8",
175
187
  "typescript": "^6.0.3",
176
188
  "zod": "^4.4.3",
177
- "@modern-js/bff-runtime": "npm:@bleedingdev/modern-js-bff-runtime@3.5.0-ultramodern.28",
178
- "@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.5.0-ultramodern.28",
179
- "@modern-js/app-tools": "npm:@bleedingdev/modern-js-app-tools@3.5.0-ultramodern.28",
180
- "@modern-js/runtime": "npm:@bleedingdev/modern-js-runtime@3.5.0-ultramodern.28",
181
- "@scripts/rstest-config": "2.66.0",
182
- "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.5.0-ultramodern.28"
189
+ "@modern-js/app-tools": "npm:@bleedingdev/modern-js-app-tools@3.5.0-ultramodern.29",
190
+ "@modern-js/bff-runtime": "npm:@bleedingdev/modern-js-bff-runtime@3.5.0-ultramodern.29",
191
+ "@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.5.0-ultramodern.29",
192
+ "@modern-js/runtime": "npm:@bleedingdev/modern-js-runtime@3.5.0-ultramodern.29",
193
+ "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.5.0-ultramodern.29",
194
+ "@scripts/rstest-config": "2.66.0"
183
195
  },
184
196
  "sideEffects": false,
185
197
  "publishConfig": {