@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.
@@ -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, normalizeBatchAllowedMethods, normalizeBatchPath, prepareJsonRequestBody, promiseWithTimeout, toBatchItemError };
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 input = encodeJson({
34
- httpMethod: contract.method,
35
- name: contract.name,
36
- requestId: options.requestId,
37
- routePath: contract.routePath
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 = Math.max(1, options.maxBatchSize ?? 16);
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 settleAmbiguousBatchRequests = (items, reason)=>settleRequests(items, (request)=>runAfterAmbiguousBatch(request, reason));
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
- await settleRequests(items, runSingle);
215
- bucket.flushing = false;
216
- if (bucket.items.length > 0 && !bucket.timer) flushBucket(bucketKey);
217
- buckets.releaseIfIdle(bucketKey, bucket);
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
- } else emitDataBatchTransportEvent(onEvent, {
273
- type: 'fallback',
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
- emitDataBatchTransportEvent(onEvent, {
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
- emitDataBatchTransportEvent(onEvent, {
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.flushing = false;
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: `${request.requestUrl.pathname}${request.requestUrl.search}`,
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.headers
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: `${request.requestUrl.pathname}${request.requestUrl.search}`,
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 = stableStringify({
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.bytes >= maxBatchBytes) {
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, normalizeBatchAllowedMethods, normalizeBatchPath, promiseWithTimeout, toBatchItemError } from "./batch.mjs";
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 = Math.max(1, dataPlatformBatchOptions?.maxBatchSize ?? 16);
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, normalizeBatchAllowedMethods, normalizeBatchPath, prepareJsonRequestBody, promiseWithTimeout, toBatchItemError };
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 input = encodeJson({
35
- httpMethod: contract.method,
36
- name: contract.name,
37
- requestId: options.requestId,
38
- routePath: contract.routePath
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
+ };
@@ -30,7 +30,6 @@ type QueuedBatchRequest = {
30
30
  };
31
31
  type BatchBucket = {
32
32
  items: QueuedBatchRequest[];
33
- bytes: number;
34
33
  batchId: string;
35
34
  sentAt: number;
36
35
  timer: ReturnType<typeof setTimeout> | null;
@@ -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.11",
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.11",
134
- "@modern-js/create-request": "npm:@bleedingdev/modern-js-create-request@3.9.0-ultramodern.11",
135
- "@modern-js/runtime-extensions": "npm:@bleedingdev/modern-js-runtime-extensions@3.9.0-ultramodern.11",
136
- "@modern-js/server-runtime-extensions": "npm:@bleedingdev/modern-js-server-runtime-extensions@3.9.0-ultramodern.11",
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
+ }