@bleedingdev/modern-js-bff-effect 3.9.0-ultramodern.16 → 3.9.0-ultramodern.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/effect/context.js +28 -4
- package/dist/cjs/effect/edge-dispatcher.js +5 -5
- package/dist/cjs/effect/edge.js +26 -6
- package/dist/cjs/effect/entry-shape.js +39 -14
- package/dist/cjs/effect/index.js +8 -8
- package/dist/cjs/effect/operation-context.js +2 -6
- package/dist/esm/effect/context.mjs +21 -6
- package/dist/esm/effect/edge-dispatcher.mjs +1 -1
- package/dist/esm/effect/edge.mjs +2 -0
- package/dist/esm/effect/entry-shape.mjs +27 -4
- package/dist/esm/effect/index.mjs +1 -1
- package/dist/esm/effect/operation-context.mjs +1 -2
- package/dist/esm-node/effect/context.mjs +21 -6
- package/dist/esm-node/effect/edge-dispatcher.mjs +1 -1
- package/dist/esm-node/effect/edge.mjs +2 -0
- package/dist/esm-node/effect/entry-shape.mjs +28 -8
- package/dist/esm-node/effect/index.mjs +1 -1
- package/dist/esm-node/effect/operation-context.mjs +1 -2
- package/dist/types/effect/context.d.ts +14 -1
- package/dist/types/effect/edge-dispatcher.d.ts +1 -1
- package/dist/types/effect/edge.d.ts +2 -0
- package/dist/types/effect/entry-shape.d.ts +12 -0
- package/dist/types/effect/handler/types.d.ts +1 -1
- package/dist/types/effect/operation-context.d.ts +0 -1
- package/package.json +26 -34
- package/src/effect/context.ts +64 -12
- package/src/effect/edge-dispatcher.ts +7 -6
- package/src/effect/edge.ts +5 -0
- package/src/effect/entry-shape.ts +93 -15
- package/src/effect/handler/batch.ts +0 -2
- package/src/effect/handler/definition.ts +0 -1
- package/src/effect/handler/types.ts +2 -3
- package/src/effect/index.ts +1 -1
- package/src/effect/operation-context.ts +0 -4
- package/dist/cjs/effect/edge-context.js +0 -61
- package/dist/esm/effect/edge-context.mjs +0 -14
- package/dist/esm-node/effect/edge-context.mjs +0 -15
- package/dist/types/effect/edge-context.d.ts +0 -5
- package/src/effect/edge-context.ts +0 -51
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
import type { EffectRpcBffDefinition } from './handler/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Module Federation share through which a backend federation host hands its
|
|
4
|
+
* package-private handler factory registry to the containers it initializes.
|
|
5
|
+
*/
|
|
6
|
+
export declare const EFFECT_BFF_HANDLER_FACTORY_REGISTRY_SHARE = "@modern-js/bff-effect/handler-factory-registry";
|
|
7
|
+
/**
|
|
8
|
+
* @internal Called by generated backend federation containers from `init()`,
|
|
9
|
+
* before any expose evaluates, so factories created by `defineEffectBff`
|
|
10
|
+
* register with the host's registry and endpoints read the host's request
|
|
11
|
+
* storage instead of bundle-local ones.
|
|
12
|
+
*/
|
|
13
|
+
export declare function adoptEffectBffShareScope(shareScope: unknown): Promise<void>;
|
|
2
14
|
type EffectBffEntryModule = {
|
|
3
15
|
api?: unknown;
|
|
4
16
|
layer?: unknown;
|
|
@@ -123,7 +123,7 @@ export type EffectRequestInterceptor = (options: {
|
|
|
123
123
|
request: Request;
|
|
124
124
|
next: () => Promise<Response>;
|
|
125
125
|
}) => Response | Promise<Response>;
|
|
126
|
-
export type EffectBffHandlerFactory<
|
|
126
|
+
export type EffectBffHandlerFactory<_TApi extends HttpApi.Constraint = HttpApi.Top, _TLayer extends EffectRuntimeLayer = EffectRuntimeLayer> = (options?: {
|
|
127
127
|
openapi?: EffectBffOpenApiConfig;
|
|
128
128
|
rpc?: Partial<EffectRpcBffHandlerOptions>;
|
|
129
129
|
dataPlatform?: Partial<EffectDataPlatformValidationOptions>;
|
|
@@ -10,6 +10,5 @@ export type EffectContextStorage = {
|
|
|
10
10
|
getStore: () => EffectContext | undefined;
|
|
11
11
|
run: <TResult>(value: EffectContext, cb: () => TResult) => TResult;
|
|
12
12
|
};
|
|
13
|
-
export declare const kEffectContextStorage: unique symbol;
|
|
14
13
|
export type CreateEffectOperationContextOptions = Omit<EffectContext, 'operationContext'>;
|
|
15
14
|
export declare const createEffectOperationContext: ({ request, path, method, }: CreateEffectOperationContextOptions) => OperationContext;
|
package/package.json
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"modern.js",
|
|
19
19
|
"ultramodern.js"
|
|
20
20
|
],
|
|
21
|
-
"version": "3.9.0-ultramodern.
|
|
21
|
+
"version": "3.9.0-ultramodern.18",
|
|
22
22
|
"files": [
|
|
23
23
|
"dist",
|
|
24
24
|
"src"
|
|
@@ -35,62 +35,49 @@
|
|
|
35
35
|
"./package.json": "./package.json",
|
|
36
36
|
".": {
|
|
37
37
|
"types": "./dist/types/index.d.ts",
|
|
38
|
-
"node":
|
|
39
|
-
|
|
40
|
-
"require": "./dist/cjs/index.js"
|
|
41
|
-
},
|
|
38
|
+
"node": "./dist/esm-node/index.mjs",
|
|
39
|
+
"import": "./dist/esm/index.mjs",
|
|
42
40
|
"default": "./dist/cjs/index.js"
|
|
43
41
|
},
|
|
44
42
|
"./effect": {
|
|
45
43
|
"types": "./dist/types/effect/index.d.ts",
|
|
46
|
-
"node":
|
|
47
|
-
|
|
48
|
-
"require": "./dist/cjs/effect/index.js"
|
|
49
|
-
},
|
|
44
|
+
"node": "./dist/esm-node/effect/index.mjs",
|
|
45
|
+
"import": "./dist/esm/effect/index.mjs",
|
|
50
46
|
"default": "./dist/cjs/effect/index.js"
|
|
51
47
|
},
|
|
48
|
+
"./context": {
|
|
49
|
+
"types": "./dist/types/effect/context.d.ts",
|
|
50
|
+
"node": "./dist/esm-node/effect/context.mjs",
|
|
51
|
+
"import": "./dist/esm/effect/context.mjs",
|
|
52
|
+
"default": "./dist/cjs/effect/context.js"
|
|
53
|
+
},
|
|
52
54
|
"./effect-edge": {
|
|
53
55
|
"types": "./dist/types/effect/edge.d.ts",
|
|
54
|
-
"node":
|
|
55
|
-
"import": "./dist/esm-node/effect/edge.mjs",
|
|
56
|
-
"require": "./dist/cjs/effect/edge.js"
|
|
57
|
-
},
|
|
56
|
+
"node": "./dist/esm-node/effect/edge.mjs",
|
|
58
57
|
"import": "./dist/esm/effect/edge.mjs",
|
|
59
58
|
"default": "./dist/esm/effect/edge.mjs"
|
|
60
59
|
},
|
|
61
60
|
"./effect-client": {
|
|
62
61
|
"types": "./dist/types/effect-client/index.d.ts",
|
|
63
|
-
"node":
|
|
64
|
-
"import": "./dist/esm-node/effect-client/index.mjs",
|
|
65
|
-
"require": "./dist/cjs/effect-client/index.js"
|
|
66
|
-
},
|
|
62
|
+
"node": "./dist/esm-node/effect-client/index.mjs",
|
|
67
63
|
"import": "./dist/esm/effect-client/index.mjs",
|
|
68
64
|
"default": "./dist/esm/effect-client/index.mjs"
|
|
69
65
|
},
|
|
70
66
|
"./microvertical-api": {
|
|
71
67
|
"types": "./dist/types/microvertical-api.d.ts",
|
|
72
|
-
"node":
|
|
73
|
-
"import": "./dist/esm-node/microvertical-api.mjs",
|
|
74
|
-
"require": "./dist/cjs/microvertical-api.js"
|
|
75
|
-
},
|
|
68
|
+
"node": "./dist/esm-node/microvertical-api.mjs",
|
|
76
69
|
"import": "./dist/esm/microvertical-api.mjs",
|
|
77
70
|
"default": "./dist/esm/microvertical-api.mjs"
|
|
78
71
|
},
|
|
79
72
|
"./data-platform": {
|
|
80
73
|
"types": "./dist/types/data-platform/index.d.ts",
|
|
81
|
-
"node":
|
|
82
|
-
"import": "./dist/esm-node/data-platform/index.mjs",
|
|
83
|
-
"require": "./dist/cjs/data-platform/index.js"
|
|
84
|
-
},
|
|
74
|
+
"node": "./dist/esm-node/data-platform/index.mjs",
|
|
85
75
|
"import": "./dist/esm/data-platform/index.mjs",
|
|
86
76
|
"default": "./dist/esm/data-platform/index.mjs"
|
|
87
77
|
},
|
|
88
78
|
"./assembly": {
|
|
89
79
|
"types": "./dist/types/assembly.d.ts",
|
|
90
|
-
"node":
|
|
91
|
-
"import": "./dist/esm-node/assembly.mjs",
|
|
92
|
-
"require": "./dist/cjs/assembly.js"
|
|
93
|
-
},
|
|
80
|
+
"node": "./dist/esm-node/assembly.mjs",
|
|
94
81
|
"default": "./dist/esm/assembly.mjs"
|
|
95
82
|
}
|
|
96
83
|
},
|
|
@@ -104,6 +91,10 @@
|
|
|
104
91
|
"./dist/types/effect/index.d.ts",
|
|
105
92
|
"./src/effect/index.ts"
|
|
106
93
|
],
|
|
94
|
+
"context": [
|
|
95
|
+
"./dist/types/effect/context.d.ts",
|
|
96
|
+
"./src/effect/context.ts"
|
|
97
|
+
],
|
|
107
98
|
"effect-edge": [
|
|
108
99
|
"./dist/types/effect/edge.d.ts",
|
|
109
100
|
"./src/effect/edge.ts"
|
|
@@ -130,10 +121,10 @@
|
|
|
130
121
|
"node": ">=26.7.0"
|
|
131
122
|
},
|
|
132
123
|
"dependencies": {
|
|
133
|
-
"@modern-js/bff-core": "npm:@bleedingdev/modern-js-bff-core@3.9.0-ultramodern.
|
|
134
|
-
"@modern-js/create-request": "npm:@bleedingdev/modern-js-create-request@3.9.0-ultramodern.
|
|
135
|
-
"@modern-js/runtime-extensions": "npm:@bleedingdev/modern-js-runtime-extensions@3.9.0-ultramodern.
|
|
136
|
-
"@modern-js/server-runtime-extensions": "npm:@bleedingdev/modern-js-server-runtime-extensions@3.9.0-ultramodern.
|
|
124
|
+
"@modern-js/bff-core": "npm:@bleedingdev/modern-js-bff-core@3.9.0-ultramodern.18",
|
|
125
|
+
"@modern-js/create-request": "npm:@bleedingdev/modern-js-create-request@3.9.0-ultramodern.18",
|
|
126
|
+
"@modern-js/runtime-extensions": "npm:@bleedingdev/modern-js-runtime-extensions@3.9.0-ultramodern.18",
|
|
127
|
+
"@modern-js/server-runtime-extensions": "npm:@bleedingdev/modern-js-server-runtime-extensions@3.9.0-ultramodern.18",
|
|
137
128
|
"@opentelemetry/api": "1.9.1",
|
|
138
129
|
"@opentelemetry/api-logs": "0.222.0",
|
|
139
130
|
"@opentelemetry/resources": "2.11.0",
|
|
@@ -163,7 +154,8 @@
|
|
|
163
154
|
"@types/node": "^26.6.2",
|
|
164
155
|
"@types/react": "^19.3.0",
|
|
165
156
|
"@typescript/native-preview": "7.0.0-dev.20260707.2",
|
|
166
|
-
"effect": "npm:@bleedingdev/effect@4.0.0-rc.117"
|
|
157
|
+
"effect": "npm:@bleedingdev/effect@4.0.0-rc.117",
|
|
158
|
+
"esbuild": "^0.28.2"
|
|
167
159
|
},
|
|
168
160
|
"sideEffects": false,
|
|
169
161
|
"publishConfig": {
|
package/src/effect/context.ts
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
// @effect-diagnostics strictBooleanExpressions:off
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
type EffectContext,
|
|
5
|
-
type EffectContextStorage,
|
|
6
|
-
kEffectContextStorage,
|
|
7
|
-
} from './operation-context';
|
|
2
|
+
import type { EffectContext, EffectContextStorage } from './operation-context';
|
|
8
3
|
|
|
9
4
|
export {
|
|
10
5
|
type CreateEffectOperationContextOptions,
|
|
@@ -12,21 +7,51 @@ export {
|
|
|
12
7
|
type EffectContext,
|
|
13
8
|
} from './operation-context';
|
|
14
9
|
|
|
10
|
+
type EffectContextStorageConstructor = new () => EffectContextStorage;
|
|
11
|
+
|
|
12
|
+
// One storage for every entry: each imports this module as
|
|
13
|
+
// `@modern-js/bff-effect/context`, the request that Module Federation shares
|
|
14
|
+
// and that the BFF bundle keeps external, so the server and its lambdas load
|
|
15
|
+
// the same instance. A backend federation container bundles its own copy and
|
|
16
|
+
// adopts the host's storage in init() instead.
|
|
15
17
|
const globalStore = globalThis as typeof globalThis & {
|
|
16
|
-
|
|
18
|
+
process?: {
|
|
19
|
+
getBuiltinModule?: (id: string) => unknown;
|
|
20
|
+
};
|
|
17
21
|
};
|
|
18
22
|
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
23
|
+
const asyncHooks = globalStore.process?.getBuiltinModule?.(
|
|
24
|
+
'node:async_hooks',
|
|
25
|
+
) as { AsyncLocalStorage?: EffectContextStorageConstructor } | undefined;
|
|
26
|
+
const AsyncLocalStorage = asyncHooks?.AsyncLocalStorage;
|
|
27
|
+
if (typeof AsyncLocalStorage !== 'function') {
|
|
28
|
+
throw new Error(
|
|
29
|
+
'[BFF][Effect] The edge runtime must provide AsyncLocalStorage. Enable Node.js compatibility or the nodejs_als compatibility flag.',
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Module Federation share through which a backend federation host hands its
|
|
35
|
+
* request storage to the containers it initializes.
|
|
36
|
+
*/
|
|
37
|
+
export const EFFECT_BFF_CONTEXT_STORAGE_SHARE =
|
|
38
|
+
'@modern-js/bff-effect/context-storage';
|
|
39
|
+
|
|
40
|
+
let effectContextStorage: EffectContextStorage = new AsyncLocalStorage();
|
|
41
|
+
let effectContextStorageUsed = false;
|
|
42
|
+
|
|
43
|
+
const usedEffectContextStorage = () => {
|
|
44
|
+
effectContextStorageUsed = true;
|
|
45
|
+
return effectContextStorage;
|
|
46
|
+
};
|
|
22
47
|
|
|
23
48
|
export const runWithEffectContext = <T>(
|
|
24
49
|
context: EffectContext,
|
|
25
50
|
cb: () => T,
|
|
26
|
-
): T =>
|
|
51
|
+
): T => usedEffectContextStorage().run(context, cb);
|
|
27
52
|
|
|
28
53
|
export const useEffectContext = (): EffectContext => {
|
|
29
|
-
const context =
|
|
54
|
+
const context = usedEffectContextStorage().getStore();
|
|
30
55
|
if (!context) {
|
|
31
56
|
throw new Error(`Can't call useEffectContext out of Effect runtime scope`);
|
|
32
57
|
}
|
|
@@ -34,4 +59,31 @@ export const useEffectContext = (): EffectContext => {
|
|
|
34
59
|
return context;
|
|
35
60
|
};
|
|
36
61
|
|
|
62
|
+
/** @internal The storage a backend federation host shares with containers. */
|
|
63
|
+
export const getEffectContextStorage = (): EffectContextStorage =>
|
|
64
|
+
effectContextStorage;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @internal Called through `adoptEffectBffShareScope()` from a backend
|
|
68
|
+
* federation container's `init()`, so its endpoints read the context the
|
|
69
|
+
* host dispatcher enters.
|
|
70
|
+
*/
|
|
71
|
+
export function adoptEffectContextStorage(storage: unknown): void {
|
|
72
|
+
const candidate = storage as Partial<EffectContextStorage> | undefined;
|
|
73
|
+
if (
|
|
74
|
+
typeof candidate?.run !== 'function' ||
|
|
75
|
+
typeof candidate.getStore !== 'function'
|
|
76
|
+
) {
|
|
77
|
+
throw new Error(
|
|
78
|
+
`[BFF][Effect] Share ${EFFECT_BFF_CONTEXT_STORAGE_SHARE} must provide an AsyncLocalStorage.`,
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
if (effectContextStorageUsed && candidate !== effectContextStorage) {
|
|
82
|
+
throw new Error(
|
|
83
|
+
'[BFF][Effect] A backend federation container received the host request storage after an Effect API already used its own. Evaluate exposes only after container init().',
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
effectContextStorage = candidate as EffectContextStorage;
|
|
87
|
+
}
|
|
88
|
+
|
|
37
89
|
export const useOperationContext = () => useEffectContext().operationContext;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
// @effect-diagnostics anyUnknownInErrorContext:off asyncFunction:off strictBooleanExpressions:off
|
|
2
|
+
|
|
3
|
+
import { runWithEffectContext } from '@modern-js/bff-effect/context';
|
|
2
4
|
import {
|
|
3
5
|
evaluateCrossProjectPolicy,
|
|
4
6
|
type NormalizedCrossProjectPolicy,
|
|
@@ -10,7 +12,6 @@ import {
|
|
|
10
12
|
type DispatchEffectBffRequestOptions,
|
|
11
13
|
dispatchEffectBffRequestWithContext,
|
|
12
14
|
} from './dispatch';
|
|
13
|
-
import { runWithEffectContext } from './edge-context';
|
|
14
15
|
import type {
|
|
15
16
|
EffectBffOpenApiConfig,
|
|
16
17
|
EffectDataPlatformValidationOptions,
|
|
@@ -22,6 +23,11 @@ import {
|
|
|
22
23
|
} from './module';
|
|
23
24
|
import type { EffectContext } from './operation-context';
|
|
24
25
|
|
|
26
|
+
export {
|
|
27
|
+
runWithEffectContext,
|
|
28
|
+
useEffectContext,
|
|
29
|
+
useOperationContext,
|
|
30
|
+
} from '@modern-js/bff-effect/context';
|
|
25
31
|
export * as Config from 'effect/Config';
|
|
26
32
|
export * as Effect from 'effect/Effect';
|
|
27
33
|
export * as Layer from 'effect/Layer';
|
|
@@ -85,11 +91,6 @@ export {
|
|
|
85
91
|
RpcWorker,
|
|
86
92
|
Utils,
|
|
87
93
|
} from 'effect/unstable/rpc';
|
|
88
|
-
export {
|
|
89
|
-
runWithEffectContext,
|
|
90
|
-
useEffectContext,
|
|
91
|
-
useOperationContext,
|
|
92
|
-
} from './edge-context';
|
|
93
94
|
export type {
|
|
94
95
|
EffectApiClientFromApi,
|
|
95
96
|
EffectBffDefinition,
|
package/src/effect/edge.ts
CHANGED
|
@@ -1,2 +1,7 @@
|
|
|
1
|
+
export { EFFECT_BFF_CONTEXT_STORAGE_SHARE } from '@modern-js/bff-effect/context';
|
|
1
2
|
export * from './edge-dispatcher';
|
|
3
|
+
export {
|
|
4
|
+
adoptEffectBffShareScope,
|
|
5
|
+
EFFECT_BFF_HANDLER_FACTORY_REGISTRY_SHARE,
|
|
6
|
+
} from './entry-shape';
|
|
2
7
|
export { createEffectBffEdgeDispatcherFactory } from './generated-entry';
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
adoptEffectContextStorage,
|
|
3
|
+
EFFECT_BFF_CONTEXT_STORAGE_SHARE,
|
|
4
|
+
} from '@modern-js/bff-effect/context';
|
|
1
5
|
import type { EffectRpcBffDefinition } from './handler/types';
|
|
2
6
|
|
|
3
7
|
type ValidatorAwareHandlerFactoryRegistry = {
|
|
@@ -5,9 +9,12 @@ type ValidatorAwareHandlerFactoryRegistry = {
|
|
|
5
9
|
is(factory: unknown): boolean;
|
|
6
10
|
};
|
|
7
11
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Module Federation share through which a backend federation host hands its
|
|
14
|
+
* package-private handler factory registry to the containers it initializes.
|
|
15
|
+
*/
|
|
16
|
+
export const EFFECT_BFF_HANDLER_FACTORY_REGISTRY_SHARE =
|
|
17
|
+
'@modern-js/bff-effect/handler-factory-registry';
|
|
11
18
|
|
|
12
19
|
function createLocalValidatorAwareHandlerFactoryRegistry(): ValidatorAwareHandlerFactoryRegistry {
|
|
13
20
|
const factories = new WeakSet<Function>();
|
|
@@ -25,11 +32,8 @@ function createLocalValidatorAwareHandlerFactoryRegistry(): ValidatorAwareHandle
|
|
|
25
32
|
function loadNodeValidatorAwareHandlerFactoryRegistry(): ValidatorAwareHandlerFactoryRegistry {
|
|
26
33
|
const moduleUrl = import.meta.url;
|
|
27
34
|
if (typeof moduleUrl !== 'string' || !moduleUrl.startsWith('file:')) {
|
|
28
|
-
// A
|
|
29
|
-
//
|
|
30
|
-
if (typeof __modernjs_backend_private_capability__ !== 'undefined') {
|
|
31
|
-
return __modernjs_backend_private_capability__;
|
|
32
|
-
}
|
|
35
|
+
// A bundled backend federation container has no file URL; its host share
|
|
36
|
+
// arrives through adoptEffectBffShareScope() during container init.
|
|
33
37
|
return createLocalValidatorAwareHandlerFactoryRegistry();
|
|
34
38
|
}
|
|
35
39
|
|
|
@@ -55,11 +59,85 @@ function loadNodeValidatorAwareHandlerFactoryRegistry(): ValidatorAwareHandlerFa
|
|
|
55
59
|
|
|
56
60
|
declare const __MODERN_EFFECT_NODE_RUNTIME__: boolean;
|
|
57
61
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
let validatorAwareHandlerFactoryRegistry:
|
|
63
|
+
| ValidatorAwareHandlerFactoryRegistry
|
|
64
|
+
| undefined;
|
|
65
|
+
|
|
66
|
+
function handlerFactoryRegistry(): ValidatorAwareHandlerFactoryRegistry {
|
|
67
|
+
validatorAwareHandlerFactoryRegistry ??=
|
|
68
|
+
typeof __MODERN_EFFECT_NODE_RUNTIME__ !== 'undefined' &&
|
|
69
|
+
__MODERN_EFFECT_NODE_RUNTIME__
|
|
70
|
+
? loadNodeValidatorAwareHandlerFactoryRegistry()
|
|
71
|
+
: createLocalValidatorAwareHandlerFactoryRegistry();
|
|
72
|
+
return validatorAwareHandlerFactoryRegistry;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
type SharedVersions = Record<string, { get?: () => unknown } | undefined>;
|
|
76
|
+
|
|
77
|
+
const adoptShared = (
|
|
78
|
+
shareScope: unknown,
|
|
79
|
+
name: string,
|
|
80
|
+
adopt: (value: unknown) => void,
|
|
81
|
+
): Promise<void> => {
|
|
82
|
+
const versions =
|
|
83
|
+
typeof shareScope === 'object' && shareScope !== null
|
|
84
|
+
? (shareScope as Record<string, SharedVersions | undefined>)[name]
|
|
85
|
+
: undefined;
|
|
86
|
+
const shared =
|
|
87
|
+
versions === undefined ? undefined : Object.values(versions)[0];
|
|
88
|
+
if (typeof shared?.get !== 'function') {
|
|
89
|
+
return Promise.resolve();
|
|
90
|
+
}
|
|
91
|
+
return Promise.resolve(shared.get()).then(factory =>
|
|
92
|
+
adopt(typeof factory === 'function' ? factory() : undefined),
|
|
93
|
+
);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* @internal Called by generated backend federation containers from `init()`,
|
|
98
|
+
* before any expose evaluates, so factories created by `defineEffectBff`
|
|
99
|
+
* register with the host's registry and endpoints read the host's request
|
|
100
|
+
* storage instead of bundle-local ones.
|
|
101
|
+
*/
|
|
102
|
+
export function adoptEffectBffShareScope(shareScope: unknown): Promise<void> {
|
|
103
|
+
return Promise.all([
|
|
104
|
+
adoptShared(
|
|
105
|
+
shareScope,
|
|
106
|
+
EFFECT_BFF_HANDLER_FACTORY_REGISTRY_SHARE,
|
|
107
|
+
registry =>
|
|
108
|
+
adoptHandlerFactoryRegistry(
|
|
109
|
+
registry as ValidatorAwareHandlerFactoryRegistry | undefined,
|
|
110
|
+
),
|
|
111
|
+
),
|
|
112
|
+
adoptShared(
|
|
113
|
+
shareScope,
|
|
114
|
+
EFFECT_BFF_CONTEXT_STORAGE_SHARE,
|
|
115
|
+
adoptEffectContextStorage,
|
|
116
|
+
),
|
|
117
|
+
]).then(() => undefined);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function adoptHandlerFactoryRegistry(
|
|
121
|
+
registry: ValidatorAwareHandlerFactoryRegistry | undefined,
|
|
122
|
+
): void {
|
|
123
|
+
if (
|
|
124
|
+
typeof registry?.register !== 'function' ||
|
|
125
|
+
typeof registry.is !== 'function'
|
|
126
|
+
) {
|
|
127
|
+
throw new Error(
|
|
128
|
+
`[BFF][Effect] Share ${EFFECT_BFF_HANDLER_FACTORY_REGISTRY_SHARE} must provide a handler factory registry.`,
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
if (
|
|
132
|
+
validatorAwareHandlerFactoryRegistry !== undefined &&
|
|
133
|
+
validatorAwareHandlerFactoryRegistry !== registry
|
|
134
|
+
) {
|
|
135
|
+
throw new Error(
|
|
136
|
+
'[BFF][Effect] A backend federation container received the host handler factory registry after an Effect API already used its own. Evaluate exposes only after container init().',
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
validatorAwareHandlerFactoryRegistry = registry;
|
|
140
|
+
}
|
|
63
141
|
|
|
64
142
|
type EffectBffEntryModule = {
|
|
65
143
|
api?: unknown;
|
|
@@ -94,7 +172,7 @@ type EffectBffEntryShapePredicates = {
|
|
|
94
172
|
export function registerValidatorAwareHandlerFactory<TFactory extends Function>(
|
|
95
173
|
factory: TFactory,
|
|
96
174
|
): TFactory {
|
|
97
|
-
return
|
|
175
|
+
return handlerFactoryRegistry().register(factory);
|
|
98
176
|
}
|
|
99
177
|
|
|
100
178
|
/**
|
|
@@ -102,7 +180,7 @@ export function registerValidatorAwareHandlerFactory<TFactory extends Function>(
|
|
|
102
180
|
* therefore forwards strict cross-project validation into createHttpApiHandler.
|
|
103
181
|
*/
|
|
104
182
|
export function isValidatorAwareHandlerFactory(factory: unknown): boolean {
|
|
105
|
-
return
|
|
183
|
+
return handlerFactoryRegistry().is(factory);
|
|
106
184
|
}
|
|
107
185
|
|
|
108
186
|
export const strictEffectApproachMessage =
|
|
@@ -6,11 +6,9 @@ import {
|
|
|
6
6
|
type DataBatchResponseItem,
|
|
7
7
|
DEFAULT_DATA_BATCH_ENDPOINT,
|
|
8
8
|
isPlainObject,
|
|
9
|
-
measureTextBytes,
|
|
10
9
|
normalizeMethod as normalizeItemMethod,
|
|
11
10
|
} from '../../data-platform';
|
|
12
11
|
import { encodeBatchText } from '../../data-platform/batch/protocol';
|
|
13
|
-
import { toHeaderRecord } from '../../headers';
|
|
14
12
|
|
|
15
13
|
export { toHeaderRecord } from '../../headers';
|
|
16
14
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// @effect-diagnostics anyUnknownInErrorContext:off asyncFunction:off globalDate:off globalTimers:off newPromise:off strictBooleanExpressions:off
|
|
2
2
|
import type { FileSystem, Path } from 'effect';
|
|
3
3
|
import * as Context from 'effect/Context';
|
|
4
|
-
import type * as EffectType from 'effect/Effect';
|
|
5
4
|
import type * as Layer from 'effect/Layer';
|
|
6
5
|
import type { Etag, HttpPlatform, HttpRouter } from 'effect/unstable/http';
|
|
7
6
|
import type {
|
|
@@ -200,8 +199,8 @@ export type EffectRequestInterceptor = (options: {
|
|
|
200
199
|
}) => Response | Promise<Response>;
|
|
201
200
|
|
|
202
201
|
export type EffectBffHandlerFactory<
|
|
203
|
-
|
|
204
|
-
|
|
202
|
+
_TApi extends HttpApi.Constraint = HttpApi.Top,
|
|
203
|
+
_TLayer extends EffectRuntimeLayer = EffectRuntimeLayer,
|
|
205
204
|
> = (options?: {
|
|
206
205
|
openapi?: EffectBffOpenApiConfig;
|
|
207
206
|
rpc?: Partial<EffectRpcBffHandlerOptions>;
|
package/src/effect/index.ts
CHANGED
|
@@ -21,10 +21,6 @@ export type EffectContextStorage = {
|
|
|
21
21
|
run: <TResult>(value: EffectContext, cb: () => TResult) => TResult;
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
-
export const kEffectContextStorage = Symbol.for(
|
|
25
|
-
'modernjs.plugin-bff.effectContextStorage',
|
|
26
|
-
);
|
|
27
|
-
|
|
28
24
|
export type CreateEffectOperationContextOptions = Omit<
|
|
29
25
|
EffectContext,
|
|
30
26
|
'operationContext'
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __webpack_require__ = {};
|
|
3
|
-
(()=>{
|
|
4
|
-
__webpack_require__.d = (exports1, getters, values)=>{
|
|
5
|
-
var define = (defs, kind)=>{
|
|
6
|
-
for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
7
|
-
enumerable: true,
|
|
8
|
-
[kind]: defs[key]
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
define(getters, "get");
|
|
12
|
-
define(values, "value");
|
|
13
|
-
};
|
|
14
|
-
})();
|
|
15
|
-
(()=>{
|
|
16
|
-
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
17
|
-
})();
|
|
18
|
-
(()=>{
|
|
19
|
-
__webpack_require__.r = (exports1)=>{
|
|
20
|
-
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
21
|
-
value: 'Module'
|
|
22
|
-
});
|
|
23
|
-
Object.defineProperty(exports1, '__esModule', {
|
|
24
|
-
value: true
|
|
25
|
-
});
|
|
26
|
-
};
|
|
27
|
-
})();
|
|
28
|
-
var __webpack_exports__ = {};
|
|
29
|
-
__webpack_require__.r(__webpack_exports__);
|
|
30
|
-
__webpack_require__.d(__webpack_exports__, {
|
|
31
|
-
createEffectOperationContext: ()=>external_operation_context_js_namespaceObject.createEffectOperationContext,
|
|
32
|
-
runWithEffectContext: ()=>runWithEffectContext,
|
|
33
|
-
useEffectContext: ()=>useEffectContext,
|
|
34
|
-
useOperationContext: ()=>useOperationContext
|
|
35
|
-
});
|
|
36
|
-
const external_operation_context_js_namespaceObject = require("./operation-context.js");
|
|
37
|
-
const globalStore = globalThis;
|
|
38
|
-
const asyncHooks = globalStore.process?.getBuiltinModule?.('node:async_hooks');
|
|
39
|
-
const AsyncLocalStorage = asyncHooks?.AsyncLocalStorage;
|
|
40
|
-
if ('function' != typeof AsyncLocalStorage) throw new Error('[BFF][Effect] The edge runtime must provide AsyncLocalStorage. Enable Node.js compatibility or the nodejs_als compatibility flag.');
|
|
41
|
-
const effectContextStorage = globalStore[external_operation_context_js_namespaceObject.kEffectContextStorage] ?? (globalStore[external_operation_context_js_namespaceObject.kEffectContextStorage] = new AsyncLocalStorage());
|
|
42
|
-
const runWithEffectContext = (context, cb)=>effectContextStorage.run(context, cb);
|
|
43
|
-
const useEffectContext = ()=>{
|
|
44
|
-
const context = effectContextStorage.getStore();
|
|
45
|
-
if (!context) throw new Error("Can't call useEffectContext out of Effect runtime scope");
|
|
46
|
-
return context;
|
|
47
|
-
};
|
|
48
|
-
const useOperationContext = ()=>useEffectContext().operationContext;
|
|
49
|
-
exports.createEffectOperationContext = __webpack_exports__.createEffectOperationContext;
|
|
50
|
-
exports.runWithEffectContext = __webpack_exports__.runWithEffectContext;
|
|
51
|
-
exports.useEffectContext = __webpack_exports__.useEffectContext;
|
|
52
|
-
exports.useOperationContext = __webpack_exports__.useOperationContext;
|
|
53
|
-
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
54
|
-
"createEffectOperationContext",
|
|
55
|
-
"runWithEffectContext",
|
|
56
|
-
"useEffectContext",
|
|
57
|
-
"useOperationContext"
|
|
58
|
-
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
59
|
-
Object.defineProperty(exports, '__esModule', {
|
|
60
|
-
value: true
|
|
61
|
-
});
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { createEffectOperationContext, kEffectContextStorage } from "./operation-context.mjs";
|
|
2
|
-
const globalStore = globalThis;
|
|
3
|
-
const asyncHooks = globalStore.process?.getBuiltinModule?.('node:async_hooks');
|
|
4
|
-
const AsyncLocalStorage = asyncHooks?.AsyncLocalStorage;
|
|
5
|
-
if ('function' != typeof AsyncLocalStorage) throw new Error('[BFF][Effect] The edge runtime must provide AsyncLocalStorage. Enable Node.js compatibility or the nodejs_als compatibility flag.');
|
|
6
|
-
const effectContextStorage = globalStore[kEffectContextStorage] ?? (globalStore[kEffectContextStorage] = new AsyncLocalStorage());
|
|
7
|
-
const runWithEffectContext = (context, cb)=>effectContextStorage.run(context, cb);
|
|
8
|
-
const useEffectContext = ()=>{
|
|
9
|
-
const context = effectContextStorage.getStore();
|
|
10
|
-
if (!context) throw new Error("Can't call useEffectContext out of Effect runtime scope");
|
|
11
|
-
return context;
|
|
12
|
-
};
|
|
13
|
-
const useOperationContext = ()=>useEffectContext().operationContext;
|
|
14
|
-
export { createEffectOperationContext, runWithEffectContext, useEffectContext, useOperationContext };
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import "node:module";
|
|
2
|
-
import { createEffectOperationContext, kEffectContextStorage } from "./operation-context.mjs";
|
|
3
|
-
const globalStore = globalThis;
|
|
4
|
-
const asyncHooks = globalStore.process?.getBuiltinModule?.('node:async_hooks');
|
|
5
|
-
const AsyncLocalStorage = asyncHooks?.AsyncLocalStorage;
|
|
6
|
-
if ('function' != typeof AsyncLocalStorage) throw new Error('[BFF][Effect] The edge runtime must provide AsyncLocalStorage. Enable Node.js compatibility or the nodejs_als compatibility flag.');
|
|
7
|
-
const effectContextStorage = globalStore[kEffectContextStorage] ?? (globalStore[kEffectContextStorage] = new AsyncLocalStorage());
|
|
8
|
-
const runWithEffectContext = (context, cb)=>effectContextStorage.run(context, cb);
|
|
9
|
-
const useEffectContext = ()=>{
|
|
10
|
-
const context = effectContextStorage.getStore();
|
|
11
|
-
if (!context) throw new Error("Can't call useEffectContext out of Effect runtime scope");
|
|
12
|
-
return context;
|
|
13
|
-
};
|
|
14
|
-
const useOperationContext = ()=>useEffectContext().operationContext;
|
|
15
|
-
export { createEffectOperationContext, runWithEffectContext, useEffectContext, useOperationContext };
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { type EffectContext } from './operation-context.js';
|
|
2
|
-
export { type CreateEffectOperationContextOptions, createEffectOperationContext, type EffectContext, } from './operation-context.js';
|
|
3
|
-
export declare const runWithEffectContext: <T>(context: EffectContext, cb: () => T) => T;
|
|
4
|
-
export declare const useEffectContext: () => EffectContext;
|
|
5
|
-
export declare const useOperationContext: () => import("@modern-js/runtime-extensions/request-context").OperationContext;
|