@contrail/util 1.3.3-alpha.7783621 → 1.4.0-alpha.ebd7d81

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/CHANGELOG.md CHANGED
@@ -7,11 +7,14 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
- ## [1.3.3] - 2026-09-03
10
+ ## [1.4.0] - 2026-09-11
11
11
 
12
- ### Fixed
12
+ ### Added
13
13
 
14
- - `ObjectUtil.mergeDeep` no longer discards a value when the target cannot be merged into. An incoming object landing on an existing array, string, or number replaces it, instead of being silently skipped. Merging two objects is unchanged: keys the source omits still survive.
14
+ - `response-size-util` measures whether a payload fits within AWS Lambda's 6MB response limit, so services can decide to offload to S3 based on actual serialized bytes rather than a row count.
15
+ - `exceedsResponseBudget(value, options?)` — the decision helper. For arrays it serializes one element at a time and stops as soon as the budget is crossed, so the cost is bounded by the budget rather than by the size of the payload.
16
+ - `getJsonByteLength(value)` / `getUtf8ByteLength(str)` — exact UTF-8 byte measurement.
17
+ - `getResponseBudgetBytes(options?)`, `LAMBDA_MAX_RESPONSE_BYTES`, `DEFAULT_RESPONSE_BUFFER_BYTES` — the budget and its defaults (6MB ceiling, 512KB buffer).
15
18
 
16
19
  ## [1.2.1] - 2026-03-25
17
20
 
package/lib/index.d.ts CHANGED
@@ -6,6 +6,7 @@ export * from './object-util/object-util';
6
6
  export * from './order-util/order-util';
7
7
  export * from './performance-util/performance-util';
8
8
  export * from './promise-util/promise-util';
9
+ export * from './response-size-util/response-size-util';
9
10
  export * from './retry-util/retry-util';
10
11
  export * from './string-util/string-util';
11
12
  export * from './timer-util/timer-util';
package/lib/index.js CHANGED
@@ -22,6 +22,7 @@ __exportStar(require("./object-util/object-util"), exports);
22
22
  __exportStar(require("./order-util/order-util"), exports);
23
23
  __exportStar(require("./performance-util/performance-util"), exports);
24
24
  __exportStar(require("./promise-util/promise-util"), exports);
25
+ __exportStar(require("./response-size-util/response-size-util"), exports);
25
26
  __exportStar(require("./retry-util/retry-util"), exports);
26
27
  __exportStar(require("./string-util/string-util"), exports);
27
28
  __exportStar(require("./timer-util/timer-util"), exports);
@@ -9,7 +9,7 @@ function mergeDeep(target, ...sources) {
9
9
  if ((0, isObject_1.isObject)(target) && (0, isObject_1.isObject)(source)) {
10
10
  for (const key in source) {
11
11
  if ((0, isObject_1.isObject)(source[key]) && !isDate(source[key])) {
12
- if (!(0, isObject_1.isObject)(target[key]))
12
+ if (!target[key])
13
13
  Object.assign(target, { [key]: {} });
14
14
  mergeDeep(target[key], source[key]);
15
15
  }
@@ -0,0 +1,10 @@
1
+ export declare const LAMBDA_MAX_RESPONSE_BYTES: number;
2
+ export declare const DEFAULT_RESPONSE_BUFFER_BYTES: number;
3
+ export interface ResponseBudgetOptions {
4
+ maxBytes?: number;
5
+ bufferBytes?: number;
6
+ }
7
+ export declare function getResponseBudgetBytes(options?: ResponseBudgetOptions): number;
8
+ export declare function getUtf8ByteLength(str: string): number;
9
+ export declare function getJsonByteLength(value: unknown): number;
10
+ export declare function exceedsResponseBudget(value: unknown, options?: ResponseBudgetOptions): boolean;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_RESPONSE_BUFFER_BYTES = exports.LAMBDA_MAX_RESPONSE_BYTES = void 0;
4
+ exports.getResponseBudgetBytes = getResponseBudgetBytes;
5
+ exports.getUtf8ByteLength = getUtf8ByteLength;
6
+ exports.getJsonByteLength = getJsonByteLength;
7
+ exports.exceedsResponseBudget = exceedsResponseBudget;
8
+ exports.LAMBDA_MAX_RESPONSE_BYTES = 6 * 1024 * 1024;
9
+ exports.DEFAULT_RESPONSE_BUFFER_BYTES = 0.5 * 1024 * 1024;
10
+ function getResponseBudgetBytes(options = {}) {
11
+ var _a, _b;
12
+ const maxBytes = (_a = options.maxBytes) !== null && _a !== void 0 ? _a : exports.LAMBDA_MAX_RESPONSE_BYTES;
13
+ const bufferBytes = (_b = options.bufferBytes) !== null && _b !== void 0 ? _b : exports.DEFAULT_RESPONSE_BUFFER_BYTES;
14
+ return Math.max(0, maxBytes - bufferBytes);
15
+ }
16
+ function getUtf8ByteLength(str) {
17
+ if (typeof Buffer !== 'undefined') {
18
+ return Buffer.byteLength(str, 'utf8');
19
+ }
20
+ return new TextEncoder().encode(str).length;
21
+ }
22
+ function getJsonByteLength(value) {
23
+ const serialized = JSON.stringify(value);
24
+ return serialized === undefined ? 0 : getUtf8ByteLength(serialized);
25
+ }
26
+ function exceedsResponseBudget(value, options = {}) {
27
+ const budgetBytes = getResponseBudgetBytes(options);
28
+ if (value === null || value === undefined) {
29
+ return false;
30
+ }
31
+ if (!Array.isArray(value)) {
32
+ return getJsonByteLength(value) > budgetBytes;
33
+ }
34
+ if (value.length === 0) {
35
+ return false;
36
+ }
37
+ let totalBytes = 2 + (value.length - 1);
38
+ for (const element of value) {
39
+ if (totalBytes > budgetBytes) {
40
+ return true;
41
+ }
42
+ const serialized = JSON.stringify(element);
43
+ totalBytes += serialized === undefined ? 4 : getUtf8ByteLength(serialized);
44
+ }
45
+ return totalBytes > budgetBytes;
46
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrail/util",
3
- "version": "1.3.3-alpha.7783621",
3
+ "version": "1.4.0-alpha.ebd7d81",
4
4
  "description": "General JavaScript utilities",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",