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