@bleedingdev/modern-js-plugin-bff-extensions 3.9.0-ultramodern.11 → 3.9.0-ultramodern.13
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/README.md +3 -3
- package/dist/cjs/backend-federation/identity.js +23 -22
- package/dist/cjs/backend-federation/node-evaluator.js +48 -0
- package/dist/cjs/backend-federation/node.js +2 -2
- package/dist/cjs/backend-federation-manifest/node.js +2 -2
- package/dist/cjs/backend-federation-manifest/validation.js +11 -7
- package/dist/cjs/cross-project-policy/node.js +8 -28
- package/dist/cjs/{effect-adapter → effect-server}/cross-project-policy.js +5 -5
- package/dist/cjs/effect-server/entry.js +63 -0
- package/dist/cjs/{effect-adapter → effect-server}/error-response.js +4 -4
- package/dist/cjs/effect-server/index.js +199 -0
- package/dist/cjs/effect-source-loader/built-entry.js +4 -5
- package/dist/cjs/effect-source-loader/loader.js +2 -1
- package/dist/cjs/effect-source-loader/operation-contracts.js +8 -31
- package/dist/cjs/effect-source-loader/paths.js +38 -10
- package/dist/esm/backend-federation/identity.mjs +18 -23
- package/dist/esm/backend-federation/node-evaluator.mjs +7 -0
- package/dist/esm/backend-federation/node.mjs +2 -2
- package/dist/esm/backend-federation-manifest/node.mjs +2 -2
- package/dist/esm/backend-federation-manifest/validation.mjs +12 -8
- package/dist/esm/cross-project-policy/node.mjs +9 -19
- package/dist/esm/{effect-adapter → effect-server}/cross-project-policy.mjs +3 -3
- package/dist/esm/effect-server/entry.mjs +15 -0
- package/dist/esm/{effect-adapter → effect-server}/error-response.mjs +2 -2
- package/dist/esm/effect-server/index.mjs +151 -0
- package/dist/esm/effect-source-loader/built-entry.mjs +5 -6
- package/dist/esm/effect-source-loader/loader.mjs +2 -1
- package/dist/esm/effect-source-loader/operation-contracts.mjs +10 -33
- package/dist/esm/effect-source-loader/paths.mjs +30 -11
- package/dist/esm-node/backend-federation/identity.mjs +18 -23
- package/dist/esm-node/backend-federation/node-evaluator.mjs +8 -0
- package/dist/esm-node/backend-federation/node.mjs +2 -2
- package/dist/esm-node/backend-federation-manifest/node.mjs +2 -2
- package/dist/esm-node/backend-federation-manifest/validation.mjs +12 -8
- package/dist/esm-node/cross-project-policy/node.mjs +9 -19
- package/dist/esm-node/{effect-adapter → effect-server}/cross-project-policy.mjs +3 -3
- package/dist/esm-node/effect-server/entry.mjs +16 -0
- package/dist/esm-node/{effect-adapter → effect-server}/error-response.mjs +2 -2
- package/dist/esm-node/effect-server/index.mjs +152 -0
- package/dist/esm-node/effect-source-loader/built-entry.mjs +5 -6
- package/dist/esm-node/effect-source-loader/loader.mjs +2 -1
- package/dist/esm-node/effect-source-loader/operation-contracts.mjs +10 -33
- package/dist/esm-node/effect-source-loader/paths.mjs +30 -11
- package/dist/types/backend-federation/identity.d.ts +3 -6
- package/dist/types/backend-federation/node-evaluator.d.ts +2 -0
- package/dist/types/cross-project-policy/node.d.ts +2 -2
- package/dist/types/effect-server/cross-project-policy.d.ts +5 -0
- package/dist/types/{effect-adapter → effect-server}/entry.d.ts +1 -1
- package/dist/types/effect-server/error-response.d.ts +2 -0
- package/dist/types/effect-server/index.d.ts +4 -0
- package/dist/types/effect-source-loader/paths.d.ts +20 -2
- package/package.json +27 -27
- package/src/backend-federation/identity.ts +39 -47
- package/src/backend-federation/node-evaluator.ts +13 -0
- package/src/backend-federation/node.ts +2 -3
- package/src/backend-federation-manifest/node.ts +2 -3
- package/src/backend-federation-manifest/validation.ts +22 -29
- package/src/cross-project-policy/node.ts +7 -38
- package/src/{effect-adapter → effect-server}/cross-project-policy.ts +8 -2
- package/src/effect-server/entry.ts +18 -0
- package/src/{effect-adapter → effect-server}/error-response.ts +1 -1
- package/src/effect-server/index.ts +242 -0
- package/src/effect-source-loader/built-entry.ts +11 -9
- package/src/effect-source-loader/loader.ts +10 -5
- package/src/effect-source-loader/operation-contracts.ts +7 -41
- package/src/effect-source-loader/paths.ts +55 -21
- package/dist/cjs/effect-adapter/entry.js +0 -99
- package/dist/cjs/effect-adapter/index.js +0 -194
- package/dist/esm/effect-adapter/entry.mjs +0 -51
- package/dist/esm/effect-adapter/index.mjs +0 -143
- package/dist/esm-node/effect-adapter/entry.mjs +0 -52
- package/dist/esm-node/effect-adapter/index.mjs +0 -144
- package/dist/types/effect-adapter/cross-project-policy.d.ts +0 -4
- package/dist/types/effect-adapter/error-response.d.ts +0 -2
- package/dist/types/effect-adapter/index.d.ts +0 -21
- package/src/effect-adapter/entry.ts +0 -96
- package/src/effect-adapter/index.ts +0 -251
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
// @effect-diagnostics anyUnknownInErrorContext:off asyncFunction:off nodeBuiltinImport:off strictBooleanExpressions:off
|
|
2
|
+
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import '@modern-js/server-runtime-extensions/server-config';
|
|
5
|
+
import {
|
|
6
|
+
dispatchEffectBffRequest,
|
|
7
|
+
type EffectApiModule,
|
|
8
|
+
type EffectBffRequestHandler,
|
|
9
|
+
resolveEffectBffModuleHandler,
|
|
10
|
+
useEffectContext,
|
|
11
|
+
} from '@modern-js/bff-effect/effect';
|
|
12
|
+
import type {
|
|
13
|
+
Context,
|
|
14
|
+
Next,
|
|
15
|
+
ServerPlugin,
|
|
16
|
+
ServerPluginAPI,
|
|
17
|
+
} from '@modern-js/server-core';
|
|
18
|
+
import { resolveOperationProducer } from '@modern-js/server-runtime-extensions/bff-policy/node';
|
|
19
|
+
import {
|
|
20
|
+
createDisposableServerRuntimeHandle,
|
|
21
|
+
type DisposableServerRuntimeHandle,
|
|
22
|
+
registerServerRuntimeDisposer,
|
|
23
|
+
} from '@modern-js/server-runtime-extensions/runtime-lifecycle';
|
|
24
|
+
import { fs, isProd, logger } from '@modern-js/utils';
|
|
25
|
+
|
|
26
|
+
import { checkCrossProjectPolicyForRequest } from '../cross-project-policy/evaluation';
|
|
27
|
+
import {
|
|
28
|
+
loadEffectBuiltModule,
|
|
29
|
+
loadEffectSourceModule,
|
|
30
|
+
} from '../effect-source-loader/loader';
|
|
31
|
+
import { resolveEffectServerCrossProjectPolicy } from './cross-project-policy';
|
|
32
|
+
import { resolveEffectServerEntryFile } from './entry';
|
|
33
|
+
import { createEffectServerRuntimeErrorResponse } from './error-response';
|
|
34
|
+
|
|
35
|
+
const EFFECT_MIDDLEWARE_BEFORE = [
|
|
36
|
+
'custom-server-hook',
|
|
37
|
+
'custom-server-middleware',
|
|
38
|
+
'render',
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
export default (): ServerPlugin => ({
|
|
42
|
+
name: '@modern-js/plugin-bff-extensions/effect-server',
|
|
43
|
+
setup(api: ServerPluginAPI) {
|
|
44
|
+
const runtimeFramework = api.getServerContext().bffRuntimeFramework;
|
|
45
|
+
if (runtimeFramework !== 'effect') {
|
|
46
|
+
throw new Error(
|
|
47
|
+
`Effect BFF server plugin requires Effect; received "${runtimeFramework}".`,
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
let handler: DisposableServerRuntimeHandle | null = null;
|
|
51
|
+
let unregisterRuntimeDisposer: (() => void) | undefined;
|
|
52
|
+
let prefix = '/api';
|
|
53
|
+
let prefixes = ['/api'];
|
|
54
|
+
let matchingPrefixes = ['/api'];
|
|
55
|
+
let retired = false;
|
|
56
|
+
|
|
57
|
+
const dispose = async () => {
|
|
58
|
+
retired = true;
|
|
59
|
+
unregisterRuntimeDisposer?.();
|
|
60
|
+
unregisterRuntimeDisposer = undefined;
|
|
61
|
+
const previous = handler;
|
|
62
|
+
handler = null;
|
|
63
|
+
await previous?.dispose();
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const loadHandler = async () => {
|
|
67
|
+
const entryFile = resolveEffectServerEntryFile(api);
|
|
68
|
+
if (!entryFile || !(await fs.pathExists(entryFile))) {
|
|
69
|
+
handler = null;
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const { appDirectory } = api.getServerContext();
|
|
74
|
+
let mod: EffectApiModule;
|
|
75
|
+
try {
|
|
76
|
+
mod = (await (isProd()
|
|
77
|
+
? loadEffectBuiltModule(entryFile)
|
|
78
|
+
: loadEffectSourceModule({
|
|
79
|
+
resourcePath: entryFile,
|
|
80
|
+
appDir: appDirectory || path.dirname(entryFile),
|
|
81
|
+
}))) as EffectApiModule;
|
|
82
|
+
} catch (error) {
|
|
83
|
+
logger.error(
|
|
84
|
+
`[BFF][Effect] Failed to load Effect entry: ${entryFile}\n${String(error)}`,
|
|
85
|
+
);
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const producer = resolveOperationProducer({
|
|
90
|
+
directories: [path.dirname(entryFile), appDirectory],
|
|
91
|
+
requestId: api.getServerConfig()?.bff?.requestId,
|
|
92
|
+
});
|
|
93
|
+
const crossProjectPolicies = new Map(
|
|
94
|
+
await Promise.all(
|
|
95
|
+
prefixes.map(
|
|
96
|
+
async prefix =>
|
|
97
|
+
[
|
|
98
|
+
prefix,
|
|
99
|
+
await resolveEffectServerCrossProjectPolicy(
|
|
100
|
+
api,
|
|
101
|
+
prefix,
|
|
102
|
+
mod,
|
|
103
|
+
producer,
|
|
104
|
+
),
|
|
105
|
+
] as const,
|
|
106
|
+
),
|
|
107
|
+
),
|
|
108
|
+
);
|
|
109
|
+
const effectConfig = api.getServerConfig()?.bff?.effect;
|
|
110
|
+
const loaded = await resolveEffectBffModuleHandler(mod, {
|
|
111
|
+
openapi: effectConfig?.openapi,
|
|
112
|
+
dataPlatform: effectConfig?.dataPlatform,
|
|
113
|
+
validateRequest: request => {
|
|
114
|
+
const { path: mountedPathname } = useEffectContext();
|
|
115
|
+
const prefix = matchingPrefixes.find(
|
|
116
|
+
item =>
|
|
117
|
+
item === '/' ||
|
|
118
|
+
mountedPathname === item ||
|
|
119
|
+
mountedPathname.startsWith(`${item}/`),
|
|
120
|
+
);
|
|
121
|
+
if (!prefix) return null;
|
|
122
|
+
const requestUrl = new URL(request.url);
|
|
123
|
+
if (prefix !== '/') {
|
|
124
|
+
requestUrl.pathname =
|
|
125
|
+
requestUrl.pathname === '/'
|
|
126
|
+
? prefix
|
|
127
|
+
: `${prefix}${requestUrl.pathname}`;
|
|
128
|
+
}
|
|
129
|
+
return checkCrossProjectPolicyForRequest(
|
|
130
|
+
new Request(requestUrl, request),
|
|
131
|
+
crossProjectPolicies.get(prefix),
|
|
132
|
+
);
|
|
133
|
+
},
|
|
134
|
+
onWarning: message => logger.warn(message),
|
|
135
|
+
});
|
|
136
|
+
if (!loaded) {
|
|
137
|
+
const error = new Error(
|
|
138
|
+
`[BFF][Effect] Invalid Effect entry module: ${entryFile}. Export defineEffectBff(...) or a { api, layer } HttpApi module.`,
|
|
139
|
+
);
|
|
140
|
+
logger.warn(error.message);
|
|
141
|
+
throw error;
|
|
142
|
+
}
|
|
143
|
+
const candidateOwner = {};
|
|
144
|
+
if (loaded.dispose)
|
|
145
|
+
registerServerRuntimeDisposer(candidateOwner, loaded.dispose);
|
|
146
|
+
const candidate = createDisposableServerRuntimeHandle(
|
|
147
|
+
candidateOwner,
|
|
148
|
+
loaded.handler,
|
|
149
|
+
);
|
|
150
|
+
if (retired) {
|
|
151
|
+
await candidate.dispose();
|
|
152
|
+
throw new Error('Cannot initialize a retired Effect server.');
|
|
153
|
+
}
|
|
154
|
+
handler = candidate;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
api.onPrepare(async () => {
|
|
158
|
+
const { middlewares: globalMiddlewares } = api.getServerContext();
|
|
159
|
+
const configuredPrefix = api.getServerConfig()?.bff?.prefix;
|
|
160
|
+
const enableHandleWeb = api.getServerConfig()?.bff?.enableHandleWeb;
|
|
161
|
+
const configuredPrefixes = Array.isArray(configuredPrefix)
|
|
162
|
+
? configuredPrefix.filter(Boolean)
|
|
163
|
+
: [configuredPrefix || '/api'];
|
|
164
|
+
prefixes = [
|
|
165
|
+
...new Set(
|
|
166
|
+
configuredPrefixes.length > 0 ? configuredPrefixes : ['/api'],
|
|
167
|
+
),
|
|
168
|
+
];
|
|
169
|
+
matchingPrefixes = [...prefixes].sort(
|
|
170
|
+
(left, right) => right.length - left.length,
|
|
171
|
+
);
|
|
172
|
+
prefix = prefixes[0] || '/api';
|
|
173
|
+
const { serverBase } = api.getServerContext() as { serverBase?: object };
|
|
174
|
+
if (serverBase)
|
|
175
|
+
unregisterRuntimeDisposer = registerServerRuntimeDisposer(
|
|
176
|
+
serverBase,
|
|
177
|
+
dispose,
|
|
178
|
+
);
|
|
179
|
+
try {
|
|
180
|
+
await loadHandler();
|
|
181
|
+
} catch (error) {
|
|
182
|
+
await dispose();
|
|
183
|
+
throw error;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const middlewarePrefixes = enableHandleWeb ? [prefix] : matchingPrefixes;
|
|
187
|
+
const middlewares = middlewarePrefixes.map(middlewarePrefix => ({
|
|
188
|
+
name: 'effect-api-handler',
|
|
189
|
+
path: enableHandleWeb ? '*' : `${middlewarePrefix}/*`,
|
|
190
|
+
method: 'all' as const,
|
|
191
|
+
order: 'post' as const,
|
|
192
|
+
before: EFFECT_MIDDLEWARE_BEFORE,
|
|
193
|
+
handler: async (context: Context, next: Next) => {
|
|
194
|
+
const activeHandler = handler;
|
|
195
|
+
if (!activeHandler) {
|
|
196
|
+
if (enableHandleWeb) {
|
|
197
|
+
await next();
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
return createEffectServerRuntimeErrorResponse(
|
|
201
|
+
api,
|
|
202
|
+
new Error(
|
|
203
|
+
'[BFF][Effect] Missing Effect entry. Define api/index or configure bff.effect.entry.',
|
|
204
|
+
),
|
|
205
|
+
context,
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const mountedPrefix = enableHandleWeb
|
|
210
|
+
? matchingPrefixes.find(
|
|
211
|
+
item =>
|
|
212
|
+
item === '/' ||
|
|
213
|
+
context.req.path === item ||
|
|
214
|
+
context.req.path.startsWith(`${item}/`),
|
|
215
|
+
) || prefix
|
|
216
|
+
: middlewarePrefix;
|
|
217
|
+
const response = await dispatchEffectBffRequest(
|
|
218
|
+
activeHandler as EffectBffRequestHandler,
|
|
219
|
+
context.req.raw,
|
|
220
|
+
{
|
|
221
|
+
prefix: mountedPrefix,
|
|
222
|
+
env: context.env as Record<string, unknown>,
|
|
223
|
+
path: context.req.path,
|
|
224
|
+
method: context.req.method,
|
|
225
|
+
onError: error =>
|
|
226
|
+
createEffectServerRuntimeErrorResponse(api, error, context),
|
|
227
|
+
},
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
if (response.status === 404 && enableHandleWeb) {
|
|
231
|
+
await next();
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return new Response(response.body, response);
|
|
236
|
+
},
|
|
237
|
+
}));
|
|
238
|
+
|
|
239
|
+
globalMiddlewares.push(...middlewares);
|
|
240
|
+
});
|
|
241
|
+
},
|
|
242
|
+
});
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { fs, upath as path } from '@modern-js/utils';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
import {
|
|
4
|
+
emittedEffectEntry,
|
|
5
|
+
relativeEffectAppPath,
|
|
6
|
+
resolveEffectEntryFile,
|
|
7
|
+
} from './paths';
|
|
6
8
|
|
|
7
9
|
export function resolveBuiltEffectEntry(
|
|
8
10
|
appDirectory: string,
|
|
@@ -12,15 +14,15 @@ export function resolveBuiltEffectEntry(
|
|
|
12
14
|
if (sourceEntry === undefined || sourceEntry.length === 0) {
|
|
13
15
|
return undefined;
|
|
14
16
|
}
|
|
15
|
-
const relativeEntry =
|
|
16
|
-
if (relativeEntry ===
|
|
17
|
+
const relativeEntry = relativeEffectAppPath(appDirectory, sourceEntry);
|
|
18
|
+
if (relativeEntry === undefined) {
|
|
17
19
|
throw new Error(
|
|
18
20
|
`Effect BFF entry must be inside the application directory: ${sourceEntry}`,
|
|
19
21
|
);
|
|
20
22
|
}
|
|
21
|
-
const builtEntry =
|
|
22
|
-
.resolve(distDirectory, relativeEntry)
|
|
23
|
-
|
|
23
|
+
const builtEntry = emittedEffectEntry(
|
|
24
|
+
path.resolve(distDirectory, relativeEntry),
|
|
25
|
+
);
|
|
24
26
|
return fs.existsSync(builtEntry) ? builtEntry : undefined;
|
|
25
27
|
}
|
|
26
28
|
|
|
@@ -62,7 +64,7 @@ export function resolveEffectEntryPaths(options: {
|
|
|
62
64
|
});
|
|
63
65
|
const relativeEffectEntry =
|
|
64
66
|
sourceEffectEntry !== undefined && sourceEffectEntry.length > 0
|
|
65
|
-
? path.relative(appDir, sourceEffectEntry)
|
|
67
|
+
? emittedEffectEntry(path.relative(appDir, sourceEffectEntry))
|
|
66
68
|
: '';
|
|
67
69
|
return { sourceEffectEntry, relativeEffectEntry };
|
|
68
70
|
}
|
|
@@ -125,10 +125,9 @@ function isBareSpecifier(specifier: string) {
|
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
/**
|
|
128
|
-
* Keep installed
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
* generated entry is relocatable and directly executable by Node 26.7.
|
|
128
|
+
* Keep installed executable dependencies external to preserve runtime identity.
|
|
129
|
+
* Source requiring compilation is bundled even when pnpm injects a workspace
|
|
130
|
+
* package into node_modules: Node does not strip types inside that directory.
|
|
132
131
|
*/
|
|
133
132
|
function externalizeInstalledDependencies(options: {
|
|
134
133
|
runtimeResolveDir: string;
|
|
@@ -167,7 +166,13 @@ function externalizeInstalledDependencies(options: {
|
|
|
167
166
|
const realPath = await fs.promises
|
|
168
167
|
.realpath(resolution.path)
|
|
169
168
|
.catch(() => resolution.path);
|
|
170
|
-
|
|
169
|
+
const loader = SOURCE_LOADERS.get(path.extname(realPath).toLowerCase());
|
|
170
|
+
if (
|
|
171
|
+
realPath.includes(`${path.sep}node_modules${path.sep}`) &&
|
|
172
|
+
loader !== 'ts' &&
|
|
173
|
+
loader !== 'tsx' &&
|
|
174
|
+
loader !== 'jsx'
|
|
175
|
+
) {
|
|
171
176
|
const runtimeResolution = await buildApi.resolve(args.path, {
|
|
172
177
|
importer: '',
|
|
173
178
|
kind: args.kind,
|
|
@@ -4,42 +4,11 @@ import {
|
|
|
4
4
|
} from '@modern-js/bff-effect/effect';
|
|
5
5
|
import {
|
|
6
6
|
buildOperationContractMap,
|
|
7
|
-
|
|
7
|
+
resolveOperationProducer,
|
|
8
8
|
} from '@modern-js/server-runtime-extensions/bff-policy/node';
|
|
9
|
-
import {
|
|
9
|
+
import { upath as path } from '@modern-js/utils';
|
|
10
10
|
import { getHttpApiRuntime, loadEffectApi } from './http-api-runtime';
|
|
11
11
|
|
|
12
|
-
function getPackageInfo(
|
|
13
|
-
resourcePath: string,
|
|
14
|
-
appDir: string,
|
|
15
|
-
onDependency?: (dependency: string) => void,
|
|
16
|
-
): { name?: string; version?: string } {
|
|
17
|
-
for (const startDir of [path.dirname(resourcePath), appDir]) {
|
|
18
|
-
let current = path.resolve(startDir);
|
|
19
|
-
for (let depth = 0; depth < 32; depth += 1) {
|
|
20
|
-
const packageJsonPath = path.join(current, 'package.json');
|
|
21
|
-
if (fs.existsSync(packageJsonPath)) {
|
|
22
|
-
onDependency?.(packageJsonPath);
|
|
23
|
-
try {
|
|
24
|
-
const packageJson = fs.readJSONSync(packageJsonPath) as {
|
|
25
|
-
name?: string;
|
|
26
|
-
version?: string;
|
|
27
|
-
};
|
|
28
|
-
return { name: packageJson.name, version: packageJson.version };
|
|
29
|
-
} catch {
|
|
30
|
-
return {};
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
const parent = path.dirname(current);
|
|
34
|
-
if (parent === current) {
|
|
35
|
-
break;
|
|
36
|
-
}
|
|
37
|
-
current = parent;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
return {};
|
|
41
|
-
}
|
|
42
|
-
|
|
43
12
|
/** Derives server policy metadata without emitting or typing a client. */
|
|
44
13
|
export async function resolveEffectOperationContracts(options: {
|
|
45
14
|
appDir: string;
|
|
@@ -58,15 +27,12 @@ export async function resolveEffectOperationContracts(options: {
|
|
|
58
27
|
api,
|
|
59
28
|
options.prefix,
|
|
60
29
|
);
|
|
61
|
-
const packageInfo = getPackageInfo(
|
|
62
|
-
options.resourcePath,
|
|
63
|
-
options.appDir,
|
|
64
|
-
options.onDependency,
|
|
65
|
-
);
|
|
66
|
-
const requestId = options.requestId?.trim() || packageInfo.name || 'default';
|
|
67
30
|
return buildOperationContractMap({
|
|
68
31
|
handlers: toOperationContractSources(endpoints),
|
|
69
|
-
|
|
70
|
-
|
|
32
|
+
...resolveOperationProducer({
|
|
33
|
+
directories: [path.dirname(options.resourcePath), options.appDir],
|
|
34
|
+
requestId: options.requestId,
|
|
35
|
+
onDependency: options.onDependency,
|
|
36
|
+
}),
|
|
71
37
|
});
|
|
72
38
|
}
|
|
@@ -9,32 +9,66 @@ const JS_OR_TS_EXTS = [
|
|
|
9
9
|
'.mts',
|
|
10
10
|
'.cjs',
|
|
11
11
|
'.cts',
|
|
12
|
-
]
|
|
12
|
+
];
|
|
13
13
|
|
|
14
|
-
export
|
|
14
|
+
export const emittedEffectEntry = (entry: string) =>
|
|
15
|
+
entry.replace(/\.(?:[cm]?ts|tsx|jsx)$/u, '.js');
|
|
16
|
+
|
|
17
|
+
export function relativeEffectAppPath(appDir: string, entry: string) {
|
|
18
|
+
const relative = path.relative(appDir, entry);
|
|
19
|
+
return relative === '..' ||
|
|
20
|
+
relative.startsWith('../') ||
|
|
21
|
+
relative.split('/').includes('node_modules')
|
|
22
|
+
? undefined
|
|
23
|
+
: relative;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function existingEntry(entry: string): string | undefined {
|
|
27
|
+
return path.extname(entry)
|
|
28
|
+
? fs.existsSync(entry)
|
|
29
|
+
? entry
|
|
30
|
+
: undefined
|
|
31
|
+
: findExists(JS_OR_TS_EXTS.map(ext => `${entry}${ext}`)) || undefined;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
type EffectEntryOptions = {
|
|
15
35
|
appDir: string;
|
|
16
36
|
apiDir: string;
|
|
17
37
|
effectEntry?: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
38
|
+
};
|
|
39
|
+
export type EffectEntry =
|
|
40
|
+
| { kind: 'app-source'; path: string | undefined }
|
|
41
|
+
| { kind: 'built-output'; path: string | undefined }
|
|
42
|
+
| { kind: 'external-sdk'; path: string | undefined };
|
|
20
43
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
if (effectEntry !== undefined && effectEntry !== '') {
|
|
33
|
-
const entryWithoutExt = path.isAbsolute(effectEntry)
|
|
34
|
-
? effectEntry
|
|
35
|
-
: path.resolve(appDir, effectEntry);
|
|
36
|
-
return resolveEntry(entryWithoutExt);
|
|
44
|
+
/** Classify ownership before resolving files: production works without source. */
|
|
45
|
+
export function resolveEffectEntry(
|
|
46
|
+
options: EffectEntryOptions & { distDir?: string },
|
|
47
|
+
): EffectEntry {
|
|
48
|
+
const { appDir, apiDir, effectEntry, distDir } = options;
|
|
49
|
+
const entry = path.resolve(appDir, effectEntry || path.join(apiDir, 'index'));
|
|
50
|
+
if (distDir && relativeEffectAppPath(distDir, entry) !== undefined) {
|
|
51
|
+
return {
|
|
52
|
+
kind: 'built-output',
|
|
53
|
+
path: existingEntry(emittedEffectEntry(entry)),
|
|
54
|
+
};
|
|
37
55
|
}
|
|
56
|
+
const relative = relativeEffectAppPath(appDir, entry);
|
|
57
|
+
if (relative === undefined) {
|
|
58
|
+
return { kind: 'external-sdk', path: existingEntry(entry) };
|
|
59
|
+
}
|
|
60
|
+
return distDir
|
|
61
|
+
? {
|
|
62
|
+
kind: 'built-output',
|
|
63
|
+
path: existingEntry(
|
|
64
|
+
emittedEffectEntry(path.resolve(distDir, relative)),
|
|
65
|
+
),
|
|
66
|
+
}
|
|
67
|
+
: { kind: 'app-source', path: existingEntry(entry) };
|
|
68
|
+
}
|
|
38
69
|
|
|
39
|
-
|
|
70
|
+
export function resolveEffectEntryFile(
|
|
71
|
+
options: EffectEntryOptions,
|
|
72
|
+
): string | undefined {
|
|
73
|
+
return resolveEffectEntry(options).path;
|
|
40
74
|
}
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __webpack_require__ = {};
|
|
3
|
-
(()=>{
|
|
4
|
-
__webpack_require__.n = (module)=>{
|
|
5
|
-
var getter = module && module.__esModule ? ()=>module['default'] : ()=>module;
|
|
6
|
-
__webpack_require__.d(getter, {
|
|
7
|
-
a: getter
|
|
8
|
-
});
|
|
9
|
-
return getter;
|
|
10
|
-
};
|
|
11
|
-
})();
|
|
12
|
-
(()=>{
|
|
13
|
-
__webpack_require__.d = (exports1, getters, values)=>{
|
|
14
|
-
var define = (defs, kind)=>{
|
|
15
|
-
for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
16
|
-
enumerable: true,
|
|
17
|
-
[kind]: defs[key]
|
|
18
|
-
});
|
|
19
|
-
};
|
|
20
|
-
define(getters, "get");
|
|
21
|
-
define(values, "value");
|
|
22
|
-
};
|
|
23
|
-
})();
|
|
24
|
-
(()=>{
|
|
25
|
-
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
26
|
-
})();
|
|
27
|
-
(()=>{
|
|
28
|
-
__webpack_require__.r = (exports1)=>{
|
|
29
|
-
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
30
|
-
value: 'Module'
|
|
31
|
-
});
|
|
32
|
-
Object.defineProperty(exports1, '__esModule', {
|
|
33
|
-
value: true
|
|
34
|
-
});
|
|
35
|
-
};
|
|
36
|
-
})();
|
|
37
|
-
var __webpack_exports__ = {};
|
|
38
|
-
__webpack_require__.r(__webpack_exports__);
|
|
39
|
-
__webpack_require__.d(__webpack_exports__, {
|
|
40
|
-
resolveEffectAdapterEntryFile: ()=>resolveEffectAdapterEntryFile
|
|
41
|
-
});
|
|
42
|
-
const external_node_path_namespaceObject = require("node:path");
|
|
43
|
-
var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_namespaceObject);
|
|
44
|
-
require("@modern-js/server-runtime-extensions/server-config");
|
|
45
|
-
const utils_namespaceObject = require("@modern-js/utils");
|
|
46
|
-
const JS_OR_TS_EXTS = [
|
|
47
|
-
'.js',
|
|
48
|
-
'.jsx',
|
|
49
|
-
'.ts',
|
|
50
|
-
'.tsx',
|
|
51
|
-
'.mjs',
|
|
52
|
-
'.mts',
|
|
53
|
-
'.cjs',
|
|
54
|
-
'.cts'
|
|
55
|
-
];
|
|
56
|
-
function resolveJsOrTsEntry(entryWithoutOrWithExt) {
|
|
57
|
-
const extension = external_node_path_default().extname(entryWithoutOrWithExt);
|
|
58
|
-
if (JS_OR_TS_EXTS.includes(extension)) return utils_namespaceObject.fs.existsSync(entryWithoutOrWithExt) ? entryWithoutOrWithExt : void 0;
|
|
59
|
-
return (0, utils_namespaceObject.findExists)(JS_OR_TS_EXTS.map((ext)=>`${entryWithoutOrWithExt}${ext}`)) || void 0;
|
|
60
|
-
}
|
|
61
|
-
function builtEntryPath(entryPath) {
|
|
62
|
-
return entryPath.replace(/\.(?:[cm]?ts|tsx|jsx)$/u, '.js');
|
|
63
|
-
}
|
|
64
|
-
function relativeAppPath(appDirectory, entryPath) {
|
|
65
|
-
const relativePath = external_node_path_default().relative(appDirectory, entryPath);
|
|
66
|
-
return '..' === relativePath || relativePath.startsWith(`..${external_node_path_default().sep}`) ? void 0 : relativePath;
|
|
67
|
-
}
|
|
68
|
-
function isDependencyPath(relativePath) {
|
|
69
|
-
return relativePath?.split(/[\\/]/u).includes('node_modules') ?? false;
|
|
70
|
-
}
|
|
71
|
-
function resolveEffectAdapterEntryFile(api) {
|
|
72
|
-
const { appDirectory, apiDirectory, distDirectory } = api.getServerContext();
|
|
73
|
-
const appRoot = external_node_path_default().resolve(appDirectory || process.cwd());
|
|
74
|
-
const productionRoot = (0, utils_namespaceObject.isProd)() && distDirectory ? external_node_path_default().resolve(distDirectory) : void 0;
|
|
75
|
-
const configuredEntry = api.getServerConfig()?.bff?.effect?.entry;
|
|
76
|
-
if (configuredEntry) {
|
|
77
|
-
const sourceEntry = external_node_path_default().isAbsolute(configuredEntry) ? configuredEntry : external_node_path_default().resolve(appRoot, configuredEntry);
|
|
78
|
-
if (productionRoot) {
|
|
79
|
-
const relativeEntry = relativeAppPath(appRoot, sourceEntry);
|
|
80
|
-
if (void 0 === relativeEntry || isDependencyPath(relativeEntry)) return resolveJsOrTsEntry(sourceEntry);
|
|
81
|
-
return relativeEntry ? resolveJsOrTsEntry(builtEntryPath(external_node_path_default().resolve(productionRoot, relativeEntry))) : void 0;
|
|
82
|
-
}
|
|
83
|
-
return resolveJsOrTsEntry(sourceEntry);
|
|
84
|
-
}
|
|
85
|
-
const resolvedApiDirectory = external_node_path_default().resolve(appRoot, apiDirectory || utils_namespaceObject.API_DIR);
|
|
86
|
-
const productionApiDirectory = productionRoot ? void 0 !== relativeAppPath(productionRoot, resolvedApiDirectory) ? resolvedApiDirectory : (()=>{
|
|
87
|
-
const relativeApiDirectory = relativeAppPath(appRoot, resolvedApiDirectory);
|
|
88
|
-
if (isDependencyPath(relativeApiDirectory)) return resolvedApiDirectory;
|
|
89
|
-
return relativeApiDirectory ? external_node_path_default().resolve(productionRoot, relativeApiDirectory) : void 0;
|
|
90
|
-
})() : resolvedApiDirectory;
|
|
91
|
-
return productionApiDirectory ? resolveJsOrTsEntry(external_node_path_default().resolve(productionApiDirectory, 'index')) : void 0;
|
|
92
|
-
}
|
|
93
|
-
exports.resolveEffectAdapterEntryFile = __webpack_exports__.resolveEffectAdapterEntryFile;
|
|
94
|
-
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
95
|
-
"resolveEffectAdapterEntryFile"
|
|
96
|
-
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
97
|
-
Object.defineProperty(exports, '__esModule', {
|
|
98
|
-
value: true
|
|
99
|
-
});
|