@bleedingdev/modern-js-plugin-bff 3.2.0-ultramodern.12 → 3.2.0-ultramodern.121
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.js +9 -5
- package/dist/cjs/constants.js +13 -9
- package/dist/cjs/index.js +9 -5
- package/dist/cjs/loader.js +32 -5
- package/dist/cjs/runtime/create-request/index.js +9 -5
- package/dist/cjs/runtime/data-platform/index.js +50 -26
- package/dist/cjs/runtime/effect/adapter.js +99 -93
- package/dist/cjs/runtime/effect/context.js +19 -7
- package/dist/cjs/runtime/effect/edge.js +169 -0
- package/dist/cjs/runtime/effect/endpoint-contracts.js +130 -0
- package/dist/cjs/runtime/effect/handler.js +642 -0
- package/dist/cjs/runtime/effect/index.js +30 -547
- package/dist/cjs/runtime/effect/module.js +151 -0
- package/dist/cjs/runtime/effect/operation-context.js +103 -0
- package/dist/cjs/runtime/effect-client/index.js +22 -6
- package/dist/cjs/runtime/effect-client/runtime.js +266 -0
- package/dist/cjs/runtime/hono/adapter.js +30 -14
- package/dist/cjs/runtime/hono/index.js +9 -5
- package/dist/cjs/runtime/hono/operators.js +9 -5
- package/dist/cjs/runtime/safe-failure.js +83 -0
- package/dist/cjs/server.js +9 -5
- package/dist/cjs/utils/clientGenerator.js +13 -9
- package/dist/cjs/utils/createHonoRoutes.js +9 -5
- package/dist/cjs/utils/crossProjectApiPlugin.js +9 -5
- package/dist/cjs/utils/crossProjectServerPolicy.js +104 -0
- package/dist/cjs/utils/effectClientGenerator.js +116 -488
- package/dist/cjs/utils/pluginGenerator.js +9 -5
- package/dist/cjs/utils/runtimeGenerator.js +9 -5
- package/dist/esm/loader.mjs +23 -0
- package/dist/esm/runtime/data-platform/index.mjs +33 -22
- package/dist/esm/runtime/effect/adapter.mjs +91 -89
- package/dist/esm/runtime/effect/context.mjs +3 -1
- package/dist/esm/runtime/effect/edge.mjs +83 -0
- package/dist/esm/runtime/effect/endpoint-contracts.mjs +68 -0
- package/dist/esm/runtime/effect/handler.mjs +470 -0
- package/dist/esm/runtime/effect/index.mjs +3 -437
- package/dist/esm/runtime/effect/module.mjs +113 -0
- package/dist/esm/runtime/effect/operation-context.mjs +65 -0
- package/dist/esm/runtime/effect-client/index.mjs +14 -2
- package/dist/esm/runtime/effect-client/runtime.mjs +228 -0
- package/dist/esm/runtime/hono/adapter.mjs +21 -9
- package/dist/esm/runtime/safe-failure.mjs +45 -0
- package/dist/esm/utils/clientGenerator.mjs +5 -5
- package/dist/esm/utils/crossProjectServerPolicy.mjs +50 -0
- package/dist/esm/utils/effectClientGenerator.mjs +105 -484
- package/dist/esm-node/loader.mjs +23 -0
- package/dist/esm-node/runtime/data-platform/index.mjs +33 -22
- package/dist/esm-node/runtime/effect/adapter.mjs +91 -89
- package/dist/esm-node/runtime/effect/context.mjs +3 -1
- package/dist/esm-node/runtime/effect/edge.mjs +84 -0
- package/dist/esm-node/runtime/effect/endpoint-contracts.mjs +69 -0
- package/dist/esm-node/runtime/effect/handler.mjs +471 -0
- package/dist/esm-node/runtime/effect/index.mjs +3 -437
- package/dist/esm-node/runtime/effect/module.mjs +114 -0
- package/dist/esm-node/runtime/effect/operation-context.mjs +66 -0
- package/dist/esm-node/runtime/effect-client/index.mjs +14 -2
- package/dist/esm-node/runtime/effect-client/runtime.mjs +229 -0
- package/dist/esm-node/runtime/hono/adapter.mjs +21 -9
- package/dist/esm-node/runtime/safe-failure.mjs +46 -0
- package/dist/esm-node/utils/clientGenerator.mjs +5 -5
- package/dist/esm-node/utils/crossProjectServerPolicy.mjs +52 -0
- package/dist/esm-node/utils/effectClientGenerator.mjs +105 -484
- package/dist/types/runtime/create-request/index.d.ts +1 -0
- package/dist/types/runtime/data-platform/index.d.ts +4 -0
- package/dist/types/runtime/effect/adapter.d.ts +25 -0
- package/dist/types/runtime/effect/context.d.ts +3 -6
- package/dist/types/runtime/effect/edge.d.ts +25 -0
- package/dist/types/runtime/effect/endpoint-contracts.d.ts +62 -0
- package/dist/types/runtime/effect/handler.d.ts +203 -0
- package/dist/types/runtime/effect/index.d.ts +2 -170
- package/dist/types/runtime/effect/module.d.ts +48 -0
- package/dist/types/runtime/effect/operation-context.d.ts +10 -0
- package/dist/types/runtime/effect-client/index.d.ts +6 -1
- package/dist/types/runtime/effect-client/runtime.d.ts +71 -0
- package/dist/types/runtime/hono/adapter.d.ts +3 -0
- package/dist/types/runtime/safe-failure.d.ts +1 -0
- package/dist/types/utils/createHonoRoutes.d.ts +3 -3
- package/dist/types/utils/crossProjectServerPolicy.d.ts +35 -0
- package/dist/types/utils/effectClientGenerator.d.ts +16 -2
- package/package.json +41 -20
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { deriveOperationVersion } from "@modern-js/bff-core";
|
|
2
2
|
import { compatibleRequire, findExists, fs, logger } from "@modern-js/utils";
|
|
3
3
|
import path from "path";
|
|
4
|
+
import { collectEffectEndpoints, createEffectEndpointContractHash, ensureLeadingSlash, extractHttpApiFromModule, normalizeEffectPrefix } from "../runtime/effect/endpoint-contracts.mjs";
|
|
4
5
|
const JS_OR_TS_EXTS = [
|
|
5
6
|
'.js',
|
|
6
7
|
'.jsx',
|
|
@@ -12,18 +13,11 @@ const JS_OR_TS_EXTS = [
|
|
|
12
13
|
'.cts'
|
|
13
14
|
];
|
|
14
15
|
const DEFAULT_REQUEST_CREATOR = '@modern-js/plugin-bff/client';
|
|
15
|
-
const
|
|
16
|
+
const EFFECT_CLIENT_RUNTIME_IMPORT = '@modern-js/plugin-bff/effect-client-runtime';
|
|
16
17
|
let httpApiRuntimePromise;
|
|
17
18
|
function isRecord(value) {
|
|
18
19
|
return 'object' == typeof value && null !== value;
|
|
19
20
|
}
|
|
20
|
-
function ensureLeadingSlash(pathname) {
|
|
21
|
-
return pathname.startsWith('/') ? pathname : `/${pathname}`;
|
|
22
|
-
}
|
|
23
|
-
function normalizePrefix(prefix) {
|
|
24
|
-
if ('/' === prefix) return '';
|
|
25
|
-
return ensureLeadingSlash(prefix || '/api');
|
|
26
|
-
}
|
|
27
21
|
function isAbsoluteUrl(value) {
|
|
28
22
|
try {
|
|
29
23
|
new URL(value);
|
|
@@ -35,32 +29,22 @@ function isAbsoluteUrl(value) {
|
|
|
35
29
|
function resolveBatchEndpoint(prefix, endpoint) {
|
|
36
30
|
const value = endpoint || '/_data/batch';
|
|
37
31
|
if (isAbsoluteUrl(value)) return value;
|
|
38
|
-
const normalizedPrefix =
|
|
32
|
+
const normalizedPrefix = normalizeEffectPrefix(prefix);
|
|
39
33
|
const normalizedEndpoint = ensureLeadingSlash(value);
|
|
40
34
|
if (!normalizedPrefix) return normalizedEndpoint;
|
|
41
35
|
if (normalizedEndpoint === normalizedPrefix || normalizedEndpoint.startsWith(`${normalizedPrefix}/`)) return normalizedEndpoint;
|
|
42
36
|
return `${normalizedPrefix}${'/' === normalizedEndpoint ? '' : normalizedEndpoint}`;
|
|
43
37
|
}
|
|
44
|
-
function
|
|
45
|
-
const normalizedPrefix = normalizePrefix(prefix);
|
|
46
|
-
const normalizedEndpointPath = ensureLeadingSlash(endpointPath);
|
|
47
|
-
const finalEndpointPath = '/' === normalizedEndpointPath ? '' : endpointPath;
|
|
48
|
-
if (!normalizedPrefix && !finalEndpointPath) return '/';
|
|
49
|
-
return `${normalizedPrefix}${finalEndpointPath || ''}`;
|
|
50
|
-
}
|
|
51
|
-
function toSafeIdentifier(name) {
|
|
52
|
-
const sanitized = name.replace(/[^a-zA-Z0-9_$]/g, '_');
|
|
53
|
-
if (!sanitized) return '_';
|
|
54
|
-
if (/^[0-9]/.test(sanitized)) return `_${sanitized}`;
|
|
55
|
-
return sanitized;
|
|
56
|
-
}
|
|
57
|
-
function getPackageName(appDir) {
|
|
38
|
+
function getPackageInfo(appDir) {
|
|
58
39
|
try {
|
|
59
40
|
const packageJsonPath = path.resolve(appDir, './package.json');
|
|
60
41
|
const packageJson = fs.readJSONSync(packageJsonPath);
|
|
61
|
-
return
|
|
42
|
+
return {
|
|
43
|
+
name: packageJson.name,
|
|
44
|
+
version: packageJson.version
|
|
45
|
+
};
|
|
62
46
|
} catch {
|
|
63
|
-
return;
|
|
47
|
+
return {};
|
|
64
48
|
}
|
|
65
49
|
}
|
|
66
50
|
async function getHttpApiRuntime() {
|
|
@@ -83,472 +67,66 @@ async function getHttpApiRuntime() {
|
|
|
83
67
|
})();
|
|
84
68
|
return httpApiRuntimePromise;
|
|
85
69
|
}
|
|
86
|
-
function resolveApiId(api) {
|
|
87
|
-
const fallback = 'EffectHttpApi';
|
|
88
|
-
const maybeApi = api;
|
|
89
|
-
if ('identifier' in maybeApi && 'string' == typeof maybeApi.identifier && maybeApi.identifier) return maybeApi.identifier;
|
|
90
|
-
return fallback;
|
|
91
|
-
}
|
|
92
|
-
function collectEffectEndpoints(httpApiRuntime, api, prefix) {
|
|
93
|
-
const endpoints = [];
|
|
94
|
-
const apiId = resolveApiId(api);
|
|
95
|
-
httpApiRuntime.reflect(api, {
|
|
96
|
-
onGroup: ()=>{},
|
|
97
|
-
onEndpoint: ({ group, endpoint })=>{
|
|
98
|
-
endpoints.push({
|
|
99
|
-
apiId,
|
|
100
|
-
groupName: String(group.identifier),
|
|
101
|
-
endpointName: String(endpoint.name),
|
|
102
|
-
method: String(endpoint.method).toUpperCase(),
|
|
103
|
-
routePath: getRoutePath(prefix, String(endpoint.path))
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
return endpoints.sort((a, b)=>{
|
|
108
|
-
if (a.groupName === b.groupName) return a.endpointName.localeCompare(b.endpointName);
|
|
109
|
-
return a.groupName.localeCompare(b.groupName);
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
70
|
async function loadEffectApi(resourcePath) {
|
|
113
71
|
const httpApiRuntime = await getHttpApiRuntime();
|
|
114
72
|
const mod = await compatibleRequire(resourcePath, false);
|
|
115
|
-
|
|
116
|
-
if (isRecord(mod) && isRecord(mod.default) && httpApiRuntime.isHttpApi(mod.default.api)) return mod.default.api;
|
|
117
|
-
if (isRecord(mod) && 'function' == typeof mod.default && 0 === mod.default.length) {
|
|
118
|
-
const output = await mod.default();
|
|
119
|
-
if (isRecord(output) && httpApiRuntime.isHttpApi(output.api)) return output.api;
|
|
120
|
-
}
|
|
121
|
-
return null;
|
|
73
|
+
return extractHttpApiFromModule(mod, httpApiRuntime.isHttpApi);
|
|
122
74
|
}
|
|
123
75
|
function renderEffectClientCode(endpoints, options) {
|
|
124
|
-
const senderDeclarations = [];
|
|
125
|
-
const operationDeclarations = [];
|
|
126
|
-
const callerDeclarations = [];
|
|
127
|
-
const groupedCallers = {};
|
|
128
|
-
const groupedOperations = {};
|
|
129
76
|
const requestCreator = options.requestCreator || DEFAULT_REQUEST_CREATOR;
|
|
130
|
-
const dataPlatformImport = DEFAULT_DATA_PLATFORM_IMPORT;
|
|
131
77
|
const httpMethodDecider = options.httpMethodDecider || 'functionName';
|
|
132
|
-
const
|
|
133
|
-
const packageName =
|
|
78
|
+
const packageInfo = getPackageInfo(options.appDir);
|
|
79
|
+
const packageName = packageInfo.name;
|
|
134
80
|
const dataPlatformAppNamespace = packageName || 'unknown-app';
|
|
135
81
|
const requestId = 'bundle' === options.target ? packageName || process.env.npm_package_name : void 0;
|
|
136
82
|
const normalizedRequestId = requestId || 'default';
|
|
137
|
-
const operationVersion =
|
|
138
|
-
const schemaHash = createOperationSchemaHash(createOperationEntries(endpoints.map((endpoint)=>({
|
|
139
|
-
name: endpoint.endpointName,
|
|
140
|
-
httpMethod: endpoint.method,
|
|
141
|
-
routePath: endpoint.routePath
|
|
142
|
-
}))), normalizedRequestId);
|
|
83
|
+
const operationVersion = deriveOperationVersion(packageInfo.version);
|
|
143
84
|
const batchConfig = options.dataPlatformBatch;
|
|
144
85
|
const batchEndpoint = resolveBatchEndpoint(options.prefix, batchConfig?.endpoint);
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
appNamespace: dataPlatformAppNamespace,
|
|
178
|
-
apiId: endpoint.apiId,
|
|
179
|
-
group: endpoint.groupName,
|
|
180
|
-
endpoint: endpoint.endpointName,
|
|
181
|
-
operationId,
|
|
182
|
-
routePath: endpoint.routePath,
|
|
183
|
-
method: endpoint.method,
|
|
184
|
-
operationVersion,
|
|
185
|
-
schemaHash,
|
|
186
|
-
version: operationVersion
|
|
187
|
-
})};`);
|
|
188
|
-
callerDeclarations.push(`const ${callVar} = (request = {}) => ${senderVar}(__prepareEffectRequest(${JSON.stringify(endpoint.method)}, ${JSON.stringify(endpoint.routePath)}, ${operationVar}, request));`);
|
|
189
|
-
groupedCallers[endpoint.groupName] ??= [];
|
|
190
|
-
groupedCallers[endpoint.groupName].push({
|
|
191
|
-
endpointName: endpoint.endpointName,
|
|
192
|
-
callVar
|
|
193
|
-
});
|
|
194
|
-
groupedOperations[endpoint.groupName] ??= [];
|
|
195
|
-
groupedOperations[endpoint.groupName].push({
|
|
196
|
-
endpointName: endpoint.endpointName,
|
|
197
|
-
operationVar
|
|
198
|
-
});
|
|
199
|
-
});
|
|
200
|
-
const groupObjectEntries = Object.entries(groupedCallers).map(([groupName, groupCallers])=>{
|
|
201
|
-
const endpointEntries = groupCallers.map((caller)=>`${JSON.stringify(caller.endpointName)}: ${caller.callVar}`).join(', ');
|
|
202
|
-
return `${JSON.stringify(groupName)}: { ${endpointEntries} }`;
|
|
203
|
-
});
|
|
204
|
-
const clientObject = groupObjectEntries.length ? `{
|
|
205
|
-
${groupObjectEntries.join(',\n ')}
|
|
206
|
-
}` : '{}';
|
|
207
|
-
const operationManifestEntries = Object.entries(groupedOperations).map(([groupName, groupOperations])=>{
|
|
208
|
-
const endpointEntries = groupOperations.map((operation)=>`${JSON.stringify(operation.endpointName)}: ${operation.operationVar}`).join(', ');
|
|
209
|
-
return `${JSON.stringify(groupName)}: { ${endpointEntries} }`;
|
|
210
|
-
});
|
|
211
|
-
const operationManifestObject = operationManifestEntries.length ? `{
|
|
212
|
-
${operationManifestEntries.join(',\n ')}
|
|
213
|
-
}` : '{}';
|
|
86
|
+
const manifest = {
|
|
87
|
+
endpoints: endpoints.map((endpoint)=>({
|
|
88
|
+
apiId: endpoint.apiId,
|
|
89
|
+
group: endpoint.groupName,
|
|
90
|
+
endpoint: endpoint.endpointName,
|
|
91
|
+
method: endpoint.method,
|
|
92
|
+
routePath: endpoint.routePath,
|
|
93
|
+
schemaHash: createEffectEndpointContractHash(endpoint, normalizedRequestId),
|
|
94
|
+
operationVersion
|
|
95
|
+
}))
|
|
96
|
+
};
|
|
97
|
+
const config = {
|
|
98
|
+
appNamespace: dataPlatformAppNamespace,
|
|
99
|
+
...requestId ? {
|
|
100
|
+
requestId
|
|
101
|
+
} : {},
|
|
102
|
+
port: options.port,
|
|
103
|
+
useEnvPort: 'server' === options.target,
|
|
104
|
+
defaultOrigin: `http://localhost:${String(options.port)}`,
|
|
105
|
+
httpMethodDecider,
|
|
106
|
+
batch: {
|
|
107
|
+
enabled: batchConfig?.enabled ?? true,
|
|
108
|
+
endpoint: batchEndpoint,
|
|
109
|
+
flushIntervalMs: batchConfig?.flushIntervalMs ?? 8,
|
|
110
|
+
maxBatchSize: batchConfig?.maxBatchSize ?? 16,
|
|
111
|
+
maxBatchBytes: batchConfig?.maxBatchBytes ?? 65536,
|
|
112
|
+
requestTimeoutMs: batchConfig?.requestTimeoutMs ?? 10000,
|
|
113
|
+
allowedMethods: batchConfig?.allowedMethods && batchConfig.allowedMethods.length > 0 ? batchConfig.allowedMethods : [
|
|
114
|
+
'GET'
|
|
115
|
+
]
|
|
116
|
+
}
|
|
117
|
+
};
|
|
214
118
|
return `import * as __requestRuntime from ${JSON.stringify(requestCreator)};
|
|
215
|
-
import {
|
|
216
|
-
createDataBatchTransport,
|
|
217
|
-
DEFAULT_DATA_BATCH_HEADER,
|
|
218
|
-
DEFAULT_DATA_ENVELOPE_HEADER,
|
|
219
|
-
createRequestEnvelope,
|
|
220
|
-
encodeRequestEnvelopeHeader,
|
|
221
|
-
} from ${JSON.stringify(dataPlatformImport)};
|
|
222
|
-
|
|
223
|
-
const createRequest = __requestRuntime.createRequest;
|
|
224
|
-
const __configureRequest =
|
|
225
|
-
typeof __requestRuntime.configure === 'function'
|
|
226
|
-
? __requestRuntime.configure
|
|
227
|
-
: undefined;
|
|
228
|
-
const __createRequestContextHeaders =
|
|
229
|
-
typeof __requestRuntime.createRequestContextHeaders === 'function'
|
|
230
|
-
? __requestRuntime.createRequestContextHeaders
|
|
231
|
-
: undefined;
|
|
232
|
-
|
|
233
|
-
const __METHODS_WITHOUT_BODY = new Set(['GET', 'DELETE', 'HEAD', 'OPTIONS']);
|
|
234
|
-
const __DATA_REQUEST_MODES = new Set(['cache-first', 'stale-while-revalidate', 'network-only']);
|
|
235
|
-
const __DATA_MUTATION_MODES = new Set(['optimistic', 'pessimistic', 'fire-and-forget']);
|
|
236
|
-
const __DEFAULT_APP_NAMESPACE = ${JSON.stringify(dataPlatformAppNamespace)};
|
|
237
|
-
const __DEFAULT_ORIGIN = 'http://localhost:${String(options.port)}';
|
|
238
|
-
const __DEFAULT_BATCH_CONFIG = ${batchConfigCode};
|
|
239
|
-
const __REQUEST_ID = ${requestId ? JSON.stringify(requestId) : 'undefined'};
|
|
240
|
-
const __RUNTIME_FETCH =
|
|
241
|
-
typeof fetch === 'function' ? fetch.bind(globalThis) : undefined;
|
|
119
|
+
import { createGeneratedEffectClient } from ${JSON.stringify(EFFECT_CLIENT_RUNTIME_IMPORT)};
|
|
242
120
|
|
|
243
|
-
|
|
244
|
-
const __configurePayload = {
|
|
245
|
-
requestId: __REQUEST_ID,
|
|
246
|
-
requireEnvelope: true,
|
|
247
|
-
identityBinding: {
|
|
248
|
-
enabled: true,
|
|
249
|
-
strict: true,
|
|
250
|
-
},
|
|
251
|
-
operationContract: {
|
|
252
|
-
enabled: true,
|
|
253
|
-
strict: true,
|
|
254
|
-
requireSchemaHash: true,
|
|
255
|
-
requireOperationVersion: true,
|
|
256
|
-
},
|
|
257
|
-
setDomain: () => {
|
|
258
|
-
if (
|
|
259
|
-
typeof window !== 'undefined' &&
|
|
260
|
-
window.location &&
|
|
261
|
-
typeof window.location.origin === 'string' &&
|
|
262
|
-
window.location.origin
|
|
263
|
-
) {
|
|
264
|
-
return window.location.origin;
|
|
265
|
-
}
|
|
121
|
+
const __manifest = ${JSON.stringify(manifest, null, 2)};
|
|
266
122
|
|
|
267
|
-
|
|
268
|
-
typeof globalThis !== 'undefined' &&
|
|
269
|
-
globalThis.location &&
|
|
270
|
-
typeof globalThis.location.origin === 'string' &&
|
|
271
|
-
globalThis.location.origin
|
|
272
|
-
) {
|
|
273
|
-
return globalThis.location.origin;
|
|
274
|
-
}
|
|
123
|
+
const __config = ${JSON.stringify(config, null, 2)};
|
|
275
124
|
|
|
276
|
-
|
|
277
|
-
},
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
if (__DEFAULT_BATCH_CONFIG.enabled !== false && __RUNTIME_FETCH) {
|
|
281
|
-
__configurePayload.request = createDataBatchTransport({
|
|
282
|
-
fetch: __RUNTIME_FETCH,
|
|
283
|
-
endpoint: __DEFAULT_BATCH_CONFIG.endpoint,
|
|
284
|
-
flushIntervalMs: __DEFAULT_BATCH_CONFIG.flushIntervalMs,
|
|
285
|
-
maxBatchSize: __DEFAULT_BATCH_CONFIG.maxBatchSize,
|
|
286
|
-
maxBatchBytes: __DEFAULT_BATCH_CONFIG.maxBatchBytes,
|
|
287
|
-
requestTimeoutMs: __DEFAULT_BATCH_CONFIG.requestTimeoutMs,
|
|
288
|
-
allowedMethods: __DEFAULT_BATCH_CONFIG.allowedMethods,
|
|
289
|
-
});
|
|
290
|
-
}
|
|
125
|
+
const __generated = createGeneratedEffectClient(__manifest, __config, __requestRuntime);
|
|
291
126
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
const __isRecord = value => typeof value === 'object' && value !== null;
|
|
296
|
-
const __stringOrUndefined = value =>
|
|
297
|
-
typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
298
|
-
const __isDataRequestMode = value =>
|
|
299
|
-
typeof value === 'string' && __DATA_REQUEST_MODES.has(value);
|
|
300
|
-
const __isDataMutationMode = value =>
|
|
301
|
-
typeof value === 'string' && __DATA_MUTATION_MODES.has(value);
|
|
302
|
-
const __normalizeOrigin = value => {
|
|
303
|
-
if (typeof value !== 'string' || value.length === 0) {
|
|
304
|
-
return undefined;
|
|
305
|
-
}
|
|
306
|
-
try {
|
|
307
|
-
return new URL(value).origin;
|
|
308
|
-
} catch {
|
|
309
|
-
return undefined;
|
|
310
|
-
}
|
|
311
|
-
};
|
|
312
|
-
|
|
313
|
-
const __normalizeRequest = (method, request = {}) => {
|
|
314
|
-
if (!__isRecord(request)) {
|
|
315
|
-
return {};
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
const payload = { ...request };
|
|
319
|
-
|
|
320
|
-
if (__isRecord(request.path) && !__isRecord(payload.params)) {
|
|
321
|
-
payload.params = request.path;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
if (__isRecord(request.urlParams) && !__isRecord(payload.query)) {
|
|
325
|
-
payload.query = request.urlParams;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
if (__isRecord(request.headers) && !__isRecord(payload.headers)) {
|
|
329
|
-
payload.headers = request.headers;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
if ('payload' in request && request.payload !== undefined) {
|
|
333
|
-
if (request.payload instanceof FormData && !('formData' in payload)) {
|
|
334
|
-
payload.formData = request.payload;
|
|
335
|
-
} else if (__METHODS_WITHOUT_BODY.has(method)) {
|
|
336
|
-
if (__isRecord(request.payload)) {
|
|
337
|
-
payload.query = __isRecord(payload.query)
|
|
338
|
-
? { ...payload.query, ...request.payload }
|
|
339
|
-
: request.payload;
|
|
340
|
-
} else if (!('body' in payload)) {
|
|
341
|
-
payload.body = request.payload;
|
|
342
|
-
}
|
|
343
|
-
} else if (__isRecord(request.payload) && !('data' in payload)) {
|
|
344
|
-
payload.data = request.payload;
|
|
345
|
-
} else if (!('body' in payload)) {
|
|
346
|
-
payload.body = request.payload;
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
return payload;
|
|
351
|
-
};
|
|
352
|
-
|
|
353
|
-
const __resolveOrigin = () => {
|
|
354
|
-
if (
|
|
355
|
-
typeof window !== 'undefined' &&
|
|
356
|
-
window.location &&
|
|
357
|
-
typeof window.location.origin === 'string' &&
|
|
358
|
-
window.location.origin
|
|
359
|
-
) {
|
|
360
|
-
return window.location.origin;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
if (
|
|
364
|
-
typeof globalThis !== 'undefined' &&
|
|
365
|
-
globalThis.location &&
|
|
366
|
-
typeof globalThis.location.origin === 'string' &&
|
|
367
|
-
globalThis.location.origin
|
|
368
|
-
) {
|
|
369
|
-
return globalThis.location.origin;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
return __DEFAULT_ORIGIN;
|
|
373
|
-
};
|
|
374
|
-
|
|
375
|
-
const __resolveTargetOrigin = dataPlatform => {
|
|
376
|
-
const explicitTargetOrigin =
|
|
377
|
-
__stringOrUndefined(dataPlatform.targetOrigin) ||
|
|
378
|
-
__stringOrUndefined(dataPlatform.endpointOrigin);
|
|
379
|
-
if (explicitTargetOrigin) {
|
|
380
|
-
return explicitTargetOrigin;
|
|
381
|
-
}
|
|
382
|
-
return __DEFAULT_ORIGIN;
|
|
383
|
-
};
|
|
384
|
-
|
|
385
|
-
const __shouldAttachEnvelopeHeader = dataPlatform => {
|
|
386
|
-
if (dataPlatform.allowCrossOriginEnvelope === true) {
|
|
387
|
-
return true;
|
|
388
|
-
}
|
|
389
|
-
const currentOrigin = __normalizeOrigin(__resolveOrigin());
|
|
390
|
-
const targetOrigin = __normalizeOrigin(__resolveTargetOrigin(dataPlatform));
|
|
391
|
-
if (!currentOrigin || !targetOrigin) {
|
|
392
|
-
return true;
|
|
393
|
-
}
|
|
394
|
-
return currentOrigin === targetOrigin;
|
|
395
|
-
};
|
|
396
|
-
|
|
397
|
-
const __toEnvelopeInput = normalizedRequest => {
|
|
398
|
-
if (!__isRecord(normalizedRequest)) {
|
|
399
|
-
return {};
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
const payload = {};
|
|
403
|
-
if (__isRecord(normalizedRequest.params)) {
|
|
404
|
-
payload.path = normalizedRequest.params;
|
|
405
|
-
}
|
|
406
|
-
if (__isRecord(normalizedRequest.query)) {
|
|
407
|
-
payload.query = normalizedRequest.query;
|
|
408
|
-
}
|
|
409
|
-
if ('data' in normalizedRequest && normalizedRequest.data !== undefined) {
|
|
410
|
-
payload.data = normalizedRequest.data;
|
|
411
|
-
}
|
|
412
|
-
if ('body' in normalizedRequest && normalizedRequest.body !== undefined) {
|
|
413
|
-
payload.body = normalizedRequest.body;
|
|
414
|
-
}
|
|
415
|
-
if (
|
|
416
|
-
typeof FormData !== 'undefined' &&
|
|
417
|
-
normalizedRequest.formData instanceof FormData
|
|
418
|
-
) {
|
|
419
|
-
payload.formData = Array.from(normalizedRequest.formData.entries()).map(
|
|
420
|
-
([key, value]) => [key, String(value)],
|
|
421
|
-
);
|
|
422
|
-
}
|
|
423
|
-
if (
|
|
424
|
-
typeof URLSearchParams !== 'undefined' &&
|
|
425
|
-
normalizedRequest.formUrlencoded instanceof URLSearchParams
|
|
426
|
-
) {
|
|
427
|
-
payload.formUrlencoded = normalizedRequest.formUrlencoded.toString();
|
|
428
|
-
}
|
|
429
|
-
return payload;
|
|
430
|
-
};
|
|
431
|
-
|
|
432
|
-
const createEffectRequestContext = requestContext => {
|
|
433
|
-
if (!__isRecord(requestContext)) {
|
|
434
|
-
return {};
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
const headers = __createRequestContextHeaders
|
|
438
|
-
? __createRequestContextHeaders(requestContext)
|
|
439
|
-
: {};
|
|
440
|
-
|
|
441
|
-
return {
|
|
442
|
-
...requestContext,
|
|
443
|
-
headers,
|
|
444
|
-
};
|
|
445
|
-
};
|
|
446
|
-
|
|
447
|
-
const __applyRequestContext = (normalizedRequest, request = {}) => {
|
|
448
|
-
if (!__isRecord(request) || !__isRecord(request.requestContext)) {
|
|
449
|
-
return normalizedRequest;
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
const requestContext = createEffectRequestContext(request.requestContext);
|
|
453
|
-
const requestHeaders = __isRecord(requestContext.headers)
|
|
454
|
-
? requestContext.headers
|
|
455
|
-
: {};
|
|
456
|
-
|
|
457
|
-
if (Object.keys(requestHeaders).length === 0) {
|
|
458
|
-
return normalizedRequest;
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
return {
|
|
462
|
-
...normalizedRequest,
|
|
463
|
-
headers: {
|
|
464
|
-
...requestHeaders,
|
|
465
|
-
...(__isRecord(normalizedRequest.headers) ? normalizedRequest.headers : {}),
|
|
466
|
-
},
|
|
467
|
-
};
|
|
468
|
-
};
|
|
469
|
-
|
|
470
|
-
const __prepareEffectRequest = (method, routePath, operation, request = {}) => {
|
|
471
|
-
const normalizedRequest = __applyRequestContext(
|
|
472
|
-
__normalizeRequest(method, request),
|
|
473
|
-
request,
|
|
474
|
-
);
|
|
475
|
-
const dataPlatform = __isRecord(request) && __isRecord(request.dataPlatform)
|
|
476
|
-
? request.dataPlatform
|
|
477
|
-
: {};
|
|
478
|
-
const strictEnvelope =
|
|
479
|
-
dataPlatform.requireEnvelope === true || dataPlatform.strict === true;
|
|
480
|
-
|
|
481
|
-
if (!strictEnvelope && !__shouldAttachEnvelopeHeader(dataPlatform)) {
|
|
482
|
-
return normalizedRequest;
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
try {
|
|
486
|
-
const namespace =
|
|
487
|
-
__stringOrUndefined(dataPlatform.appNamespace) || __DEFAULT_APP_NAMESPACE;
|
|
488
|
-
const origin = __stringOrUndefined(dataPlatform.origin) || __resolveOrigin();
|
|
489
|
-
const envelope = createRequestEnvelope({
|
|
490
|
-
operation: {
|
|
491
|
-
...operation,
|
|
492
|
-
appNamespace: namespace,
|
|
493
|
-
},
|
|
494
|
-
scope: {
|
|
495
|
-
appNamespace: namespace,
|
|
496
|
-
origin,
|
|
497
|
-
tenantId: __stringOrUndefined(dataPlatform.tenantId),
|
|
498
|
-
userId: __stringOrUndefined(dataPlatform.userId),
|
|
499
|
-
sessionId: __stringOrUndefined(dataPlatform.sessionId),
|
|
500
|
-
},
|
|
501
|
-
requestInput: {
|
|
502
|
-
method,
|
|
503
|
-
routePath,
|
|
504
|
-
payload: __toEnvelopeInput(normalizedRequest),
|
|
505
|
-
},
|
|
506
|
-
requestMode: __isDataRequestMode(dataPlatform.requestMode)
|
|
507
|
-
? dataPlatform.requestMode
|
|
508
|
-
: undefined,
|
|
509
|
-
mutationMode: __isDataMutationMode(dataPlatform.mutationMode)
|
|
510
|
-
? dataPlatform.mutationMode
|
|
511
|
-
: undefined,
|
|
512
|
-
selectionPlan: __isRecord(dataPlatform.selectionPlan)
|
|
513
|
-
? dataPlatform.selectionPlan
|
|
514
|
-
: undefined,
|
|
515
|
-
traceContext: __isRecord(dataPlatform.traceContext)
|
|
516
|
-
? dataPlatform.traceContext
|
|
517
|
-
: undefined,
|
|
518
|
-
requireTraceContext: dataPlatform.requireTraceContext === true,
|
|
519
|
-
});
|
|
520
|
-
|
|
521
|
-
const headerName =
|
|
522
|
-
__stringOrUndefined(dataPlatform.envelopeHeader) ||
|
|
523
|
-
DEFAULT_DATA_ENVELOPE_HEADER;
|
|
524
|
-
const headers = __isRecord(normalizedRequest.headers)
|
|
525
|
-
? { ...normalizedRequest.headers }
|
|
526
|
-
: {};
|
|
527
|
-
|
|
528
|
-
if (dataPlatform.batch === false) {
|
|
529
|
-
headers[DEFAULT_DATA_BATCH_HEADER] = 'off';
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
headers[headerName] = encodeRequestEnvelopeHeader(envelope);
|
|
533
|
-
|
|
534
|
-
return {
|
|
535
|
-
...normalizedRequest,
|
|
536
|
-
headers,
|
|
537
|
-
};
|
|
538
|
-
} catch (error) {
|
|
539
|
-
if (strictEnvelope) {
|
|
540
|
-
throw error;
|
|
541
|
-
}
|
|
542
|
-
return normalizedRequest;
|
|
543
|
-
}
|
|
544
|
-
};
|
|
545
|
-
|
|
546
|
-
${senderDeclarations.join('\n')}
|
|
547
|
-
${operationDeclarations.join('\n')}
|
|
548
|
-
${callerDeclarations.join('\n')}
|
|
549
|
-
|
|
550
|
-
const client = ${clientObject};
|
|
551
|
-
const operationManifest = ${operationManifestObject};
|
|
127
|
+
const client = __generated.client;
|
|
128
|
+
const operationManifest = __generated.operationManifest;
|
|
129
|
+
const createEffectRequestContext = __generated.createEffectRequestContext;
|
|
552
130
|
const effectBffModule = {
|
|
553
131
|
client,
|
|
554
132
|
operationManifest,
|
|
@@ -559,7 +137,23 @@ export { client, createEffectRequestContext, operationManifest };
|
|
|
559
137
|
export default effectBffModule;
|
|
560
138
|
`;
|
|
561
139
|
}
|
|
562
|
-
function
|
|
140
|
+
function renderClientShape(endpoints, valueType) {
|
|
141
|
+
if (0 === endpoints.length) return `Record<string, Record<string, ${valueType}>>`;
|
|
142
|
+
const groups = new Map();
|
|
143
|
+
for (const endpoint of endpoints){
|
|
144
|
+
const group = groups.get(endpoint.groupName) || [];
|
|
145
|
+
group.push(endpoint.endpointName);
|
|
146
|
+
groups.set(endpoint.groupName, group);
|
|
147
|
+
}
|
|
148
|
+
const groupEntries = [
|
|
149
|
+
...groups.entries()
|
|
150
|
+
].map(([groupName, names])=>{
|
|
151
|
+
const endpointEntries = names.map((name)=>` ${JSON.stringify(name)}: ${valueType};`).join('\n');
|
|
152
|
+
return ` ${JSON.stringify(groupName)}: {\n${endpointEntries}\n };`;
|
|
153
|
+
});
|
|
154
|
+
return `{\n${groupEntries.join('\n')}\n}`;
|
|
155
|
+
}
|
|
156
|
+
function renderEffectClientDeclaration(endpoints = []) {
|
|
563
157
|
return `export type EffectClientOperation = (
|
|
564
158
|
request?: unknown,
|
|
565
159
|
) => Promise<unknown>;
|
|
@@ -581,37 +175,64 @@ export type EffectOperationManifest = Record<
|
|
|
581
175
|
string,
|
|
582
176
|
Record<string, EffectOperationDescriptor>
|
|
583
177
|
>;
|
|
178
|
+
export type EffectOperationContext = {
|
|
179
|
+
requestId?: string;
|
|
180
|
+
operationId?: string;
|
|
181
|
+
routePath?: string;
|
|
182
|
+
method?: string;
|
|
183
|
+
schemaHash?: string;
|
|
184
|
+
operationVersion?: number;
|
|
185
|
+
locale?: string;
|
|
186
|
+
traceparent?: string;
|
|
187
|
+
traceId?: string;
|
|
188
|
+
spanId?: string;
|
|
189
|
+
source?: string;
|
|
190
|
+
scope?: Record<string, unknown>;
|
|
191
|
+
sessionClaims?: Record<string, unknown>;
|
|
192
|
+
attributes?: Record<string, unknown>;
|
|
193
|
+
};
|
|
584
194
|
export type EffectRequestContext = {
|
|
585
195
|
headers?: Record<string, string>;
|
|
586
196
|
locale?: string;
|
|
197
|
+
operationContext?: EffectOperationContext;
|
|
587
198
|
traceparent?: string;
|
|
588
199
|
traceId?: string;
|
|
589
200
|
spanId?: string;
|
|
590
201
|
};
|
|
202
|
+
export type GeneratedEffectClient = ${renderClientShape(endpoints, 'EffectClientOperation')};
|
|
203
|
+
export type GeneratedEffectOperationManifest = ${renderClientShape(endpoints, "EffectOperationDescriptor")};
|
|
591
204
|
|
|
592
|
-
export declare const client:
|
|
205
|
+
export declare const client: GeneratedEffectClient;
|
|
593
206
|
export declare const createEffectRequestContext: (
|
|
594
207
|
requestContext: Record<string, unknown>,
|
|
595
208
|
) => EffectRequestContext;
|
|
596
|
-
export declare const operationManifest:
|
|
209
|
+
export declare const operationManifest: GeneratedEffectOperationManifest;
|
|
597
210
|
declare const effectBffModule: {
|
|
598
|
-
client:
|
|
211
|
+
client: GeneratedEffectClient;
|
|
599
212
|
createEffectRequestContext: typeof createEffectRequestContext;
|
|
600
|
-
operationManifest:
|
|
213
|
+
operationManifest: GeneratedEffectOperationManifest;
|
|
601
214
|
};
|
|
602
215
|
|
|
603
216
|
export default effectBffModule;
|
|
604
217
|
`;
|
|
605
218
|
}
|
|
606
|
-
async function
|
|
219
|
+
async function generateEffectClient(options) {
|
|
607
220
|
const api = await loadEffectApi(options.resourcePath);
|
|
608
221
|
if (!api) {
|
|
609
222
|
logger.warn(`[BFF][Effect] Failed to generate client for ${options.resourcePath}: unable to resolve exported HttpApi.`);
|
|
610
223
|
return null;
|
|
611
224
|
}
|
|
612
225
|
const httpApiRuntime = await getHttpApiRuntime();
|
|
613
|
-
const endpoints = collectEffectEndpoints(httpApiRuntime, api, options.prefix);
|
|
614
|
-
return
|
|
226
|
+
const endpoints = collectEffectEndpoints(httpApiRuntime.reflect, api, options.prefix);
|
|
227
|
+
return {
|
|
228
|
+
code: renderEffectClientCode(endpoints, options),
|
|
229
|
+
declaration: renderEffectClientDeclaration(endpoints),
|
|
230
|
+
endpoints
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
async function generateEffectClientCode(options) {
|
|
234
|
+
const artifacts = await generateEffectClient(options);
|
|
235
|
+
return artifacts ? artifacts.code : null;
|
|
615
236
|
}
|
|
616
237
|
function resolveEffectEntryFile(options) {
|
|
617
238
|
const { appDir, apiDir, effectEntry } = options;
|
|
@@ -620,4 +241,4 @@ function resolveEffectEntryFile(options) {
|
|
|
620
241
|
if (path.extname(entryWithoutExt)) return fs.existsSync(entryWithoutExt) ? entryWithoutExt : void 0;
|
|
621
242
|
return findExists(JS_OR_TS_EXTS.map((ext)=>`${entryWithoutExt}${ext}`));
|
|
622
243
|
}
|
|
623
|
-
export { generateEffectClientCode, renderEffectClientDeclaration, resolveEffectEntryFile };
|
|
244
|
+
export { generateEffectClient, generateEffectClientCode, renderEffectClientDeclaration, resolveEffectEntryFile };
|