New:Socket for Asana Is Now Available.Learn more
Get Started

@n8n/utils

Package Overview
Dependencies
Maintainers
5
Versions
50
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@n8n/utils - npm Package Compare versions

Comparing version
1.41.0
to
1.42.0
+237
dist/json/json-size-exceeds.cjs
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
//#region src/json/json-size-exceeds.ts
const QUOTES_SIZE = 2;
const COLON_SIZE = 1;
const COMMA_SIZE = 1;
const EMPTY_CONTAINER_SIZE = 2;
const NULL_SIZE = 4;
const TRUE_SIZE = 4;
const FALSE_SIZE = 5;
const SIGN_SIZE = 1;
/** Magnitude from which a number serializes in exponential notation. */
const EXPONENTIAL_NOTATION_THRESHOLD = 1e21;
/** `{"type":"Buffer","data":[]}` around the bytes of a Buffer. */
const BUFFER_ENVELOPE_SIZE = 27;
/** Longest a byte serializes to inside that envelope, as in `255,`. */
const MAX_BUFFER_BYTE_SIZE = 4;
/**
* Widest a number can serialize to, as in `-0.0000075911789601505095`. Bounds the
* elements of a binary view, which are counted without being visited.
*/
const MAX_NUMBER_SIZE = 25;
const SHORT_ESCAPE_SIZE = 2;
const UNICODE_ESCAPE_SIZE = 6;
const ONE_BYTE_SIZE = 1;
const TWO_BYTE_SIZE = 2;
const THREE_BYTE_SIZE = 3;
const SURROGATE_PAIR_SIZE = 4;
const CONTROL_MAX = 31;
const QUOTE = 34;
const BACKSLASH = 92;
const ASCII_MAX = 127;
const TWO_BYTE_MAX = 2047;
const HIGH_SURROGATE_MIN = 55296;
const HIGH_SURROGATE_MAX = 56319;
const LOW_SURROGATE_MIN = 56320;
const LOW_SURROGATE_MAX = 57343;
/** Control characters serialization escapes with a letter instead of a code point. */
const LETTER_ESCAPED_CONTROLS = /* @__PURE__ */ new Set([
8,
9,
10,
12,
13
]);
/** Key `JSON.stringify` hands to the `toJSON` of the value it is called on. */
const ROOT_KEY = "";
/**
* Tells whether a value exceeds a JSON size limit, without serializing it.
*
* The measure is an upper bound, so a value is never reported as fitting a size
* it does not fit. It overshoots by one byte per non-empty container, and counts
* binary data at the widest its bytes can serialize to.
*
* @param value Value to measure as if it were passed to `JSON.stringify`.
* @param maxBytes Limit the serialization must stay within.
* @returns `true` unless the serialization is certainly `maxBytes` or shorter.
*
* @remarks Time O(n) in the members and characters of `value`, memory O(depth).
* Calls `toJSON` on the members defining one, as serialization would.
*/
function jsonSizeExceeds(value, maxBytes) {
const walk = {
maxBytes,
frames: [],
ancestors: /* @__PURE__ */ new Set(),
size: 0
};
addValue(walk, replacedValue(value, ROOT_KEY));
while (walk.frames.length > 0 && walk.size <= maxBytes) advance(walk, walk.frames[walk.frames.length - 1]);
return walk.size > maxBytes;
}
/** Bytes left before the limit. Negative once the limit is crossed. */
function remaining(walk) {
return walk.maxBytes - walk.size;
}
/** Measures the next member of the innermost container, or closes it. */
function advance(walk, frame) {
if ("elements" in frame) advanceElements(walk, frame);
else advanceEntries(walk, frame);
}
function advanceElements(walk, frame) {
if (frame.index === frame.elements.length) close(walk, frame.elements);
else {
const index = frame.index;
frame.index += 1;
walk.size += COMMA_SIZE;
addValue(walk, replacedValue(frame.elements[index], index));
}
}
function advanceEntries(walk, frame) {
if (frame.index === frame.keys.length) close(walk, frame.entries);
else {
const key = frame.keys[frame.index];
frame.index += 1;
addEntry(walk, key, replacedValue(frame.entries[key], key));
}
}
/** Adds an entry, unless serialization drops it along with its key. */
function addEntry(walk, key, value) {
if (!isDroppedFromObjects(value)) {
walk.size += 2 + stringSize(key, remaining(walk));
addValue(walk, value);
}
}
/**
* Adds what a value occupies on its own, and opens it when it has members.
* Measuring stops once the limit is crossed, so a size cut short is still above it.
*/
function addValue(walk, value) {
if (isContainer(value)) open(walk, value);
else walk.size += leafSize(value, remaining(walk));
}
/**
* Adds a container's own delimiters and queues its members, or the whole of it
* when its size follows from its length alone.
*/
function open(walk, container) {
if (!walk.ancestors.has(container)) {
const binarySize = maxBinaryViewSize(container);
if (binarySize === void 0) {
walk.size += EMPTY_CONTAINER_SIZE;
walk.ancestors.add(container);
walk.frames.push(frameFor(container));
} else walk.size += binarySize;
}
}
function close(walk, container) {
walk.ancestors.delete(container);
walk.frames.pop();
}
function frameFor(container) {
return Array.isArray(container) ? {
elements: container,
index: 0
} : {
entries: container,
keys: Object.keys(container),
index: 0
};
}
/** The value serialization puts in place of this one, given the key holding it. */
function replacedValue(value, key) {
return isSelfSerializing(value) ? value.toJSON(String(key)) : value;
}
function isSelfSerializing(value) {
return isContainer(value) && !Buffer.isBuffer(value) && "toJSON" in value && typeof value.toJSON === "function";
}
/**
* Bytes a Buffer or another binary view occupies serialized, or `undefined` for
* a container whose members have to be walked.
*/
function maxBinaryViewSize(container) {
if (Buffer.isBuffer(container)) return BUFFER_ENVELOPE_SIZE + MAX_BUFFER_BYTE_SIZE * container.length;
return isIndexedView(container) ? maxIndexedViewSize(container) : void 0;
}
/**
* Bytes an indexed view occupies as the object of index/element entries it
* serializes to. Derived from its length, because listing those keys would hold
* one string per element in memory.
*/
function maxIndexedViewSize(view) {
const lastIndex = Math.max(view.length - 1, 0);
const maxEntrySize = QUOTES_SIZE + decimalDigits(lastIndex) + COLON_SIZE + MAX_NUMBER_SIZE + COMMA_SIZE;
return EMPTY_CONTAINER_SIZE + view.length * maxEntrySize;
}
/** Bytes a value with no members occupies serialized. */
function leafSize(value, budget) {
switch (typeof value) {
case "string": return stringSize(value, budget);
case "number": return numberSize(value);
case "boolean": return value ? TRUE_SIZE : FALSE_SIZE;
default: return NULL_SIZE;
}
}
/** Bytes a string occupies serialized, escapes and quotes included. */
function stringSize(value, budget) {
return QUOTES_SIZE + escapedContentSize(value, budget - QUOTES_SIZE);
}
/**
* Bytes the escaped characters of a string occupy, quotes excluded. Reads the
* string one code unit at a time so that nothing is copied, and stops once
* `budget` is gone, since what is already counted then settles the answer.
*/
function escapedContentSize(value, budget) {
let size = 0;
let index = 0;
while (index < value.length && size <= budget) {
const code = value.charCodeAt(index);
const paired = isHighSurrogate(code) && isLowSurrogate(value.charCodeAt(index + 1));
size += paired ? SURROGATE_PAIR_SIZE : codeUnitSize(code);
index += paired ? 2 : 1;
}
return size;
}
/** Bytes a single code unit occupies, escaped and encoded as serialization would. */
function codeUnitSize(code) {
if (code === QUOTE || code === BACKSLASH) return SHORT_ESCAPE_SIZE;
if (code <= CONTROL_MAX) return LETTER_ESCAPED_CONTROLS.has(code) ? SHORT_ESCAPE_SIZE : UNICODE_ESCAPE_SIZE;
if (code <= ASCII_MAX) return ONE_BYTE_SIZE;
if (code <= TWO_BYTE_MAX) return TWO_BYTE_SIZE;
return isSurrogate(code) ? UNICODE_ESCAPE_SIZE : THREE_BYTE_SIZE;
}
/** Bytes a number occupies serialized. */
function numberSize(value) {
if (!Number.isFinite(value)) return NULL_SIZE;
const magnitude = Math.abs(value);
return Number.isInteger(value) && magnitude < EXPONENTIAL_NOTATION_THRESHOLD ? (value < 0 ? SIGN_SIZE : 0) + decimalDigits(magnitude) : String(value).length;
}
/** Digits the integer part of a magnitude is written with. */
function decimalDigits(magnitude) {
const digits = magnitude < 1 ? 1 : Math.floor(Math.log10(magnitude)) + 1;
return magnitude < 10 ** digits ? digits : digits + 1;
}
/** Whether serializing an object drops the entry holding this value, key included. */
function isDroppedFromObjects(value) {
const type = typeof value;
return type === "undefined" || type === "function" || type === "symbol";
}
function isContainer(value) {
return typeof value === "object" && value !== null;
}
function isIndexedView(value) {
return ArrayBuffer.isView(value) && "length" in value && typeof value.length === "number";
}
function isHighSurrogate(code) {
return code >= HIGH_SURROGATE_MIN && code <= HIGH_SURROGATE_MAX;
}
function isLowSurrogate(code) {
return code >= LOW_SURROGATE_MIN && code <= LOW_SURROGATE_MAX;
}
function isSurrogate(code) {
return code >= HIGH_SURROGATE_MIN && code <= LOW_SURROGATE_MAX;
}
//#endregion
exports.jsonSizeExceeds = jsonSizeExceeds;
//# sourceMappingURL=json-size-exceeds.cjs.map
{"version":3,"file":"json-size-exceeds.cjs","names":[],"sources":["../../src/json/json-size-exceeds.ts"],"sourcesContent":["type JsonContainer = Record<string, unknown> | unknown[];\n\n/** A value serialization replaces with the result of its own `toJSON`. */\ntype SelfSerializing = JsonContainer & { toJSON: (key: string) => unknown };\n\n/** A view over binary data, serialized as one entry per element. */\ntype IndexedView = ArrayBufferView & { length: number };\n\n/** An array being measured, and how far through its elements the walk is. */\ntype ElementsFrame = { readonly elements: unknown[]; index: number };\n\n/** An object being measured, and how far through its keys the walk is. */\ntype EntriesFrame = {\n\treadonly entries: Record<string, unknown>;\n\treadonly keys: string[];\n\tindex: number;\n};\n\ntype Frame = ElementsFrame | EntriesFrame;\n\n/** Bytes counted so far, and the containers the walk still has to finish. */\ntype Walk = {\n\treadonly maxBytes: number;\n\treadonly frames: Frame[];\n\treadonly ancestors: Set<JsonContainer>;\n\tsize: number;\n};\n\nconst QUOTES_SIZE = 2; // `\"\"` around a string or a key\nconst COLON_SIZE = 1;\nconst COMMA_SIZE = 1;\nconst EMPTY_CONTAINER_SIZE = 2; // `{}` or `[]`\nconst NULL_SIZE = 4;\nconst TRUE_SIZE = 4;\nconst FALSE_SIZE = 5;\nconst SIGN_SIZE = 1;\n\n/** Magnitude from which a number serializes in exponential notation. */\nconst EXPONENTIAL_NOTATION_THRESHOLD = 1e21;\n\n/** `{\"type\":\"Buffer\",\"data\":[]}` around the bytes of a Buffer. */\nconst BUFFER_ENVELOPE_SIZE = 27;\n\n/** Longest a byte serializes to inside that envelope, as in `255,`. */\nconst MAX_BUFFER_BYTE_SIZE = 4;\n\n/**\n * Widest a number can serialize to, as in `-0.0000075911789601505095`. Bounds the\n * elements of a binary view, which are counted without being visited.\n */\nconst MAX_NUMBER_SIZE = 25;\n\nconst SHORT_ESCAPE_SIZE = 2; // `\\n`, `\\\"`, `\\\\`\nconst UNICODE_ESCAPE_SIZE = 6; // `\\u001f`, and a lone surrogate\nconst ONE_BYTE_SIZE = 1;\nconst TWO_BYTE_SIZE = 2;\nconst THREE_BYTE_SIZE = 3;\nconst SURROGATE_PAIR_SIZE = 4; // one code point spread over two code units\n\nconst CONTROL_MAX = 0x1f;\nconst QUOTE = 0x22;\nconst BACKSLASH = 0x5c;\nconst ASCII_MAX = 0x7f;\nconst TWO_BYTE_MAX = 0x7ff;\nconst HIGH_SURROGATE_MIN = 0xd800;\nconst HIGH_SURROGATE_MAX = 0xdbff;\nconst LOW_SURROGATE_MIN = 0xdc00;\nconst LOW_SURROGATE_MAX = 0xdfff;\n\n/** Control characters serialization escapes with a letter instead of a code point. */\nconst LETTER_ESCAPED_CONTROLS = new Set([0x08, 0x09, 0x0a, 0x0c, 0x0d]);\n\n/** Key `JSON.stringify` hands to the `toJSON` of the value it is called on. */\nconst ROOT_KEY = '';\n\n/**\n * Tells whether a value exceeds a JSON size limit, without serializing it.\n *\n * The measure is an upper bound, so a value is never reported as fitting a size\n * it does not fit. It overshoots by one byte per non-empty container, and counts\n * binary data at the widest its bytes can serialize to.\n *\n * @param value Value to measure as if it were passed to `JSON.stringify`.\n * @param maxBytes Limit the serialization must stay within.\n * @returns `true` unless the serialization is certainly `maxBytes` or shorter.\n *\n * @remarks Time O(n) in the members and characters of `value`, memory O(depth).\n * Calls `toJSON` on the members defining one, as serialization would.\n */\nexport function jsonSizeExceeds(value: unknown, maxBytes: number): boolean {\n\tconst walk: Walk = { maxBytes, frames: [], ancestors: new Set(), size: 0 };\n\n\taddValue(walk, replacedValue(value, ROOT_KEY));\n\twhile (walk.frames.length > 0 && walk.size <= maxBytes) {\n\t\tadvance(walk, walk.frames[walk.frames.length - 1]);\n\t}\n\n\treturn walk.size > maxBytes;\n}\n\n/** Bytes left before the limit. Negative once the limit is crossed. */\nfunction remaining(walk: Walk): number {\n\treturn walk.maxBytes - walk.size;\n}\n\n/** Measures the next member of the innermost container, or closes it. */\nfunction advance(walk: Walk, frame: Frame): void {\n\tif ('elements' in frame) {\n\t\tadvanceElements(walk, frame);\n\t} else {\n\t\tadvanceEntries(walk, frame);\n\t}\n}\n\nfunction advanceElements(walk: Walk, frame: ElementsFrame): void {\n\tif (frame.index === frame.elements.length) {\n\t\tclose(walk, frame.elements);\n\t} else {\n\t\tconst index = frame.index;\n\t\tframe.index += 1;\n\t\twalk.size += COMMA_SIZE;\n\t\taddValue(walk, replacedValue(frame.elements[index], index));\n\t}\n}\n\nfunction advanceEntries(walk: Walk, frame: EntriesFrame): void {\n\tif (frame.index === frame.keys.length) {\n\t\tclose(walk, frame.entries);\n\t} else {\n\t\tconst key = frame.keys[frame.index];\n\t\tframe.index += 1;\n\t\taddEntry(walk, key, replacedValue(frame.entries[key], key));\n\t}\n}\n\n/** Adds an entry, unless serialization drops it along with its key. */\nfunction addEntry(walk: Walk, key: string, value: unknown): void {\n\tif (!isDroppedFromObjects(value)) {\n\t\twalk.size += COMMA_SIZE + COLON_SIZE + stringSize(key, remaining(walk));\n\t\taddValue(walk, value);\n\t}\n}\n\n/**\n * Adds what a value occupies on its own, and opens it when it has members.\n * Measuring stops once the limit is crossed, so a size cut short is still above it.\n */\nfunction addValue(walk: Walk, value: unknown): void {\n\tif (isContainer(value)) {\n\t\topen(walk, value);\n\t} else {\n\t\twalk.size += leafSize(value, remaining(walk));\n\t}\n}\n\n/**\n * Adds a container's own delimiters and queues its members, or the whole of it\n * when its size follows from its length alone.\n */\nfunction open(walk: Walk, container: JsonContainer): void {\n\t// A container reached from inside itself makes serialization fail, so it has\n\t// no size to answer with, and walking into it again would not end.\n\tif (!walk.ancestors.has(container)) {\n\t\tconst binarySize = maxBinaryViewSize(container);\n\n\t\tif (binarySize === undefined) {\n\t\t\twalk.size += EMPTY_CONTAINER_SIZE;\n\t\t\twalk.ancestors.add(container);\n\t\t\twalk.frames.push(frameFor(container));\n\t\t} else {\n\t\t\twalk.size += binarySize;\n\t\t}\n\t}\n}\n\nfunction close(walk: Walk, container: JsonContainer): void {\n\twalk.ancestors.delete(container);\n\twalk.frames.pop();\n}\n\nfunction frameFor(container: JsonContainer): Frame {\n\treturn Array.isArray(container)\n\t\t? { elements: container, index: 0 }\n\t\t: { entries: container, keys: Object.keys(container), index: 0 };\n}\n\n/** The value serialization puts in place of this one, given the key holding it. */\nfunction replacedValue(value: unknown, key: string | number): unknown {\n\treturn isSelfSerializing(value) ? value.toJSON(String(key)) : value;\n}\n\nfunction isSelfSerializing(value: unknown): value is SelfSerializing {\n\treturn (\n\t\tisContainer(value) &&\n\t\t// A Buffer would hand over an array of one number per byte, which its own\n\t\t// measure derives from its length instead.\n\t\t!Buffer.isBuffer(value) &&\n\t\t'toJSON' in value &&\n\t\ttypeof value.toJSON === 'function'\n\t);\n}\n\n/**\n * Bytes a Buffer or another binary view occupies serialized, or `undefined` for\n * a container whose members have to be walked.\n */\nfunction maxBinaryViewSize(container: JsonContainer): number | undefined {\n\tif (Buffer.isBuffer(container)) {\n\t\treturn BUFFER_ENVELOPE_SIZE + MAX_BUFFER_BYTE_SIZE * container.length;\n\t}\n\n\treturn isIndexedView(container) ? maxIndexedViewSize(container) : undefined;\n}\n\n/**\n * Bytes an indexed view occupies as the object of index/element entries it\n * serializes to. Derived from its length, because listing those keys would hold\n * one string per element in memory.\n */\nfunction maxIndexedViewSize(view: IndexedView): number {\n\tconst lastIndex = Math.max(view.length - 1, 0);\n\tconst maxEntrySize =\n\t\tQUOTES_SIZE + decimalDigits(lastIndex) + COLON_SIZE + MAX_NUMBER_SIZE + COMMA_SIZE;\n\n\treturn EMPTY_CONTAINER_SIZE + view.length * maxEntrySize;\n}\n\n/** Bytes a value with no members occupies serialized. */\nfunction leafSize(value: unknown, budget: number): number {\n\tswitch (typeof value) {\n\t\tcase 'string':\n\t\t\treturn stringSize(value, budget);\n\t\tcase 'number':\n\t\t\treturn numberSize(value);\n\t\tcase 'boolean':\n\t\t\treturn value ? TRUE_SIZE : FALSE_SIZE;\n\t\tdefault:\n\t\t\treturn NULL_SIZE;\n\t}\n}\n\n/** Bytes a string occupies serialized, escapes and quotes included. */\nfunction stringSize(value: string, budget: number): number {\n\treturn QUOTES_SIZE + escapedContentSize(value, budget - QUOTES_SIZE);\n}\n\n/**\n * Bytes the escaped characters of a string occupy, quotes excluded. Reads the\n * string one code unit at a time so that nothing is copied, and stops once\n * `budget` is gone, since what is already counted then settles the answer.\n */\nfunction escapedContentSize(value: string, budget: number): number {\n\tlet size = 0;\n\tlet index = 0;\n\n\twhile (index < value.length && size <= budget) {\n\t\tconst code = value.charCodeAt(index);\n\t\tconst paired = isHighSurrogate(code) && isLowSurrogate(value.charCodeAt(index + 1));\n\n\t\tsize += paired ? SURROGATE_PAIR_SIZE : codeUnitSize(code);\n\t\tindex += paired ? 2 : 1;\n\t}\n\n\treturn size;\n}\n\n/** Bytes a single code unit occupies, escaped and encoded as serialization would. */\nfunction codeUnitSize(code: number): number {\n\tif (code === QUOTE || code === BACKSLASH) {\n\t\treturn SHORT_ESCAPE_SIZE;\n\t}\n\n\tif (code <= CONTROL_MAX) {\n\t\treturn LETTER_ESCAPED_CONTROLS.has(code) ? SHORT_ESCAPE_SIZE : UNICODE_ESCAPE_SIZE;\n\t}\n\n\tif (code <= ASCII_MAX) {\n\t\treturn ONE_BYTE_SIZE;\n\t}\n\n\tif (code <= TWO_BYTE_MAX) {\n\t\treturn TWO_BYTE_SIZE;\n\t}\n\n\t// A surrogate left without its other half, which serialization escapes.\n\treturn isSurrogate(code) ? UNICODE_ESCAPE_SIZE : THREE_BYTE_SIZE;\n}\n\n/** Bytes a number occupies serialized. */\nfunction numberSize(value: number): number {\n\tif (!Number.isFinite(value)) {\n\t\treturn NULL_SIZE;\n\t}\n\n\tconst magnitude = Math.abs(value);\n\tconst isPlainInteger = Number.isInteger(value) && magnitude < EXPONENTIAL_NOTATION_THRESHOLD;\n\n\t// A plain integer has a length its magnitude gives away. Any other number has\n\t// to be formatted to be measured, and nothing shorter would be exact.\n\treturn isPlainInteger\n\t\t? (value < 0 ? SIGN_SIZE : 0) + decimalDigits(magnitude)\n\t\t: String(value).length;\n}\n\n/** Digits the integer part of a magnitude is written with. */\nfunction decimalDigits(magnitude: number): number {\n\tconst digits = magnitude < 1 ? 1 : Math.floor(Math.log10(magnitude)) + 1;\n\n\t// A rounding error in log10 costs a digit on some exact powers of ten.\n\treturn magnitude < 10 ** digits ? digits : digits + 1;\n}\n\n/** Whether serializing an object drops the entry holding this value, key included. */\nfunction isDroppedFromObjects(value: unknown): boolean {\n\tconst type = typeof value;\n\treturn type === 'undefined' || type === 'function' || type === 'symbol';\n}\n\nfunction isContainer(value: unknown): value is JsonContainer {\n\treturn typeof value === 'object' && value !== null;\n}\n\nfunction isIndexedView(value: object): value is IndexedView {\n\treturn ArrayBuffer.isView(value) && 'length' in value && typeof value.length === 'number';\n}\n\nfunction isHighSurrogate(code: number): boolean {\n\treturn code >= HIGH_SURROGATE_MIN && code <= HIGH_SURROGATE_MAX;\n}\n\nfunction isLowSurrogate(code: number): boolean {\n\treturn code >= LOW_SURROGATE_MIN && code <= LOW_SURROGATE_MAX;\n}\n\nfunction isSurrogate(code: number): boolean {\n\treturn code >= HIGH_SURROGATE_MIN && code <= LOW_SURROGATE_MAX;\n}\n"],"mappings":"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"}
//#region src/json/json-size-exceeds.d.ts
declare function jsonSizeExceeds(value: unknown, maxBytes: number): boolean;
//#endregion
export { jsonSizeExceeds };
//# sourceMappingURL=json-size-exceeds.d.cts.map
//#region src/json/json-size-exceeds.d.ts
declare function jsonSizeExceeds(value: unknown, maxBytes: number): boolean;
//#endregion
export { jsonSizeExceeds };
//# sourceMappingURL=json-size-exceeds.d.mts.map
//#region src/json/json-size-exceeds.ts
const QUOTES_SIZE = 2;
const COLON_SIZE = 1;
const COMMA_SIZE = 1;
const EMPTY_CONTAINER_SIZE = 2;
const NULL_SIZE = 4;
const TRUE_SIZE = 4;
const FALSE_SIZE = 5;
const SIGN_SIZE = 1;
/** Magnitude from which a number serializes in exponential notation. */
const EXPONENTIAL_NOTATION_THRESHOLD = 1e21;
/** `{"type":"Buffer","data":[]}` around the bytes of a Buffer. */
const BUFFER_ENVELOPE_SIZE = 27;
/** Longest a byte serializes to inside that envelope, as in `255,`. */
const MAX_BUFFER_BYTE_SIZE = 4;
/**
* Widest a number can serialize to, as in `-0.0000075911789601505095`. Bounds the
* elements of a binary view, which are counted without being visited.
*/
const MAX_NUMBER_SIZE = 25;
const SHORT_ESCAPE_SIZE = 2;
const UNICODE_ESCAPE_SIZE = 6;
const ONE_BYTE_SIZE = 1;
const TWO_BYTE_SIZE = 2;
const THREE_BYTE_SIZE = 3;
const SURROGATE_PAIR_SIZE = 4;
const CONTROL_MAX = 31;
const QUOTE = 34;
const BACKSLASH = 92;
const ASCII_MAX = 127;
const TWO_BYTE_MAX = 2047;
const HIGH_SURROGATE_MIN = 55296;
const HIGH_SURROGATE_MAX = 56319;
const LOW_SURROGATE_MIN = 56320;
const LOW_SURROGATE_MAX = 57343;
/** Control characters serialization escapes with a letter instead of a code point. */
const LETTER_ESCAPED_CONTROLS = /* @__PURE__ */ new Set([
8,
9,
10,
12,
13
]);
/** Key `JSON.stringify` hands to the `toJSON` of the value it is called on. */
const ROOT_KEY = "";
/**
* Tells whether a value exceeds a JSON size limit, without serializing it.
*
* The measure is an upper bound, so a value is never reported as fitting a size
* it does not fit. It overshoots by one byte per non-empty container, and counts
* binary data at the widest its bytes can serialize to.
*
* @param value Value to measure as if it were passed to `JSON.stringify`.
* @param maxBytes Limit the serialization must stay within.
* @returns `true` unless the serialization is certainly `maxBytes` or shorter.
*
* @remarks Time O(n) in the members and characters of `value`, memory O(depth).
* Calls `toJSON` on the members defining one, as serialization would.
*/
function jsonSizeExceeds(value, maxBytes) {
const walk = {
maxBytes,
frames: [],
ancestors: /* @__PURE__ */ new Set(),
size: 0
};
addValue(walk, replacedValue(value, ROOT_KEY));
while (walk.frames.length > 0 && walk.size <= maxBytes) advance(walk, walk.frames[walk.frames.length - 1]);
return walk.size > maxBytes;
}
/** Bytes left before the limit. Negative once the limit is crossed. */
function remaining(walk) {
return walk.maxBytes - walk.size;
}
/** Measures the next member of the innermost container, or closes it. */
function advance(walk, frame) {
if ("elements" in frame) advanceElements(walk, frame);
else advanceEntries(walk, frame);
}
function advanceElements(walk, frame) {
if (frame.index === frame.elements.length) close(walk, frame.elements);
else {
const index = frame.index;
frame.index += 1;
walk.size += COMMA_SIZE;
addValue(walk, replacedValue(frame.elements[index], index));
}
}
function advanceEntries(walk, frame) {
if (frame.index === frame.keys.length) close(walk, frame.entries);
else {
const key = frame.keys[frame.index];
frame.index += 1;
addEntry(walk, key, replacedValue(frame.entries[key], key));
}
}
/** Adds an entry, unless serialization drops it along with its key. */
function addEntry(walk, key, value) {
if (!isDroppedFromObjects(value)) {
walk.size += 2 + stringSize(key, remaining(walk));
addValue(walk, value);
}
}
/**
* Adds what a value occupies on its own, and opens it when it has members.
* Measuring stops once the limit is crossed, so a size cut short is still above it.
*/
function addValue(walk, value) {
if (isContainer(value)) open(walk, value);
else walk.size += leafSize(value, remaining(walk));
}
/**
* Adds a container's own delimiters and queues its members, or the whole of it
* when its size follows from its length alone.
*/
function open(walk, container) {
if (!walk.ancestors.has(container)) {
const binarySize = maxBinaryViewSize(container);
if (binarySize === void 0) {
walk.size += EMPTY_CONTAINER_SIZE;
walk.ancestors.add(container);
walk.frames.push(frameFor(container));
} else walk.size += binarySize;
}
}
function close(walk, container) {
walk.ancestors.delete(container);
walk.frames.pop();
}
function frameFor(container) {
return Array.isArray(container) ? {
elements: container,
index: 0
} : {
entries: container,
keys: Object.keys(container),
index: 0
};
}
/** The value serialization puts in place of this one, given the key holding it. */
function replacedValue(value, key) {
return isSelfSerializing(value) ? value.toJSON(String(key)) : value;
}
function isSelfSerializing(value) {
return isContainer(value) && !Buffer.isBuffer(value) && "toJSON" in value && typeof value.toJSON === "function";
}
/**
* Bytes a Buffer or another binary view occupies serialized, or `undefined` for
* a container whose members have to be walked.
*/
function maxBinaryViewSize(container) {
if (Buffer.isBuffer(container)) return BUFFER_ENVELOPE_SIZE + MAX_BUFFER_BYTE_SIZE * container.length;
return isIndexedView(container) ? maxIndexedViewSize(container) : void 0;
}
/**
* Bytes an indexed view occupies as the object of index/element entries it
* serializes to. Derived from its length, because listing those keys would hold
* one string per element in memory.
*/
function maxIndexedViewSize(view) {
const lastIndex = Math.max(view.length - 1, 0);
const maxEntrySize = QUOTES_SIZE + decimalDigits(lastIndex) + COLON_SIZE + MAX_NUMBER_SIZE + COMMA_SIZE;
return EMPTY_CONTAINER_SIZE + view.length * maxEntrySize;
}
/** Bytes a value with no members occupies serialized. */
function leafSize(value, budget) {
switch (typeof value) {
case "string": return stringSize(value, budget);
case "number": return numberSize(value);
case "boolean": return value ? TRUE_SIZE : FALSE_SIZE;
default: return NULL_SIZE;
}
}
/** Bytes a string occupies serialized, escapes and quotes included. */
function stringSize(value, budget) {
return QUOTES_SIZE + escapedContentSize(value, budget - QUOTES_SIZE);
}
/**
* Bytes the escaped characters of a string occupy, quotes excluded. Reads the
* string one code unit at a time so that nothing is copied, and stops once
* `budget` is gone, since what is already counted then settles the answer.
*/
function escapedContentSize(value, budget) {
let size = 0;
let index = 0;
while (index < value.length && size <= budget) {
const code = value.charCodeAt(index);
const paired = isHighSurrogate(code) && isLowSurrogate(value.charCodeAt(index + 1));
size += paired ? SURROGATE_PAIR_SIZE : codeUnitSize(code);
index += paired ? 2 : 1;
}
return size;
}
/** Bytes a single code unit occupies, escaped and encoded as serialization would. */
function codeUnitSize(code) {
if (code === QUOTE || code === BACKSLASH) return SHORT_ESCAPE_SIZE;
if (code <= CONTROL_MAX) return LETTER_ESCAPED_CONTROLS.has(code) ? SHORT_ESCAPE_SIZE : UNICODE_ESCAPE_SIZE;
if (code <= ASCII_MAX) return ONE_BYTE_SIZE;
if (code <= TWO_BYTE_MAX) return TWO_BYTE_SIZE;
return isSurrogate(code) ? UNICODE_ESCAPE_SIZE : THREE_BYTE_SIZE;
}
/** Bytes a number occupies serialized. */
function numberSize(value) {
if (!Number.isFinite(value)) return NULL_SIZE;
const magnitude = Math.abs(value);
return Number.isInteger(value) && magnitude < EXPONENTIAL_NOTATION_THRESHOLD ? (value < 0 ? SIGN_SIZE : 0) + decimalDigits(magnitude) : String(value).length;
}
/** Digits the integer part of a magnitude is written with. */
function decimalDigits(magnitude) {
const digits = magnitude < 1 ? 1 : Math.floor(Math.log10(magnitude)) + 1;
return magnitude < 10 ** digits ? digits : digits + 1;
}
/** Whether serializing an object drops the entry holding this value, key included. */
function isDroppedFromObjects(value) {
const type = typeof value;
return type === "undefined" || type === "function" || type === "symbol";
}
function isContainer(value) {
return typeof value === "object" && value !== null;
}
function isIndexedView(value) {
return ArrayBuffer.isView(value) && "length" in value && typeof value.length === "number";
}
function isHighSurrogate(code) {
return code >= HIGH_SURROGATE_MIN && code <= HIGH_SURROGATE_MAX;
}
function isLowSurrogate(code) {
return code >= LOW_SURROGATE_MIN && code <= LOW_SURROGATE_MAX;
}
function isSurrogate(code) {
return code >= HIGH_SURROGATE_MIN && code <= LOW_SURROGATE_MAX;
}
//#endregion
export { jsonSizeExceeds };
//# sourceMappingURL=json-size-exceeds.mjs.map
{"version":3,"file":"json-size-exceeds.mjs","names":[],"sources":["../../src/json/json-size-exceeds.ts"],"sourcesContent":["type JsonContainer = Record<string, unknown> | unknown[];\n\n/** A value serialization replaces with the result of its own `toJSON`. */\ntype SelfSerializing = JsonContainer & { toJSON: (key: string) => unknown };\n\n/** A view over binary data, serialized as one entry per element. */\ntype IndexedView = ArrayBufferView & { length: number };\n\n/** An array being measured, and how far through its elements the walk is. */\ntype ElementsFrame = { readonly elements: unknown[]; index: number };\n\n/** An object being measured, and how far through its keys the walk is. */\ntype EntriesFrame = {\n\treadonly entries: Record<string, unknown>;\n\treadonly keys: string[];\n\tindex: number;\n};\n\ntype Frame = ElementsFrame | EntriesFrame;\n\n/** Bytes counted so far, and the containers the walk still has to finish. */\ntype Walk = {\n\treadonly maxBytes: number;\n\treadonly frames: Frame[];\n\treadonly ancestors: Set<JsonContainer>;\n\tsize: number;\n};\n\nconst QUOTES_SIZE = 2; // `\"\"` around a string or a key\nconst COLON_SIZE = 1;\nconst COMMA_SIZE = 1;\nconst EMPTY_CONTAINER_SIZE = 2; // `{}` or `[]`\nconst NULL_SIZE = 4;\nconst TRUE_SIZE = 4;\nconst FALSE_SIZE = 5;\nconst SIGN_SIZE = 1;\n\n/** Magnitude from which a number serializes in exponential notation. */\nconst EXPONENTIAL_NOTATION_THRESHOLD = 1e21;\n\n/** `{\"type\":\"Buffer\",\"data\":[]}` around the bytes of a Buffer. */\nconst BUFFER_ENVELOPE_SIZE = 27;\n\n/** Longest a byte serializes to inside that envelope, as in `255,`. */\nconst MAX_BUFFER_BYTE_SIZE = 4;\n\n/**\n * Widest a number can serialize to, as in `-0.0000075911789601505095`. Bounds the\n * elements of a binary view, which are counted without being visited.\n */\nconst MAX_NUMBER_SIZE = 25;\n\nconst SHORT_ESCAPE_SIZE = 2; // `\\n`, `\\\"`, `\\\\`\nconst UNICODE_ESCAPE_SIZE = 6; // `\\u001f`, and a lone surrogate\nconst ONE_BYTE_SIZE = 1;\nconst TWO_BYTE_SIZE = 2;\nconst THREE_BYTE_SIZE = 3;\nconst SURROGATE_PAIR_SIZE = 4; // one code point spread over two code units\n\nconst CONTROL_MAX = 0x1f;\nconst QUOTE = 0x22;\nconst BACKSLASH = 0x5c;\nconst ASCII_MAX = 0x7f;\nconst TWO_BYTE_MAX = 0x7ff;\nconst HIGH_SURROGATE_MIN = 0xd800;\nconst HIGH_SURROGATE_MAX = 0xdbff;\nconst LOW_SURROGATE_MIN = 0xdc00;\nconst LOW_SURROGATE_MAX = 0xdfff;\n\n/** Control characters serialization escapes with a letter instead of a code point. */\nconst LETTER_ESCAPED_CONTROLS = new Set([0x08, 0x09, 0x0a, 0x0c, 0x0d]);\n\n/** Key `JSON.stringify` hands to the `toJSON` of the value it is called on. */\nconst ROOT_KEY = '';\n\n/**\n * Tells whether a value exceeds a JSON size limit, without serializing it.\n *\n * The measure is an upper bound, so a value is never reported as fitting a size\n * it does not fit. It overshoots by one byte per non-empty container, and counts\n * binary data at the widest its bytes can serialize to.\n *\n * @param value Value to measure as if it were passed to `JSON.stringify`.\n * @param maxBytes Limit the serialization must stay within.\n * @returns `true` unless the serialization is certainly `maxBytes` or shorter.\n *\n * @remarks Time O(n) in the members and characters of `value`, memory O(depth).\n * Calls `toJSON` on the members defining one, as serialization would.\n */\nexport function jsonSizeExceeds(value: unknown, maxBytes: number): boolean {\n\tconst walk: Walk = { maxBytes, frames: [], ancestors: new Set(), size: 0 };\n\n\taddValue(walk, replacedValue(value, ROOT_KEY));\n\twhile (walk.frames.length > 0 && walk.size <= maxBytes) {\n\t\tadvance(walk, walk.frames[walk.frames.length - 1]);\n\t}\n\n\treturn walk.size > maxBytes;\n}\n\n/** Bytes left before the limit. Negative once the limit is crossed. */\nfunction remaining(walk: Walk): number {\n\treturn walk.maxBytes - walk.size;\n}\n\n/** Measures the next member of the innermost container, or closes it. */\nfunction advance(walk: Walk, frame: Frame): void {\n\tif ('elements' in frame) {\n\t\tadvanceElements(walk, frame);\n\t} else {\n\t\tadvanceEntries(walk, frame);\n\t}\n}\n\nfunction advanceElements(walk: Walk, frame: ElementsFrame): void {\n\tif (frame.index === frame.elements.length) {\n\t\tclose(walk, frame.elements);\n\t} else {\n\t\tconst index = frame.index;\n\t\tframe.index += 1;\n\t\twalk.size += COMMA_SIZE;\n\t\taddValue(walk, replacedValue(frame.elements[index], index));\n\t}\n}\n\nfunction advanceEntries(walk: Walk, frame: EntriesFrame): void {\n\tif (frame.index === frame.keys.length) {\n\t\tclose(walk, frame.entries);\n\t} else {\n\t\tconst key = frame.keys[frame.index];\n\t\tframe.index += 1;\n\t\taddEntry(walk, key, replacedValue(frame.entries[key], key));\n\t}\n}\n\n/** Adds an entry, unless serialization drops it along with its key. */\nfunction addEntry(walk: Walk, key: string, value: unknown): void {\n\tif (!isDroppedFromObjects(value)) {\n\t\twalk.size += COMMA_SIZE + COLON_SIZE + stringSize(key, remaining(walk));\n\t\taddValue(walk, value);\n\t}\n}\n\n/**\n * Adds what a value occupies on its own, and opens it when it has members.\n * Measuring stops once the limit is crossed, so a size cut short is still above it.\n */\nfunction addValue(walk: Walk, value: unknown): void {\n\tif (isContainer(value)) {\n\t\topen(walk, value);\n\t} else {\n\t\twalk.size += leafSize(value, remaining(walk));\n\t}\n}\n\n/**\n * Adds a container's own delimiters and queues its members, or the whole of it\n * when its size follows from its length alone.\n */\nfunction open(walk: Walk, container: JsonContainer): void {\n\t// A container reached from inside itself makes serialization fail, so it has\n\t// no size to answer with, and walking into it again would not end.\n\tif (!walk.ancestors.has(container)) {\n\t\tconst binarySize = maxBinaryViewSize(container);\n\n\t\tif (binarySize === undefined) {\n\t\t\twalk.size += EMPTY_CONTAINER_SIZE;\n\t\t\twalk.ancestors.add(container);\n\t\t\twalk.frames.push(frameFor(container));\n\t\t} else {\n\t\t\twalk.size += binarySize;\n\t\t}\n\t}\n}\n\nfunction close(walk: Walk, container: JsonContainer): void {\n\twalk.ancestors.delete(container);\n\twalk.frames.pop();\n}\n\nfunction frameFor(container: JsonContainer): Frame {\n\treturn Array.isArray(container)\n\t\t? { elements: container, index: 0 }\n\t\t: { entries: container, keys: Object.keys(container), index: 0 };\n}\n\n/** The value serialization puts in place of this one, given the key holding it. */\nfunction replacedValue(value: unknown, key: string | number): unknown {\n\treturn isSelfSerializing(value) ? value.toJSON(String(key)) : value;\n}\n\nfunction isSelfSerializing(value: unknown): value is SelfSerializing {\n\treturn (\n\t\tisContainer(value) &&\n\t\t// A Buffer would hand over an array of one number per byte, which its own\n\t\t// measure derives from its length instead.\n\t\t!Buffer.isBuffer(value) &&\n\t\t'toJSON' in value &&\n\t\ttypeof value.toJSON === 'function'\n\t);\n}\n\n/**\n * Bytes a Buffer or another binary view occupies serialized, or `undefined` for\n * a container whose members have to be walked.\n */\nfunction maxBinaryViewSize(container: JsonContainer): number | undefined {\n\tif (Buffer.isBuffer(container)) {\n\t\treturn BUFFER_ENVELOPE_SIZE + MAX_BUFFER_BYTE_SIZE * container.length;\n\t}\n\n\treturn isIndexedView(container) ? maxIndexedViewSize(container) : undefined;\n}\n\n/**\n * Bytes an indexed view occupies as the object of index/element entries it\n * serializes to. Derived from its length, because listing those keys would hold\n * one string per element in memory.\n */\nfunction maxIndexedViewSize(view: IndexedView): number {\n\tconst lastIndex = Math.max(view.length - 1, 0);\n\tconst maxEntrySize =\n\t\tQUOTES_SIZE + decimalDigits(lastIndex) + COLON_SIZE + MAX_NUMBER_SIZE + COMMA_SIZE;\n\n\treturn EMPTY_CONTAINER_SIZE + view.length * maxEntrySize;\n}\n\n/** Bytes a value with no members occupies serialized. */\nfunction leafSize(value: unknown, budget: number): number {\n\tswitch (typeof value) {\n\t\tcase 'string':\n\t\t\treturn stringSize(value, budget);\n\t\tcase 'number':\n\t\t\treturn numberSize(value);\n\t\tcase 'boolean':\n\t\t\treturn value ? TRUE_SIZE : FALSE_SIZE;\n\t\tdefault:\n\t\t\treturn NULL_SIZE;\n\t}\n}\n\n/** Bytes a string occupies serialized, escapes and quotes included. */\nfunction stringSize(value: string, budget: number): number {\n\treturn QUOTES_SIZE + escapedContentSize(value, budget - QUOTES_SIZE);\n}\n\n/**\n * Bytes the escaped characters of a string occupy, quotes excluded. Reads the\n * string one code unit at a time so that nothing is copied, and stops once\n * `budget` is gone, since what is already counted then settles the answer.\n */\nfunction escapedContentSize(value: string, budget: number): number {\n\tlet size = 0;\n\tlet index = 0;\n\n\twhile (index < value.length && size <= budget) {\n\t\tconst code = value.charCodeAt(index);\n\t\tconst paired = isHighSurrogate(code) && isLowSurrogate(value.charCodeAt(index + 1));\n\n\t\tsize += paired ? SURROGATE_PAIR_SIZE : codeUnitSize(code);\n\t\tindex += paired ? 2 : 1;\n\t}\n\n\treturn size;\n}\n\n/** Bytes a single code unit occupies, escaped and encoded as serialization would. */\nfunction codeUnitSize(code: number): number {\n\tif (code === QUOTE || code === BACKSLASH) {\n\t\treturn SHORT_ESCAPE_SIZE;\n\t}\n\n\tif (code <= CONTROL_MAX) {\n\t\treturn LETTER_ESCAPED_CONTROLS.has(code) ? SHORT_ESCAPE_SIZE : UNICODE_ESCAPE_SIZE;\n\t}\n\n\tif (code <= ASCII_MAX) {\n\t\treturn ONE_BYTE_SIZE;\n\t}\n\n\tif (code <= TWO_BYTE_MAX) {\n\t\treturn TWO_BYTE_SIZE;\n\t}\n\n\t// A surrogate left without its other half, which serialization escapes.\n\treturn isSurrogate(code) ? UNICODE_ESCAPE_SIZE : THREE_BYTE_SIZE;\n}\n\n/** Bytes a number occupies serialized. */\nfunction numberSize(value: number): number {\n\tif (!Number.isFinite(value)) {\n\t\treturn NULL_SIZE;\n\t}\n\n\tconst magnitude = Math.abs(value);\n\tconst isPlainInteger = Number.isInteger(value) && magnitude < EXPONENTIAL_NOTATION_THRESHOLD;\n\n\t// A plain integer has a length its magnitude gives away. Any other number has\n\t// to be formatted to be measured, and nothing shorter would be exact.\n\treturn isPlainInteger\n\t\t? (value < 0 ? SIGN_SIZE : 0) + decimalDigits(magnitude)\n\t\t: String(value).length;\n}\n\n/** Digits the integer part of a magnitude is written with. */\nfunction decimalDigits(magnitude: number): number {\n\tconst digits = magnitude < 1 ? 1 : Math.floor(Math.log10(magnitude)) + 1;\n\n\t// A rounding error in log10 costs a digit on some exact powers of ten.\n\treturn magnitude < 10 ** digits ? digits : digits + 1;\n}\n\n/** Whether serializing an object drops the entry holding this value, key included. */\nfunction isDroppedFromObjects(value: unknown): boolean {\n\tconst type = typeof value;\n\treturn type === 'undefined' || type === 'function' || type === 'symbol';\n}\n\nfunction isContainer(value: unknown): value is JsonContainer {\n\treturn typeof value === 'object' && value !== null;\n}\n\nfunction isIndexedView(value: object): value is IndexedView {\n\treturn ArrayBuffer.isView(value) && 'length' in value && typeof value.length === 'number';\n}\n\nfunction isHighSurrogate(code: number): boolean {\n\treturn code >= HIGH_SURROGATE_MIN && code <= HIGH_SURROGATE_MAX;\n}\n\nfunction isLowSurrogate(code: number): boolean {\n\treturn code >= LOW_SURROGATE_MIN && code <= LOW_SURROGATE_MAX;\n}\n\nfunction isSurrogate(code: number): boolean {\n\treturn code >= HIGH_SURROGATE_MIN && code <= LOW_SURROGATE_MAX;\n}\n"],"mappings":"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"}
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
//#region src/sleep.ts
async function sleepWithAbort(ms, abortSignal) {
return await new Promise((resolve, reject) => {
if (abortSignal.aborted) {
reject(/* @__PURE__ */ new Error("Aborted"));
return;
}
const timeout = setTimeout(resolve, ms);
abortSignal.addEventListener("abort", () => {
clearTimeout(timeout);
reject(/* @__PURE__ */ new Error("Aborted"));
}, { once: true });
});
}
/**
* Resolves after `ms` milliseconds, or rejects early if `abortSignal` is aborted.
*/
async function sleep(ms, abortSignal) {
if (!abortSignal) return await new Promise((resolve) => setTimeout(resolve, ms));
return await sleepWithAbort(ms, abortSignal);
}
//#endregion
exports.sleep = sleep;
//# sourceMappingURL=sleep.cjs.map
{"version":3,"file":"sleep.cjs","names":[],"sources":["../src/sleep.ts"],"sourcesContent":["async function sleepWithAbort(ms: number, abortSignal: AbortSignal): Promise<void> {\n\treturn await new Promise((resolve, reject) => {\n\t\tif (abortSignal.aborted) {\n\t\t\treject(new Error('Aborted'));\n\t\t\treturn;\n\t\t}\n\n\t\tconst timeout = setTimeout(resolve, ms);\n\n\t\tabortSignal.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\treject(new Error('Aborted'));\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t});\n}\n\n/**\n * Resolves after `ms` milliseconds, or rejects early if `abortSignal` is aborted.\n */\nexport async function sleep(ms: number, abortSignal?: AbortSignal): Promise<void> {\n\tif (!abortSignal) {\n\t\treturn await new Promise((resolve) => setTimeout(resolve, ms));\n\t}\n\n\treturn await sleepWithAbort(ms, abortSignal);\n}\n"],"mappings":";;AAAA,eAAe,eAAe,IAAY,aAAyC;CAClF,OAAO,MAAM,IAAI,SAAS,SAAS,WAAW;EAC7C,IAAI,YAAY,SAAS;GACxB,uBAAO,IAAI,MAAM,SAAS,CAAC;GAC3B;EACD;EAEA,MAAM,UAAU,WAAW,SAAS,EAAE;EAEtC,YAAY,iBACX,eACM;GACL,aAAa,OAAO;GACpB,uBAAO,IAAI,MAAM,SAAS,CAAC;EAC5B,GACA,EAAE,MAAM,KAAK,CACd;CACD,CAAC;AACF;;;;AAKA,eAAsB,MAAM,IAAY,aAA0C;CACjF,IAAI,CAAC,aACJ,OAAO,MAAM,IAAI,SAAS,YAAY,WAAW,SAAS,EAAE,CAAC;CAG9D,OAAO,MAAM,eAAe,IAAI,WAAW;AAC5C"}
//#region src/sleep.d.ts
declare function sleep(ms: number, abortSignal?: AbortSignal): Promise<void>;
//#endregion
export { sleep };
//# sourceMappingURL=sleep.d.cts.map
//#region src/sleep.d.ts
declare function sleep(ms: number, abortSignal?: AbortSignal): Promise<void>;
//#endregion
export { sleep };
//# sourceMappingURL=sleep.d.mts.map
//#region src/sleep.ts
async function sleepWithAbort(ms, abortSignal) {
return await new Promise((resolve, reject) => {
if (abortSignal.aborted) {
reject(/* @__PURE__ */ new Error("Aborted"));
return;
}
const timeout = setTimeout(resolve, ms);
abortSignal.addEventListener("abort", () => {
clearTimeout(timeout);
reject(/* @__PURE__ */ new Error("Aborted"));
}, { once: true });
});
}
/**
* Resolves after `ms` milliseconds, or rejects early if `abortSignal` is aborted.
*/
async function sleep(ms, abortSignal) {
if (!abortSignal) return await new Promise((resolve) => setTimeout(resolve, ms));
return await sleepWithAbort(ms, abortSignal);
}
//#endregion
export { sleep };
//# sourceMappingURL=sleep.mjs.map
{"version":3,"file":"sleep.mjs","names":[],"sources":["../src/sleep.ts"],"sourcesContent":["async function sleepWithAbort(ms: number, abortSignal: AbortSignal): Promise<void> {\n\treturn await new Promise((resolve, reject) => {\n\t\tif (abortSignal.aborted) {\n\t\t\treject(new Error('Aborted'));\n\t\t\treturn;\n\t\t}\n\n\t\tconst timeout = setTimeout(resolve, ms);\n\n\t\tabortSignal.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\treject(new Error('Aborted'));\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t});\n}\n\n/**\n * Resolves after `ms` milliseconds, or rejects early if `abortSignal` is aborted.\n */\nexport async function sleep(ms: number, abortSignal?: AbortSignal): Promise<void> {\n\tif (!abortSignal) {\n\t\treturn await new Promise((resolve) => setTimeout(resolve, ms));\n\t}\n\n\treturn await sleepWithAbort(ms, abortSignal);\n}\n"],"mappings":";AAAA,eAAe,eAAe,IAAY,aAAyC;CAClF,OAAO,MAAM,IAAI,SAAS,SAAS,WAAW;EAC7C,IAAI,YAAY,SAAS;GACxB,uBAAO,IAAI,MAAM,SAAS,CAAC;GAC3B;EACD;EAEA,MAAM,UAAU,WAAW,SAAS,EAAE;EAEtC,YAAY,iBACX,eACM;GACL,aAAa,OAAO;GACpB,uBAAO,IAAI,MAAM,SAAS,CAAC;EAC5B,GACA,EAAE,MAAM,KAAK,CACd;CACD,CAAC;AACF;;;;AAKA,eAAsB,MAAM,IAAY,aAA0C;CACjF,IAAI,CAAC,aACJ,OAAO,MAAM,IAAI,SAAS,YAAY,WAAW,SAAS,EAAE,CAAC;CAG9D,OAAO,MAAM,eAAe,IAAI,WAAW;AAC5C"}
+4
-4
{
"name": "@n8n/utils",
"type": "module",
"version": "1.41.0",
"version": "1.42.0",
"files": [

@@ -31,3 +31,3 @@ "dist",

"nanoid": "3.3.8",
"@n8n/constants": "0.32.0"
"@n8n/constants": "0.33.0"
},

@@ -41,5 +41,5 @@ "devDependencies": {

"vitest": "^4.1.9",
"@n8n/typescript-config": "1.9.0",
"@n8n/eslint-config": "0.0.1",
"@n8n/vitest-config": "1.19.0"
"@n8n/vitest-config": "1.19.0",
"@n8n/typescript-config": "1.9.0"
},

@@ -46,0 +46,0 @@ "license": "SEE LICENSE IN LICENSE.md",