@bleedingdev/modern-js-bff-effect 3.9.0-ultramodern.11 → 3.9.0-ultramodern.12
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/data-platform/batch/options.js +48 -0
- package/dist/cjs/data-platform/batch/queue.js +48 -83
- package/dist/cjs/effect/handler/batch-handler.js +2 -3
- package/dist/cjs/effect/handler/batch.js +0 -9
- package/dist/cjs/effect-client/cross-project.js +5 -8
- package/dist/esm/data-platform/batch/options.mjs +10 -0
- package/dist/esm/data-platform/batch/queue.mjs +48 -83
- package/dist/esm/effect/handler/batch-handler.mjs +3 -4
- package/dist/esm/effect/handler/batch.mjs +1 -7
- package/dist/esm/effect-client/cross-project.mjs +6 -9
- package/dist/esm-node/data-platform/batch/options.mjs +11 -0
- package/dist/esm-node/data-platform/batch/queue.mjs +48 -83
- package/dist/esm-node/effect/handler/batch-handler.mjs +3 -4
- package/dist/esm-node/effect/handler/batch.mjs +1 -7
- package/dist/esm-node/effect-client/cross-project.mjs +6 -9
- package/dist/types/data-platform/batch/options.d.ts +7 -0
- package/dist/types/data-platform/batch/queue.d.ts +0 -1
- package/dist/types/effect/handler/batch.d.ts +0 -1
- package/package.json +5 -5
- package/src/data-platform/batch/options.ts +20 -0
- package/src/data-platform/batch/queue.ts +61 -89
- package/src/effect/handler/batch-handler.ts +6 -12
- package/src/effect/handler/batch.ts +0 -10
- package/src/effect-client/cross-project.ts +9 -14
|
@@ -6,12 +6,6 @@ function normalizeBatchPath(pathname) {
|
|
|
6
6
|
if (!pathname.startsWith('/')) return `/${pathname}`;
|
|
7
7
|
return pathname;
|
|
8
8
|
}
|
|
9
|
-
function normalizeBatchAllowedMethods(allowedMethods) {
|
|
10
|
-
const source = Array.isArray(allowedMethods) && allowedMethods.length > 0 ? allowedMethods : [
|
|
11
|
-
'GET'
|
|
12
|
-
];
|
|
13
|
-
return new Set(source.map((method)=>method.toUpperCase()));
|
|
14
|
-
}
|
|
15
9
|
function isBatchRequestPayload(value) {
|
|
16
10
|
return isPlainObject(value) && 2 === value.protocolVersion && 'string' == typeof value.batchId && 'number' == typeof value.sentAt && Array.isArray(value.items);
|
|
17
11
|
}
|
|
@@ -109,4 +103,4 @@ async function mapWithConcurrency(items, concurrency, mapper) {
|
|
|
109
103
|
return output;
|
|
110
104
|
}
|
|
111
105
|
export { toHeaderRecord } from "../../headers.mjs";
|
|
112
|
-
export { BatchItemTimeoutError, createBatchValidationResponse, isBatchRequestPayload, mapWithConcurrency,
|
|
106
|
+
export { BatchItemTimeoutError, createBatchValidationResponse, isBatchRequestPayload, mapWithConcurrency, normalizeBatchPath, prepareJsonRequestBody, promiseWithTimeout, toBatchItemError };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BFF_ENVELOPE_HEADER, BFF_OPERATION_CONTEXT_DETAIL_HEADER, BFF_OPERATION_CONTEXT_HEADER, resolveCrossProjectRequestObservation } from "@modern-js/server-runtime-extensions/bff-policy";
|
|
1
|
+
import { BFF_ENVELOPE_HEADER, BFF_OPERATION_CONTEXT_DETAIL_HEADER, BFF_OPERATION_CONTEXT_HEADER, digestOperationContract, resolveCrossProjectRequestObservation } from "@modern-js/server-runtime-extensions/bff-policy";
|
|
2
2
|
import { HttpClient, HttpClientRequest } from "effect/unstable/http";
|
|
3
3
|
import { HttpApi } from "effect/unstable/httpapi";
|
|
4
4
|
import * as __rspack_external_effect_Effect_41060786 from "effect/Effect";
|
|
@@ -30,14 +30,11 @@ function withCrossProjectPolicy(api, options, client) {
|
|
|
30
30
|
const contract = observed && contracts[`${observed.method}:${observed.routePath}`];
|
|
31
31
|
if (void 0 === contract) return __rspack_external_effect_Effect_41060786.die(new Error('[BFF][Effect] Request has no matching shared operation contract.'));
|
|
32
32
|
return __rspack_external_effect_Effect_41060786.gen(function*() {
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
});
|
|
39
|
-
const digest = yield* __rspack_external_effect_Effect_41060786.promise(()=>globalThis.crypto.subtle.digest('SHA-256', new TextEncoder().encode(input)));
|
|
40
|
-
const schemaHash = Array.from(new Uint8Array(digest), (value)=>value.toString(16).padStart(2, '0')).join('');
|
|
33
|
+
const schemaHash = yield* __rspack_external_effect_Effect_41060786.promise(()=>digestOperationContract({
|
|
34
|
+
httpMethod: contract.method,
|
|
35
|
+
name: contract.name,
|
|
36
|
+
routePath: contract.routePath
|
|
37
|
+
}, options.requestId));
|
|
41
38
|
return request.pipe(HttpClientRequest.setHeader(BFF_ENVELOPE_HEADER, encodeJson({
|
|
42
39
|
requestId: options.requestId
|
|
43
40
|
})), HttpClientRequest.setHeader(BFF_OPERATION_CONTEXT_HEADER, contract.operationId), HttpClientRequest.setHeader(BFF_OPERATION_CONTEXT_DETAIL_HEADER, encodeJson({
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
function normalizeBatchLimits(options = {}) {
|
|
3
|
+
return {
|
|
4
|
+
maxBatchSize: Math.max(1, options.maxBatchSize ?? 16),
|
|
5
|
+
maxBatchBytes: Math.max(1024, options.maxBatchBytes ?? 65536),
|
|
6
|
+
allowedMethods: new Set((void 0 !== options.allowedMethods && options.allowedMethods.length > 0 ? options.allowedMethods : [
|
|
7
|
+
'GET'
|
|
8
|
+
]).map((method)=>method.toUpperCase()))
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export { normalizeBatchLimits };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import "node:module";
|
|
2
2
|
import { stableStringify } from "../codec.mjs";
|
|
3
3
|
import { DEFAULT_DATA_BATCH_HEADER } from "../types.mjs";
|
|
4
|
+
import { normalizeBatchLimits } from "./options.mjs";
|
|
4
5
|
import { decodeBatchBody, isNullBodyStatus } from "./protocol.mjs";
|
|
5
6
|
import { createBatchId, measureTextBytes, normalizeMethod, shouldBatchRequest, toHeaderRecord, toRequestBody } from "./request.mjs";
|
|
6
7
|
import { isBatchResponsePayload, parseResponseLikeCreateRequest } from "./response.mjs";
|
|
@@ -79,7 +80,6 @@ class BatchBucketRegistry {
|
|
|
79
80
|
if (existing) return existing;
|
|
80
81
|
const next = {
|
|
81
82
|
items: [],
|
|
82
|
-
bytes: 0,
|
|
83
83
|
batchId: createBatchId(),
|
|
84
84
|
sentAt: Date.now(),
|
|
85
85
|
timer: null,
|
|
@@ -98,12 +98,8 @@ class BatchBucketRegistry {
|
|
|
98
98
|
}
|
|
99
99
|
function createBatchTransportQueue({ options, baseFetch, bucketRegistry }) {
|
|
100
100
|
const flushIntervalMs = Math.max(0, options.flushIntervalMs ?? 8);
|
|
101
|
-
const maxBatchSize =
|
|
102
|
-
const maxBatchBytes = Math.max(1024, options.maxBatchBytes ?? 65536);
|
|
101
|
+
const { maxBatchSize, maxBatchBytes, allowedMethods } = normalizeBatchLimits(options);
|
|
103
102
|
const requestTimeoutMs = options.requestTimeoutMs;
|
|
104
|
-
const allowedMethods = new Set((options.allowedMethods && options.allowedMethods.length > 0 ? options.allowedMethods : [
|
|
105
|
-
'GET'
|
|
106
|
-
]).map((method)=>method.toUpperCase()));
|
|
107
103
|
const onEvent = options.onEvent;
|
|
108
104
|
const buckets = bucketRegistry ?? new BatchBucketRegistry();
|
|
109
105
|
const pendingByKey = new Map();
|
|
@@ -136,7 +132,6 @@ function createBatchTransportQueue({ options, baseFetch, bucketRegistry }) {
|
|
|
136
132
|
const index = bucket.items.indexOf(request);
|
|
137
133
|
if (-1 === index) return;
|
|
138
134
|
bucket.items.splice(index, 1);
|
|
139
|
-
bucket.bytes = measurePayload(bucket, bucket.items);
|
|
140
135
|
if (0 === bucket.items.length && bucket.timer) {
|
|
141
136
|
clearTimeout(bucket.timer);
|
|
142
137
|
bucket.timer = null;
|
|
@@ -178,7 +173,11 @@ function createBatchTransportQueue({ options, baseFetch, bucketRegistry }) {
|
|
|
178
173
|
if (!SAFE_REPLAY_METHODS.has(request.item.method)) throw new Error(`Batch result is unknown for ${request.item.method}; automatic replay is disabled (${reason}).`);
|
|
179
174
|
return runSingle(request);
|
|
180
175
|
};
|
|
181
|
-
const
|
|
176
|
+
const finishFlush = (bucketKey, bucket)=>{
|
|
177
|
+
bucket.flushing = false;
|
|
178
|
+
if (bucket.items.length > 0 && !bucket.timer) flushBucket(bucketKey);
|
|
179
|
+
buckets.releaseIfIdle(bucketKey, bucket);
|
|
180
|
+
};
|
|
182
181
|
const flushBucket = async (bucketKey)=>{
|
|
183
182
|
const bucket = buckets.get(bucketKey);
|
|
184
183
|
if (!bucket || bucket.flushing) return;
|
|
@@ -195,7 +194,6 @@ function createBatchTransportQueue({ options, baseFetch, bucketRegistry }) {
|
|
|
195
194
|
sentAt: bucket.sentAt
|
|
196
195
|
};
|
|
197
196
|
bucket.items = [];
|
|
198
|
-
bucket.bytes = 0;
|
|
199
197
|
rotatePayloadIdentity(bucket);
|
|
200
198
|
const firstItem = items[0];
|
|
201
199
|
if (!firstItem) {
|
|
@@ -211,14 +209,25 @@ function createBatchTransportQueue({ options, baseFetch, bucketRegistry }) {
|
|
|
211
209
|
size: items.length,
|
|
212
210
|
reason: disabledEndpoints.has(endpoint) ? 'batch-disabled' : void 0
|
|
213
211
|
});
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
212
|
+
try {
|
|
213
|
+
await settleRequests(items, runSingle);
|
|
214
|
+
} finally{
|
|
215
|
+
finishFlush(bucketKey, bucket);
|
|
216
|
+
}
|
|
218
217
|
return;
|
|
219
218
|
}
|
|
220
219
|
const payload = createPayload(payloadIdentity, items);
|
|
221
220
|
const batchId = payload.batchId;
|
|
221
|
+
const settleAmbiguousBatchRequests = (reason)=>{
|
|
222
|
+
emitDataBatchTransportEvent(onEvent, {
|
|
223
|
+
type: 'fallback',
|
|
224
|
+
endpoint,
|
|
225
|
+
batchId,
|
|
226
|
+
size: items.length,
|
|
227
|
+
reason
|
|
228
|
+
});
|
|
229
|
+
return settleRequests(items, (request)=>runAfterAmbiguousBatch(request, reason));
|
|
230
|
+
};
|
|
222
231
|
emitDataBatchTransportEvent(onEvent, {
|
|
223
232
|
type: 'flush',
|
|
224
233
|
endpoint,
|
|
@@ -269,42 +278,13 @@ function createBatchTransportQueue({ options, baseFetch, bucketRegistry }) {
|
|
|
269
278
|
batchId,
|
|
270
279
|
reason: `batch-endpoint-unavailable-${String(response.status)}`
|
|
271
280
|
});
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
endpoint,
|
|
275
|
-
batchId,
|
|
276
|
-
size: items.length,
|
|
277
|
-
reason: `batch-response-${String(response.status)}`
|
|
278
|
-
});
|
|
279
|
-
await settleAmbiguousBatchRequests(items, `batch-response-${String(response.status)}`);
|
|
280
|
-
bucket.flushing = false;
|
|
281
|
+
await settleRequests(items, (request)=>runAfterAmbiguousBatch(request, `batch-response-${String(response.status)}`));
|
|
282
|
+
} else await settleAmbiguousBatchRequests(`batch-response-${String(response.status)}`);
|
|
281
283
|
return;
|
|
282
284
|
}
|
|
283
285
|
const result = await runWithSignal(controller.signal, async ()=>response.json());
|
|
284
|
-
if (!isBatchResponsePayload(result))
|
|
285
|
-
|
|
286
|
-
type: 'fallback',
|
|
287
|
-
endpoint,
|
|
288
|
-
batchId,
|
|
289
|
-
size: items.length,
|
|
290
|
-
reason: 'invalid-batch-response'
|
|
291
|
-
});
|
|
292
|
-
await settleAmbiguousBatchRequests(items, 'invalid-batch-response');
|
|
293
|
-
bucket.flushing = false;
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
if (result.batchId !== batchId) {
|
|
297
|
-
emitDataBatchTransportEvent(onEvent, {
|
|
298
|
-
type: 'fallback',
|
|
299
|
-
endpoint,
|
|
300
|
-
batchId,
|
|
301
|
-
size: items.length,
|
|
302
|
-
reason: 'mismatched-batch-id'
|
|
303
|
-
});
|
|
304
|
-
await settleAmbiguousBatchRequests(items, 'mismatched-batch-id');
|
|
305
|
-
bucket.flushing = false;
|
|
306
|
-
return;
|
|
307
|
-
}
|
|
286
|
+
if (!isBatchResponsePayload(result)) return void await settleAmbiguousBatchRequests('invalid-batch-response');
|
|
287
|
+
if (result.batchId !== batchId) return void await settleAmbiguousBatchRequests('mismatched-batch-id');
|
|
308
288
|
const itemMap = new Map();
|
|
309
289
|
for (const item of result.items)itemMap.set(item.id, item);
|
|
310
290
|
await settleRequests(items, async (request)=>{
|
|
@@ -328,19 +308,10 @@ function createBatchTransportQueue({ options, baseFetch, bucketRegistry }) {
|
|
|
328
308
|
});
|
|
329
309
|
return;
|
|
330
310
|
}
|
|
331
|
-
|
|
332
|
-
type: 'fallback',
|
|
333
|
-
endpoint,
|
|
334
|
-
batchId,
|
|
335
|
-
size: items.length,
|
|
336
|
-
reason: 'batch-transport-error'
|
|
337
|
-
});
|
|
338
|
-
await settleAmbiguousBatchRequests(items, 'batch-transport-error');
|
|
311
|
+
await settleAmbiguousBatchRequests('batch-transport-error');
|
|
339
312
|
} finally{
|
|
340
313
|
for (const item of items)item.abortBatchIfUnused = void 0;
|
|
341
|
-
bucket
|
|
342
|
-
if (bucket.items.length > 0 && !bucket.timer) flushBucket(bucketKey);
|
|
343
|
-
buckets.releaseIfIdle(bucketKey, bucket);
|
|
314
|
+
finishFlush(bucketKey, bucket);
|
|
344
315
|
}
|
|
345
316
|
};
|
|
346
317
|
const pendingReadPromises = new Map();
|
|
@@ -364,7 +335,20 @@ function createBatchTransportQueue({ options, baseFetch, bucketRegistry }) {
|
|
|
364
335
|
const sourceSignal = initDefinesSignal ? initSignal ?? void 0 : sourceRequest?.signal;
|
|
365
336
|
const requestUrl = toAbsoluteUrl(input);
|
|
366
337
|
const endpoint = normalizeBatchEndpoint(requestUrl, options.endpoint).toString();
|
|
338
|
+
const itemHeaders = {
|
|
339
|
+
...headers
|
|
340
|
+
};
|
|
341
|
+
delete itemHeaders.authorization;
|
|
342
|
+
delete itemHeaders.cookie;
|
|
367
343
|
return {
|
|
344
|
+
itemHeaders,
|
|
345
|
+
itemPath: `${requestUrl.pathname}${requestUrl.search}`,
|
|
346
|
+
bucketKey: stableStringify({
|
|
347
|
+
endpoint,
|
|
348
|
+
authorization: headers.authorization ?? null,
|
|
349
|
+
cookie: headers.cookie ?? null,
|
|
350
|
+
credentials
|
|
351
|
+
}),
|
|
368
352
|
requestUrl,
|
|
369
353
|
endpoint,
|
|
370
354
|
method,
|
|
@@ -397,22 +381,11 @@ function createBatchTransportQueue({ options, baseFetch, bucketRegistry }) {
|
|
|
397
381
|
batchEndpoint: request.endpoint,
|
|
398
382
|
requestUrl: request.requestUrl
|
|
399
383
|
})) return;
|
|
400
|
-
const itemHeaders = {
|
|
401
|
-
...request.headers
|
|
402
|
-
};
|
|
403
|
-
delete itemHeaders.authorization;
|
|
404
|
-
delete itemHeaders.cookie;
|
|
405
|
-
const bucketKey = stableStringify({
|
|
406
|
-
endpoint: request.endpoint,
|
|
407
|
-
authorization: request.headers.authorization ?? null,
|
|
408
|
-
cookie: request.headers.cookie ?? null,
|
|
409
|
-
credentials: request.credentials
|
|
410
|
-
});
|
|
411
384
|
return stableStringify({
|
|
412
|
-
bucketKey,
|
|
413
|
-
path:
|
|
385
|
+
bucketKey: request.bucketKey,
|
|
386
|
+
path: request.itemPath,
|
|
414
387
|
method: request.method,
|
|
415
|
-
headers: itemHeaders,
|
|
388
|
+
headers: request.itemHeaders,
|
|
416
389
|
body: null
|
|
417
390
|
});
|
|
418
391
|
};
|
|
@@ -430,26 +403,19 @@ function createBatchTransportQueue({ options, baseFetch, bucketRegistry }) {
|
|
|
430
403
|
const itemId = `${Date.now().toString(36)}_${nextItemId.toString(36)}_${Math.random().toString(16).slice(2, 8)}`;
|
|
431
404
|
nextItemId += 1;
|
|
432
405
|
const itemHeaders = {
|
|
433
|
-
...request.
|
|
406
|
+
...request.itemHeaders
|
|
434
407
|
};
|
|
435
|
-
delete itemHeaders.authorization;
|
|
436
|
-
delete itemHeaders.cookie;
|
|
437
408
|
if (preparedBody.body && preparedBody.inferredContentType && !itemHeaders['content-type']) itemHeaders['content-type'] = preparedBody.inferredContentType;
|
|
438
409
|
const item = {
|
|
439
410
|
id: itemId,
|
|
440
|
-
path:
|
|
411
|
+
path: request.itemPath,
|
|
441
412
|
method: request.method,
|
|
442
413
|
headers: itemHeaders,
|
|
443
414
|
...preparedBody.body ? {
|
|
444
415
|
body: preparedBody.body
|
|
445
416
|
} : {}
|
|
446
417
|
};
|
|
447
|
-
const bucketKey =
|
|
448
|
-
endpoint: request.endpoint,
|
|
449
|
-
authorization: request.headers.authorization ?? null,
|
|
450
|
-
cookie: request.headers.cookie ?? null,
|
|
451
|
-
credentials: request.credentials
|
|
452
|
-
});
|
|
418
|
+
const { bucketKey } = request;
|
|
453
419
|
const key = stableStringify({
|
|
454
420
|
bucketKey,
|
|
455
421
|
path: item.path,
|
|
@@ -543,13 +509,12 @@ function createBatchTransportQueue({ options, baseFetch, bucketRegistry }) {
|
|
|
543
509
|
}
|
|
544
510
|
}
|
|
545
511
|
bucket.items.push(queued);
|
|
546
|
-
bucket.bytes = measurePayload(bucket, bucket.items);
|
|
547
512
|
emitDataBatchTransportEvent(onEvent, {
|
|
548
513
|
type: 'enqueue',
|
|
549
514
|
endpoint: request.endpoint,
|
|
550
515
|
size: bucket.items.length
|
|
551
516
|
});
|
|
552
|
-
if (bucket.items.length >= maxBatchSize || bucket.
|
|
517
|
+
if (bucket.items.length >= maxBatchSize || measurePayload(bucket, bucket.items) >= maxBatchBytes) {
|
|
553
518
|
flushBucket(bucketKey);
|
|
554
519
|
return queued.promise;
|
|
555
520
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import "node:module";
|
|
2
2
|
import { DEFAULT_DATA_BATCH_HEADER, DEFAULT_DATA_ENVELOPE_HEADER, decodeRequestEnvelopeHeader, isPlainObject, normalizeMethod } from "../../data-platform/index.mjs";
|
|
3
|
+
import { normalizeBatchLimits } from "../../data-platform/batch/options.mjs";
|
|
3
4
|
import { decodeBatchBody, isBatchBody, toBatchResponseItem } from "../../data-platform/batch/protocol.mjs";
|
|
4
|
-
import { BatchItemTimeoutError, createBatchValidationResponse, isBatchRequestPayload, mapWithConcurrency,
|
|
5
|
+
import { BatchItemTimeoutError, createBatchValidationResponse, isBatchRequestPayload, mapWithConcurrency, normalizeBatchPath, promiseWithTimeout, toBatchItemError } from "./batch.mjs";
|
|
5
6
|
import { getMountedPrefixFromContext, removeMountedPrefixFromBatchPath } from "./routing.mjs";
|
|
6
7
|
import * as __rspack_external_effect_Effect_41060786 from "effect/Effect";
|
|
7
8
|
const HOP_BY_HOP_BATCH_ITEM_HEADERS = new Set([
|
|
@@ -92,11 +93,9 @@ function createDataPlatformBatchRequestHandler(options) {
|
|
|
92
93
|
const dataPlatformBatchOptions = options.dataPlatform?.batch;
|
|
93
94
|
const batchEnabled = dataPlatformBatchOptions?.enabled !== false;
|
|
94
95
|
const batchPath = normalizeBatchPath(dataPlatformBatchOptions?.endpoint);
|
|
95
|
-
const batchMaxSize
|
|
96
|
-
const batchMaxBytes = Math.max(1024, dataPlatformBatchOptions?.maxBatchBytes ?? 65536);
|
|
96
|
+
const { maxBatchSize: batchMaxSize, maxBatchBytes: batchMaxBytes, allowedMethods: batchAllowedMethods } = normalizeBatchLimits(dataPlatformBatchOptions);
|
|
97
97
|
const batchConcurrency = Math.max(1, dataPlatformBatchOptions?.maxConcurrency ?? 4);
|
|
98
98
|
const batchItemTimeoutMs = Math.max(0, dataPlatformBatchOptions?.requestTimeoutMs ?? 10000);
|
|
99
|
-
const batchAllowedMethods = normalizeBatchAllowedMethods(dataPlatformBatchOptions?.allowedMethods);
|
|
100
99
|
const envelopeHeader = options.dataPlatform?.envelopeHeader || DEFAULT_DATA_ENVELOPE_HEADER;
|
|
101
100
|
const normalizedEnvelopeHeader = envelopeHeader.toLowerCase();
|
|
102
101
|
const handle = async (request, context)=>{
|
|
@@ -7,12 +7,6 @@ function normalizeBatchPath(pathname) {
|
|
|
7
7
|
if (!pathname.startsWith('/')) return `/${pathname}`;
|
|
8
8
|
return pathname;
|
|
9
9
|
}
|
|
10
|
-
function normalizeBatchAllowedMethods(allowedMethods) {
|
|
11
|
-
const source = Array.isArray(allowedMethods) && allowedMethods.length > 0 ? allowedMethods : [
|
|
12
|
-
'GET'
|
|
13
|
-
];
|
|
14
|
-
return new Set(source.map((method)=>method.toUpperCase()));
|
|
15
|
-
}
|
|
16
10
|
function isBatchRequestPayload(value) {
|
|
17
11
|
return isPlainObject(value) && 2 === value.protocolVersion && 'string' == typeof value.batchId && 'number' == typeof value.sentAt && Array.isArray(value.items);
|
|
18
12
|
}
|
|
@@ -110,4 +104,4 @@ async function mapWithConcurrency(items, concurrency, mapper) {
|
|
|
110
104
|
return output;
|
|
111
105
|
}
|
|
112
106
|
export { toHeaderRecord } from "../../headers.mjs";
|
|
113
|
-
export { BatchItemTimeoutError, createBatchValidationResponse, isBatchRequestPayload, mapWithConcurrency,
|
|
107
|
+
export { BatchItemTimeoutError, createBatchValidationResponse, isBatchRequestPayload, mapWithConcurrency, normalizeBatchPath, prepareJsonRequestBody, promiseWithTimeout, toBatchItemError };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "node:module";
|
|
2
|
-
import { BFF_ENVELOPE_HEADER, BFF_OPERATION_CONTEXT_DETAIL_HEADER, BFF_OPERATION_CONTEXT_HEADER, resolveCrossProjectRequestObservation } from "@modern-js/server-runtime-extensions/bff-policy";
|
|
2
|
+
import { BFF_ENVELOPE_HEADER, BFF_OPERATION_CONTEXT_DETAIL_HEADER, BFF_OPERATION_CONTEXT_HEADER, digestOperationContract, resolveCrossProjectRequestObservation } from "@modern-js/server-runtime-extensions/bff-policy";
|
|
3
3
|
import { HttpClient, HttpClientRequest } from "effect/unstable/http";
|
|
4
4
|
import { HttpApi } from "effect/unstable/httpapi";
|
|
5
5
|
import * as __rspack_external_effect_Effect_41060786 from "effect/Effect";
|
|
@@ -31,14 +31,11 @@ function withCrossProjectPolicy(api, options, client) {
|
|
|
31
31
|
const contract = observed && contracts[`${observed.method}:${observed.routePath}`];
|
|
32
32
|
if (void 0 === contract) return __rspack_external_effect_Effect_41060786.die(new Error('[BFF][Effect] Request has no matching shared operation contract.'));
|
|
33
33
|
return __rspack_external_effect_Effect_41060786.gen(function*() {
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
});
|
|
40
|
-
const digest = yield* __rspack_external_effect_Effect_41060786.promise(()=>globalThis.crypto.subtle.digest('SHA-256', new TextEncoder().encode(input)));
|
|
41
|
-
const schemaHash = Array.from(new Uint8Array(digest), (value)=>value.toString(16).padStart(2, '0')).join('');
|
|
34
|
+
const schemaHash = yield* __rspack_external_effect_Effect_41060786.promise(()=>digestOperationContract({
|
|
35
|
+
httpMethod: contract.method,
|
|
36
|
+
name: contract.name,
|
|
37
|
+
routePath: contract.routePath
|
|
38
|
+
}, options.requestId));
|
|
42
39
|
return request.pipe(HttpClientRequest.setHeader(BFF_ENVELOPE_HEADER, encodeJson({
|
|
43
40
|
requestId: options.requestId
|
|
44
41
|
})), HttpClientRequest.setHeader(BFF_OPERATION_CONTEXT_HEADER, contract.operationId), HttpClientRequest.setHeader(BFF_OPERATION_CONTEXT_DETAIL_HEADER, encodeJson({
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DataBatchTransportOptions } from '../types.js';
|
|
2
|
+
/** Wire limits and method eligibility are identical on both sides. */
|
|
3
|
+
export declare function normalizeBatchLimits(options?: Pick<DataBatchTransportOptions, 'maxBatchSize' | 'maxBatchBytes' | 'allowedMethods'>): {
|
|
4
|
+
maxBatchSize: number;
|
|
5
|
+
maxBatchBytes: number;
|
|
6
|
+
allowedMethods: Set<string>;
|
|
7
|
+
};
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { type DataBatchRequestPayload, type DataBatchResponseItem } from '../../data-platform/index.js';
|
|
2
2
|
export { toHeaderRecord } from '../../headers.js';
|
|
3
3
|
export declare function normalizeBatchPath(pathname: string | undefined): `/${string}`;
|
|
4
|
-
export declare function normalizeBatchAllowedMethods(allowedMethods: string[] | undefined): Set<string>;
|
|
5
4
|
type ParsedBatchRequestPayload = Omit<DataBatchRequestPayload, 'items'> & {
|
|
6
5
|
items: unknown[];
|
|
7
6
|
};
|
package/package.json
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"modern.js",
|
|
19
19
|
"ultramodern.js"
|
|
20
20
|
],
|
|
21
|
-
"version": "3.9.0-ultramodern.
|
|
21
|
+
"version": "3.9.0-ultramodern.12",
|
|
22
22
|
"files": [
|
|
23
23
|
"dist",
|
|
24
24
|
"src"
|
|
@@ -130,10 +130,10 @@
|
|
|
130
130
|
"node": ">=26.7.0"
|
|
131
131
|
},
|
|
132
132
|
"dependencies": {
|
|
133
|
-
"@modern-js/bff-core": "npm:@bleedingdev/modern-js-bff-core@3.9.0-ultramodern.
|
|
134
|
-
"@modern-js/create-request": "npm:@bleedingdev/modern-js-create-request@3.9.0-ultramodern.
|
|
135
|
-
"@modern-js/runtime-extensions": "npm:@bleedingdev/modern-js-runtime-extensions@3.9.0-ultramodern.
|
|
136
|
-
"@modern-js/server-runtime-extensions": "npm:@bleedingdev/modern-js-server-runtime-extensions@3.9.0-ultramodern.
|
|
133
|
+
"@modern-js/bff-core": "npm:@bleedingdev/modern-js-bff-core@3.9.0-ultramodern.12",
|
|
134
|
+
"@modern-js/create-request": "npm:@bleedingdev/modern-js-create-request@3.9.0-ultramodern.12",
|
|
135
|
+
"@modern-js/runtime-extensions": "npm:@bleedingdev/modern-js-runtime-extensions@3.9.0-ultramodern.12",
|
|
136
|
+
"@modern-js/server-runtime-extensions": "npm:@bleedingdev/modern-js-server-runtime-extensions@3.9.0-ultramodern.12",
|
|
137
137
|
"@opentelemetry/api": "1.9.1",
|
|
138
138
|
"@opentelemetry/api-logs": "0.222.0",
|
|
139
139
|
"@opentelemetry/resources": "2.11.0",
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { DataBatchTransportOptions } from '../types';
|
|
2
|
+
|
|
3
|
+
/** Wire limits and method eligibility are identical on both sides. */
|
|
4
|
+
export function normalizeBatchLimits(
|
|
5
|
+
options: Pick<
|
|
6
|
+
DataBatchTransportOptions,
|
|
7
|
+
'maxBatchSize' | 'maxBatchBytes' | 'allowedMethods'
|
|
8
|
+
> = {},
|
|
9
|
+
) {
|
|
10
|
+
return {
|
|
11
|
+
maxBatchSize: Math.max(1, options.maxBatchSize ?? 16),
|
|
12
|
+
maxBatchBytes: Math.max(1024, options.maxBatchBytes ?? 64 * 1024),
|
|
13
|
+
allowedMethods: new Set(
|
|
14
|
+
(options.allowedMethods !== undefined && options.allowedMethods.length > 0
|
|
15
|
+
? options.allowedMethods
|
|
16
|
+
: ['GET']
|
|
17
|
+
).map(method => method.toUpperCase()),
|
|
18
|
+
),
|
|
19
|
+
};
|
|
20
|
+
}
|