@bleedingdev/modern-js-plugin-bff 3.5.0-ultramodern.99 → 3.8.1-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.
- package/dist/cjs/cli/compress.js +1 -1
- package/dist/cjs/cli/generator.js +106 -97
- package/dist/cjs/cli/serverGlobalVars.js +43 -57
- package/dist/cjs/cli.js +6 -2
- package/dist/cjs/loader.js +6 -5
- package/dist/cjs/runtime/effect/adapter/cross-project-policy.js +17 -12
- package/dist/cjs/runtime/effect/adapter/entry.js +13 -5
- package/dist/cjs/runtime/effect/adapter/error-response.js +11 -9
- package/dist/cjs/runtime/effect/adapter.js +2 -2
- package/dist/cjs/runtime/effect/backend-federation/load.js +26 -17
- package/dist/cjs/runtime/effect/backend-federation/plugin.js +12 -2
- package/dist/cjs/runtime/effect/backend-federation/remotes.js +5 -4
- package/dist/cjs/runtime/effect/backend-federation/runtime.js +80 -16
- package/dist/cjs/runtime/effect/edge-dispatcher.js +148 -0
- package/dist/cjs/runtime/effect/edge.js +19 -100
- package/dist/cjs/runtime/effect/handler/definition.js +1 -0
- package/dist/cjs/runtime/effect/handler/http.js +17 -6
- package/dist/cjs/utils/crossProjectApiPlugin.js +21 -2
- package/dist/cjs/utils/effect-client-generator/generator.js +17 -16
- package/dist/cjs/utils/effect-client-generator/paths.js +4 -15
- package/dist/cjs/utils/effect-client-generator/rendering.js +8 -19
- package/dist/cjs/utils/effect-client-generator/runtime.js +15 -32
- package/dist/cjs/utils/effectSourceLoader.js +70 -10
- package/dist/cjs/utils/pluginGenerator.js +4 -4
- package/dist/esm/cli/compress.mjs +1 -1
- package/dist/esm/cli/generator.mjs +108 -98
- package/dist/esm/cli/serverGlobalVars.mjs +44 -48
- package/dist/esm/cli.mjs +2 -0
- package/dist/esm/loader.mjs +6 -5
- package/dist/esm/runtime/effect/adapter/cross-project-policy.mjs +17 -12
- package/dist/esm/runtime/effect/adapter/entry.mjs +13 -5
- package/dist/esm/runtime/effect/adapter/error-response.mjs +11 -9
- package/dist/esm/runtime/effect/adapter.mjs +3 -3
- package/dist/esm/runtime/effect/backend-federation/load.mjs +26 -17
- package/dist/esm/runtime/effect/backend-federation/plugin.mjs +12 -2
- package/dist/esm/runtime/effect/backend-federation/remotes.mjs +5 -4
- package/dist/esm/runtime/effect/backend-federation/runtime.mjs +80 -16
- package/dist/esm/runtime/effect/edge-dispatcher.mjs +38 -0
- package/dist/esm/runtime/effect/edge.mjs +1 -38
- package/dist/esm/runtime/effect/handler/definition.mjs +1 -0
- package/dist/esm/runtime/effect/handler/http.mjs +17 -6
- package/dist/esm/utils/crossProjectApiPlugin.mjs +16 -3
- package/dist/esm/utils/effect-client-generator/generator.mjs +17 -16
- package/dist/esm/utils/effect-client-generator/paths.mjs +5 -6
- package/dist/esm/utils/effect-client-generator/rendering.mjs +9 -10
- package/dist/esm/utils/effect-client-generator/runtime.mjs +16 -23
- package/dist/esm/utils/effectSourceLoader.mjs +69 -12
- package/dist/esm/utils/pluginGenerator.mjs +5 -5
- package/dist/esm-node/cli/compress.mjs +1 -1
- package/dist/esm-node/cli/generator.mjs +108 -98
- package/dist/esm-node/cli/serverGlobalVars.mjs +44 -48
- package/dist/esm-node/cli.mjs +2 -0
- package/dist/esm-node/loader.mjs +6 -5
- package/dist/esm-node/runtime/effect/adapter/cross-project-policy.mjs +17 -12
- package/dist/esm-node/runtime/effect/adapter/entry.mjs +13 -5
- package/dist/esm-node/runtime/effect/adapter/error-response.mjs +11 -9
- package/dist/esm-node/runtime/effect/adapter.mjs +3 -3
- package/dist/esm-node/runtime/effect/backend-federation/load.mjs +26 -17
- package/dist/esm-node/runtime/effect/backend-federation/plugin.mjs +12 -2
- package/dist/esm-node/runtime/effect/backend-federation/remotes.mjs +5 -4
- package/dist/esm-node/runtime/effect/backend-federation/runtime.mjs +80 -16
- package/dist/esm-node/runtime/effect/edge-dispatcher.mjs +39 -0
- package/dist/esm-node/runtime/effect/edge.mjs +1 -38
- package/dist/esm-node/runtime/effect/handler/definition.mjs +1 -0
- package/dist/esm-node/runtime/effect/handler/http.mjs +17 -6
- package/dist/esm-node/utils/crossProjectApiPlugin.mjs +16 -3
- package/dist/esm-node/utils/effect-client-generator/generator.mjs +17 -16
- package/dist/esm-node/utils/effect-client-generator/paths.mjs +5 -6
- package/dist/esm-node/utils/effect-client-generator/rendering.mjs +9 -10
- package/dist/esm-node/utils/effect-client-generator/runtime.mjs +16 -23
- package/dist/esm-node/utils/effectSourceLoader.mjs +69 -12
- package/dist/esm-node/utils/pluginGenerator.mjs +5 -5
- package/dist/types/cli/generator.d.ts +2 -2
- package/dist/types/cli/serverGlobalVars.d.ts +4 -2
- package/dist/types/cli.d.ts +1 -0
- package/dist/types/runtime/effect/adapter/cross-project-policy.d.ts +1 -1
- package/dist/types/runtime/effect/backend-federation/runtime.d.ts +1 -1
- package/dist/types/runtime/effect/edge-dispatcher.d.ts +26 -0
- package/dist/types/runtime/effect/edge.d.ts +1 -26
- package/dist/types/runtime/effect/handler/definition.d.ts +2 -12
- package/dist/types/runtime/effect/handler/http.d.ts +2 -1
- package/dist/types/runtime/effect/handler/types.d.ts +5 -0
- package/dist/types/utils/crossProjectApiPlugin.d.ts +2 -0
- package/dist/types/utils/effectSourceLoader.d.ts +10 -0
- package/dist/types/utils/pluginGenerator.d.ts +3 -1
- package/package.json +34 -18
|
@@ -3,27 +3,36 @@ import { BACKEND_FEDERATION_EFFECT_EXPOSE } from "@modern-js/utils/universal";
|
|
|
3
3
|
import { formatBackendFederationIdentityIssues, validateExpectedBackendFederationIdentity } from "./identity.mjs";
|
|
4
4
|
import { createBackendFederationRuntime } from "./runtime.mjs";
|
|
5
5
|
import { isRecord, normalizeExpose } from "./utils.mjs";
|
|
6
|
+
import * as __rspack_external_effect_Effect_41060786 from "effect/Effect";
|
|
7
|
+
import * as __rspack_external_effect_Logger_1691a01b from "effect/Logger";
|
|
6
8
|
const LEGACY_LOAD_WARNING = '[BFF][Effect] loadBackendFederatedEffectApi was called without an expected delivery-unit identity (expected.unitId + expected.buildMarker). Identity-less public backend loads are deprecated (ADR-0019/MV-G23) and will be rejected in a future major.';
|
|
7
|
-
|
|
9
|
+
const legacyWarningLogger = __rspack_external_effect_Logger_1691a01b.withLeveledConsole(__rspack_external_effect_Logger_1691a01b.formatLogFmt);
|
|
10
|
+
function warnLegacyLoad() {
|
|
11
|
+
__rspack_external_effect_Effect_41060786.runSync(__rspack_external_effect_Effect_41060786.provideService(__rspack_external_effect_Effect_41060786.logWarning(LEGACY_LOAD_WARNING), __rspack_external_effect_Logger_1691a01b.CurrentLoggers, new Set([
|
|
12
|
+
legacyWarningLogger
|
|
13
|
+
])));
|
|
14
|
+
}
|
|
15
|
+
function loadBackendFederatedEffectApi(options) {
|
|
8
16
|
const remoteName = options.remote?.name ?? options.remoteName;
|
|
9
|
-
if (
|
|
10
|
-
if (void 0 === options.expected)
|
|
17
|
+
if (void 0 === remoteName || 0 === remoteName.length) return Promise.reject(new Error('[BFF][Effect] Missing backend federation remote name.'));
|
|
18
|
+
if (void 0 === options.expected) warnLegacyLoad();
|
|
11
19
|
const runtime = options.runtime ?? createBackendFederationRuntime(options);
|
|
12
20
|
const expose = options.expose ?? options.remote?.expose ?? BACKEND_FEDERATION_EFFECT_EXPOSE;
|
|
13
21
|
const remoteRequest = `${remoteName}/${normalizeExpose(expose)}`;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
return runtime.loadRemote(remoteRequest).then((loaded)=>{
|
|
23
|
+
if (!isRecord(loaded)) throw new Error(`[BFF][Effect] Backend federation expose ${remoteRequest} must load an object module.`);
|
|
24
|
+
const backendContract = loaded.backendFederationContract;
|
|
25
|
+
if (!isRecord(backendContract) || true !== backendContract.strictEffectApproach) throw new Error(`[BFF][Effect] Backend federation expose ${remoteRequest} must expose strict Effect metadata (strictEffectApproach: true).`);
|
|
26
|
+
if ('effect' !== backendContract.runtimeFramework) throw new Error(`[BFF][Effect] Backend federation expose ${remoteRequest} must expose strict Effect metadata (runtimeFramework: "effect").`);
|
|
27
|
+
if ('string' == typeof backendContract.name && backendContract.name !== remoteName) throw new Error(`[BFF][Effect] Backend federation expose ${remoteRequest} metadata name mismatch: expected ${remoteName}, received ${backendContract.name}.`);
|
|
28
|
+
if (!('runtime' in loaded)) throw new Error(`[BFF][Effect] Backend federation expose ${remoteRequest} must expose api and runtime.`);
|
|
29
|
+
if (void 0 !== options.expected) {
|
|
30
|
+
const issues = validateExpectedBackendFederationIdentity(loaded, options.expected, {
|
|
31
|
+
allowMissingIdentityMetadata: true === options.allowMissingIdentityMetadata
|
|
32
|
+
});
|
|
33
|
+
if (issues.length > 0) throw new Error(`[BFF][Effect] Backend federation expose ${remoteRequest} delivery-unit identity mismatch: ${formatBackendFederationIdentityIssues(issues)}.`);
|
|
34
|
+
}
|
|
35
|
+
return loaded;
|
|
36
|
+
});
|
|
28
37
|
}
|
|
29
38
|
export { loadBackendFederatedEffectApi };
|
|
@@ -2,13 +2,23 @@ import "node:module";
|
|
|
2
2
|
function createBackendFederationLoadEntryPlugin(options) {
|
|
3
3
|
return {
|
|
4
4
|
name: 'modernjs-backend-federation-load-entry',
|
|
5
|
-
|
|
6
|
-
return options.resolveEntry({
|
|
5
|
+
loadEntry ({ remoteInfo }) {
|
|
6
|
+
return Promise.resolve(options.resolveEntry({
|
|
7
7
|
name: remoteInfo.name,
|
|
8
8
|
entry: remoteInfo.entry,
|
|
9
9
|
type: remoteInfo.type,
|
|
10
10
|
entryGlobalName: remoteInfo.entryGlobalName,
|
|
11
11
|
shareScope: remoteInfo.shareScope
|
|
12
|
+
})).then((entry)=>{
|
|
13
|
+
if (void 0 === entry) return;
|
|
14
|
+
return {
|
|
15
|
+
get (id) {
|
|
16
|
+
return ()=>Promise.resolve(entry.get(id)).then((factory)=>factory());
|
|
17
|
+
},
|
|
18
|
+
init (...args) {
|
|
19
|
+
return entry.init?.(...args);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
12
22
|
});
|
|
13
23
|
}
|
|
14
24
|
};
|
|
@@ -3,10 +3,11 @@ function collectRemotes(options) {
|
|
|
3
3
|
const remotes = [
|
|
4
4
|
...options.remotes ?? []
|
|
5
5
|
];
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
const configuredRemote = options.remote;
|
|
7
|
+
if (void 0 !== configuredRemote) {
|
|
8
|
+
const existingIndex = remotes.findIndex((remote)=>remote.name === configuredRemote.name);
|
|
9
|
+
if (existingIndex >= 0) remotes[existingIndex] = configuredRemote;
|
|
10
|
+
else remotes.push(configuredRemote);
|
|
10
11
|
}
|
|
11
12
|
return remotes;
|
|
12
13
|
}
|
|
@@ -1,27 +1,91 @@
|
|
|
1
1
|
import "node:module";
|
|
2
|
+
import { ModuleFederation } from "@module-federation/runtime";
|
|
2
3
|
import { loadBackendFederationExpose } from "./entry.mjs";
|
|
4
|
+
import { createBackendFederationLoadEntryPlugin } from "./plugin.mjs";
|
|
3
5
|
import { collectRemotes } from "./remotes.mjs";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
return `./${normalizeExpose(expose)}`;
|
|
6
|
+
function _check_private_redeclaration(obj, privateCollection) {
|
|
7
|
+
if (privateCollection.has(obj)) throw new TypeError("Cannot initialize the same private elements twice on an object");
|
|
7
8
|
}
|
|
9
|
+
function _class_apply_descriptor_get(receiver, descriptor) {
|
|
10
|
+
if (descriptor.get) return descriptor.get.call(receiver);
|
|
11
|
+
return descriptor.value;
|
|
12
|
+
}
|
|
13
|
+
function _class_apply_descriptor_set(receiver, descriptor, value) {
|
|
14
|
+
if (descriptor.set) descriptor.set.call(receiver, value);
|
|
15
|
+
else {
|
|
16
|
+
if (!descriptor.writable) throw new TypeError("attempted to set read only private field");
|
|
17
|
+
descriptor.value = value;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function _class_extract_field_descriptor(receiver, privateMap, action) {
|
|
21
|
+
if (!privateMap.has(receiver)) throw new TypeError("attempted to " + action + " private field on non-instance");
|
|
22
|
+
return privateMap.get(receiver);
|
|
23
|
+
}
|
|
24
|
+
function _class_private_field_get(receiver, privateMap) {
|
|
25
|
+
var descriptor = _class_extract_field_descriptor(receiver, privateMap, "get");
|
|
26
|
+
return _class_apply_descriptor_get(receiver, descriptor);
|
|
27
|
+
}
|
|
28
|
+
function _class_private_field_init(obj, privateMap, value) {
|
|
29
|
+
_check_private_redeclaration(obj, privateMap);
|
|
30
|
+
privateMap.set(obj, value);
|
|
31
|
+
}
|
|
32
|
+
function _class_private_field_set(receiver, privateMap, value) {
|
|
33
|
+
var descriptor = _class_extract_field_descriptor(receiver, privateMap, "set");
|
|
34
|
+
_class_apply_descriptor_set(receiver, descriptor, value);
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
let nextRuntimeId = 0;
|
|
8
38
|
function parseRemoteRequest(request) {
|
|
9
39
|
const [remoteName, ...exposeParts] = request.split('/');
|
|
10
|
-
if (
|
|
11
|
-
return
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
40
|
+
if (void 0 === remoteName || 0 === remoteName.length || 0 === exposeParts.length) return;
|
|
41
|
+
return remoteName;
|
|
42
|
+
}
|
|
43
|
+
function createLocalEntryPlugin(options, remotes) {
|
|
44
|
+
return createBackendFederationLoadEntryPlugin({
|
|
45
|
+
resolveEntry (resolvedRemote) {
|
|
46
|
+
const remote = remotes.find((candidate)=>candidate.name === resolvedRemote.name);
|
|
47
|
+
if (void 0 === remote) return;
|
|
48
|
+
return {
|
|
49
|
+
get (expose) {
|
|
50
|
+
return ()=>loadBackendFederationExpose(remote, expose, options);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function isolateRegisteredRemoteEntries(remotes) {
|
|
57
|
+
const runtimeId = nextRuntimeId;
|
|
58
|
+
nextRuntimeId += 1;
|
|
59
|
+
return remotes.map((remote)=>({
|
|
60
|
+
...remote,
|
|
61
|
+
entry: `${remote.entry}#modernjs-backend-runtime-${runtimeId}`
|
|
62
|
+
}));
|
|
63
|
+
}
|
|
64
|
+
var _remoteNames = /*#__PURE__*/ new WeakMap();
|
|
65
|
+
class BackendFederationRuntime extends ModuleFederation {
|
|
66
|
+
loadRemote(request, loadOptions) {
|
|
67
|
+
const remoteName = parseRemoteRequest(request);
|
|
68
|
+
if (void 0 === remoteName) return Promise.reject(new Error(`[BFF][Effect] Invalid backend federation request ${request}.`));
|
|
69
|
+
if (!_class_private_field_get(this, _remoteNames).has(remoteName)) return Promise.reject(new Error(`[BFF][Effect] Missing backend federation remote ${remoteName}.`));
|
|
70
|
+
return super.loadRemote(request, loadOptions);
|
|
71
|
+
}
|
|
72
|
+
constructor(options, remotes){
|
|
73
|
+
super({
|
|
74
|
+
name: options.hostName,
|
|
75
|
+
remotes: isolateRegisteredRemoteEntries(remotes),
|
|
76
|
+
shared: {},
|
|
77
|
+
plugins: [
|
|
78
|
+
createLocalEntryPlugin(options, remotes)
|
|
79
|
+
]
|
|
80
|
+
}), _class_private_field_init(this, _remoteNames, {
|
|
81
|
+
writable: true,
|
|
82
|
+
value: void 0
|
|
83
|
+
});
|
|
84
|
+
_class_private_field_set(this, _remoteNames, new Set(remotes.map((remote)=>remote.name)));
|
|
85
|
+
}
|
|
15
86
|
}
|
|
16
87
|
function createBackendFederationRuntime(options) {
|
|
17
88
|
const remotes = collectRemotes(options);
|
|
18
|
-
return
|
|
19
|
-
async loadRemote (request) {
|
|
20
|
-
const { remoteName, expose } = parseRemoteRequest(request);
|
|
21
|
-
const remote = remotes.find((candidate)=>candidate.name === remoteName);
|
|
22
|
-
if (!remote) throw new Error(`[BFF][Effect] Missing backend federation remote ${remoteName}.`);
|
|
23
|
-
return loadBackendFederationExpose(remote, expose, options);
|
|
24
|
-
}
|
|
25
|
-
};
|
|
89
|
+
return new BackendFederationRuntime(options, remotes);
|
|
26
90
|
}
|
|
27
91
|
export { createBackendFederationRuntime };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import { dispatchEffectBffRequestWithContext } from "./dispatch.mjs";
|
|
3
|
+
import { runWithEffectContext, useEffectContext, useOperationContext } from "./edge-context.mjs";
|
|
4
|
+
import { resolveEffectBffModuleHandler } from "./module.mjs";
|
|
5
|
+
export * from "./handler.mjs";
|
|
6
|
+
async function dispatchEffectBffRequest(handler, request, options = {}) {
|
|
7
|
+
return dispatchEffectBffRequestWithContext(handler, request, {
|
|
8
|
+
...options,
|
|
9
|
+
runWithEffectContext: runWithEffectContext
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
async function createEffectBffEdgeDispatcher(options) {
|
|
13
|
+
const loaded = await resolveEffectBffModuleHandler(options.module, {
|
|
14
|
+
openapi: options.openapi,
|
|
15
|
+
dataPlatform: options.dataPlatform,
|
|
16
|
+
onWarning: options.onWarning
|
|
17
|
+
});
|
|
18
|
+
if (!loaded) throw new Error('[BFF][Effect] Invalid Effect edge module. Export defineEffectBff(...) or a { api, layer } HttpApi module.');
|
|
19
|
+
return {
|
|
20
|
+
dispatch: (request, dispatchOptions = {})=>dispatchEffectBffRequest(loaded.handler, request, {
|
|
21
|
+
...dispatchOptions,
|
|
22
|
+
prefix: options.prefix,
|
|
23
|
+
onError: options.onError
|
|
24
|
+
}),
|
|
25
|
+
dispose: async ()=>{
|
|
26
|
+
await loaded.dispose?.();
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const createEffectBffTestHandler = createEffectBffEdgeHandler;
|
|
31
|
+
async function createEffectBffEdgeHandler(options) {
|
|
32
|
+
const dispatcher = await createEffectBffEdgeDispatcher(options);
|
|
33
|
+
return {
|
|
34
|
+
handler: dispatcher.dispatch,
|
|
35
|
+
dispose: dispatcher.dispose
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export { createEffectOperationContext } from "./operation-context.mjs";
|
|
39
|
+
export { createEffectBffEdgeDispatcher, createEffectBffEdgeHandler, createEffectBffTestHandler, dispatchEffectBffRequest, runWithEffectContext, useEffectContext, useOperationContext };
|
|
@@ -1,40 +1,3 @@
|
|
|
1
1
|
import "node:module";
|
|
2
|
-
|
|
3
|
-
import { runWithEffectContext, useEffectContext, useOperationContext } from "./edge-context.mjs";
|
|
4
|
-
import { resolveEffectBffModuleHandler } from "./module.mjs";
|
|
5
|
-
export * from "./handler.mjs";
|
|
6
|
-
async function dispatchEffectBffRequest(handler, request, options = {}) {
|
|
7
|
-
return dispatchEffectBffRequestWithContext(handler, request, {
|
|
8
|
-
...options,
|
|
9
|
-
runWithEffectContext: runWithEffectContext
|
|
10
|
-
});
|
|
11
|
-
}
|
|
12
|
-
async function createEffectBffEdgeDispatcher(options) {
|
|
13
|
-
const loaded = await resolveEffectBffModuleHandler(options.module, {
|
|
14
|
-
openapi: options.openapi,
|
|
15
|
-
dataPlatform: options.dataPlatform,
|
|
16
|
-
onWarning: options.onWarning
|
|
17
|
-
});
|
|
18
|
-
if (!loaded) throw new Error('[BFF][Effect] Invalid Effect edge module. Export defineEffectBff(...) or a { api, layer } HttpApi module.');
|
|
19
|
-
return {
|
|
20
|
-
dispatch: (request, dispatchOptions = {})=>dispatchEffectBffRequest(loaded.handler, request, {
|
|
21
|
-
...dispatchOptions,
|
|
22
|
-
prefix: options.prefix,
|
|
23
|
-
onError: options.onError
|
|
24
|
-
}),
|
|
25
|
-
dispose: async ()=>{
|
|
26
|
-
await loaded.dispose?.();
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
const createEffectBffTestHandler = createEffectBffEdgeHandler;
|
|
31
|
-
async function createEffectBffEdgeHandler(options) {
|
|
32
|
-
const dispatcher = await createEffectBffEdgeDispatcher(options);
|
|
33
|
-
return {
|
|
34
|
-
handler: dispatcher.dispatch,
|
|
35
|
-
dispose: dispatcher.dispose
|
|
36
|
-
};
|
|
37
|
-
}
|
|
2
|
+
export * from "./edge-dispatcher.mjs";
|
|
38
3
|
export { BACKEND_FEDERATION_CONTRACT_VERSION, BACKEND_FEDERATION_EFFECT_EXPOSE, BACKEND_FEDERATION_MANIFEST_FILE, BACKEND_FEDERATION_NODE_ADAPTER_VERSION, createBackendFederationLoadEntryPlugin, createBackendFederationRuntime, loadBackendFederatedEffectApi, validateExpectedBackendFederationIdentity } from "./backend-federation.mjs";
|
|
39
|
-
export { createEffectOperationContext } from "./operation-context.mjs";
|
|
40
|
-
export { createEffectBffEdgeDispatcher, createEffectBffEdgeHandler, createEffectBffTestHandler, dispatchEffectBffRequest, runWithEffectContext, useEffectContext, useOperationContext };
|
|
@@ -17,6 +17,7 @@ function defineEffectBff(definition) {
|
|
|
17
17
|
openapi: options?.openapi,
|
|
18
18
|
rpc: mergedRpcOptions,
|
|
19
19
|
dataPlatform: mergeDataPlatformOptions(definition.dataPlatform, options?.dataPlatform),
|
|
20
|
+
interceptRequest: definition.interceptRequest,
|
|
20
21
|
validateRequest: options?.validateRequest
|
|
21
22
|
});
|
|
22
23
|
};
|
|
@@ -13,23 +13,30 @@ function createHttpApiHandler(options) {
|
|
|
13
13
|
const openApiLayer = createOpenApiLayer(options.api, options.openapi);
|
|
14
14
|
const mergedLayer = openApiLayer ? __rspack_external_effect_Layer_69c46453.mergeAll(apiLayer, openApiLayer) : apiLayer;
|
|
15
15
|
const httpApiHandler = HttpRouter.toWebHandler(mergedLayer);
|
|
16
|
-
const
|
|
17
|
-
const policyDenial = options.validateRequest?.(request);
|
|
18
|
-
if (policyDenial) return policyDenial;
|
|
16
|
+
const dispatchHttpApiRequest = async (request, context)=>{
|
|
19
17
|
const preparedRequest = await prepareJsonRequestBody(request);
|
|
20
18
|
if (preparedRequest instanceof Response) return preparedRequest;
|
|
21
19
|
const validationError = validateDataPlatformRequestEnvelope(preparedRequest, options.dataPlatform);
|
|
22
20
|
if (validationError) return validationError;
|
|
23
21
|
return httpApiHandler.handler(preparedRequest, toEffectServiceContext(context));
|
|
24
22
|
};
|
|
23
|
+
const withRequestPolicy = async (request, context)=>{
|
|
24
|
+
const policyDenial = options.validateRequest?.(request);
|
|
25
|
+
if (policyDenial) return policyDenial;
|
|
26
|
+
const next = ()=>dispatchHttpApiRequest(request, context);
|
|
27
|
+
return options.interceptRequest ? options.interceptRequest({
|
|
28
|
+
request,
|
|
29
|
+
next
|
|
30
|
+
}) : next();
|
|
31
|
+
};
|
|
25
32
|
const batchHandler = createDataPlatformBatchRequestHandler({
|
|
26
33
|
dataPlatform: options.dataPlatform,
|
|
27
|
-
handleItem:
|
|
34
|
+
handleItem: withRequestPolicy
|
|
28
35
|
});
|
|
29
36
|
const handleHttpApiRequest = async (request, context)=>{
|
|
30
37
|
const pathname = getRequestPathname(request);
|
|
31
38
|
if (batchHandler.enabled && pathname === batchHandler.path) return batchHandler.handle(request, context);
|
|
32
|
-
return
|
|
39
|
+
return withRequestPolicy(request, context);
|
|
33
40
|
};
|
|
34
41
|
if (!options.rpc) return {
|
|
35
42
|
handler: handleHttpApiRequest,
|
|
@@ -44,7 +51,11 @@ function createHttpApiHandler(options) {
|
|
|
44
51
|
if (isRpcRequest(request, rpcPath)) {
|
|
45
52
|
const policyDenial = options.validateRequest?.(request);
|
|
46
53
|
if (policyDenial) return policyDenial;
|
|
47
|
-
|
|
54
|
+
const next = ()=>rpcHandler.handler(request, toEffectServiceContext(context));
|
|
55
|
+
return options.interceptRequest ? options.interceptRequest({
|
|
56
|
+
request,
|
|
57
|
+
next
|
|
58
|
+
}) : next();
|
|
48
59
|
}
|
|
49
60
|
return handleHttpApiRequest(request, context);
|
|
50
61
|
},
|
|
@@ -6,6 +6,8 @@ const API_DIR = '{apiDirectory}';
|
|
|
6
6
|
const LAMBDA_DIR = '{lambdaDirectory}';
|
|
7
7
|
const DIST_DIR = '{distDirectory}';
|
|
8
8
|
const RUNTIME_FRAMEWORK = '{runtimeFramework}';
|
|
9
|
+
const EFFECT_ENTRY = '{effectEntry}';
|
|
10
|
+
const OPERATION_CONTRACTS_JSON = '{operationContracts}';
|
|
9
11
|
const NODE_MODULES = 'node_modules';
|
|
10
12
|
const crossProjectApiPlugin = ()=>({
|
|
11
13
|
name: '@modern-js/plugin-independent-bff',
|
|
@@ -17,7 +19,8 @@ const crossProjectApiPlugin = ()=>({
|
|
|
17
19
|
const { appDirectory: originAppDirectory } = api.getAppContext();
|
|
18
20
|
const sdkPath = path.join(originAppDirectory, NODE_MODULES, PACKAGE_NAME);
|
|
19
21
|
const sdkDistPath = path.join(sdkPath, DIST_DIR);
|
|
20
|
-
const
|
|
22
|
+
const effectEntry = EFFECT_ENTRY ? path.join(sdkDistPath, EFFECT_ENTRY) : void 0;
|
|
23
|
+
const apiDirectory = effectEntry ? path.dirname(effectEntry) : path.join(sdkDistPath, API_DIR);
|
|
21
24
|
const lambdaDirectory = path.resolve(sdkDistPath, LAMBDA_DIR);
|
|
22
25
|
api.updateAppContext({
|
|
23
26
|
apiDirectory,
|
|
@@ -32,10 +35,16 @@ const crossProjectApiPlugin = ()=>({
|
|
|
32
35
|
}
|
|
33
36
|
const configuredRuntimeFramework = config?.bff?.runtimeFramework;
|
|
34
37
|
if (configuredRuntimeFramework && configuredRuntimeFramework !== RUNTIME_FRAMEWORK) throw new Error(`[${PACKAGE_NAME}] Runtime framework mismatch for cross-project BFF. Detected "${configuredRuntimeFramework}", but producer SDK requires "${RUNTIME_FRAMEWORK}".`);
|
|
38
|
+
resolvedConfig.bff ??= {};
|
|
35
39
|
resolvedConfig.bff.prefix = PREFIX;
|
|
36
40
|
resolvedConfig.bff.runtimeFramework = RUNTIME_FRAMEWORK;
|
|
41
|
+
if (EFFECT_ENTRY) resolvedConfig.bff.effect = {
|
|
42
|
+
...resolvedConfig.bff.effect,
|
|
43
|
+
entry: effectEntry
|
|
44
|
+
};
|
|
37
45
|
resolvedConfig.bff.isCrossProjectServer = true;
|
|
38
46
|
resolvedConfig.bff.requestId = resolvedConfig.bff.requestId || config?.bff?.requestId || PACKAGE_NAME || 'default';
|
|
47
|
+
const generatedOperationContracts = "{operationContracts}" === OPERATION_CONTRACTS_JSON ? {} : JSON.parse(OPERATION_CONTRACTS_JSON);
|
|
39
48
|
resolvedConfig.bff.crossProjectPolicy = {
|
|
40
49
|
...resolvedConfig.bff.crossProjectPolicy || {},
|
|
41
50
|
enabled: resolvedConfig.bff.crossProjectPolicy?.enabled ?? true,
|
|
@@ -44,7 +53,11 @@ const crossProjectApiPlugin = ()=>({
|
|
|
44
53
|
requireOperationContextDetails: resolvedConfig.bff.crossProjectPolicy?.requireOperationContextDetails ?? true,
|
|
45
54
|
requireOperationSchemaHash: resolvedConfig.bff.crossProjectPolicy?.requireOperationSchemaHash ?? true,
|
|
46
55
|
requireOperationVersion: resolvedConfig.bff.crossProjectPolicy?.requireOperationVersion ?? true,
|
|
47
|
-
allowUnknownOperations: resolvedConfig.bff.crossProjectPolicy?.allowUnknownOperations ?? false
|
|
56
|
+
allowUnknownOperations: resolvedConfig.bff.crossProjectPolicy?.allowUnknownOperations ?? false,
|
|
57
|
+
expectedOperationContracts: {
|
|
58
|
+
...resolvedConfig.bff.crossProjectPolicy?.expectedOperationContracts || {},
|
|
59
|
+
...generatedOperationContracts
|
|
60
|
+
}
|
|
48
61
|
};
|
|
49
62
|
return resolvedConfig;
|
|
50
63
|
});
|
|
@@ -52,4 +65,4 @@ const crossProjectApiPlugin = ()=>({
|
|
|
52
65
|
});
|
|
53
66
|
const utils_crossProjectApiPlugin = crossProjectApiPlugin;
|
|
54
67
|
export default utils_crossProjectApiPlugin;
|
|
55
|
-
export { API_DIR, DIST_DIR, LAMBDA_DIR, PACKAGE_NAME, PREFIX, RUNTIME_FRAMEWORK, crossProjectApiPlugin };
|
|
68
|
+
export { API_DIR, DIST_DIR, EFFECT_ENTRY, LAMBDA_DIR, OPERATION_CONTRACTS_JSON, PACKAGE_NAME, PREFIX, RUNTIME_FRAMEWORK, crossProjectApiPlugin };
|
|
@@ -3,26 +3,27 @@ import { logger } from "@modern-js/utils";
|
|
|
3
3
|
import { collectEffectEndpoints } from "../../runtime/effect/endpoint-contracts.mjs";
|
|
4
4
|
import { renderEffectClientCode, renderEffectClientDeclaration } from "./rendering.mjs";
|
|
5
5
|
import { getHttpApiRuntime, loadEffectApi } from "./runtime.mjs";
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
function generateEffectClient(options) {
|
|
7
|
+
return loadEffectApi({
|
|
8
8
|
appDir: options.appDir,
|
|
9
9
|
resourcePath: options.resourcePath,
|
|
10
10
|
onDependency: options.onDependency
|
|
11
|
+
}).then((api)=>{
|
|
12
|
+
if (null === api) {
|
|
13
|
+
logger.warn(`[BFF][Effect] Failed to generate client for ${options.resourcePath}: unable to resolve exported HttpApi.`);
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
return getHttpApiRuntime().then((httpApiRuntime)=>{
|
|
17
|
+
const endpoints = collectEffectEndpoints(httpApiRuntime.reflect, api, options.prefix);
|
|
18
|
+
return {
|
|
19
|
+
code: renderEffectClientCode(endpoints, options),
|
|
20
|
+
declaration: renderEffectClientDeclaration(endpoints),
|
|
21
|
+
endpoints
|
|
22
|
+
};
|
|
23
|
+
});
|
|
11
24
|
});
|
|
12
|
-
if (!api) {
|
|
13
|
-
logger.warn(`[BFF][Effect] Failed to generate client for ${options.resourcePath}: unable to resolve exported HttpApi.`);
|
|
14
|
-
return null;
|
|
15
|
-
}
|
|
16
|
-
const httpApiRuntime = await getHttpApiRuntime();
|
|
17
|
-
const endpoints = collectEffectEndpoints(httpApiRuntime.reflect, api, options.prefix);
|
|
18
|
-
return {
|
|
19
|
-
code: renderEffectClientCode(endpoints, options),
|
|
20
|
-
declaration: renderEffectClientDeclaration(endpoints),
|
|
21
|
-
endpoints
|
|
22
|
-
};
|
|
23
25
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
return artifacts ? artifacts.code : null;
|
|
26
|
+
function generateEffectClientCode(options) {
|
|
27
|
+
return generateEffectClient(options).then((artifacts)=>null === artifacts ? null : artifacts.code);
|
|
27
28
|
}
|
|
28
29
|
export { generateEffectClient, generateEffectClientCode };
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import "node:module";
|
|
2
|
-
import { findExists, fs } from "@modern-js/utils";
|
|
3
|
-
import path from "path";
|
|
2
|
+
import { findExists, fs, upath } from "@modern-js/utils";
|
|
4
3
|
const JS_OR_TS_EXTS = [
|
|
5
4
|
'.js',
|
|
6
5
|
'.jsx',
|
|
@@ -14,13 +13,13 @@ const JS_OR_TS_EXTS = [
|
|
|
14
13
|
function resolveEffectEntryFile(options) {
|
|
15
14
|
const { appDir, apiDir, effectEntry } = options;
|
|
16
15
|
const resolveEntry = (entryWithoutExt)=>{
|
|
17
|
-
if (
|
|
16
|
+
if ('' !== upath.extname(entryWithoutExt)) return fs.existsSync(entryWithoutExt) ? entryWithoutExt : void 0;
|
|
18
17
|
return findExists(JS_OR_TS_EXTS.map((ext)=>`${entryWithoutExt}${ext}`));
|
|
19
18
|
};
|
|
20
|
-
if (effectEntry) {
|
|
21
|
-
const entryWithoutExt =
|
|
19
|
+
if (void 0 !== effectEntry && '' !== effectEntry) {
|
|
20
|
+
const entryWithoutExt = upath.isAbsolute(effectEntry) ? effectEntry : upath.resolve(appDir, effectEntry);
|
|
22
21
|
return resolveEntry(entryWithoutExt);
|
|
23
22
|
}
|
|
24
|
-
return resolveEntry(
|
|
23
|
+
return resolveEntry(upath.resolve(apiDir, 'index'));
|
|
25
24
|
}
|
|
26
25
|
export { resolveEffectEntryFile };
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import "node:module";
|
|
2
2
|
import { deriveOperationVersion } from "@modern-js/bff-core";
|
|
3
|
-
import { fs } from "@modern-js/utils";
|
|
4
|
-
import path from "path";
|
|
3
|
+
import { fs, upath } from "@modern-js/utils";
|
|
5
4
|
import { createEffectEndpointContractHash, ensureLeadingSlash, normalizeEffectPrefix } from "../../runtime/effect/endpoint-contracts.mjs";
|
|
6
5
|
const DEFAULT_REQUEST_CREATOR = '@modern-js/plugin-bff/client';
|
|
7
6
|
const EFFECT_CLIENT_RUNTIME_IMPORT = '@modern-js/plugin-bff/effect-client-runtime';
|
|
@@ -14,17 +13,17 @@ function isAbsoluteUrl(value) {
|
|
|
14
13
|
}
|
|
15
14
|
}
|
|
16
15
|
function resolveBatchEndpoint(prefix, endpoint) {
|
|
17
|
-
const value = endpoint || '/_data/batch';
|
|
16
|
+
const value = void 0 === endpoint || '' === endpoint ? '/_data/batch' : endpoint;
|
|
18
17
|
if (isAbsoluteUrl(value)) return value;
|
|
19
18
|
const normalizedPrefix = normalizeEffectPrefix(prefix);
|
|
20
19
|
const normalizedEndpoint = ensureLeadingSlash(value);
|
|
21
|
-
if (
|
|
20
|
+
if ('' === normalizedPrefix) return normalizedEndpoint;
|
|
22
21
|
if (normalizedEndpoint === normalizedPrefix || normalizedEndpoint.startsWith(`${normalizedPrefix}/`)) return normalizedEndpoint;
|
|
23
22
|
return `${normalizedPrefix}${'/' === normalizedEndpoint ? '' : normalizedEndpoint}`;
|
|
24
23
|
}
|
|
25
24
|
function getPackageInfo(appDir) {
|
|
26
25
|
try {
|
|
27
|
-
const packageJsonPath =
|
|
26
|
+
const packageJsonPath = upath.resolve(appDir, './package.json');
|
|
28
27
|
const packageJson = fs.readJSONSync(packageJsonPath);
|
|
29
28
|
return {
|
|
30
29
|
name: packageJson.name,
|
|
@@ -39,9 +38,9 @@ function renderEffectClientCode(endpoints, options) {
|
|
|
39
38
|
const httpMethodDecider = options.httpMethodDecider || 'functionName';
|
|
40
39
|
const packageInfo = getPackageInfo(options.appDir);
|
|
41
40
|
const packageName = packageInfo.name;
|
|
42
|
-
const dataPlatformAppNamespace = packageName || 'unknown-app';
|
|
43
|
-
const requestId = 'bundle' === options.target ? packageName
|
|
44
|
-
const normalizedRequestId = requestId || 'default';
|
|
41
|
+
const dataPlatformAppNamespace = void 0 === packageName || '' === packageName ? 'unknown-app' : packageName;
|
|
42
|
+
const requestId = 'bundle' === options.target ? void 0 !== packageName && '' !== packageName ? packageName : void 0 : void 0;
|
|
43
|
+
const normalizedRequestId = void 0 === requestId || '' === requestId ? 'default' : requestId;
|
|
45
44
|
const operationVersion = deriveOperationVersion(packageInfo.version);
|
|
46
45
|
const batchConfig = options.dataPlatformBatch;
|
|
47
46
|
const batchEndpoint = resolveBatchEndpoint(options.prefix, batchConfig?.endpoint);
|
|
@@ -58,7 +57,7 @@ function renderEffectClientCode(endpoints, options) {
|
|
|
58
57
|
};
|
|
59
58
|
const config = {
|
|
60
59
|
appNamespace: dataPlatformAppNamespace,
|
|
61
|
-
...requestId ? {
|
|
60
|
+
...void 0 !== requestId && '' !== requestId ? {
|
|
62
61
|
requestId
|
|
63
62
|
} : {},
|
|
64
63
|
port: options.port,
|
|
@@ -72,7 +71,7 @@ function renderEffectClientCode(endpoints, options) {
|
|
|
72
71
|
maxBatchSize: batchConfig?.maxBatchSize ?? 16,
|
|
73
72
|
maxBatchBytes: batchConfig?.maxBatchBytes ?? 65536,
|
|
74
73
|
requestTimeoutMs: batchConfig?.requestTimeoutMs ?? 10000,
|
|
75
|
-
allowedMethods: batchConfig?.allowedMethods && batchConfig.allowedMethods.length > 0 ? batchConfig.allowedMethods : [
|
|
74
|
+
allowedMethods: batchConfig?.allowedMethods !== void 0 && batchConfig.allowedMethods.length > 0 ? batchConfig.allowedMethods : [
|
|
76
75
|
'GET'
|
|
77
76
|
]
|
|
78
77
|
}
|
|
@@ -1,36 +1,29 @@
|
|
|
1
1
|
import __rslib_shim_module__ from "node:module";
|
|
2
2
|
const require = /*#__PURE__*/ __rslib_shim_module__.createRequire(/*#__PURE__*/ (()=>import.meta.url)());
|
|
3
|
-
import { compatibleRequire } from "@modern-js/utils";
|
|
4
|
-
import path from "path";
|
|
3
|
+
import { compatibleRequire, upath } from "@modern-js/utils";
|
|
5
4
|
import { extractHttpApiFromModule } from "../../runtime/effect/endpoint-contracts.mjs";
|
|
6
5
|
import { loadEffectSourceModule } from "../effectSourceLoader.mjs";
|
|
7
6
|
let httpApiRuntimePromise;
|
|
8
7
|
function isRecord(value) {
|
|
9
8
|
return 'object' == typeof value && null !== value;
|
|
10
9
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if (isRecord(mod) && isRecord(mod.HttpApi)) {
|
|
24
|
-
const maybeHttpApi = mod.HttpApi;
|
|
25
|
-
if ('function' == typeof maybeHttpApi.isHttpApi && 'function' == typeof maybeHttpApi.reflect) return maybeHttpApi;
|
|
26
|
-
}
|
|
10
|
+
function isHttpApiRuntime(value) {
|
|
11
|
+
return isRecord(value) && 'function' == typeof value.isHttpApi && 'function' == typeof value.reflect;
|
|
12
|
+
}
|
|
13
|
+
function getHttpApiRuntime() {
|
|
14
|
+
if (void 0 === httpApiRuntimePromise) httpApiRuntimePromise = compatibleRequire('effect/unstable/httpapi', false).catch((error)=>{
|
|
15
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
16
|
+
if (!message.includes("Cannot find module 'effect/unstable/httpapi'")) throw error;
|
|
17
|
+
const effectPackageJson = require.resolve('effect/package.json');
|
|
18
|
+
const effectHttpApiRuntimePath = upath.join(upath.dirname(effectPackageJson), 'dist', 'unstable', 'httpapi', 'index.js');
|
|
19
|
+
return compatibleRequire(effectHttpApiRuntimePath, false);
|
|
20
|
+
}).then((mod)=>{
|
|
21
|
+
if (isRecord(mod) && isHttpApiRuntime(mod.HttpApi)) return mod.HttpApi;
|
|
27
22
|
throw new Error('[BFF][Effect] Unable to resolve HttpApi runtime from effect/unstable/httpapi.');
|
|
28
|
-
})
|
|
23
|
+
});
|
|
29
24
|
return httpApiRuntimePromise;
|
|
30
25
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const mod = await loadEffectSourceModule(options);
|
|
34
|
-
return extractHttpApiFromModule(mod, httpApiRuntime.isHttpApi);
|
|
26
|
+
function loadEffectApi(options) {
|
|
27
|
+
return getHttpApiRuntime().then((httpApiRuntime)=>loadEffectSourceModule(options).then((mod)=>extractHttpApiFromModule(mod, httpApiRuntime.isHttpApi)));
|
|
35
28
|
}
|
|
36
29
|
export { getHttpApiRuntime, loadEffectApi };
|