es-toolkit 1.52.0-dev.2094 → 1.52.0-dev.2096

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/browser.global.js +4 -4
  2. package/dist/index.d.mts +2 -1
  3. package/dist/index.d.ts +2 -1
  4. package/dist/index.js +2 -0
  5. package/dist/index.mjs +2 -1
  6. package/dist/util/hash/browser.d.mts +26 -0
  7. package/dist/util/hash/browser.d.ts +26 -0
  8. package/dist/util/hash/browser.js +31 -0
  9. package/dist/util/hash/browser.mjs +30 -0
  10. package/dist/util/hash/node.d.mts +26 -0
  11. package/dist/util/hash/node.d.ts +26 -0
  12. package/dist/util/hash/node.js +494 -0
  13. package/dist/util/hash/node.mjs +493 -0
  14. package/dist/util/hash/sha256.js +158 -0
  15. package/dist/util/hash/sha256.mjs +158 -0
  16. package/dist/util/index.d.mts +2 -1
  17. package/dist/util/index.d.ts +2 -1
  18. package/dist/util/index.js +2 -0
  19. package/dist/util/index.mjs +2 -1
  20. package/dist/util/serialize/compareValues.js +23 -0
  21. package/dist/util/serialize/compareValues.mjs +23 -0
  22. package/dist/util/serialize/serialize.d.mts +44 -0
  23. package/dist/util/serialize/serialize.d.ts +44 -0
  24. package/dist/util/serialize/serialize.js +64 -0
  25. package/dist/util/serialize/serialize.mjs +63 -0
  26. package/dist/util/serialize/serializeBigInt.js +15 -0
  27. package/dist/util/serialize/serializeBigInt.mjs +15 -0
  28. package/dist/util/serialize/serializeFunction.js +26 -0
  29. package/dist/util/serialize/serializeFunction.mjs +26 -0
  30. package/dist/util/serialize/serializeNumber.js +21 -0
  31. package/dist/util/serialize/serializeNumber.mjs +21 -0
  32. package/dist/util/serialize/serializeObject.js +85 -0
  33. package/dist/util/serialize/serializeObject.mjs +85 -0
  34. package/dist/util/serialize/serializePlainObject.js +31 -0
  35. package/dist/util/serialize/serializePlainObject.mjs +31 -0
  36. package/dist/util/serialize/serializeString.js +18 -0
  37. package/dist/util/serialize/serializeString.mjs +18 -0
  38. package/dist/util/serialize/serializeSymbol.js +23 -0
  39. package/dist/util/serialize/serializeSymbol.mjs +23 -0
  40. package/package.json +47 -1
  41. package/util/hash.d.ts +1 -0
  42. package/util/hash.js +1 -0
@@ -0,0 +1,30 @@
1
+ import { serialize } from "../serialize/serialize.mjs";
2
+ import { sha256 } from "./sha256.mjs";
3
+ //#region src/util/hash/browser.ts
4
+ /**
5
+ * Hashes any value into a stable 43-character string.
6
+ *
7
+ * The value is serialized with `serialize`, so two values with the same
8
+ * structure always hash to the same string regardless of key insertion
9
+ * order, and then digested with SHA-256 and encoded in Base64URL format.
10
+ *
11
+ * The hash is stable across platforms, but it is not designed for security
12
+ * purposes; intentional collisions can be crafted from user input.
13
+ *
14
+ * This entry uses a pure JavaScript SHA-256 implementation; in Node.js,
15
+ * the native `node:crypto` implementation with identical output is used
16
+ * instead.
17
+ *
18
+ * @param value - The value to hash.
19
+ * @returns The Base64URL-encoded SHA-256 hash of the serialized value.
20
+ * @throws {TypeError} If the value contains an object that cannot be serialized.
21
+ *
22
+ * @example
23
+ * hash({ b: 2, a: 1 }) === hash({ a: 1, b: 2 }); // true
24
+ * hash([1, 2, 3]); // "phXuruId5Red4IDejDBSyNqQEThAa6ccOMAyhF99VPQ" (43 characters)
25
+ */
26
+ function hash(value) {
27
+ return sha256(serialize(value));
28
+ }
29
+ //#endregion
30
+ export { hash };
@@ -0,0 +1,26 @@
1
+ //#region src/util/hash/node.d.ts
2
+ /**
3
+ * Hashes any value into a stable 43-character string.
4
+ *
5
+ * The value is serialized with `serialize`, so two values with the same
6
+ * structure always hash to the same string regardless of key insertion
7
+ * order, and then digested with SHA-256 and encoded in Base64URL format.
8
+ *
9
+ * The hash is stable across platforms, but it is not designed for security
10
+ * purposes; intentional collisions can be crafted from user input.
11
+ *
12
+ * This entry uses the native `node:crypto` implementation and requires
13
+ * Node.js 20.12 or later; in browsers, a pure JavaScript implementation
14
+ * with identical output is used instead.
15
+ *
16
+ * @param value - The value to hash.
17
+ * @returns The Base64URL-encoded SHA-256 hash of the serialized value.
18
+ * @throws {TypeError} If the value contains an object that cannot be serialized.
19
+ *
20
+ * @example
21
+ * hash({ b: 2, a: 1 }) === hash({ a: 1, b: 2 }); // true
22
+ * hash([1, 2, 3]); // "phXuruId5Red4IDejDBSyNqQEThAa6ccOMAyhF99VPQ" (43 characters)
23
+ */
24
+ declare function hash(value: unknown): string;
25
+ //#endregion
26
+ export { hash };
@@ -0,0 +1,26 @@
1
+ //#region src/util/hash/node.d.ts
2
+ /**
3
+ * Hashes any value into a stable 43-character string.
4
+ *
5
+ * The value is serialized with `serialize`, so two values with the same
6
+ * structure always hash to the same string regardless of key insertion
7
+ * order, and then digested with SHA-256 and encoded in Base64URL format.
8
+ *
9
+ * The hash is stable across platforms, but it is not designed for security
10
+ * purposes; intentional collisions can be crafted from user input.
11
+ *
12
+ * This entry uses the native `node:crypto` implementation and requires
13
+ * Node.js 20.12 or later; in browsers, a pure JavaScript implementation
14
+ * with identical output is used instead.
15
+ *
16
+ * @param value - The value to hash.
17
+ * @returns The Base64URL-encoded SHA-256 hash of the serialized value.
18
+ * @throws {TypeError} If the value contains an object that cannot be serialized.
19
+ *
20
+ * @example
21
+ * hash({ b: 2, a: 1 }) === hash({ a: 1, b: 2 }); // true
22
+ * hash([1, 2, 3]); // "phXuruId5Red4IDejDBSyNqQEThAa6ccOMAyhF99VPQ" (43 characters)
23
+ */
24
+ declare function hash(value: unknown): string;
25
+ //#endregion
26
+ export { hash };
@@ -0,0 +1,494 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let node_crypto = require("node:crypto");
3
+ //#region src/util/serialize/serializeBigInt.ts
4
+ /**
5
+ * Serializes a bigint into a string with an `n` suffix, like a bigint literal.
6
+ *
7
+ * @param value - The bigint to serialize.
8
+ * @returns The serialized string.
9
+ *
10
+ * @example
11
+ * serializeBigInt(123n); // "123n"
12
+ */
13
+ function serializeBigInt(value) {
14
+ return `${value}n`;
15
+ }
16
+ //#endregion
17
+ //#region src/util/serialize/serializeFunction.ts
18
+ /**
19
+ * Serializes a function into a string of the form `name:source`.
20
+ *
21
+ * Native functions have no meaningful source, so they are serialized as
22
+ * `name:[native]`. For other functions, newlines and their surrounding
23
+ * whitespace are collapsed so that formatting differences do not change
24
+ * the output.
25
+ *
26
+ * @param value - The function to serialize.
27
+ * @returns The serialized string.
28
+ *
29
+ * @example
30
+ * function sum(a, b) {
31
+ * return a + b;
32
+ * }
33
+ * serializeFunction(sum); // "sum:function sum(a, b) {return a + b;}"
34
+ * serializeFunction(Math.max); // "max:[native]"
35
+ */
36
+ function serializeFunction(value) {
37
+ const source = Function.prototype.toString.call(value);
38
+ if (source.endsWith("[native code] }")) return `${value.name}:[native]`;
39
+ return `${value.name}:${source.replace(/\s*\n\s*/g, "")}`;
40
+ }
41
+ //#endregion
42
+ //#region src/util/serialize/serializeNumber.ts
43
+ /**
44
+ * Serializes a number into a string.
45
+ *
46
+ * `-0` is serialized as `0`, and `NaN` and `Infinity` are serialized
47
+ * as their string representations.
48
+ *
49
+ * @param value - The number to serialize.
50
+ * @returns The serialized string.
51
+ *
52
+ * @example
53
+ * serializeNumber(1); // "1"
54
+ * serializeNumber(-0); // "0"
55
+ * serializeNumber(NaN); // "NaN"
56
+ * serializeNumber(Infinity); // "Infinity"
57
+ */
58
+ function serializeNumber(value) {
59
+ return String(value);
60
+ }
61
+ //#endregion
62
+ //#region src/util/serialize/compareValues.ts
63
+ /**
64
+ * Compares two values for sorting `Set` values and `Map` keys.
65
+ *
66
+ * Numbers are compared numerically and strings by code unit. Any other
67
+ * combination is compared by the code unit order of the serialized values.
68
+ *
69
+ * @param a - The first value to compare.
70
+ * @param b - The second value to compare.
71
+ * @param refs - The circular reference context shared with the surrounding serialization.
72
+ * @returns A negative number if `a` sorts before `b`, a positive number if
73
+ * `a` sorts after `b`, and `0` if they are equal.
74
+ */
75
+ function compareValues(a, b, refs) {
76
+ if (typeof a === "number" && typeof b === "number") return a - b;
77
+ const serializedA = typeof a === "string" && typeof b === "string" ? a : serializeValue(a, refs);
78
+ const serializedB = typeof a === "string" && typeof b === "string" ? b : serializeValue(b, refs);
79
+ if (serializedA === serializedB) return 0;
80
+ return serializedA < serializedB ? -1 : 1;
81
+ }
82
+ //#endregion
83
+ //#region src/util/serialize/serializeString.ts
84
+ /**
85
+ * Serializes a string into a single-quoted string literal.
86
+ *
87
+ * The string is not escaped; the output is intended for hashing and
88
+ * change detection, not for parsing or re-evaluation.
89
+ *
90
+ * @param value - The string to serialize.
91
+ * @returns The serialized string.
92
+ *
93
+ * @example
94
+ * serializeString('abc'); // "'abc'"
95
+ */
96
+ function serializeString(value) {
97
+ return `'${value}'`;
98
+ }
99
+ //#endregion
100
+ //#region src/util/serialize/serializePlainObject.ts
101
+ /**
102
+ * Serializes the own enumerable string-keyed properties of an object
103
+ * into a `{'key':value}` string.
104
+ *
105
+ * Keys are sorted by code unit so that the output does not depend on
106
+ * property insertion order, and always quoted so that a key containing
107
+ * `:` or `,` cannot be confused with the surrounding structure. Symbol
108
+ * keys and non-enumerable properties are ignored.
109
+ *
110
+ * @param object - The object to serialize.
111
+ * @param refs - The circular reference context shared with the surrounding serialization.
112
+ * @returns The serialized string.
113
+ *
114
+ * @example
115
+ * serializePlainObject({ b: 2, a: 1 }, new Map()); // "{'a':1,'b':2}"
116
+ */
117
+ function serializePlainObject(object, refs) {
118
+ const keys = Object.keys(object).sort();
119
+ let result = "{";
120
+ for (let i = 0; i < keys.length; i++) {
121
+ const key = keys[i];
122
+ if (i > 0) result += ",";
123
+ result += `${serializeString(key)}:${serializeValue(object[key], refs)}`;
124
+ }
125
+ return result + "}";
126
+ }
127
+ //#endregion
128
+ //#region src/predicate/isArrayBuffer.ts
129
+ /**
130
+ * Checks if a given value is `ArrayBuffer`.
131
+ *
132
+ * This function can also serve as a type predicate in TypeScript, narrowing the type of the argument to `ArrayBuffer`.
133
+ *
134
+ * @param value The value to check if it is a `ArrayBuffer`.
135
+ * @returns Returns `true` if `value` is a `ArrayBuffer`, else `false`.
136
+ *
137
+ * @example
138
+ * const value1 = new ArrayBuffer();
139
+ * const value2 = new Array();
140
+ * const value3 = new Map();
141
+ *
142
+ * console.log(isArrayBuffer(value1)); // true
143
+ * console.log(isArrayBuffer(value2)); // false
144
+ * console.log(isArrayBuffer(value3)); // false
145
+ */
146
+ function isArrayBuffer(value) {
147
+ return value instanceof ArrayBuffer;
148
+ }
149
+ //#endregion
150
+ //#region src/predicate/isDate.ts
151
+ /**
152
+ * Checks if `value` is a Date object.
153
+ *
154
+ * @param value The value to check.
155
+ * @returns Returns `true` if `value` is a Date object, `false` otherwise.
156
+ *
157
+ * @example
158
+ * const value1 = new Date();
159
+ * const value2 = '2024-01-01';
160
+ *
161
+ * console.log(isDate(value1)); // true
162
+ * console.log(isDate(value2)); // false
163
+ */
164
+ function isDate(value) {
165
+ return value instanceof Date;
166
+ }
167
+ //#endregion
168
+ //#region src/predicate/isError.ts
169
+ /**
170
+ * Checks if `value` is an Error object.
171
+ *
172
+ * @param value The value to check.
173
+ * @returns Returns `true` if `value` is an Error object, `false` otherwise.
174
+ *
175
+ * @example
176
+ * ```typescript
177
+ * console.log(isError(new Error())); // true
178
+ * console.log(isError('Error')); // false
179
+ * console.log(isError({ name: 'Error', message: '' })); // false
180
+ * ```
181
+ */
182
+ function isError(value) {
183
+ return value instanceof Error;
184
+ }
185
+ //#endregion
186
+ //#region src/predicate/isMap.ts
187
+ /**
188
+ * Checks if a given value is `Map`.
189
+ *
190
+ * This function can also serve as a type predicate in TypeScript, narrowing the type of the argument to `Map`.
191
+ *
192
+ * @param value The value to check if it is a `Map`.
193
+ * @returns Returns `true` if `value` is a `Map`, else `false`.
194
+ *
195
+ * @example
196
+ * const value1 = new Map();
197
+ * const value2 = new Set();
198
+ * const value3 = new WeakMap();
199
+ *
200
+ * console.log(isMap(value1)); // true
201
+ * console.log(isMap(value2)); // false
202
+ * console.log(isMap(value3)); // false
203
+ */
204
+ function isMap(value) {
205
+ return value instanceof Map;
206
+ }
207
+ //#endregion
208
+ //#region src/predicate/isPlainObject.ts
209
+ /**
210
+ * Checks if a given value is a plain object.
211
+ *
212
+ * @param value - The value to check.
213
+ * @returns True if the value is a plain object, otherwise false.
214
+ *
215
+ * @example
216
+ * ```typescript
217
+ * // ✅👇 True
218
+ *
219
+ * isPlainObject({ }); // ✅
220
+ * isPlainObject({ key: 'value' }); // ✅
221
+ * isPlainObject({ key: new Date() }); // ✅
222
+ * isPlainObject(new Object()); // ✅
223
+ * isPlainObject(Object.create(null)); // ✅
224
+ * isPlainObject({ nested: { key: true} }); // ✅
225
+ * isPlainObject(new Proxy({}, {})); // ✅
226
+ * isPlainObject({ [Symbol('tag')]: 'A' }); // ✅
227
+ *
228
+ * // ✅👇 (cross-realms, node context, workers, ...)
229
+ * const runInNewContext = await import('node:vm').then(
230
+ * (mod) => mod.runInNewContext
231
+ * );
232
+ * isPlainObject(runInNewContext('({})')); // ✅
233
+ *
234
+ * // ❌👇 False
235
+ *
236
+ * class Test { };
237
+ * isPlainObject(new Test()) // ❌
238
+ * isPlainObject(10); // ❌
239
+ * isPlainObject(null); // ❌
240
+ * isPlainObject('hello'); // ❌
241
+ * isPlainObject([]); // ❌
242
+ * isPlainObject(new Date()); // ❌
243
+ * isPlainObject(new Uint8Array([1])); // ❌
244
+ * isPlainObject(Buffer.from('ABC')); // ❌
245
+ * isPlainObject(Promise.resolve({})); // ❌
246
+ * isPlainObject(Object.create({})); // ❌
247
+ * isPlainObject(new (class Cls {})); // ❌
248
+ * isPlainObject(globalThis); // ❌,
249
+ * ```
250
+ */
251
+ function isPlainObject(value) {
252
+ if (!value || typeof value !== "object") return false;
253
+ const proto = Object.getPrototypeOf(value);
254
+ if (!(proto === null || proto === Object.prototype || Object.getPrototypeOf(proto) === null)) return false;
255
+ return Object.prototype.toString.call(value) === "[object Object]";
256
+ }
257
+ //#endregion
258
+ //#region src/predicate/isRegExp.ts
259
+ /**
260
+ * Checks if `value` is a RegExp.
261
+ *
262
+ * @param value The value to check.
263
+ * @returns Returns `true` if `value` is a RegExp, `false` otherwise.
264
+ *
265
+ * @example
266
+ * const value1 = /abc/;
267
+ * const value2 = '/abc/';
268
+ *
269
+ * console.log(isRegExp(value1)); // true
270
+ * console.log(isRegExp(value2)); // false
271
+ */
272
+ function isRegExp(value) {
273
+ return value instanceof RegExp;
274
+ }
275
+ //#endregion
276
+ //#region src/predicate/isSet.ts
277
+ /**
278
+ * Checks if a given value is `Set`.
279
+ *
280
+ * This function can also serve as a type predicate in TypeScript, narrowing the type of the argument to `Set`.
281
+ *
282
+ * @param value The value to check if it is a `Set`.
283
+ * @returns Returns `true` if `value` is a `Set`, else `false`.
284
+ *
285
+ * @example
286
+ * const value1 = new Set();
287
+ * const value2 = new Map();
288
+ * const value3 = new WeakSet();
289
+ *
290
+ * console.log(isSet(value1)); // true
291
+ * console.log(isSet(value2)); // false
292
+ * console.log(isSet(value3)); // false
293
+ */
294
+ function isSet(value) {
295
+ return value instanceof Set;
296
+ }
297
+ //#endregion
298
+ //#region src/predicate/isTypedArray.ts
299
+ /**
300
+ * Checks if a value is a TypedArray.
301
+ * @param x The value to check.
302
+ * @returns Returns true if `x` is a TypedArray, false otherwise.
303
+ *
304
+ * @example
305
+ * const arr = new Uint8Array([1, 2, 3]);
306
+ * isTypedArray(arr); // true
307
+ *
308
+ * const regularArray = [1, 2, 3];
309
+ * isTypedArray(regularArray); // false
310
+ *
311
+ * const buffer = new ArrayBuffer(16);
312
+ * isTypedArray(buffer); // false
313
+ */
314
+ function isTypedArray(x) {
315
+ return ArrayBuffer.isView(x) && !(x instanceof DataView);
316
+ }
317
+ //#endregion
318
+ //#region src/util/serialize/serializeObject.ts
319
+ /**
320
+ * Serializes an object, handling circular references and repeated references.
321
+ *
322
+ * The first time an object is visited, it is registered as `#ref{n}` where `n`
323
+ * is the visit order; if the object is reached again while it is still being
324
+ * serialized, the back-reference is emitted instead. Once completed, the
325
+ * serialized string is memoized so that repeated references serialize
326
+ * in constant time.
327
+ *
328
+ * @param value - The object to serialize, or `null`.
329
+ * @param refs - The circular reference context shared across one serialization.
330
+ * @returns The serialized string.
331
+ * @throws {TypeError} If the object cannot be serialized.
332
+ */
333
+ function serializeObject(value, refs) {
334
+ if (value === null) return "null";
335
+ const cached = refs.get(value);
336
+ if (cached !== void 0) return cached;
337
+ refs.set(value, `#ref${refs.size}`);
338
+ const result = serializeObjectImpl(value, refs);
339
+ refs.set(value, result);
340
+ return result;
341
+ }
342
+ function serializeObjectImpl(value, refs) {
343
+ if (Array.isArray(value)) return serializeArray(value, refs);
344
+ if (isPlainObject(value)) return serializePlainObject(value, refs);
345
+ if (isDate(value)) return Number.isNaN(value.getTime()) ? "Date(null)" : `Date(${serializeString(value.toISOString())})`;
346
+ if (isRegExp(value)) return `RegExp(${value.toString()})`;
347
+ if (isSet(value)) return `Set${serializeArray(Array.from(value).sort((a, b) => compareValues(a, b, refs)), refs)}`;
348
+ if (isMap(value)) return serializeEntries("Map", value.entries(), refs);
349
+ if (isTypedArray(value)) {
350
+ const name = value[Symbol.toStringTag];
351
+ if (name === "BigInt64Array" || name === "BigUint64Array") return `${name}[${value.join("n,")}${value.length > 0 ? "n" : ""}]`;
352
+ return `${name}[${value.join(",")}]`;
353
+ }
354
+ if (isArrayBuffer(value)) return `ArrayBuffer[${new Uint8Array(value).join(",")}]`;
355
+ if (isError(value)) return `Error(${value.name}: ${serializeString(value.message)})`;
356
+ const tag = Object.prototype.toString.call(value).slice(8, -1);
357
+ if (tag === "Object") return serializeClassInstance(value, refs);
358
+ if (typeof value.entries === "function") return serializeEntries(tag, value.entries(), refs);
359
+ throw new TypeError(`Cannot serialize ${tag}`);
360
+ }
361
+ function serializeArray(array, refs) {
362
+ let result = "[";
363
+ for (let i = 0; i < array.length; i++) {
364
+ if (i > 0) result += ",";
365
+ result += serializeValue(array[i], refs);
366
+ }
367
+ return result + "]";
368
+ }
369
+ function serializeEntries(tag, entries, refs) {
370
+ const sortedEntries = Array.from(entries).sort((a, b) => compareValues(a[0], b[0], refs));
371
+ let result = `${tag}{`;
372
+ for (let i = 0; i < sortedEntries.length; i++) {
373
+ const [key, value] = sortedEntries[i];
374
+ if (i > 0) result += ",";
375
+ result += `${serializeValue(key, refs)}:${serializeValue(value, refs)}`;
376
+ }
377
+ return result + "}";
378
+ }
379
+ function serializeClassInstance(value, refs) {
380
+ const constructor = value.constructor;
381
+ const name = constructor === Object || constructor === void 0 ? "" : constructor.name;
382
+ if ("toJSON" in value && typeof value.toJSON === "function") {
383
+ const json = value.toJSON();
384
+ if (json !== null && typeof json === "object") return name + serializeObject(json, refs);
385
+ return `${name}(${serializeValue(json, refs)})`;
386
+ }
387
+ return name + serializePlainObject(value, refs);
388
+ }
389
+ //#endregion
390
+ //#region src/util/serialize/serializeSymbol.ts
391
+ /**
392
+ * Serializes a symbol into a string using its description.
393
+ *
394
+ * The description is quoted like any other string, so a symbol without a
395
+ * description (`Symbol()`) is distinguishable from one with an empty
396
+ * description (`Symbol('')`). Note that two different symbols with the same
397
+ * description still serialize to the same string, since a symbol's identity
398
+ * cannot be captured in a string.
399
+ *
400
+ * @param value - The symbol to serialize.
401
+ * @returns The serialized string.
402
+ *
403
+ * @example
404
+ * serializeSymbol(Symbol('test')); // "Symbol('test')"
405
+ * serializeSymbol(Symbol()); // "Symbol()"
406
+ */
407
+ function serializeSymbol(value) {
408
+ return value.description === void 0 ? "Symbol()" : `Symbol(${serializeString(value.description)})`;
409
+ }
410
+ //#endregion
411
+ //#region src/util/serialize/serialize.ts
412
+ /**
413
+ * Serializes any value into a stable string.
414
+ *
415
+ * Two values with the same structure always serialize to the same string,
416
+ * regardless of key insertion order, so the output is suitable for hashing,
417
+ * cache keys, and change detection. It is not designed for security purposes;
418
+ * intentional collisions can be crafted from user input.
419
+ *
420
+ * Plain object keys, `Map` keys, and `Set` values are sorted, so the output
421
+ * does not depend on insertion order. String keys are always quoted, so a
422
+ * string key never collides with a key of another type. Circular references
423
+ * are serialized as `#ref{n}` back-references, where `n` is the order in
424
+ * which the object was first visited.
425
+ *
426
+ * Objects that cannot be serialized meaningfully, such as `Promise`, `WeakMap`,
427
+ * or `Blob`, throw a `TypeError`.
428
+ *
429
+ * @param value - The value to serialize.
430
+ * @returns The serialized string.
431
+ * @throws {TypeError} If the value contains an object that cannot be serialized.
432
+ *
433
+ * @example
434
+ * serialize({ b: 2, a: 1 }); // "{'a':1,'b':2}"
435
+ * serialize([1, 2n, 'a', { k: 1 }]); // "[1,2n,'a',{'k':1}]"
436
+ * serialize(new Set([3, 1, 2])); // "Set[1,2,3]"
437
+ * serialize(new Date(0)); // "Date('1970-01-01T00:00:00.000Z')"
438
+ *
439
+ * const obj = {};
440
+ * obj.self = obj;
441
+ * serialize(obj); // "{'self':#ref0}"
442
+ */
443
+ function serialize(value) {
444
+ return serializeValue(value, /* @__PURE__ */ new Map());
445
+ }
446
+ /**
447
+ * Serializes a value with a shared circular reference context.
448
+ *
449
+ * @param value - The value to serialize.
450
+ * @param refs - Objects that are being serialized or have been serialized,
451
+ * mapped to their back-reference placeholder or completed serialization.
452
+ * @returns The serialized string.
453
+ */
454
+ function serializeValue(value, refs) {
455
+ switch (typeof value) {
456
+ case "string": return serializeString(value);
457
+ case "number": return serializeNumber(value);
458
+ case "bigint": return serializeBigInt(value);
459
+ case "symbol": return serializeSymbol(value);
460
+ case "function": return serializeFunction(value);
461
+ case "object": return serializeObject(value, refs);
462
+ case "boolean": return String(value);
463
+ case "undefined": return "undefined";
464
+ }
465
+ }
466
+ //#endregion
467
+ //#region src/util/hash/node.ts
468
+ /**
469
+ * Hashes any value into a stable 43-character string.
470
+ *
471
+ * The value is serialized with `serialize`, so two values with the same
472
+ * structure always hash to the same string regardless of key insertion
473
+ * order, and then digested with SHA-256 and encoded in Base64URL format.
474
+ *
475
+ * The hash is stable across platforms, but it is not designed for security
476
+ * purposes; intentional collisions can be crafted from user input.
477
+ *
478
+ * This entry uses the native `node:crypto` implementation and requires
479
+ * Node.js 20.12 or later; in browsers, a pure JavaScript implementation
480
+ * with identical output is used instead.
481
+ *
482
+ * @param value - The value to hash.
483
+ * @returns The Base64URL-encoded SHA-256 hash of the serialized value.
484
+ * @throws {TypeError} If the value contains an object that cannot be serialized.
485
+ *
486
+ * @example
487
+ * hash({ b: 2, a: 1 }) === hash({ a: 1, b: 2 }); // true
488
+ * hash([1, 2, 3]); // "phXuruId5Red4IDejDBSyNqQEThAa6ccOMAyhF99VPQ" (43 characters)
489
+ */
490
+ function hash(value) {
491
+ return (0, node_crypto.hash)("sha256", serialize(value), "base64url");
492
+ }
493
+ //#endregion
494
+ exports.hash = hash;