@ibodr/utils 0.0.1

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.
@@ -0,0 +1,3098 @@
1
+ export { default as isEqual } from 'lodash.isequal';
2
+ export { default as isEqualWith } from 'lodash.isequalwith';
3
+ export { default as throttle } from 'lodash.throttle';
4
+ export { default as uniq } from 'lodash.uniq';
5
+
6
+ /**
7
+ * Rotate the contents of an array by a specified offset.
8
+ *
9
+ * Creates a new array with elements shifted to the left by the specified number of positions.
10
+ * Both positive and negative offsets result in left shifts (elements move left, with elements
11
+ * from the front wrapping to the back).
12
+ *
13
+ * @param arr - The array to rotate
14
+ * @param offset - The number of positions to shift left (both positive and negative values shift left)
15
+ * @returns A new array with elements shifted left by the specified offset
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * rotateArray([1, 2, 3, 4], 1) // [2, 3, 4, 1]
20
+ * rotateArray([1, 2, 3, 4], -1) // [2, 3, 4, 1]
21
+ * rotateArray(['a', 'b', 'c'], 2) // ['c', 'a', 'b']
22
+ * ```
23
+ * @public
24
+ */
25
+ declare function rotateArray<T>(arr: T[], offset: number): T[];
26
+ /**
27
+ * Remove duplicate items from an array.
28
+ *
29
+ * Creates a new array with duplicate items removed. Uses strict equality by default,
30
+ * or a custom equality function if provided. Order of first occurrence is preserved.
31
+ *
32
+ * @param input - The array to deduplicate
33
+ * @param equals - Optional custom equality function to compare items (defaults to strict equality)
34
+ * @returns A new array with duplicate items removed
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * dedupe([1, 2, 2, 3, 1]) // [1, 2, 3]
39
+ * dedupe(['a', 'b', 'a', 'c']) // ['a', 'b', 'c']
40
+ *
41
+ * // With custom equality function
42
+ * const objects = [{id: 1}, {id: 2}, {id: 1}]
43
+ * dedupe(objects, (a, b) => a.id === b.id) // [{id: 1}, {id: 2}]
44
+ * ```
45
+ * @public
46
+ */
47
+ declare function dedupe<T>(input: T[], equals?: (a: any, b: any) => boolean): T[];
48
+ /**
49
+ * Remove null and undefined values from an array.
50
+ *
51
+ * Creates a new array with all null and undefined values filtered out.
52
+ * The resulting array has a refined type that excludes null and undefined.
53
+ *
54
+ * @param arr - The array to compact
55
+ * @returns A new array with null and undefined values removed
56
+ *
57
+ * @example
58
+ * ```ts
59
+ * compact([1, null, 2, undefined, 3]) // [1, 2, 3]
60
+ * compact(['a', null, 'b', undefined]) // ['a', 'b']
61
+ * ```
62
+ * @internal
63
+ */
64
+ declare function compact<T>(arr: T[]): NonNullable<T>[];
65
+ /**
66
+ * Get the last element of an array.
67
+ *
68
+ * Returns the last element of an array, or undefined if the array is empty.
69
+ * Works with readonly arrays and preserves the element type.
70
+ *
71
+ * @param arr - The array to get the last element from
72
+ * @returns The last element of the array, or undefined if the array is empty
73
+ *
74
+ * @example
75
+ * ```ts
76
+ * last([1, 2, 3]) // 3
77
+ * last(['a', 'b', 'c']) // 'c'
78
+ * last([]) // undefined
79
+ * ```
80
+ * @internal
81
+ */
82
+ declare function last<T>(arr: readonly T[]): T | undefined;
83
+ /**
84
+ * Find the item in an array with the minimum value according to a function.
85
+ *
86
+ * Finds the array item that produces the smallest value when passed through
87
+ * the provided function. Returns undefined for empty arrays.
88
+ *
89
+ * @param arr - The array to search
90
+ * @param fn - Function to compute the comparison value for each item
91
+ * @returns The item with the minimum value, or undefined if the array is empty
92
+ *
93
+ * @example
94
+ * ```ts
95
+ * const people = [{name: 'Alice', age: 30}, {name: 'Bob', age: 25}]
96
+ * minBy(people, p => p.age) // {name: 'Bob', age: 25}
97
+ *
98
+ * minBy([3, 1, 4, 1, 5], x => x) // 1
99
+ * minBy([], x => x) // undefined
100
+ * ```
101
+ * @internal
102
+ */
103
+ declare function minBy<T>(arr: readonly T[], fn: (item: T) => number): T | undefined;
104
+ /**
105
+ * Find the item in an array with the maximum value according to a function.
106
+ *
107
+ * Finds the array item that produces the largest value when passed through
108
+ * the provided function. Returns undefined for empty arrays.
109
+ *
110
+ * @param arr - The array to search
111
+ * @param fn - Function to compute the comparison value for each item
112
+ * @returns The item with the maximum value, or undefined if the array is empty
113
+ *
114
+ * @example
115
+ * ```ts
116
+ * const people = [{name: 'Alice', age: 30}, {name: 'Bob', age: 25}]
117
+ * maxBy(people, p => p.age) // {name: 'Alice', age: 30}
118
+ *
119
+ * maxBy([3, 1, 4, 1, 5], x => x) // 5
120
+ * maxBy([], x => x) // undefined
121
+ * ```
122
+ * @internal
123
+ */
124
+ declare function maxBy<T>(arr: readonly T[], fn: (item: T) => number): T | undefined;
125
+ /**
126
+ * Split an array into two arrays based on a predicate function.
127
+ *
128
+ * Partitions an array into two arrays: one containing items that satisfy
129
+ * the predicate, and another containing items that do not. The original array order is preserved.
130
+ *
131
+ * @param arr - The array to partition
132
+ * @param predicate - The predicate function to test each item
133
+ * @returns A tuple of two arrays: [satisfying items, non-satisfying items]
134
+ *
135
+ * @example
136
+ * ```ts
137
+ * const [evens, odds] = partition([1, 2, 3, 4, 5], x => x % 2 === 0)
138
+ * // evens: [2, 4], odds: [1, 3, 5]
139
+ *
140
+ * const [adults, minors] = partition(
141
+ * [{name: 'Alice', age: 30}, {name: 'Bob', age: 17}],
142
+ * person => person.age >= 18
143
+ * )
144
+ * // adults: [{name: 'Alice', age: 30}], minors: [{name: 'Bob', age: 17}]
145
+ * ```
146
+ * @internal
147
+ */
148
+ declare function partition<T>(arr: T[], predicate: (item: T) => boolean): [T[], T[]];
149
+ /**
150
+ * Check if two arrays are shallow equal.
151
+ *
152
+ * Compares two arrays for shallow equality by checking if they have the same length
153
+ * and the same elements at each index using Object.is comparison. Returns true if arrays are
154
+ * the same reference, have different lengths, or any elements differ.
155
+ *
156
+ * @param arr1 - First array to compare
157
+ * @param arr2 - Second array to compare
158
+ * @returns True if arrays are shallow equal, false otherwise
159
+ *
160
+ * @example
161
+ * ```ts
162
+ * areArraysShallowEqual([1, 2, 3], [1, 2, 3]) // true
163
+ * areArraysShallowEqual([1, 2, 3], [1, 2, 4]) // false
164
+ * areArraysShallowEqual(['a', 'b'], ['a', 'b']) // true
165
+ * areArraysShallowEqual([1, 2], [1, 2, 3]) // false
166
+ *
167
+ * const obj = {x: 1}
168
+ * areArraysShallowEqual([obj], [obj]) // true (same reference)
169
+ * areArraysShallowEqual([{x: 1}], [{x: 1}]) // false (different objects)
170
+ * ```
171
+ * @internal
172
+ */
173
+ declare function areArraysShallowEqual<T>(arr1: readonly T[], arr2: readonly T[]): boolean;
174
+ /**
175
+ * Merge custom entries with defaults, replacing defaults that have matching keys.
176
+ *
177
+ * Combines two arrays by keeping all custom entries and only the default entries
178
+ * that don't have a matching key in the custom entries. Custom entries always override defaults.
179
+ * The result contains remaining defaults first, followed by all custom entries.
180
+ *
181
+ * @param key - The property name to use as the unique identifier
182
+ * @param customEntries - Array of custom entries that will override defaults
183
+ * @param defaults - Array of default entries
184
+ * @returns A new array with defaults filtered out where custom entries exist, plus all custom entries
185
+ *
186
+ * @example
187
+ * ```ts
188
+ * const defaults = [{type: 'text', value: 'default'}, {type: 'number', value: 0}]
189
+ * const custom = [{type: 'text', value: 'custom'}]
190
+ *
191
+ * mergeArraysAndReplaceDefaults('type', custom, defaults)
192
+ * // Result: [{type: 'number', value: 0}, {type: 'text', value: 'custom'}]
193
+ *
194
+ * const tools = [{id: 'select', name: 'Select'}, {id: 'draw', name: 'Draw'}]
195
+ * const customTools = [{id: 'select', name: 'Custom Select'}]
196
+ *
197
+ * mergeArraysAndReplaceDefaults('id', customTools, tools)
198
+ * // Result: [{id: 'draw', name: 'Draw'}, {id: 'select', name: 'Custom Select'}]
199
+ * ```
200
+ * @internal
201
+ */
202
+ declare function mergeArraysAndReplaceDefaults<const Key extends string, T extends {
203
+ [K in Key]: string;
204
+ }>(key: Key, customEntries: readonly T[], defaults: readonly T[]): T[];
205
+
206
+ /*!
207
+ * MIT License: https://github.com/NoHomey/bind-decorator/blob/master/License
208
+ * Copyright (c) 2016 Ivo Stratev
209
+ */
210
+ /**
211
+ * Decorator that binds a method to its class instance (legacy stage-2 TypeScript decorators).
212
+ * When applied to a class method, ensures `this` always refers to the class instance,
213
+ * even when the method is called as a callback or event handler.
214
+ *
215
+ * @param target - The prototype of the class being decorated
216
+ * @param propertyKey - The name of the method being decorated
217
+ * @param descriptor - The property descriptor for the method being decorated
218
+ * @returns The modified property descriptor with bound method access
219
+ * @example
220
+ * ```typescript
221
+ * class MyClass {
222
+ * name = 'example';
223
+ *
224
+ * @bind
225
+ * getName() {
226
+ * return this.name;
227
+ * }
228
+ * }
229
+ *
230
+ * const instance = new MyClass();
231
+ * const callback = instance.getName;
232
+ * console.log(callback()); // 'example' (this is properly bound)
233
+ * ```
234
+ * @public
235
+ */
236
+ declare function bind<T extends (...args: any[]) => any>(target: object, propertyKey: string, descriptor: TypedPropertyDescriptor<T>): TypedPropertyDescriptor<T>;
237
+ /**
238
+ * Decorator that binds a method to its class instance (TC39 decorators standard).
239
+ * When applied to a class method, ensures `this` always refers to the class instance,
240
+ * even when the method is called as a callback or event handler.
241
+ *
242
+ * @param originalMethod - The original method being decorated
243
+ * @param context - The decorator context containing metadata about the method
244
+ * @example
245
+ * ```typescript
246
+ * class EventHandler {
247
+ * message = 'Hello World';
248
+ *
249
+ * @bind
250
+ * handleClick() {
251
+ * console.log(this.message);
252
+ * }
253
+ * }
254
+ *
255
+ * const handler = new EventHandler();
256
+ * document.addEventListener('click', handler.handleClick); // 'this' is properly bound
257
+ * ```
258
+ * @public
259
+ */
260
+ declare function bind<This extends object, T extends (...args: any[]) => any>(originalMethod: T, context: ClassMethodDecoratorContext<This, T>): void;
261
+
262
+ /**
263
+ * A lightweight cache implementation using WeakMap for storing key-value pairs.
264
+ *
265
+ * A micro cache that stores computed values associated with object keys.
266
+ * Uses WeakMap internally, which means keys can be garbage collected when no other
267
+ * references exist, and only object keys are supported. Provides lazy computation
268
+ * with memoization.
269
+ *
270
+ * @example
271
+ * ```ts
272
+ * const cache = new WeakCache<User, string>()
273
+ * const user = { id: 1, name: 'Alice' }
274
+ *
275
+ * // Get cached value, computing it if not present
276
+ * const displayName = cache.get(user, (u) => `${u.name} (#${u.id})`)
277
+ * // Returns 'Alice (#1)'
278
+ *
279
+ * // Subsequent calls return cached value
280
+ * const sameName = cache.get(user, (u) => `${u.name} (#${u.id})`)
281
+ * // Returns 'Alice (#1)' without recomputing
282
+ * ```
283
+ * @public
284
+ */
285
+ declare class WeakCache<K extends object, V> {
286
+ /**
287
+ * The internal WeakMap storage for cached key-value pairs.
288
+ *
289
+ * @public
290
+ */
291
+ items: WeakMap<K, V>;
292
+ /**
293
+ * Get the cached value for a given key, computing it if not already cached.
294
+ *
295
+ * Retrieves the cached value associated with the given key. If no cached
296
+ * value exists, calls the provided callback function to compute the value, stores it
297
+ * in the cache, and returns it. Subsequent calls with the same key will return the
298
+ * cached value without recomputation.
299
+ *
300
+ * @param item - The object key to retrieve the cached value for
301
+ * @param cb - Callback function that computes the value when not already cached
302
+ * @returns The cached value if it exists, otherwise the newly computed value from the callback
303
+ *
304
+ * @example
305
+ * ```ts
306
+ * const cache = new WeakCache<HTMLElement, DOMRect>()
307
+ * const element = document.getElementById('my-element')!
308
+ *
309
+ * // First call computes and caches the bounding rect
310
+ * const rect1 = cache.get(element, (el) => el.getBoundingClientRect())
311
+ *
312
+ * // Second call returns cached value
313
+ * const rect2 = cache.get(element, (el) => el.getBoundingClientRect())
314
+ * // rect1 and rect2 are the same object
315
+ * ```
316
+ */
317
+ get<P extends K>(item: P, cb: (item: P) => V): NonNullable<V>;
318
+ }
319
+
320
+ /**
321
+ * Represents a successful result containing a value.
322
+ *
323
+ * Interface for the success case of a Result type, containing the computed value.
324
+ * Used in conjunction with ErrorResult to create a discriminated union for error handling.
325
+ *
326
+ * @example
327
+ * ```ts
328
+ * const success: OkResult<string> = { ok: true, value: 'Hello World' }
329
+ * if (success.ok) {
330
+ * console.log(success.value) // 'Hello World'
331
+ * }
332
+ * ```
333
+ * @public
334
+ */
335
+ interface OkResult<T> {
336
+ readonly ok: true;
337
+ readonly value: T;
338
+ }
339
+ /**
340
+ * Represents a failed result containing an error.
341
+ *
342
+ * Interface for the error case of a Result type, containing the error information.
343
+ * Used in conjunction with OkResult to create a discriminated union for error handling.
344
+ *
345
+ * @example
346
+ * ```ts
347
+ * const failure: ErrorResult<string> = { ok: false, error: 'Something went wrong' }
348
+ * if (!failure.ok) {
349
+ * console.error(failure.error) // 'Something went wrong'
350
+ * }
351
+ * ```
352
+ * @public
353
+ */
354
+ interface ErrorResult<E> {
355
+ readonly ok: false;
356
+ readonly error: E;
357
+ }
358
+ /**
359
+ * A discriminated union type for handling success and error cases.
360
+ *
361
+ * Represents either a successful result with a value or a failed result with an error.
362
+ * This pattern provides type-safe error handling without throwing exceptions. The 'ok' property
363
+ * serves as the discriminant for type narrowing.
364
+ *
365
+ * @example
366
+ * ```ts
367
+ * function divide(a: number, b: number): Result<number, string> {
368
+ * if (b === 0) {
369
+ * return Result.err('Division by zero')
370
+ * }
371
+ * return Result.ok(a / b)
372
+ * }
373
+ *
374
+ * const result = divide(10, 2)
375
+ * if (result.ok) {
376
+ * console.log(`Result: ${result.value}`) // Result: 5
377
+ * } else {
378
+ * console.error(`Error: ${result.error}`)
379
+ * }
380
+ * ```
381
+ * @public
382
+ */
383
+ type Result<T, E> = OkResult<T> | ErrorResult<E>;
384
+ /**
385
+ * Utility object for creating Result instances.
386
+ *
387
+ * Provides factory methods for creating OkResult and ErrorResult instances.
388
+ * This is the preferred way to construct Result values for consistent structure.
389
+ *
390
+ * @example
391
+ * ```ts
392
+ * // Create success result
393
+ * const success = Result.ok(42)
394
+ * // success: OkResult<number> = { ok: true, value: 42 }
395
+ *
396
+ * // Create error result
397
+ * const failure = Result.err('Invalid input')
398
+ * // failure: ErrorResult<string> = { ok: false, error: 'Invalid input' }
399
+ * ```
400
+ * @public
401
+ */
402
+ declare const Result: {
403
+ /**
404
+ * Create a successful result containing a value.
405
+ *
406
+ * @param value - The success value to wrap
407
+ * @returns An OkResult containing the value
408
+ */
409
+ ok<T>(value: T): OkResult<T>;
410
+ /**
411
+ * Create a failed result containing an error.
412
+ *
413
+ * @param error - The error value to wrap
414
+ * @returns An ErrorResult containing the error
415
+ */
416
+ err<E>(error: E): ErrorResult<E>;
417
+ /**
418
+ * Create a successful result containing an array of values.
419
+ *
420
+ * If any of the results are errors, the returned result will be an error containing the first error.
421
+ *
422
+ * @param results - The array of results to wrap
423
+ * @returns An OkResult containing the array of values
424
+ */
425
+ all<T>(results: Result<T, any>[]): Result<T[], any>;
426
+ };
427
+ /**
428
+ * Throws an error for unhandled switch cases in exhaustive switch statements.
429
+ *
430
+ * Utility function to ensure exhaustive handling of discriminated unions in switch
431
+ * statements. When called, it indicates a programming error where a case was not handled.
432
+ * The TypeScript 'never' type ensures this function is only reachable if all cases aren't covered.
433
+ *
434
+ * @param value - The unhandled value (typed as 'never' for exhaustiveness checking)
435
+ * @param property - Optional property name to extract from the value for better error messages
436
+ * @returns Never returns (always throws)
437
+ *
438
+ * @example
439
+ * ```ts
440
+ * type Shape = 'circle' | 'square' | 'triangle'
441
+ *
442
+ * function getArea(shape: Shape): number {
443
+ * switch (shape) {
444
+ * case 'circle': return Math.PI * 5 * 5
445
+ * case 'square': return 10 * 10
446
+ * case 'triangle': return 0.5 * 10 * 8
447
+ * default: return exhaustiveSwitchError(shape)
448
+ * }
449
+ * }
450
+ * ```
451
+ * @internal
452
+ */
453
+ declare function exhaustiveSwitchError(value: never, property?: string): never;
454
+ /**
455
+ * Assert that a value is truthy, throwing an error if it's not.
456
+ *
457
+ * TypeScript assertion function that throws an error if the provided value is falsy.
458
+ * After this function executes successfully, TypeScript narrows the type to exclude falsy values.
459
+ * Stack trace is omitted from the error for cleaner debugging.
460
+ *
461
+ * @param value - The value to assert as truthy
462
+ * @param message - Optional custom error message
463
+ *
464
+ * @example
465
+ * ```ts
466
+ * const user = getUser() // User | null
467
+ * assert(user, 'User must be logged in')
468
+ * // TypeScript now knows user is non-null
469
+ * console.log(user.name) // Safe to access properties
470
+ * ```
471
+ * @internal
472
+ */
473
+ declare const assert: (value: unknown, message?: string) => asserts value;
474
+ /**
475
+ * Assert that a value is not null or undefined.
476
+ *
477
+ * Throws an error if the value is null or undefined, otherwise returns the value
478
+ * with a refined type that excludes null and undefined. Stack trace is omitted for cleaner debugging.
479
+ *
480
+ * @param value - The value to check for null/undefined
481
+ * @param message - Optional custom error message
482
+ * @returns The value with null and undefined excluded from the type
483
+ *
484
+ * @example
485
+ * ```ts
486
+ * const element = document.getElementById('my-id') // HTMLElement | null
487
+ * const safeElement = assertExists(element, 'Element not found')
488
+ * // TypeScript now knows safeElement is HTMLElement (not null)
489
+ * safeElement.addEventListener('click', handler) // Safe to call methods
490
+ * ```
491
+ * @internal
492
+ */
493
+ declare const assertExists: <T>(value: T, message?: string | undefined) => NonNullable<T>;
494
+ /**
495
+ * Create a Promise with externally accessible resolve and reject functions.
496
+ *
497
+ * Creates a Promise along with its resolve and reject functions exposed as
498
+ * properties on the returned object. This allows external code to control when the
499
+ * Promise resolves or rejects, useful for coordination between async operations.
500
+ *
501
+ * @returns A Promise object with additional resolve and reject methods
502
+ *
503
+ * @example
504
+ * ```ts
505
+ * const deferred = promiseWithResolve<string>()
506
+ *
507
+ * // Set up the promise consumer
508
+ * deferred.then(value => console.log(`Resolved: ${value}`))
509
+ * deferred.catch(error => console.error(`Rejected: ${error}`))
510
+ *
511
+ * // Later, resolve from external code
512
+ * setTimeout(() => {
513
+ * deferred.resolve('Hello World')
514
+ * }, 1000)
515
+ * ```
516
+ * @internal
517
+ */
518
+ declare function promiseWithResolve<T>(): Promise<T> & {
519
+ resolve(value: T): void;
520
+ reject(reason?: any): void;
521
+ };
522
+ /**
523
+ * Create a Promise that resolves after a specified delay.
524
+ *
525
+ * Utility function for introducing delays in async code. Returns a Promise
526
+ * that resolves with undefined after the specified number of milliseconds. Useful for
527
+ * implementing timeouts, rate limiting, or adding delays in testing scenarios.
528
+ *
529
+ * @param ms - The delay in milliseconds
530
+ * @returns A Promise that resolves after the specified delay
531
+ *
532
+ * @example
533
+ * ```ts
534
+ * async function delayedOperation() {
535
+ * console.log('Starting...')
536
+ * await sleep(1000) // Wait 1 second
537
+ * console.log('Done!')
538
+ * }
539
+ *
540
+ * // Can also be used with .then()
541
+ * sleep(500).then(() => {
542
+ * console.log('Half second has passed')
543
+ * })
544
+ * ```
545
+ * @internal
546
+ */
547
+ declare function sleep(ms: number): Promise<void>;
548
+
549
+ /**
550
+ * Makes all properties in a type and all nested properties optional recursively.
551
+ * This is useful for creating partial update objects where you only want to specify
552
+ * some deeply nested properties while leaving others unchanged.
553
+ *
554
+ * @example
555
+ * ```ts
556
+ * interface User {
557
+ * name: string
558
+ * settings: {
559
+ * theme: string
560
+ * notifications: {
561
+ * email: boolean
562
+ * push: boolean
563
+ * }
564
+ * }
565
+ * }
566
+ *
567
+ * type PartialUser = RecursivePartial<User>
568
+ * // Result: {
569
+ * // name?: string
570
+ * // settings?: {
571
+ * // theme?: string
572
+ * // notifications?: {
573
+ * // email?: boolean
574
+ * // push?: boolean
575
+ * // }
576
+ * // }
577
+ * // }
578
+ *
579
+ * const update: PartialUser = {
580
+ * settings: {
581
+ * notifications: {
582
+ * email: false
583
+ * }
584
+ * }
585
+ * }
586
+ * ```
587
+ *
588
+ * @public
589
+ */
590
+ type RecursivePartial<T> = {
591
+ [P in keyof T]?: RecursivePartial<T[P]>;
592
+ };
593
+ /**
594
+ * Expands a type definition to show its full structure in IDE tooltips and error messages.
595
+ * This utility type forces TypeScript to resolve and display the complete type structure
596
+ * instead of showing complex conditional types or intersections as-is.
597
+ *
598
+ * @example
599
+ * ```ts
600
+ * type User = { name: string }
601
+ * type WithId = { id: string }
602
+ * type UserWithId = User & WithId
603
+ *
604
+ * // Without Expand, IDE shows: User & WithId
605
+ * // With Expand, IDE shows: { name: string; id: string }
606
+ * type ExpandedUserWithId = Expand<UserWithId>
607
+ *
608
+ * // Useful for complex intersections
609
+ * type ComplexType = Expand<BaseType & Mixin1 & Mixin2>
610
+ * ```
611
+ *
612
+ * @public
613
+ */
614
+ type Expand<T> = T extends infer O ? {
615
+ [K in keyof O]: O[K];
616
+ } : never;
617
+ /**
618
+ * A value that may be returned synchronously or as a `Promise` / `PromiseLike`.
619
+ * Use with `await` or `Promise.resolve(...)` to normalize to a single `Promise`.
620
+ *
621
+ * @public
622
+ */
623
+ type Awaitable<T> = T | PromiseLike<T>;
624
+ /**
625
+ * Makes specified keys in a type required while keeping all other properties as-is.
626
+ * This is useful when you need to ensure certain optional properties are provided
627
+ * in specific contexts without affecting the entire type structure.
628
+ *
629
+ * @example
630
+ * ```ts
631
+ * interface Shape {
632
+ * id: string
633
+ * x?: number
634
+ * y?: number
635
+ * visible?: boolean
636
+ * }
637
+ *
638
+ * // Make position properties required
639
+ * type PositionedShape = Required<Shape, 'x' | 'y'>
640
+ * // Result: {
641
+ * // id: string
642
+ * // x: number // now required
643
+ * // y: number // now required
644
+ * // visible?: boolean
645
+ * // }
646
+ *
647
+ * const shape: PositionedShape = {
648
+ * id: 'rect1',
649
+ * x: 10, // must provide
650
+ * y: 20, // must provide
651
+ * // visible is still optional
652
+ * }
653
+ * ```
654
+ *
655
+ * @internal
656
+ */
657
+ type Required<T, K extends keyof T> = Expand<Omit<T, K> & {
658
+ [P in K]-?: T[P];
659
+ }>;
660
+ /**
661
+ * Automatically makes properties optional if their type includes `undefined`.
662
+ * This transforms properties like `prop: string | undefined` to `prop?: string | undefined`,
663
+ * making the API more ergonomic by not requiring explicit undefined assignments.
664
+ *
665
+ * @example
666
+ * ```ts
667
+ * interface RawConfig {
668
+ * name: string
669
+ * theme: string | undefined
670
+ * debug: boolean | undefined
671
+ * version: number
672
+ * }
673
+ *
674
+ * type Config = MakeUndefinedOptional<RawConfig>
675
+ * // Result: {
676
+ * // name: string
677
+ * // theme?: string | undefined // now optional
678
+ * // debug?: boolean | undefined // now optional
679
+ * // version: number
680
+ * // }
681
+ *
682
+ * const config: Config = {
683
+ * name: 'MyApp',
684
+ * version: 1
685
+ * // theme and debug can be omitted instead of explicitly set to undefined
686
+ * }
687
+ * ```
688
+ *
689
+ * @public
690
+ */
691
+ type MakeUndefinedOptional<T extends object> = Expand<{
692
+ [P in {
693
+ [K in keyof T]: undefined extends T[K] ? never : K;
694
+ }[keyof T]]: T[P];
695
+ } & {
696
+ [P in {
697
+ [K in keyof T]: undefined extends T[K] ? K : never;
698
+ }[keyof T]]?: T[P];
699
+ }>;
700
+
701
+ /**
702
+ * Create a debounced version of a function that delays execution until after a specified wait time.
703
+ *
704
+ * Debouncing ensures that a function is only executed once after a specified delay,
705
+ * even if called multiple times in rapid succession. Each new call resets the timer. The debounced
706
+ * function returns a Promise that resolves with the result of the original function. Includes a
707
+ * cancel method to prevent execution if needed.
708
+ *
709
+ * @param callback - The function to debounce (can be sync or async)
710
+ * @param wait - The delay in milliseconds before executing the function
711
+ * @returns A debounced function that returns a Promise and includes a cancel method
712
+ *
713
+ * @example
714
+ * ```ts
715
+ * // Debounce a search function
716
+ * const searchAPI = (query: string) => fetch(`/search?q=${query}`)
717
+ * const debouncedSearch = debounce(searchAPI, 300)
718
+ *
719
+ * // Multiple rapid calls will only execute the last one after 300ms
720
+ * debouncedSearch('react').then(result => console.log(result))
721
+ * debouncedSearch('react hooks') // This cancels the previous call
722
+ * debouncedSearch('react typescript') // Only this will execute
723
+ *
724
+ * // Cancel pending execution
725
+ * debouncedSearch.cancel()
726
+ *
727
+ * // With async/await
728
+ * const saveData = debounce(async (data: any) => {
729
+ * return await api.save(data)
730
+ * }, 1000)
731
+ *
732
+ * const result = await saveData({name: 'John'})
733
+ * ```
734
+ *
735
+ * @public
736
+ * @see source - https://gist.github.com/ca0v/73a31f57b397606c9813472f7493a940
737
+ */
738
+ declare function debounce<T extends unknown[], U>(callback: (...args: T) => Awaitable<U>, wait: number): {
739
+ (...args: T): Promise<U>;
740
+ cancel(): void;
741
+ };
742
+
743
+ /** @public */
744
+ interface ErrorAnnotations {
745
+ tags: Record<string, number | string | boolean | bigint | symbol | null | undefined>;
746
+ extras: Record<string, unknown>;
747
+ }
748
+ /**
749
+ * Annotate an error with tags and additional data. Annotations won't overwrite existing ones.
750
+ * Retrieve them with `getErrorAnnotations`.
751
+ *
752
+ * @param error - The error object to annotate
753
+ * @param annotations - Partial annotations to add (tags and/or extras)
754
+ * @returns void
755
+ * @example
756
+ * ```ts
757
+ * const error = new Error('Something went wrong')
758
+ * annotateError(error, {
759
+ * tags: { userId: '123', operation: 'save' },
760
+ * extras: { timestamp: Date.now() }
761
+ * })
762
+ * ```
763
+ *
764
+ * @internal
765
+ */
766
+ declare function annotateError(error: unknown, annotations: Partial<ErrorAnnotations>): void;
767
+ /**
768
+ * Retrieve annotations that have been added to an error object.
769
+ *
770
+ * @param error - The error object to get annotations from
771
+ * @returns The error annotations (tags and extras) or empty objects if none exist
772
+ * @example
773
+ * ```ts
774
+ * const error = new Error('Something went wrong')
775
+ * annotateError(error, { tags: { userId: '123' } })
776
+ * const annotations = getErrorAnnotations(error)
777
+ * console.log(annotations.tags.userId) // '123'
778
+ * ```
779
+ *
780
+ * @internal
781
+ */
782
+ declare function getErrorAnnotations(error: Error): ErrorAnnotations;
783
+
784
+ /**
785
+ * A queue that executes tasks sequentially with optional delay between tasks.
786
+ *
787
+ * ExecutionQueue ensures that tasks are executed one at a time in the order they were added,
788
+ * with an optional timeout delay between each task execution. This is useful for rate limiting,
789
+ * preventing race conditions, or controlling the flow of asynchronous operations.
790
+ *
791
+ * @example
792
+ * ```ts
793
+ * // Create a queue with 100ms delay between tasks
794
+ * const queue = new ExecutionQueue(100)
795
+ *
796
+ * // Add tasks to the queue
797
+ * const result1 = await queue.push(() => fetch('/api/data'))
798
+ * const result2 = await queue.push(async () => {
799
+ * const data = await processData()
800
+ * return data
801
+ * })
802
+ *
803
+ * // Check if queue is empty
804
+ * if (queue.isEmpty()) {
805
+ * console.log('All tasks completed')
806
+ * }
807
+ *
808
+ * // Clean up
809
+ * queue.close()
810
+ * ```
811
+ *
812
+ * @internal
813
+ */
814
+ declare class ExecutionQueue {
815
+ private readonly timeout?;
816
+ private queue;
817
+ private running;
818
+ /**
819
+ * Creates a new ExecutionQueue.
820
+ *
821
+ * Creates a new execution queue that will process tasks sequentially.
822
+ * If a timeout is provided, there will be a delay between each task execution,
823
+ * which is useful for rate limiting or controlling execution flow.
824
+ *
825
+ * timeout - Optional delay in milliseconds between task executions
826
+ * @example
827
+ * ```ts
828
+ * // Create queue without delay
829
+ * const fastQueue = new ExecutionQueue()
830
+ *
831
+ * // Create queue with 500ms delay between tasks
832
+ * const slowQueue = new ExecutionQueue(500)
833
+ * ```
834
+ */
835
+ constructor(timeout?: number | undefined);
836
+ /**
837
+ * Checks if the queue is empty and not currently running a task.
838
+ *
839
+ * Determines whether the execution queue has completed all tasks and is idle.
840
+ * Returns true only when there are no pending tasks in the queue AND no task is currently being executed.
841
+ *
842
+ * @returns True if the queue has no pending tasks and is not currently executing
843
+ * @example
844
+ * ```ts
845
+ * const queue = new ExecutionQueue()
846
+ *
847
+ * console.log(queue.isEmpty()) // true - queue is empty
848
+ *
849
+ * queue.push(() => console.log('task'))
850
+ * console.log(queue.isEmpty()) // false - task is running/pending
851
+ * ```
852
+ */
853
+ isEmpty(): boolean;
854
+ private run;
855
+ /**
856
+ * Adds a task to the queue and returns a promise that resolves with the task's result.
857
+ *
858
+ * Enqueues a task for sequential execution. The task will be executed after all
859
+ * previously queued tasks have completed. If a timeout was specified in the constructor,
860
+ * there will be a delay between this task and the next one.
861
+ *
862
+ * @param task - The function to execute (can be sync or async)
863
+ * @returns Promise that resolves with the task's return value
864
+ * @example
865
+ * ```ts
866
+ * const queue = new ExecutionQueue(100)
867
+ *
868
+ * // Add async task
869
+ * const result = await queue.push(async () => {
870
+ * const response = await fetch('/api/data')
871
+ * return response.json()
872
+ * })
873
+ *
874
+ * // Add sync task
875
+ * const number = await queue.push(() => 42)
876
+ * ```
877
+ */
878
+ push<T>(task: () => T): Promise<Awaited<T>>;
879
+ /**
880
+ * Clears all pending tasks from the queue.
881
+ *
882
+ * Immediately removes all pending tasks from the queue. Any currently
883
+ * running task will complete normally, but no additional tasks will be executed.
884
+ * This method does not wait for the current task to finish.
885
+ *
886
+ * @returns void
887
+ * @example
888
+ * ```ts
889
+ * const queue = new ExecutionQueue()
890
+ *
891
+ * // Add several tasks
892
+ * queue.push(() => console.log('task 1'))
893
+ * queue.push(() => console.log('task 2'))
894
+ * queue.push(() => console.log('task 3'))
895
+ *
896
+ * // Clear all pending tasks
897
+ * queue.close()
898
+ * // Only 'task 1' will execute if it was already running
899
+ * ```
900
+ */
901
+ close(): void;
902
+ }
903
+
904
+ /**
905
+ * Utility class providing helper methods for file and blob operations.
906
+ *
907
+ * FileHelpers contains static methods for common file operations including
908
+ * URL fetching, format conversion, and MIME type manipulation. All methods work with
909
+ * web APIs like fetch, FileReader, and Blob/File objects.
910
+ *
911
+ * @example
912
+ * ```ts
913
+ * // Fetch and convert a remote image to data URL
914
+ * const dataUrl = await FileHelpers.urlToDataUrl('https://example.com/image.png')
915
+ *
916
+ * // Convert user-selected file to text
917
+ * const text = await FileHelpers.blobToText(userFile)
918
+ *
919
+ * // Change file MIME type
920
+ * const newFile = FileHelpers.rewriteMimeType(originalFile, 'application/json')
921
+ * ```
922
+ *
923
+ * @public
924
+ */
925
+ declare class FileHelpers {
926
+ /**
927
+ * Converts a URL to an ArrayBuffer by fetching the resource.
928
+ *
929
+ * Fetches the resource at the given URL and returns its content as an ArrayBuffer.
930
+ * This is useful for loading binary data like images, videos, or other file types.
931
+ *
932
+ * @param url - The URL of the file to fetch
933
+ * @returns Promise that resolves to the file content as an ArrayBuffer
934
+ * @example
935
+ * ```ts
936
+ * const buffer = await FileHelpers.urlToArrayBuffer('https://example.com/image.png')
937
+ * console.log(buffer.byteLength) // Size of the file in bytes
938
+ * ```
939
+ * @public
940
+ */
941
+ static urlToArrayBuffer(url: string): Promise<ArrayBuffer>;
942
+ /**
943
+ * Converts a URL to a Blob by fetching the resource.
944
+ *
945
+ * Fetches the resource at the given URL and returns its content as a Blob object.
946
+ * Blobs are useful for handling file data in web applications.
947
+ *
948
+ * @param url - The URL of the file to fetch
949
+ * @returns Promise that resolves to the file content as a Blob
950
+ * @example
951
+ * ```ts
952
+ * const blob = await FileHelpers.urlToBlob('https://example.com/document.pdf')
953
+ * console.log(blob.type) // 'application/pdf'
954
+ * console.log(blob.size) // Size in bytes
955
+ * ```
956
+ * @public
957
+ */
958
+ static urlToBlob(url: string): Promise<Blob>;
959
+ /**
960
+ * Converts a URL to a data URL by fetching the resource.
961
+ *
962
+ * Fetches the resource at the given URL and converts it to a base64-encoded data URL.
963
+ * If the URL is already a data URL, it returns the URL unchanged. This is useful for embedding
964
+ * resources directly in HTML or CSS.
965
+ *
966
+ * @param url - The URL of the file to convert, or an existing data URL
967
+ * @returns Promise that resolves to a data URL string
968
+ * @example
969
+ * ```ts
970
+ * const dataUrl = await FileHelpers.urlToDataUrl('https://example.com/image.jpg')
971
+ * // Returns: 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEA...'
972
+ *
973
+ * const existing = await FileHelpers.urlToDataUrl('data:text/plain;base64,SGVsbG8=')
974
+ * // Returns the same data URL unchanged
975
+ * ```
976
+ * @public
977
+ */
978
+ static urlToDataUrl(url: string): Promise<string>;
979
+ /**
980
+ * Convert a Blob to a base64 encoded data URL.
981
+ *
982
+ * Converts a Blob object to a base64-encoded data URL using the FileReader API.
983
+ * This is useful for displaying images or embedding file content directly in HTML.
984
+ *
985
+ * @param file - The Blob object to convert
986
+ * @returns Promise that resolves to a base64-encoded data URL string
987
+ * @example
988
+ * ```ts
989
+ * const blob = new Blob(['Hello World'], { type: 'text/plain' })
990
+ * const dataUrl = await FileHelpers.blobToDataUrl(blob)
991
+ * // Returns: 'data:text/plain;base64,SGVsbG8gV29ybGQ='
992
+ *
993
+ * // With an image file
994
+ * const imageDataUrl = await FileHelpers.blobToDataUrl(myImageFile)
995
+ * // Can be used directly in img src attribute
996
+ * ```
997
+ * @public
998
+ */
999
+ static blobToDataUrl(file: Blob): Promise<string>;
1000
+ /**
1001
+ * Convert a Blob to a unicode text string.
1002
+ *
1003
+ * Reads the content of a Blob object as a UTF-8 text string using the FileReader API.
1004
+ * This is useful for reading text files or extracting text content from blobs.
1005
+ *
1006
+ * @param file - The Blob object to convert to text
1007
+ * @returns Promise that resolves to the text content as a string
1008
+ * @example
1009
+ * ```ts
1010
+ * const textBlob = new Blob(['Hello World'], { type: 'text/plain' })
1011
+ * const text = await FileHelpers.blobToText(textBlob)
1012
+ * console.log(text) // 'Hello World'
1013
+ *
1014
+ * // With a text file from user input
1015
+ * const content = await FileHelpers.blobToText(myTextFile)
1016
+ * console.log(content) // File content as string
1017
+ * ```
1018
+ * @public
1019
+ */
1020
+ static blobToText(file: Blob): Promise<string>;
1021
+ /**
1022
+ * Creates a new Blob or File with a different MIME type.
1023
+ *
1024
+ * Creates a copy of the given Blob or File with a new MIME type while preserving
1025
+ * all other properties. If the current MIME type already matches the new one, returns the
1026
+ * original object unchanged. For File objects, preserves the filename.
1027
+ *
1028
+ * @param blob - The Blob or File object to modify
1029
+ * @param newMimeType - The new MIME type to assign
1030
+ * @returns A new Blob or File with the updated MIME type
1031
+ * @example
1032
+ * ```ts
1033
+ * // Change a generic blob to a specific image type
1034
+ * const blob = new Blob([imageData])
1035
+ * const imageBlob = FileHelpers.rewriteMimeType(blob, 'image/png')
1036
+ *
1037
+ * // Change a file's MIME type while preserving filename
1038
+ * const file = new File([data], 'document.txt', { type: 'text/plain' })
1039
+ * const jsonFile = FileHelpers.rewriteMimeType(file, 'application/json')
1040
+ * console.log(jsonFile.name) // 'document.txt' (preserved)
1041
+ * console.log(jsonFile.type) // 'application/json' (updated)
1042
+ * ```
1043
+ * @public
1044
+ */
1045
+ static rewriteMimeType(blob: Blob, newMimeType: string): Blob;
1046
+ static rewriteMimeType(blob: File, newMimeType: string): File;
1047
+ }
1048
+
1049
+ /**
1050
+ * When a function is wrapped in `omitFromStackTrace`, if it throws an error the stack trace won't
1051
+ * include the function itself or any stack frames above it. Useful for assertion-style function
1052
+ * where the error will ideally originate from the call-site rather than within the implementation
1053
+ * of the assert fn.
1054
+ *
1055
+ * Only works in platforms that support `Error.captureStackTrace` (ie v8).
1056
+ *
1057
+ * @param fn - The function to wrap and exclude from stack traces
1058
+ * @returns A wrapped version of the function that omits itself from error stack traces
1059
+ * @example
1060
+ * ```ts
1061
+ * const assertPositive = omitFromStackTrace((value: number) => {
1062
+ * if (value <= 0) throw new Error('Value must be positive')
1063
+ * return value
1064
+ * })
1065
+ *
1066
+ * assertPositive(-1) // Error stack trace will point to this line, not inside assertPositive
1067
+ * ```
1068
+ * @internal
1069
+ */
1070
+ declare function omitFromStackTrace<Args extends Array<unknown>, Return>(fn: (...args: Args) => Return): (...args: Args) => Return;
1071
+ /**
1072
+ * Does nothing, but it's really really good at it.
1073
+ * @internal
1074
+ */
1075
+ declare const noop: () => void;
1076
+
1077
+ /**
1078
+ * Hash a string using the FNV-1a algorithm.
1079
+ *
1080
+ * Generates a deterministic hash value for a given string using a variant of the FNV-1a
1081
+ * (Fowler-Noll-Vo) algorithm. The hash is returned as a string representation of a 32-bit integer.
1082
+ *
1083
+ * @param string - The input string to hash
1084
+ * @returns A string representation of the 32-bit hash value
1085
+ * @example
1086
+ * ```ts
1087
+ * const hash = getHashForString('hello world')
1088
+ * console.log(hash) // '-862545276'
1089
+ *
1090
+ * // Same input always produces same hash
1091
+ * const hash2 = getHashForString('hello world')
1092
+ * console.log(hash === hash2) // true
1093
+ * ```
1094
+ * @public
1095
+ */
1096
+ declare function getHashForString(string: string): string;
1097
+ /**
1098
+ * Hash an object by converting it to JSON and then hashing the resulting string.
1099
+ *
1100
+ * Converts the object to a JSON string using JSON.stringify and then applies the same
1101
+ * hashing algorithm as getHashForString. Useful for creating consistent hash values
1102
+ * for objects, though the hash depends on JSON serialization order.
1103
+ *
1104
+ * @param obj - The object to hash (any JSON-serializable value)
1105
+ * @returns A string representation of the 32-bit hash value
1106
+ * @example
1107
+ * ```ts
1108
+ * const hash1 = getHashForObject({ name: 'John', age: 30 })
1109
+ * const hash2 = getHashForObject({ name: 'John', age: 30 })
1110
+ * console.log(hash1 === hash2) // true
1111
+ *
1112
+ * // Arrays work too
1113
+ * const arrayHash = getHashForObject([1, 2, 3, 'hello'])
1114
+ * console.log(arrayHash) // '-123456789'
1115
+ * ```
1116
+ * @public
1117
+ */
1118
+ declare function getHashForObject(obj: any): string;
1119
+ /**
1120
+ * Hash an ArrayBuffer using the FNV-1a algorithm.
1121
+ *
1122
+ * Generates a deterministic hash value for binary data stored in an ArrayBuffer.
1123
+ * Processes the buffer byte by byte using the same hashing algorithm as getHashForString.
1124
+ * Useful for creating consistent identifiers for binary data like images or files.
1125
+ *
1126
+ * @param buffer - The ArrayBuffer containing binary data to hash
1127
+ * @returns A string representation of the 32-bit hash value
1128
+ * @example
1129
+ * ```ts
1130
+ * // Hash some binary data
1131
+ * const data = new Uint8Array([1, 2, 3, 4, 5])
1132
+ * const hash = getHashForBuffer(data.buffer)
1133
+ * console.log(hash) // '123456789'
1134
+ *
1135
+ * // Hash image file data
1136
+ * const fileBuffer = await file.arrayBuffer()
1137
+ * const fileHash = getHashForBuffer(fileBuffer)
1138
+ * console.log(fileHash) // Unique hash for the file
1139
+ * ```
1140
+ * @public
1141
+ */
1142
+ declare function getHashForBuffer(buffer: ArrayBuffer): string;
1143
+ /**
1144
+ * Applies a string transformation algorithm that rearranges and modifies characters.
1145
+ *
1146
+ * Performs a series of character manipulations on the input string including
1147
+ * character repositioning through splicing operations and numeric character transformations.
1148
+ * This appears to be a custom encoding/obfuscation function.
1149
+ *
1150
+ * @param str - The input string to transform
1151
+ * @returns The transformed string after applying all manipulations
1152
+ * @example
1153
+ * ```ts
1154
+ * const result = lns('hello123')
1155
+ * console.log(result) // Transformed string (exact output depends on algorithm)
1156
+ *
1157
+ * // Can be used for simple string obfuscation
1158
+ * const obfuscated = lns('sensitive-data')
1159
+ * console.log(obfuscated) // Obfuscated version
1160
+ * ```
1161
+ * @public
1162
+ */
1163
+ declare function lns(str: string): string;
1164
+
1165
+ /*!
1166
+ * MIT License: https://github.com/ai/nanoid/blob/main/LICENSE
1167
+ * Modified code originally from <https://github.com/ai/nanoid>
1168
+ * Copyright 2017 Andrey Sitnik <andrey@sitnik.ru>
1169
+ *
1170
+ * `nanoid` is currently only distributed as an ES module. Some tools (jest, playwright) don't
1171
+ * properly support ESM-only code yet, and tldraw itself is distributed as both an ES module and a
1172
+ * CommonJS module. By including nanoid here, we can make sure it works well in every environment
1173
+ * where tldraw is used. We can also remove some unused features like custom alphabets.
1174
+ */
1175
+ /**
1176
+ * Mock the unique ID generator with a custom implementation for testing.
1177
+ *
1178
+ * Replaces the internal ID generation function with a custom one. This is useful
1179
+ * for testing scenarios where you need predictable or deterministic IDs.
1180
+ *
1181
+ * @param fn - The mock function that should return a string ID. Takes optional size parameter.
1182
+ * @example
1183
+ * ```ts
1184
+ * // Mock with predictable IDs for testing
1185
+ * mockUniqueId((size = 21) => 'test-id-' + size)
1186
+ * console.log(uniqueId()) // 'test-id-21'
1187
+ * console.log(uniqueId(10)) // 'test-id-10'
1188
+ *
1189
+ * // Restore original implementation when done
1190
+ * restoreUniqueId()
1191
+ * ```
1192
+ * @internal
1193
+ */
1194
+ declare function mockUniqueId(fn: (size?: number) => string): void;
1195
+ /**
1196
+ * Restore the original unique ID generator after mocking.
1197
+ *
1198
+ * Resets the ID generation function back to the original nanoid implementation.
1199
+ * This should be called after testing to restore normal ID generation behavior.
1200
+ *
1201
+ * @example
1202
+ * ```ts
1203
+ * // After mocking for tests
1204
+ * mockUniqueId(() => 'mock-id')
1205
+ *
1206
+ * // Restore original behavior
1207
+ * restoreUniqueId()
1208
+ * console.log(uniqueId()) // Now generates real random IDs again
1209
+ * ```
1210
+ * @internal
1211
+ */
1212
+ declare function restoreUniqueId(): void;
1213
+ /**
1214
+ * Generate a unique ID using a modified nanoid algorithm.
1215
+ *
1216
+ * Generates a cryptographically secure random string ID using URL-safe characters.
1217
+ * The default size is 21 characters, which provides a good balance of uniqueness
1218
+ * and brevity. Uses the global crypto API for secure random number generation.
1219
+ *
1220
+ * @param size - Optional length of the generated ID (defaults to 21 characters)
1221
+ * @returns A unique string identifier
1222
+ * @example
1223
+ * ```ts
1224
+ * // Generate default 21-character ID
1225
+ * const id = uniqueId()
1226
+ * console.log(id) // 'V1StGXR8_Z5jdHi6B-myT'
1227
+ *
1228
+ * // Generate shorter ID
1229
+ * const shortId = uniqueId(10)
1230
+ * console.log(shortId) // 'V1StGXR8_Z'
1231
+ *
1232
+ * // Generate longer ID
1233
+ * const longId = uniqueId(32)
1234
+ * console.log(longId) // 'V1StGXR8_Z5jdHi6B-myTVKahvjdx...'
1235
+ * ```
1236
+ * @public
1237
+ */
1238
+ declare function uniqueId(size?: number): string;
1239
+
1240
+ /**
1241
+ * Get the first item from an iterable Set or Map.
1242
+ *
1243
+ * @param value - The iterable Set or Map to get the first item from
1244
+ * @returns The first value from the Set or Map
1245
+ * @example
1246
+ * ```ts
1247
+ * const A = getFirstFromIterable(new Set([1, 2, 3])) // 1
1248
+ * const B = getFirstFromIterable(
1249
+ * new Map([
1250
+ * ['a', 1],
1251
+ * ['b', 2],
1252
+ * ])
1253
+ * ) // 1
1254
+ * ```
1255
+ * @public
1256
+ */
1257
+ declare function getFirstFromIterable<T = unknown>(set: Set<T> | Map<any, T>): T;
1258
+
1259
+ /** Simple LRU cache backed by a Map's insertion-order iteration. @public */
1260
+ declare class LruCache<K, V> {
1261
+ private maxSize;
1262
+ private map;
1263
+ constructor(maxSize: number);
1264
+ get(key: K): V | undefined;
1265
+ set(key: K, value: V): void;
1266
+ has(key: K): boolean;
1267
+ get size(): number;
1268
+ }
1269
+
1270
+ /**
1271
+ * A type that represents any valid JSON value. This includes primitives (boolean, null, string, number),
1272
+ * arrays of JSON values, and objects with string keys and JSON values.
1273
+ *
1274
+ * @example
1275
+ * ```ts
1276
+ * const jsonData: JsonValue = {
1277
+ * name: "Alice",
1278
+ * age: 30,
1279
+ * active: true,
1280
+ * tags: ["user", "premium"],
1281
+ * metadata: null
1282
+ * }
1283
+ * ```
1284
+ *
1285
+ * @public
1286
+ */
1287
+ type JsonValue = JsonPrimitive | JsonArray | JsonObject;
1288
+ /**
1289
+ * A type representing JSON primitive values: boolean, null, string, or number.
1290
+ * These are the atomic values that can appear in JSON data.
1291
+ *
1292
+ * @example
1293
+ * ```ts
1294
+ * const primitives: JsonPrimitive[] = [
1295
+ * true,
1296
+ * null,
1297
+ * "hello",
1298
+ * 42
1299
+ * ]
1300
+ * ```
1301
+ *
1302
+ * @public
1303
+ */
1304
+ type JsonPrimitive = boolean | null | string | number;
1305
+ /**
1306
+ * A type representing a JSON array containing any valid JSON values.
1307
+ * Arrays can contain mixed types of JSON values including nested arrays and objects.
1308
+ *
1309
+ * @example
1310
+ * ```ts
1311
+ * const jsonArray: JsonArray = [
1312
+ * "text",
1313
+ * 123,
1314
+ * true,
1315
+ * { nested: "object" },
1316
+ * [1, 2, 3]
1317
+ * ]
1318
+ * ```
1319
+ *
1320
+ * @public
1321
+ */
1322
+ type JsonArray = JsonValue[];
1323
+ /**
1324
+ * A type representing a JSON object with string keys and JSON values.
1325
+ * Object values can be undefined to handle optional properties safely.
1326
+ *
1327
+ * @example
1328
+ * ```ts
1329
+ * const jsonObject: JsonObject = {
1330
+ * required: "value",
1331
+ * optional: undefined,
1332
+ * nested: {
1333
+ * deep: "property"
1334
+ * },
1335
+ * array: [1, 2, 3]
1336
+ * }
1337
+ * ```
1338
+ *
1339
+ * @public
1340
+ */
1341
+ interface JsonObject {
1342
+ [key: string]: JsonValue | undefined;
1343
+ }
1344
+
1345
+ /**
1346
+ * Array of all supported image MIME types, combining static, vector, and animated types.
1347
+ *
1348
+ * @example
1349
+ * ```ts
1350
+ * import { DEFAULT_SUPPORTED_IMAGE_TYPES } from '@ibodr/utils'
1351
+ *
1352
+ * const isSupported = DEFAULT_SUPPORTED_IMAGE_TYPES.includes('image/png')
1353
+ * console.log(isSupported) // true
1354
+ * ```
1355
+ * @public
1356
+ */
1357
+ declare const DEFAULT_SUPPORTED_IMAGE_TYPES: readonly ("image/svg+xml" | "image/jpeg" | "image/png" | "image/webp" | "image/gif" | "image/apng" | "image/avif")[];
1358
+ /**
1359
+ * Array of supported video MIME types.
1360
+ *
1361
+ * @example
1362
+ * ```ts
1363
+ * import { DEFAULT_SUPPORT_VIDEO_TYPES } from '@ibodr/utils'
1364
+ *
1365
+ * const isVideo = DEFAULT_SUPPORT_VIDEO_TYPES.includes('video/mp4')
1366
+ * console.log(isVideo) // true
1367
+ * ```
1368
+ * @public
1369
+ */
1370
+ declare const DEFAULT_SUPPORT_VIDEO_TYPES: readonly ("video/mp4" | "video/webm" | "video/quicktime")[];
1371
+ /**
1372
+ * Array of all supported media MIME types, combining images and videos.
1373
+ *
1374
+ * @example
1375
+ * ```ts
1376
+ * import { DEFAULT_SUPPORTED_MEDIA_TYPES } from '@ibodr/utils'
1377
+ *
1378
+ * const isMediaFile = DEFAULT_SUPPORTED_MEDIA_TYPES.includes('video/mp4')
1379
+ * console.log(isMediaFile) // true
1380
+ * ```
1381
+ * @public
1382
+ */
1383
+ declare const DEFAULT_SUPPORTED_MEDIA_TYPES: readonly ("image/svg+xml" | "image/jpeg" | "image/png" | "image/webp" | "image/gif" | "image/apng" | "image/avif" | "video/mp4" | "video/webm" | "video/quicktime")[];
1384
+ /**
1385
+ * Comma-separated string of all supported media MIME types, useful for HTML file input accept attributes.
1386
+ *
1387
+ * @example
1388
+ * ```ts
1389
+ * import { DEFAULT_SUPPORTED_MEDIA_TYPE_LIST } from '@ibodr/utils'
1390
+ *
1391
+ * // Use in HTML file input for media uploads
1392
+ * const input = document.createElement('input')
1393
+ * input.type = 'file'
1394
+ * input.accept = DEFAULT_SUPPORTED_MEDIA_TYPE_LIST
1395
+ * input.addEventListener('change', (e) => {
1396
+ * const files = (e.target as HTMLInputElement).files
1397
+ * if (files) console.log(`Selected ${files.length} file(s)`)
1398
+ * })
1399
+ * ```
1400
+ * @public
1401
+ */
1402
+ declare const DEFAULT_SUPPORTED_MEDIA_TYPE_LIST: string;
1403
+ /**
1404
+ * Helpers for media
1405
+ *
1406
+ * @public
1407
+ */
1408
+ declare class MediaHelpers {
1409
+ /**
1410
+ * Load a video element from a URL with cross-origin support.
1411
+ *
1412
+ * @param src - The URL of the video to load
1413
+ * @param doc - Optional document to create the video element in
1414
+ * @returns Promise that resolves to the loaded HTMLVideoElement
1415
+ * @example
1416
+ * ```ts
1417
+ * const video = await MediaHelpers.loadVideo('https://example.com/video.mp4')
1418
+ * console.log(`Video dimensions: ${video.videoWidth}x${video.videoHeight}`)
1419
+ * ```
1420
+ * @public
1421
+ */
1422
+ static loadVideo(src: string, doc?: Document): Promise<HTMLVideoElement>;
1423
+ /**
1424
+ * Extract a frame from a video element as a data URL.
1425
+ *
1426
+ * @param video - The HTMLVideoElement to extract frame from
1427
+ * @param time - The time in seconds to extract the frame from (default: 0)
1428
+ * @returns Promise that resolves to a data URL of the video frame
1429
+ * @example
1430
+ * ```ts
1431
+ * const video = await MediaHelpers.loadVideo('https://example.com/video.mp4')
1432
+ * const frameDataUrl = await MediaHelpers.getVideoFrameAsDataUrl(video, 5.0)
1433
+ * // Use frameDataUrl as image thumbnail
1434
+ * const img = document.createElement('img')
1435
+ * img.src = frameDataUrl
1436
+ * ```
1437
+ * @public
1438
+ */
1439
+ static getVideoFrameAsDataUrl(video: HTMLVideoElement, time?: number): Promise<string>;
1440
+ /**
1441
+ * Load an image from a URL and get its dimensions along with the image element.
1442
+ *
1443
+ * @param src - The URL of the image to load
1444
+ * @param doc - Optional document to use for DOM operations (e.g. measuring SVG dimensions)
1445
+ * @returns Promise that resolves to an object with width, height, and the image element
1446
+ * @example
1447
+ * ```ts
1448
+ * const { w, h, image } = await MediaHelpers.getImageAndDimensions('https://example.com/image.png')
1449
+ * console.log(`Image size: ${w}x${h}`)
1450
+ * // Image is ready to use
1451
+ * document.body.appendChild(image)
1452
+ * ```
1453
+ * @public
1454
+ */
1455
+ static getImageAndDimensions(src: string, doc?: Document): Promise<{
1456
+ w: number;
1457
+ h: number;
1458
+ image: HTMLImageElement;
1459
+ }>;
1460
+ /**
1461
+ * Get the size of a video blob
1462
+ *
1463
+ * @param blob - A Blob containing the video
1464
+ * @param doc - Optional document to create elements in
1465
+ * @returns Promise that resolves to an object with width and height properties
1466
+ * @example
1467
+ * ```ts
1468
+ * const file = new File([...], 'video.mp4', { type: 'video/mp4' })
1469
+ * const { w, h } = await MediaHelpers.getVideoSize(file)
1470
+ * console.log(`Video dimensions: ${w}x${h}`)
1471
+ * ```
1472
+ * @public
1473
+ */
1474
+ static getVideoSize(blob: Blob, doc?: Document): Promise<{
1475
+ w: number;
1476
+ h: number;
1477
+ }>;
1478
+ /**
1479
+ * Get the size of an image blob
1480
+ *
1481
+ * @param blob - A Blob containing the image
1482
+ * @param doc - Optional document to use for DOM operations
1483
+ * @returns Promise that resolves to an object with width and height properties
1484
+ * @example
1485
+ * ```ts
1486
+ * const file = new File([...], 'image.png', { type: 'image/png' })
1487
+ * const { w, h } = await MediaHelpers.getImageSize(file)
1488
+ * console.log(`Image dimensions: ${w}x${h}`)
1489
+ * ```
1490
+ * @public
1491
+ */
1492
+ static getImageSize(blob: Blob, doc?: Document): Promise<{
1493
+ w: number;
1494
+ h: number;
1495
+ pixelRatio: number;
1496
+ }>;
1497
+ /**
1498
+ * Check if a media file blob contains animation data.
1499
+ *
1500
+ * @param file - The Blob to check for animation
1501
+ * @returns Promise that resolves to true if the file is animated, false otherwise
1502
+ * @example
1503
+ * ```ts
1504
+ * const file = new File([...], 'animation.gif', { type: 'image/gif' })
1505
+ * const animated = await MediaHelpers.isAnimated(file)
1506
+ * console.log(animated ? 'Animated' : 'Static')
1507
+ * ```
1508
+ * @public
1509
+ */
1510
+ static isAnimated(file: Blob): Promise<boolean>;
1511
+ /**
1512
+ * Check if a MIME type represents an animated image format.
1513
+ *
1514
+ * @param mimeType - The MIME type to check
1515
+ * @returns True if the MIME type is an animated image format, false otherwise
1516
+ * @example
1517
+ * ```ts
1518
+ * const isAnimated = MediaHelpers.isAnimatedImageType('image/gif')
1519
+ * console.log(isAnimated) // true
1520
+ * ```
1521
+ * @public
1522
+ */
1523
+ static isAnimatedImageType(mimeType: string | null): boolean;
1524
+ /**
1525
+ * Check if a MIME type represents a static (non-animated) image format.
1526
+ *
1527
+ * @param mimeType - The MIME type to check
1528
+ * @returns True if the MIME type is a static image format, false otherwise
1529
+ * @example
1530
+ * ```ts
1531
+ * const isStatic = MediaHelpers.isStaticImageType('image/jpeg')
1532
+ * console.log(isStatic) // true
1533
+ * ```
1534
+ * @public
1535
+ */
1536
+ static isStaticImageType(mimeType: string | null): boolean;
1537
+ /**
1538
+ * Check if a MIME type represents a vector image format.
1539
+ *
1540
+ * @param mimeType - The MIME type to check
1541
+ * @returns True if the MIME type is a vector image format, false otherwise
1542
+ * @example
1543
+ * ```ts
1544
+ * const isVector = MediaHelpers.isVectorImageType('image/svg+xml')
1545
+ * console.log(isVector) // true
1546
+ * ```
1547
+ * @public
1548
+ */
1549
+ static isVectorImageType(mimeType: string | null): boolean;
1550
+ /**
1551
+ * Check if a MIME type represents any supported image format (static, animated, or vector).
1552
+ *
1553
+ * @param mimeType - The MIME type to check
1554
+ * @returns True if the MIME type is a supported image format, false otherwise
1555
+ * @example
1556
+ * ```ts
1557
+ * const isImage = MediaHelpers.isImageType('image/png')
1558
+ * console.log(isImage) // true
1559
+ * ```
1560
+ * @public
1561
+ */
1562
+ static isImageType(mimeType: string): boolean;
1563
+ /**
1564
+ * Utility function to create an object URL from a blob, execute a function with it, and automatically clean it up.
1565
+ *
1566
+ * @param blob - The Blob to create an object URL for
1567
+ * @param fn - Function to execute with the object URL
1568
+ * @returns Promise that resolves to the result of the function
1569
+ * @example
1570
+ * ```ts
1571
+ * const result = await MediaHelpers.usingObjectURL(imageBlob, async (url) => {
1572
+ * const { w, h } = await MediaHelpers.getImageAndDimensions(url)
1573
+ * return { width: w, height: h }
1574
+ * })
1575
+ * // Object URL is automatically revoked after function completes
1576
+ * console.log(`Image dimensions: ${result.width}x${result.height}`)
1577
+ * ```
1578
+ * @public
1579
+ */
1580
+ static usingObjectURL<T>(blob: Blob, fn: (url: string) => Promise<T>): Promise<T>;
1581
+ }
1582
+
1583
+ /*!
1584
+ * MIT License: https://github.com/alexgorbatchev/crc/blob/master/LICENSE
1585
+ * Copyright: 2014 Alex Gorbatchev
1586
+ * Code: crc32, https://github.com/alexgorbatchev/crc/blob/master/src/calculators/crc32.ts
1587
+ */
1588
+ /**
1589
+ * Utility class for reading and manipulating PNG image files.
1590
+ * Provides methods for parsing PNG chunks, validating PNG format, and modifying PNG metadata.
1591
+ *
1592
+ * @example
1593
+ * ```ts
1594
+ * // Validate PNG file from blob
1595
+ * const blob = new Blob([pngData], { type: 'image/png' })
1596
+ * const view = new DataView(await blob.arrayBuffer())
1597
+ * const isPng = PngHelpers.isPng(view, 0)
1598
+ *
1599
+ * // Parse PNG metadata for image processing
1600
+ * const chunks = PngHelpers.readChunks(view)
1601
+ * const physChunk = PngHelpers.findChunk(view, 'pHYs')
1602
+ *
1603
+ * // Create high-DPI PNG for export
1604
+ * const highDpiBlob = PngHelpers.setPhysChunk(view, 2, { type: 'image/png' })
1605
+ * ```
1606
+ *
1607
+ * @public
1608
+ */
1609
+ declare class PngHelpers {
1610
+ /**
1611
+ * Checks if binary data at the specified offset contains a valid PNG file signature.
1612
+ * Validates the 8-byte PNG signature: 89 50 4E 47 0D 0A 1A 0A.
1613
+ *
1614
+ * @param view - DataView containing the binary data to check
1615
+ * @param offset - Byte offset where the PNG signature should start
1616
+ * @returns True if the data contains a valid PNG signature, false otherwise
1617
+ *
1618
+ * @example
1619
+ * ```ts
1620
+ * // Validate PNG from file upload
1621
+ * const file = event.target.files[0]
1622
+ * const buffer = await file.arrayBuffer()
1623
+ * const view = new DataView(buffer)
1624
+ *
1625
+ * if (PngHelpers.isPng(view, 0)) {
1626
+ * console.log('Valid PNG file detected')
1627
+ * // Process PNG file...
1628
+ * } else {
1629
+ * console.error('Not a valid PNG file')
1630
+ * }
1631
+ * ```
1632
+ */
1633
+ static isPng(view: DataView, offset: number): boolean;
1634
+ /**
1635
+ * Reads the 4-character chunk type identifier from a PNG chunk header.
1636
+ *
1637
+ * @param view - DataView containing the PNG data
1638
+ * @param offset - Byte offset of the chunk type field (after length field)
1639
+ * @returns 4-character string representing the chunk type (e.g., 'IHDR', 'IDAT', 'IEND')
1640
+ *
1641
+ * @example
1642
+ * ```ts
1643
+ * // Read chunk type from PNG header (after 8-byte signature)
1644
+ * const chunkType = PngHelpers.getChunkType(dataView, 8)
1645
+ * console.log(chunkType) // 'IHDR' (Image Header)
1646
+ *
1647
+ * // Read chunk type at a specific position during parsing
1648
+ * let offset = 8 // Skip PNG signature
1649
+ * const chunkLength = dataView.getUint32(offset)
1650
+ * const type = PngHelpers.getChunkType(dataView, offset + 4)
1651
+ * ```
1652
+ */
1653
+ static getChunkType(view: DataView, offset: number): string;
1654
+ /**
1655
+ * Parses all chunks in a PNG file and returns their metadata.
1656
+ * Skips duplicate IDAT chunks but includes all other chunk types.
1657
+ *
1658
+ * @param view - DataView containing the complete PNG file data
1659
+ * @param offset - Starting byte offset (defaults to 0)
1660
+ * @returns Record mapping chunk types to their metadata (start position, data offset, and size)
1661
+ * @throws Error if the data is not a valid PNG file
1662
+ *
1663
+ * @example
1664
+ * ```ts
1665
+ * // Parse PNG structure for metadata extraction
1666
+ * const view = new DataView(await blob.arrayBuffer())
1667
+ * const chunks = PngHelpers.readChunks(view)
1668
+ *
1669
+ * // Check for specific chunks
1670
+ * const ihdrChunk = chunks['IHDR']
1671
+ * const physChunk = chunks['pHYs']
1672
+ *
1673
+ * if (physChunk) {
1674
+ * console.log(`Found pixel density info at byte ${physChunk.start}`)
1675
+ * } else {
1676
+ * console.log('No pixel density information found')
1677
+ * }
1678
+ * ```
1679
+ */
1680
+ static readChunks(view: DataView, offset?: number): Record<string, {
1681
+ dataOffset: number;
1682
+ size: number;
1683
+ start: number;
1684
+ }>;
1685
+ /**
1686
+ * Parses the pHYs (physical pixel dimensions) chunk data.
1687
+ * Reads pixels per unit for X and Y axes, and the unit specifier.
1688
+ *
1689
+ * @param view - DataView containing the PNG data
1690
+ * @param offset - Byte offset of the pHYs chunk data
1691
+ * @returns Object with ppux (pixels per unit X), ppuy (pixels per unit Y), and unit specifier
1692
+ *
1693
+ * @example
1694
+ * ```ts
1695
+ * // Extract pixel density information for DPI calculation
1696
+ * const physChunk = PngHelpers.findChunk(dataView, 'pHYs')
1697
+ * if (physChunk) {
1698
+ * const physData = PngHelpers.parsePhys(dataView, physChunk.dataOffset)
1699
+ *
1700
+ * if (physData.unit === 1) { // meters
1701
+ * const dpiX = Math.round(physData.ppux * 0.0254)
1702
+ * const dpiY = Math.round(physData.ppuy * 0.0254)
1703
+ * console.log(`DPI: ${dpiX} x ${dpiY}`)
1704
+ * }
1705
+ * }
1706
+ * ```
1707
+ */
1708
+ static parsePhys(view: DataView, offset: number): {
1709
+ ppux: number;
1710
+ ppuy: number;
1711
+ unit: number;
1712
+ };
1713
+ /**
1714
+ * Finds a specific chunk type in the PNG file and returns its metadata.
1715
+ *
1716
+ * @param view - DataView containing the PNG file data
1717
+ * @param type - 4-character chunk type to search for (e.g., 'pHYs', 'IDAT')
1718
+ * @returns Chunk metadata object if found, undefined otherwise
1719
+ *
1720
+ * @example
1721
+ * ```ts
1722
+ * // Look for pixel density information in PNG
1723
+ * const physChunk = PngHelpers.findChunk(dataView, 'pHYs')
1724
+ * if (physChunk) {
1725
+ * const physData = PngHelpers.parsePhys(dataView, physChunk.dataOffset)
1726
+ * console.log(`Found pHYs chunk with ${physData.ppux} x ${physData.ppuy} pixels per unit`)
1727
+ * }
1728
+ *
1729
+ * // Check for text metadata
1730
+ * const textChunk = PngHelpers.findChunk(dataView, 'tEXt')
1731
+ * if (textChunk) {
1732
+ * console.log(`Found text metadata at byte ${textChunk.start}`)
1733
+ * }
1734
+ * ```
1735
+ */
1736
+ static findChunk(view: DataView, type: string): {
1737
+ dataOffset: number;
1738
+ size: number;
1739
+ start: number;
1740
+ };
1741
+ /**
1742
+ * Adds or replaces a pHYs chunk in a PNG file to set pixel density for high-DPI displays.
1743
+ * The method determines insertion point by prioritizing IDAT chunk position over existing pHYs,
1744
+ * creates a properly formatted pHYs chunk with CRC validation, and returns a new Blob.
1745
+ *
1746
+ * @param view - DataView containing the original PNG file data
1747
+ * @param dpr - Device pixel ratio multiplier (defaults to 1)
1748
+ * @param options - Optional Blob constructor options for MIME type and other properties
1749
+ * @returns New Blob containing the PNG with updated pixel density information
1750
+ *
1751
+ * @example
1752
+ * ```ts
1753
+ * // Export PNG with proper pixel density for high-DPI displays
1754
+ * const canvas = document.createElement('canvas')
1755
+ * const ctx = canvas.getContext('2d')
1756
+ * // ... draw content to canvas ...
1757
+ *
1758
+ * canvas.toBlob(async (blob) => {
1759
+ * if (blob) {
1760
+ * const view = new DataView(await blob.arrayBuffer())
1761
+ * // Create 2x DPI version for Retina displays
1762
+ * const highDpiBlob = PngHelpers.setPhysChunk(view, 2, { type: 'image/png' })
1763
+ * // Download or use the blob...
1764
+ * }
1765
+ * }, 'image/png')
1766
+ * ```
1767
+ */
1768
+ static setPhysChunk(view: DataView, dpr?: number, options?: BlobPropertyBag): Blob;
1769
+ }
1770
+
1771
+ /**
1772
+ * Just a wrapper around `window.fetch` that sets the `referrerPolicy` to `strict-origin-when-cross-origin`.
1773
+ *
1774
+ * @param input - A Request object or string containing the URL to fetch
1775
+ * @param init - Optional request initialization options
1776
+ * @returns Promise that resolves to the Response object
1777
+ * @internal
1778
+ */
1779
+ declare function fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
1780
+ /**
1781
+ * Just a wrapper around `new Image`, and yeah, it's a bit strange that it's in the network.ts file
1782
+ * but the main concern here is the referrerPolicy and setting it correctly.
1783
+ *
1784
+ * @param width - Optional width for the image element
1785
+ * @param height - Optional height for the image element
1786
+ * @returns HTMLImageElement with referrerPolicy set to 'strict-origin-when-cross-origin'
1787
+ * @internal
1788
+ */
1789
+ declare const Image: (width?: number, height?: number) => HTMLImageElement;
1790
+
1791
+ /**
1792
+ * Linear interpolate between two values.
1793
+ *
1794
+ * @param a - The start value
1795
+ * @param b - The end value
1796
+ * @param t - The interpolation factor (0-1)
1797
+ * @returns The interpolated value
1798
+ * @example
1799
+ * ```ts
1800
+ * const halfway = lerp(0, 100, 0.5) // 50
1801
+ * const quarter = lerp(10, 20, 0.25) // 12.5
1802
+ * ```
1803
+ * @public
1804
+ */
1805
+ declare function lerp(a: number, b: number, t: number): number;
1806
+ /**
1807
+ * Inverse lerp between two values. Given a value `t` in the range [a, b], returns a number between
1808
+ * 0 and 1.
1809
+ *
1810
+ * @param a - The start value of the range
1811
+ * @param b - The end value of the range
1812
+ * @param t - The value within the range [a, b]
1813
+ * @returns The normalized position (0-1) of t within the range [a, b]
1814
+ * @example
1815
+ * ```ts
1816
+ * const position = invLerp(0, 100, 25) // 0.25
1817
+ * const normalized = invLerp(10, 20, 15) // 0.5
1818
+ * ```
1819
+ * @public
1820
+ */
1821
+ declare function invLerp(a: number, b: number, t: number): number;
1822
+ /**
1823
+ * Seeded random number generator, using [xorshift](https://en.wikipedia.org/wiki/Xorshift). The
1824
+ * result will always be between -1 and 1.
1825
+ *
1826
+ * Adapted from [seedrandom](https://github.com/davidbau/seedrandom).
1827
+ *
1828
+ * @param seed - The seed string for deterministic random generation (defaults to empty string)
1829
+ * @returns A function that will return a random number between -1 and 1 each time it is called
1830
+ * @example
1831
+ * ```ts
1832
+ * const random = rng('my-seed')
1833
+ * const num1 = random() // Always the same for this seed
1834
+ * const num2 = random() // Next number in sequence
1835
+ *
1836
+ * // Different seed produces different sequence
1837
+ * const otherRandom = rng('other-seed')
1838
+ * const different = otherRandom() // Different value
1839
+ * ```
1840
+ * @public
1841
+ */
1842
+ declare function rng(seed?: string): () => number;
1843
+ /**
1844
+ * Modulate a value between two ranges.
1845
+ *
1846
+ * @example
1847
+ *
1848
+ * ```ts
1849
+ * const A = modulate(0, [0, 1], [0, 100]) // 0
1850
+ * const B = modulate(0.5, [0, 1], [0, 100]) // 50
1851
+ * const C = modulate(1, [0, 1], [0, 100]) // 100
1852
+ * ```
1853
+ *
1854
+ * @param value - The interpolation value.
1855
+ * @param rangeA - From [low, high]
1856
+ * @param rangeB - To [low, high]
1857
+ * @param clamp - Whether to clamp the the result to [low, high]
1858
+ * @public
1859
+ */
1860
+ declare function modulate(value: number, rangeA: number[], rangeB: number[], clamp?: boolean): number;
1861
+
1862
+ /**
1863
+ * Safely checks if an object has a specific property as its own property (not inherited).
1864
+ * Uses Object.prototype.hasOwnProperty.call to avoid issues with objects that have null prototype
1865
+ * or have overridden the hasOwnProperty method.
1866
+ *
1867
+ * @param obj - The object to check
1868
+ * @param key - The property key to check for
1869
+ * @returns True if the object has the property as its own property, false otherwise
1870
+ * @example
1871
+ * ```ts
1872
+ * const obj = { name: 'Alice', age: 30 }
1873
+ * hasOwnProperty(obj, 'name') // true
1874
+ * hasOwnProperty(obj, 'toString') // false (inherited)
1875
+ * hasOwnProperty(obj, 'unknown') // false
1876
+ * ```
1877
+ * @internal
1878
+ */
1879
+ declare function hasOwnProperty(obj: object, key: string): boolean;
1880
+ /**
1881
+ * Safely gets an object's own property value (not inherited). Returns undefined if the property
1882
+ * doesn't exist as an own property. Provides type-safe access with proper TypeScript inference.
1883
+ *
1884
+ * @param obj - The object to get the property from
1885
+ * @param key - The property key to retrieve
1886
+ * @returns The property value if it exists as an own property, undefined otherwise
1887
+ * @example
1888
+ * ```ts
1889
+ * const user = { name: 'Alice', age: 30 }
1890
+ * const name = getOwnProperty(user, 'name') // 'Alice'
1891
+ * const missing = getOwnProperty(user, 'unknown') // undefined
1892
+ * const inherited = getOwnProperty(user, 'toString') // undefined (inherited)
1893
+ * ```
1894
+ * @internal
1895
+ */
1896
+ declare function getOwnProperty<K extends string, V>(obj: Partial<Record<K, V>>, key: K): V | undefined;
1897
+ /** @internal */
1898
+ declare function getOwnProperty<O extends object>(obj: O, key: string): O[keyof O] | undefined;
1899
+ /** @internal */
1900
+ declare function getOwnProperty(obj: object, key: string): unknown;
1901
+ /**
1902
+ * An alias for `Object.keys` that treats the object as a map and so preserves the type of the keys.
1903
+ * Unlike standard Object.keys which returns string[], this maintains the specific string literal types.
1904
+ *
1905
+ * @param object - The object to get keys from
1906
+ * @returns Array of keys with preserved string literal types
1907
+ * @example
1908
+ * ```ts
1909
+ * const config = { theme: 'dark', lang: 'en' } as const
1910
+ * const keys = objectMapKeys(config)
1911
+ * // keys is Array<'theme' | 'lang'> instead of string[]
1912
+ * ```
1913
+ * @internal
1914
+ */
1915
+ declare function objectMapKeys<Key extends string>(object: {
1916
+ readonly [K in Key]: unknown;
1917
+ }): Array<Key>;
1918
+ /**
1919
+ * An alias for `Object.values` that treats the object as a map and so preserves the type of the
1920
+ * values. Unlike standard Object.values which returns unknown[], this maintains the specific value types.
1921
+ *
1922
+ * @param object - The object to get values from
1923
+ * @returns Array of values with preserved types
1924
+ * @example
1925
+ * ```ts
1926
+ * const scores = { alice: 85, bob: 92, charlie: 78 }
1927
+ * const values = objectMapValues(scores)
1928
+ * // values is Array<number> instead of unknown[]
1929
+ * ```
1930
+ * @internal
1931
+ */
1932
+ declare function objectMapValues<Key extends string, Value>(object: {
1933
+ [K in Key]: Value;
1934
+ }): Array<Value>;
1935
+ /**
1936
+ * An alias for `Object.entries` that treats the object as a map and so preserves the type of the
1937
+ * keys and values. Unlike standard Object.entries which returns `Array<[string, unknown]>`, this maintains specific types.
1938
+ *
1939
+ * @param object - The object to get entries from
1940
+ * @returns Array of key-value pairs with preserved types
1941
+ * @example
1942
+ * ```ts
1943
+ * const user = { name: 'Alice', age: 30 }
1944
+ * const entries = objectMapEntries(user)
1945
+ * // entries is Array<['name' | 'age', string | number]>
1946
+ * ```
1947
+ * @internal
1948
+ */
1949
+ declare function objectMapEntries<Obj extends object>(object: Obj): Array<[keyof Obj, Obj[keyof Obj]]>;
1950
+ /**
1951
+ * Returns the entries of an object as an iterable iterator.
1952
+ * Useful when working with large collections, to avoid allocating an array.
1953
+ * Only yields own properties (not inherited ones).
1954
+ *
1955
+ * @param object - The object to iterate over
1956
+ * @returns Iterator yielding key-value pairs with preserved types
1957
+ * @example
1958
+ * ```ts
1959
+ * const largeMap = { a: 1, b: 2, c: 3 } // Imagine thousands of entries
1960
+ * for (const [key, value] of objectMapEntriesIterable(largeMap)) {
1961
+ * // Process entries one at a time without creating a large array
1962
+ * console.log(key, value)
1963
+ * }
1964
+ * ```
1965
+ * @internal
1966
+ */
1967
+ declare function objectMapEntriesIterable<Key extends string, Value>(object: {
1968
+ [K in Key]: Value;
1969
+ }): IterableIterator<[Key, Value]>;
1970
+ /**
1971
+ * An alias for `Object.fromEntries` that treats the object as a map and so preserves the type of the
1972
+ * keys and values. Creates an object from key-value pairs with proper TypeScript typing.
1973
+ *
1974
+ * @param entries - Array of key-value pairs to convert to an object
1975
+ * @returns Object with preserved key and value types
1976
+ * @example
1977
+ * ```ts
1978
+ * const pairs: Array<['name' | 'age', string | number]> = [['name', 'Alice'], ['age', 30]]
1979
+ * const obj = objectMapFromEntries(pairs)
1980
+ * // obj is { name: string | number, age: string | number }
1981
+ * ```
1982
+ * @internal
1983
+ */
1984
+ declare function objectMapFromEntries<Key extends string, Value>(entries: ReadonlyArray<readonly [Key, Value]>): {
1985
+ [K in Key]: Value;
1986
+ };
1987
+ /**
1988
+ * Filters an object using a predicate function, returning a new object with only the entries
1989
+ * that pass the predicate. Optimized to return the original object if no changes are needed.
1990
+ *
1991
+ * @param object - The object to filter
1992
+ * @param predicate - Function that tests each key-value pair
1993
+ * @returns A new object with only the entries that pass the predicate, or the original object if unchanged
1994
+ * @example
1995
+ * ```ts
1996
+ * const scores = { alice: 85, bob: 92, charlie: 78 }
1997
+ * const passing = filterEntries(scores, (name, score) => score >= 80)
1998
+ * // { alice: 85, bob: 92 }
1999
+ * ```
2000
+ * @internal
2001
+ */
2002
+ declare function filterEntries<Key extends string, Value>(object: {
2003
+ [K in Key]: Value;
2004
+ }, predicate: (key: Key, value: Value) => boolean): {
2005
+ [K in Key]: Value;
2006
+ };
2007
+ /**
2008
+ * Maps the values of an object to new values using a mapper function, preserving keys.
2009
+ * The mapper function receives both the key and value for each entry.
2010
+ *
2011
+ * @param object - The object whose values to transform
2012
+ * @param mapper - Function that transforms each value (receives key and value)
2013
+ * @returns A new object with the same keys but transformed values
2014
+ * @example
2015
+ * ```ts
2016
+ * const prices = { apple: 1.50, banana: 0.75, orange: 2.00 }
2017
+ * const withTax = mapObjectMapValues(prices, (fruit, price) => price * 1.08)
2018
+ * // { apple: 1.62, banana: 0.81, orange: 2.16 }
2019
+ * ```
2020
+ * @internal
2021
+ */
2022
+ declare function mapObjectMapValues<Key extends string, ValueBefore, ValueAfter>(object: {
2023
+ readonly [K in Key]: ValueBefore;
2024
+ }, mapper: (key: Key, value: ValueBefore) => ValueAfter): {
2025
+ [K in Key]: ValueAfter;
2026
+ };
2027
+ /**
2028
+ * Performs a shallow equality check between two objects. Compares all enumerable own properties
2029
+ * using Object.is for value comparison. Returns true if both objects have the same keys and values.
2030
+ *
2031
+ * @param obj1 - First object to compare
2032
+ * @param obj2 - Second object to compare
2033
+ * @returns True if objects are shallow equal, false otherwise
2034
+ * @example
2035
+ * ```ts
2036
+ * const a = { x: 1, y: 2 }
2037
+ * const b = { x: 1, y: 2 }
2038
+ * const c = { x: 1, y: 3 }
2039
+ * areObjectsShallowEqual(a, b) // true
2040
+ * areObjectsShallowEqual(a, c) // false
2041
+ * areObjectsShallowEqual(a, a) // true (same reference)
2042
+ * ```
2043
+ * @internal
2044
+ */
2045
+ declare function areObjectsShallowEqual<T extends object>(obj1: T, obj2: T): boolean;
2046
+ /**
2047
+ * Groups an array of values into a record by a key extracted from each value.
2048
+ * The key selector function is called for each element to determine the grouping key.
2049
+ *
2050
+ * @param array - The array to group
2051
+ * @param keySelector - Function that extracts the grouping key from each value
2052
+ * @returns A record where keys are the extracted keys and values are arrays of grouped items
2053
+ * @example
2054
+ * ```ts
2055
+ * const people = [
2056
+ * { name: 'Alice', age: 25 },
2057
+ * { name: 'Bob', age: 30 },
2058
+ * { name: 'Charlie', age: 25 }
2059
+ * ]
2060
+ * const byAge = groupBy(people, person => `age-${person.age}`)
2061
+ * // { 'age-25': [Alice, Charlie], 'age-30': [Bob] }
2062
+ * ```
2063
+ * @internal
2064
+ */
2065
+ declare function groupBy<K extends string, V>(array: ReadonlyArray<V>, keySelector: (value: V) => K): Record<K, V[]>;
2066
+ /**
2067
+ * Creates a new object with specified keys omitted from the original object.
2068
+ * Uses shallow copying and then deletes the unwanted keys.
2069
+ *
2070
+ * @param obj - The source object
2071
+ * @param keys - Array of key names to omit from the result
2072
+ * @returns A new object without the specified keys
2073
+ * @example
2074
+ * ```ts
2075
+ * const user = { id: '123', name: 'Alice', password: 'secret', email: 'alice@example.com' }
2076
+ * const publicUser = omit(user, ['password'])
2077
+ * // { id: '123', name: 'Alice', email: 'alice@example.com' }
2078
+ * ```
2079
+ * @internal
2080
+ */
2081
+ declare function omit(obj: Record<string, unknown>, keys: ReadonlyArray<string>): Record<string, unknown>;
2082
+ /**
2083
+ * Compares two objects and returns an array of keys where the values differ.
2084
+ * Uses Object.is for comparison, which handles NaN and -0/+0 correctly.
2085
+ * Only checks keys present in the first object.
2086
+ *
2087
+ * @param obj1 - The first object (keys to check come from this object)
2088
+ * @param obj2 - The second object to compare against
2089
+ * @returns Array of keys where values differ between the objects
2090
+ * @example
2091
+ * ```ts
2092
+ * const before = { name: 'Alice', age: 25, city: 'NYC' }
2093
+ * const after = { name: 'Alice', age: 26, city: 'NYC' }
2094
+ * const changed = getChangedKeys(before, after)
2095
+ * // ['age']
2096
+ * ```
2097
+ * @internal
2098
+ */
2099
+ declare function getChangedKeys<T extends object>(obj1: T, obj2: T): (keyof T)[];
2100
+ /**
2101
+ * Deep equality comparison that allows for floating-point precision errors.
2102
+ * Numbers are considered equal if they differ by less than the threshold.
2103
+ * Uses lodash.isequalwith internally for the deep comparison logic.
2104
+ *
2105
+ * @param obj1 - First object to compare
2106
+ * @param obj2 - Second object to compare
2107
+ * @param threshold - Maximum difference allowed between numbers (default: 0.000001)
2108
+ * @returns True if objects are deeply equal with floating-point tolerance
2109
+ * @example
2110
+ * ```ts
2111
+ * const a = { x: 0.1 + 0.2 } // 0.30000000000000004
2112
+ * const b = { x: 0.3 }
2113
+ * isEqualAllowingForFloatingPointErrors(a, b) // true
2114
+ *
2115
+ * const c = { coords: [1.0000001, 2.0000001] }
2116
+ * const d = { coords: [1.0000002, 2.0000002] }
2117
+ * isEqualAllowingForFloatingPointErrors(c, d) // true
2118
+ * ```
2119
+ * @internal
2120
+ */
2121
+ declare function isEqualAllowingForFloatingPointErrors(obj1: object, obj2: object, threshold?: number): boolean;
2122
+
2123
+ /**
2124
+ * Measures and logs the execution time of a callback function.
2125
+ * Executes the provided callback and logs the duration to the console with styled output.
2126
+ *
2127
+ * @param name - Descriptive name for the operation being measured
2128
+ * @param cb - Callback function to execute and measure
2129
+ * @returns The return value of the callback function
2130
+ *
2131
+ * @example
2132
+ * ```ts
2133
+ * const result = measureCbDuration('data processing', () => {
2134
+ * return processLargeDataSet(data)
2135
+ * })
2136
+ * // Console output: "Perf data processing took 42.5ms"
2137
+ * ```
2138
+ *
2139
+ * @internal
2140
+ */
2141
+ declare function measureCbDuration(name: string, cb: () => any): any;
2142
+ /**
2143
+ * Decorator that measures and logs the execution time of class methods.
2144
+ * Wraps the decorated method to automatically log its execution duration.
2145
+ *
2146
+ * @param _target - The class prototype (unused)
2147
+ * @param propertyKey - Name of the method being decorated
2148
+ * @param descriptor - Property descriptor of the method
2149
+ * @returns Modified property descriptor with timing measurement
2150
+ *
2151
+ * @example
2152
+ * ```ts
2153
+ * class DataProcessor {
2154
+ * @measureDuration
2155
+ * processData(data: unknown[]) {
2156
+ * return data.map(item => transform(item))
2157
+ * }
2158
+ * }
2159
+ * // When processData is called, logs: "Perf processData took: 15.2ms"
2160
+ * ```
2161
+ *
2162
+ * @internal
2163
+ */
2164
+ declare function measureDuration(_target: any, propertyKey: string, descriptor: PropertyDescriptor): PropertyDescriptor;
2165
+ /**
2166
+ * Decorator that measures method execution time and tracks running averages.
2167
+ * Wraps the decorated method to log both current execution time and running average.
2168
+ * Maintains a running total and count for each decorated method to calculate averages.
2169
+ *
2170
+ * @param _target - The class prototype (unused)
2171
+ * @param propertyKey - Name of the method being decorated
2172
+ * @param descriptor - Property descriptor of the method
2173
+ * @returns Modified property descriptor with timing measurement and averaging
2174
+ *
2175
+ * @example
2176
+ * ```ts
2177
+ * class RenderEngine {
2178
+ * @measureAverageDuration
2179
+ * renderFrame() {
2180
+ * // Rendering logic here
2181
+ * }
2182
+ * }
2183
+ * // After multiple calls, logs: "Perf renderFrame took 16.67ms | average 15.83ms"
2184
+ * ```
2185
+ *
2186
+ * @internal
2187
+ */
2188
+ declare function measureAverageDuration(_target: any, propertyKey: string, descriptor: PropertyDescriptor): PropertyDescriptor;
2189
+
2190
+ /**
2191
+ * A utility class for measuring and tracking frame rate performance during operations.
2192
+ * Provides visual feedback in the browser console with color-coded FPS indicators.
2193
+ *
2194
+ * @example
2195
+ * ```ts
2196
+ * const tracker = new PerformanceTracker()
2197
+ *
2198
+ * tracker.start('render')
2199
+ * renderShapes()
2200
+ * tracker.stop() // Logs performance info to console
2201
+ *
2202
+ * // Check if tracking is active
2203
+ * if (tracker.isStarted()) {
2204
+ * console.log('Still tracking performance')
2205
+ * }
2206
+ * ```
2207
+ *
2208
+ * @public
2209
+ */
2210
+ declare class PerformanceTracker {
2211
+ private startTime;
2212
+ private name;
2213
+ private frames;
2214
+ private started;
2215
+ private frame;
2216
+ /**
2217
+ * Records animation frames to calculate frame rate.
2218
+ * Called automatically during performance tracking.
2219
+ */
2220
+ recordFrame: () => void;
2221
+ /**
2222
+ * Starts performance tracking for a named operation.
2223
+ *
2224
+ * @param name - A descriptive name for the operation being tracked
2225
+ *
2226
+ * @example
2227
+ * ```ts
2228
+ * tracker.start('canvas-render')
2229
+ * // ... perform rendering operations
2230
+ * tracker.stop()
2231
+ * ```
2232
+ */
2233
+ start(name: string): void;
2234
+ /**
2235
+ * Stops performance tracking and logs results to the console.
2236
+ *
2237
+ * Displays the operation name, frame rate, and uses color coding:
2238
+ * - Green background: \> 55 FPS (good performance)
2239
+ * - Yellow background: 30-55 FPS (moderate performance)
2240
+ * - Red background: \< 30 FPS (poor performance)
2241
+ *
2242
+ * @example
2243
+ * ```ts
2244
+ * tracker.start('interaction')
2245
+ * handleUserInteraction()
2246
+ * tracker.stop() // Logs: "Perf Interaction 60 fps"
2247
+ * ```
2248
+ */
2249
+ stop(): void;
2250
+ /**
2251
+ * Checks whether performance tracking is currently active.
2252
+ *
2253
+ * @returns True if tracking is in progress, false otherwise
2254
+ *
2255
+ * @example
2256
+ * ```ts
2257
+ * if (!tracker.isStarted()) {
2258
+ * tracker.start('new-operation')
2259
+ * }
2260
+ * ```
2261
+ */
2262
+ isStarted(): boolean;
2263
+ }
2264
+
2265
+ /**
2266
+ * A string made up of an integer part followed by a fraction part. The fraction point consists of
2267
+ * zero or more digits with no trailing zeros. Based on
2268
+ * {@link https://observablehq.com/@dgreensp/implementing-fractional-indexing}.
2269
+ *
2270
+ * @public
2271
+ */
2272
+ type IndexKey = string & {
2273
+ __brand: 'indexKey';
2274
+ };
2275
+ /**
2276
+ * The index key for the first index - 'a0'.
2277
+ * @public
2278
+ */
2279
+ declare const ZERO_INDEX_KEY: IndexKey;
2280
+ /**
2281
+ * Validates that a string is a valid IndexKey.
2282
+ * @param index - The string to validate.
2283
+ * @throws Error if the index is invalid.
2284
+ * @internal
2285
+ */
2286
+ declare function validateIndexKey(index: string): asserts index is IndexKey;
2287
+ /**
2288
+ * Get a number of indices between two indices.
2289
+ * @param below - The index below.
2290
+ * @param above - The index above.
2291
+ * @param n - The number of indices to get.
2292
+ * @returns An array of n IndexKey values between below and above.
2293
+ * @example
2294
+ * ```ts
2295
+ * const indices = getIndicesBetween('a0' as IndexKey, 'a2' as IndexKey, 2)
2296
+ * console.log(indices) // ['a0V', 'a1']
2297
+ * ```
2298
+ * @public
2299
+ */
2300
+ declare function getIndicesBetween(below: IndexKey | null | undefined, above: IndexKey | null | undefined, n: number): IndexKey[];
2301
+ /**
2302
+ * Get a number of indices above an index.
2303
+ * @param below - The index below.
2304
+ * @param n - The number of indices to get.
2305
+ * @returns An array of n IndexKey values above the given index.
2306
+ * @example
2307
+ * ```ts
2308
+ * const indices = getIndicesAbove('a0' as IndexKey, 3)
2309
+ * console.log(indices) // ['a1', 'a2', 'a3']
2310
+ * ```
2311
+ * @public
2312
+ */
2313
+ declare function getIndicesAbove(below: IndexKey | null | undefined, n: number): IndexKey[];
2314
+ /**
2315
+ * Get a number of indices below an index.
2316
+ * @param above - The index above.
2317
+ * @param n - The number of indices to get.
2318
+ * @returns An array of n IndexKey values below the given index.
2319
+ * @example
2320
+ * ```ts
2321
+ * const indices = getIndicesBelow('a2' as IndexKey, 2)
2322
+ * console.log(indices) // ['a1', 'a0V']
2323
+ * ```
2324
+ * @public
2325
+ */
2326
+ declare function getIndicesBelow(above: IndexKey | null | undefined, n: number): IndexKey[];
2327
+ /**
2328
+ * Get the index between two indices.
2329
+ * @param below - The index below.
2330
+ * @param above - The index above.
2331
+ * @returns A single IndexKey value between below and above.
2332
+ * @example
2333
+ * ```ts
2334
+ * const index = getIndexBetween('a0' as IndexKey, 'a2' as IndexKey)
2335
+ * console.log(index) // 'a1'
2336
+ * ```
2337
+ * @public
2338
+ */
2339
+ declare function getIndexBetween(below: IndexKey | null | undefined, above: IndexKey | null | undefined): IndexKey;
2340
+ /**
2341
+ * Get the index above a given index.
2342
+ * @param below - The index below.
2343
+ * @returns An IndexKey value above the given index.
2344
+ * @example
2345
+ * ```ts
2346
+ * const index = getIndexAbove('a0' as IndexKey)
2347
+ * console.log(index) // 'a1'
2348
+ * ```
2349
+ * @public
2350
+ */
2351
+ declare function getIndexAbove(below?: IndexKey | null | undefined): IndexKey;
2352
+ /**
2353
+ * Get the index below a given index.
2354
+ * @param above - The index above.
2355
+ * @returns An IndexKey value below the given index.
2356
+ * @example
2357
+ * ```ts
2358
+ * const index = getIndexBelow('a2' as IndexKey)
2359
+ * console.log(index) // 'a1'
2360
+ * ```
2361
+ * @public
2362
+ */
2363
+ declare function getIndexBelow(above?: IndexKey | null | undefined): IndexKey;
2364
+ /**
2365
+ * Get n number of indices, starting at an index.
2366
+ * @param n - The number of indices to get.
2367
+ * @param start - The index to start at.
2368
+ * @returns An array containing the start index plus n additional IndexKey values.
2369
+ * @example
2370
+ * ```ts
2371
+ * const indices = getIndices(3, 'a1' as IndexKey)
2372
+ * console.log(indices) // ['a1', 'a2', 'a3', 'a4']
2373
+ * ```
2374
+ * @public
2375
+ */
2376
+ declare function getIndices(n: number, start?: IndexKey): IndexKey[];
2377
+ /**
2378
+ * Sort by index.
2379
+ * @param a - An object with an index property.
2380
+ * @param b - An object with an index property.
2381
+ * @returns A number indicating sort order (-1, 0, or 1).
2382
+ * @example
2383
+ * ```ts
2384
+ * const shapes = [
2385
+ * { id: 'b', index: 'a2' as IndexKey },
2386
+ * { id: 'a', index: 'a1' as IndexKey }
2387
+ * ]
2388
+ * const sorted = shapes.sort(sortByIndex)
2389
+ * console.log(sorted) // [{ id: 'a', index: 'a1' }, { id: 'b', index: 'a2' }]
2390
+ * ```
2391
+ * @public
2392
+ */
2393
+ declare function sortByIndex<T extends {
2394
+ index: IndexKey;
2395
+ }>(a: T, b: T): 1 | -1 | 0;
2396
+ /**
2397
+ * Sort by index, or null.
2398
+ * @param a - An object with an index property.
2399
+ * @param b - An object with an index property.
2400
+ * @public
2401
+ */
2402
+ declare function sortByMaybeIndex<T extends {
2403
+ index?: IndexKey | null;
2404
+ }>(a: T, b: T): 1 | -1 | 0;
2405
+
2406
+ /**
2407
+ * Retries an async operation with configurable attempt count, wait duration, and error filtering.
2408
+ * Executes the provided async function repeatedly until it succeeds or the maximum number of attempts is reached.
2409
+ * Includes support for abort signals and custom error matching to determine which errors should trigger retries.
2410
+ *
2411
+ * @param fn - The async function to retry on failure
2412
+ * @param options - Configuration options for retry behavior:
2413
+ * - `attempts`: Maximum number of retry attempts (default: 3)
2414
+ * - `waitDuration`: Milliseconds to wait between retry attempts (default: 1000)
2415
+ * - `abortSignal`: Optional AbortSignal to cancel the retry operation
2416
+ * - `matchError`: Optional function to determine if an error should trigger a retry
2417
+ * @returns Promise that resolves with the function's return value on success
2418
+ *
2419
+ * @example
2420
+ * ```ts
2421
+ * // Basic retry with default settings (3 attempts, 1 second wait)
2422
+ * const data = await retry(async () => {
2423
+ * const response = await fetch('/api/data')
2424
+ * if (!response.ok) throw new Error('Network error')
2425
+ * return response.json()
2426
+ * })
2427
+ *
2428
+ * // Custom retry configuration
2429
+ * const result = await retry(
2430
+ * async () => unreliableApiCall(),
2431
+ * {
2432
+ * attempts: 5,
2433
+ * waitDuration: 2000,
2434
+ * matchError: (error) => error instanceof NetworkError
2435
+ * }
2436
+ * )
2437
+ *
2438
+ * // With abort signal for cancellation
2439
+ * const controller = new AbortController()
2440
+ * setTimeout(() => controller.abort(), 10000) // Cancel after 10 seconds
2441
+ *
2442
+ * const data = await retry(
2443
+ * async () => fetchData(),
2444
+ * {
2445
+ * attempts: 10,
2446
+ * abortSignal: controller.signal
2447
+ * }
2448
+ * )
2449
+ * ```
2450
+ *
2451
+ * @internal
2452
+ */
2453
+ declare function retry<T>(fn: (args: {
2454
+ attempt: number;
2455
+ remaining: number;
2456
+ total: number;
2457
+ }) => Promise<T>, { attempts, waitDuration, abortSignal, matchError, }?: {
2458
+ attempts?: number;
2459
+ waitDuration?: number;
2460
+ abortSignal?: AbortSignal;
2461
+ matchError?(error: unknown): boolean;
2462
+ }): Promise<T>;
2463
+
2464
+ /**
2465
+ * Compares two objects by their id property for use with Array.sort().
2466
+ * Sorts objects in ascending order based on their id values.
2467
+ *
2468
+ * @param a - First object to compare
2469
+ * @param b - Second object to compare
2470
+ * @returns 1 if a.id \> b.id, -1 if a.id \<= b.id
2471
+ *
2472
+ * @example
2473
+ * ```ts
2474
+ * const items = [
2475
+ * { id: 'c', name: 'Charlie' },
2476
+ * { id: 'a', name: 'Alice' },
2477
+ * { id: 'b', name: 'Bob' },
2478
+ * ]
2479
+ *
2480
+ * const sorted = items.sort(sortById)
2481
+ * // [{ id: 'a', name: 'Alice' }, { id: 'b', name: 'Bob' }, { id: 'c', name: 'Charlie' }]
2482
+ * ```
2483
+ *
2484
+ * @public
2485
+ */
2486
+ declare function sortById<T extends {
2487
+ id: any;
2488
+ }>(a: T, b: T): 1 | -1;
2489
+
2490
+ /**
2491
+ * Get a value from local storage.
2492
+ *
2493
+ * @param key - The key to get.
2494
+ * @returns The stored value as a string, or null if not found or storage is unavailable.
2495
+ * @example
2496
+ * ```ts
2497
+ * const userTheme = getFromLocalStorage('user-theme')
2498
+ * if (userTheme) {
2499
+ * console.log('Stored theme:', userTheme)
2500
+ * }
2501
+ * ```
2502
+ * @internal
2503
+ */
2504
+ declare function getFromLocalStorage(key: string): string | null;
2505
+ /**
2506
+ * Set a value in local storage. Will not throw an error if localStorage is not available.
2507
+ *
2508
+ * @param key - The key to set.
2509
+ * @param value - The value to set.
2510
+ * @returns void
2511
+ * @example
2512
+ * ```ts
2513
+ * const preferences = { theme: 'dark', language: 'en' }
2514
+ * setInLocalStorage('user-preferences', JSON.stringify(preferences))
2515
+ * ```
2516
+ * @internal
2517
+ */
2518
+ declare function setInLocalStorage(key: string, value: string): void;
2519
+ /**
2520
+ * Remove a value from local storage. Will not throw an error if localStorage is not available.
2521
+ *
2522
+ * @param key - The key to remove.
2523
+ * @returns void
2524
+ * @example
2525
+ * ```ts
2526
+ * deleteFromLocalStorage('user-preferences')
2527
+ * // Value is now removed from localStorage
2528
+ * ```
2529
+ * @internal
2530
+ */
2531
+ declare function deleteFromLocalStorage(key: string): void;
2532
+ /**
2533
+ * Clear all values from local storage. Will not throw an error if localStorage is not available.
2534
+ *
2535
+ * @returns void
2536
+ * @example
2537
+ * ```ts
2538
+ * clearLocalStorage()
2539
+ * // All localStorage data is now cleared
2540
+ * ```
2541
+ * @internal
2542
+ */
2543
+ declare function clearLocalStorage(): void;
2544
+ /**
2545
+ * Get a value from session storage.
2546
+ *
2547
+ * @param key - The key to get.
2548
+ * @returns The stored value as a string, or null if not found or storage is unavailable.
2549
+ * @example
2550
+ * ```ts
2551
+ * const currentTool = getFromSessionStorage('current-tool')
2552
+ * if (currentTool) {
2553
+ * console.log('Active tool:', currentTool)
2554
+ * }
2555
+ * ```
2556
+ * @internal
2557
+ */
2558
+ declare function getFromSessionStorage(key: string): string | null;
2559
+ /**
2560
+ * Set a value in session storage. Will not throw an error if sessionStorage is not available.
2561
+ *
2562
+ * @param key - The key to set.
2563
+ * @param value - The value to set.
2564
+ * @returns void
2565
+ * @example
2566
+ * ```ts
2567
+ * setInSessionStorage('current-tool', 'select')
2568
+ * setInSessionStorage('temp-data', JSON.stringify({ x: 100, y: 200 }))
2569
+ * ```
2570
+ * @internal
2571
+ */
2572
+ declare function setInSessionStorage(key: string, value: string): void;
2573
+ /**
2574
+ * Remove a value from session storage. Will not throw an error if sessionStorage is not available.
2575
+ *
2576
+ * @param key - The key to remove.
2577
+ * @returns void
2578
+ * @example
2579
+ * ```ts
2580
+ * deleteFromSessionStorage('temp-data')
2581
+ * // Value is now removed from sessionStorage
2582
+ * ```
2583
+ * @internal
2584
+ */
2585
+ declare function deleteFromSessionStorage(key: string): void;
2586
+ /**
2587
+ * Clear all values from session storage. Will not throw an error if sessionStorage is not available.
2588
+ *
2589
+ * @returns void
2590
+ * @example
2591
+ * ```ts
2592
+ * clearSessionStorage()
2593
+ * // All sessionStorage data is now cleared
2594
+ * ```
2595
+ * @internal
2596
+ */
2597
+ declare function clearSessionStorage(): void;
2598
+
2599
+ /**
2600
+ * Creates an enum-like object from string values where each key maps to itself.
2601
+ * Useful for creating string constant objects with type safety and autocompletion.
2602
+ * @param values - The string values to create the enum from.
2603
+ * @returns An object where each provided string is both the key and value.
2604
+ * @example
2605
+ * ```ts
2606
+ * const Colors = stringEnum('red', 'green', 'blue')
2607
+ * // Results in: { red: 'red', green: 'green', blue: 'blue' }
2608
+ *
2609
+ * // Type-safe usage
2610
+ * function setColor(color: keyof typeof Colors) {
2611
+ * console.log(`Setting color to ${Colors[color]}`)
2612
+ * }
2613
+ *
2614
+ * setColor('red') // ✓ Valid
2615
+ * setColor('yellow') // ✗ TypeScript error
2616
+ * ```
2617
+ * @internal
2618
+ */
2619
+ declare function stringEnum<T extends string>(...values: T[]): {
2620
+ [K in T]: K;
2621
+ };
2622
+
2623
+ /**
2624
+ * A scheduler class that manages a queue of functions to be executed at a target frame rate.
2625
+ * Each instance maintains its own queue and state, allowing for separate throttling contexts
2626
+ * (e.g., UI operations vs network sync operations).
2627
+ *
2628
+ * @public
2629
+ */
2630
+ declare class FpsScheduler {
2631
+ private targetFps;
2632
+ private targetTimePerFrame;
2633
+ private fpsQueue;
2634
+ private frameRaf;
2635
+ private flushRaf;
2636
+ private lastFlushTime;
2637
+ constructor(targetFps?: number);
2638
+ updateTargetFps(targetFps: number): void;
2639
+ private flush;
2640
+ private tick;
2641
+ /**
2642
+ * Creates a throttled version of a function that executes at most once per frame.
2643
+ * The default target frame rate is set by the FpsScheduler instance.
2644
+ * Subsequent calls within the same frame are ignored, ensuring smooth performance
2645
+ * for high-frequency events like mouse movements or scroll events.
2646
+ *
2647
+ * @param fn - The function to throttle, optionally with a cancel method
2648
+ * @returns A throttled function with an optional cancel method to remove pending calls
2649
+ *
2650
+ * @public
2651
+ */
2652
+ fpsThrottle(fn: {
2653
+ (): void;
2654
+ cancel?(): void;
2655
+ }): {
2656
+ (): void;
2657
+ cancel?(): void;
2658
+ };
2659
+ /**
2660
+ * Schedules a function to execute on the next animation frame.
2661
+ * If the same function is passed multiple times before the frame executes,
2662
+ * it will only be called once, effectively batching multiple calls.
2663
+ *
2664
+ * @param fn - The function to execute on the next frame
2665
+ * @returns A cancel function that can prevent execution if called before the next frame
2666
+ *
2667
+ * @public
2668
+ */
2669
+ throttleToNextFrame(fn: () => void): () => void;
2670
+ }
2671
+ /**
2672
+ * Creates a throttled version of a function that executes at most once per frame.
2673
+ * The default target frame rate is 120fps, but can be customized per function.
2674
+ * Subsequent calls within the same frame are ignored, ensuring smooth performance
2675
+ * for high-frequency events like mouse movements or scroll events.
2676
+ *
2677
+ * Uses the default throttle instance for UI operations. If you need a separate
2678
+ * throttling queue (e.g., for network operations), create your own Throttle instance.
2679
+ *
2680
+ * @param fn - The function to throttle, optionally with a cancel method
2681
+ * @returns A throttled function with an optional cancel method to remove pending calls
2682
+ *
2683
+ * @example
2684
+ * ```ts
2685
+ * // Default 120fps throttling
2686
+ * const updateCanvas = fpsThrottle(() => {
2687
+ * // This will run at most once per frame (~8.33ms)
2688
+ * redrawCanvas()
2689
+ * })
2690
+ *
2691
+ * // Call as often as you want - automatically throttled to 120fps
2692
+ * document.addEventListener('mousemove', updateCanvas)
2693
+ *
2694
+ * // Cancel pending calls if needed
2695
+ * updateCanvas.cancel?.()
2696
+ * ```
2697
+ *
2698
+ * @internal
2699
+ */
2700
+ declare function fpsThrottle(fn: {
2701
+ (): void;
2702
+ cancel?(): void;
2703
+ }): {
2704
+ (): void;
2705
+ cancel?(): void;
2706
+ };
2707
+ /**
2708
+ * Schedules a function to execute on the next animation frame, targeting 120fps.
2709
+ * If the same function is passed multiple times before the frame executes,
2710
+ * it will only be called once, effectively batching multiple calls.
2711
+ *
2712
+ * Uses the default throttle instance for UI operations.
2713
+ *
2714
+ * @param fn - The function to execute on the next frame
2715
+ * @returns A cancel function that can prevent execution if called before the next frame
2716
+ *
2717
+ * @example
2718
+ * ```ts
2719
+ * const updateUI = throttleToNextFrame(() => {
2720
+ * // Batches multiple calls into the next animation frame
2721
+ * updateStatusBar()
2722
+ * refreshToolbar()
2723
+ * })
2724
+ *
2725
+ * // Multiple calls within the same frame are batched
2726
+ * updateUI() // Will execute
2727
+ * updateUI() // Ignored (same function already queued)
2728
+ * updateUI() // Ignored (same function already queued)
2729
+ *
2730
+ * // Get cancel function to prevent execution
2731
+ * const cancel = updateUI()
2732
+ * cancel() // Prevents execution if called before next frame
2733
+ * ```
2734
+ *
2735
+ * @internal
2736
+ */
2737
+ declare function throttleToNextFrame(fn: () => void): () => void;
2738
+
2739
+ /**
2740
+ * A utility class for managing timeouts, intervals, and animation frames with context-based organization and automatic cleanup.
2741
+ * Helps prevent memory leaks by organizing timers into named contexts that can be cleared together.
2742
+ * @example
2743
+ * ```ts
2744
+ * const timers = new Timers()
2745
+ *
2746
+ * // Set timers with context organization
2747
+ * timers.setTimeout('ui', () => console.log('Auto save'), 5000)
2748
+ * timers.setInterval('ui', () => console.log('Refresh'), 1000)
2749
+ * timers.requestAnimationFrame('ui', () => console.log('Render'))
2750
+ *
2751
+ * // Clear all timers for a context
2752
+ * timers.dispose('ui')
2753
+ *
2754
+ * // Or get context-bound functions
2755
+ * const uiTimers = timers.forContext('ui')
2756
+ * uiTimers.setTimeout(() => console.log('Contextual timeout'), 1000)
2757
+ * ```
2758
+ * @public
2759
+ */
2760
+ declare class Timers {
2761
+ private timeouts;
2762
+ private intervals;
2763
+ private rafs;
2764
+ /**
2765
+ * Creates a new Timers instance with bound methods for safe callback usage.
2766
+ * @example
2767
+ * ```ts
2768
+ * const timers = new Timers()
2769
+ * // Methods are pre-bound, safe to use as callbacks
2770
+ * element.addEventListener('click', timers.dispose)
2771
+ * ```
2772
+ */
2773
+ constructor();
2774
+ /**
2775
+ * Creates a timeout that will be tracked under the specified context.
2776
+ * @param contextId - The context identifier to group this timer under.
2777
+ * @param handler - The function to execute when the timeout expires.
2778
+ * @param timeout - The delay in milliseconds (default: 0).
2779
+ * @param args - Additional arguments to pass to the handler.
2780
+ * @returns The timer ID that can be used with clearTimeout.
2781
+ * @example
2782
+ * ```ts
2783
+ * const timers = new Timers()
2784
+ * const id = timers.setTimeout('autosave', () => save(), 5000)
2785
+ * // Timer will be automatically cleared when 'autosave' context is disposed
2786
+ * ```
2787
+ * @public
2788
+ */
2789
+ setTimeout(contextId: string, handler: TimerHandler, timeout?: number, ...args: any[]): number;
2790
+ /**
2791
+ * Creates an interval that will be tracked under the specified context.
2792
+ * @param contextId - The context identifier to group this timer under.
2793
+ * @param handler - The function to execute repeatedly.
2794
+ * @param timeout - The delay in milliseconds between executions (default: 0).
2795
+ * @param args - Additional arguments to pass to the handler.
2796
+ * @returns The interval ID that can be used with clearInterval.
2797
+ * @example
2798
+ * ```ts
2799
+ * const timers = new Timers()
2800
+ * const id = timers.setInterval('refresh', () => updateData(), 1000)
2801
+ * // Interval will be automatically cleared when 'refresh' context is disposed
2802
+ * ```
2803
+ * @public
2804
+ */
2805
+ setInterval(contextId: string, handler: TimerHandler, timeout?: number, ...args: any[]): number;
2806
+ /**
2807
+ * Requests an animation frame that will be tracked under the specified context.
2808
+ * @param contextId - The context identifier to group this animation frame under.
2809
+ * @param callback - The function to execute on the next animation frame.
2810
+ * @returns The request ID that can be used with cancelAnimationFrame.
2811
+ * @example
2812
+ * ```ts
2813
+ * const timers = new Timers()
2814
+ * const id = timers.requestAnimationFrame('render', () => draw())
2815
+ * // Animation frame will be automatically cancelled when 'render' context is disposed
2816
+ * ```
2817
+ * @public
2818
+ */
2819
+ requestAnimationFrame(contextId: string, callback: FrameRequestCallback): number;
2820
+ /**
2821
+ * Disposes of all timers associated with the specified context.
2822
+ * Clears all timeouts, intervals, and animation frames for the given context ID.
2823
+ * @param contextId - The context identifier whose timers should be cleared.
2824
+ * @returns void
2825
+ * @example
2826
+ * ```ts
2827
+ * const timers = new Timers()
2828
+ * timers.setTimeout('ui', () => console.log('timeout'), 1000)
2829
+ * timers.setInterval('ui', () => console.log('interval'), 500)
2830
+ *
2831
+ * // Clear all 'ui' context timers
2832
+ * timers.dispose('ui')
2833
+ * ```
2834
+ * @public
2835
+ */
2836
+ dispose(contextId: string): void;
2837
+ /**
2838
+ * Disposes of all timers across all contexts.
2839
+ * Clears every timeout, interval, and animation frame managed by this instance.
2840
+ * @returns void
2841
+ * @example
2842
+ * ```ts
2843
+ * const timers = new Timers()
2844
+ * timers.setTimeout('ui', () => console.log('ui'), 1000)
2845
+ * timers.setTimeout('background', () => console.log('bg'), 2000)
2846
+ *
2847
+ * // Clear everything
2848
+ * timers.disposeAll()
2849
+ * ```
2850
+ * @public
2851
+ */
2852
+ disposeAll(): void;
2853
+ /**
2854
+ * Returns an object with timer methods bound to a specific context.
2855
+ * Convenient for getting context-specific timer functions without repeatedly passing the contextId.
2856
+ * @param contextId - The context identifier to bind the returned methods to.
2857
+ * @returns An object with setTimeout, setInterval, requestAnimationFrame, and dispose methods bound to the context.
2858
+ * @example
2859
+ * ```ts
2860
+ * const timers = new Timers()
2861
+ * const uiTimers = timers.forContext('ui')
2862
+ *
2863
+ * // These are equivalent to calling timers.setTimeout('ui', ...)
2864
+ * uiTimers.setTimeout(() => console.log('timeout'), 1000)
2865
+ * uiTimers.setInterval(() => console.log('interval'), 500)
2866
+ * uiTimers.requestAnimationFrame(() => console.log('frame'))
2867
+ *
2868
+ * // Dispose only this context
2869
+ * uiTimers.dispose()
2870
+ * ```
2871
+ * @public
2872
+ */
2873
+ forContext(contextId: string): {
2874
+ setTimeout: (handler: TimerHandler, timeout?: number, ...args: any[]) => number;
2875
+ setInterval: (handler: TimerHandler, timeout?: number, ...args: any[]) => number;
2876
+ requestAnimationFrame: (callback: FrameRequestCallback) => number;
2877
+ dispose: () => void;
2878
+ };
2879
+ }
2880
+
2881
+ /**
2882
+ * Safely parses a URL string without throwing exceptions on invalid input.
2883
+ * Returns a URL object for valid URLs or undefined for invalid ones.
2884
+ *
2885
+ * @param url - The URL string to parse
2886
+ * @param baseUrl - Optional base URL to resolve relative URLs against
2887
+ * @returns A URL object if parsing succeeds, undefined if it fails
2888
+ *
2889
+ * @example
2890
+ * ```ts
2891
+ * // Valid absolute URL
2892
+ * const url1 = safeParseUrl('https://example.com')
2893
+ * if (url1) {
2894
+ * console.log(`Valid URL: ${url1.href}`) // "Valid URL: https://example.com/"
2895
+ * }
2896
+ *
2897
+ * // Invalid URL
2898
+ * const url2 = safeParseUrl('not-a-url')
2899
+ * console.log(url2) // undefined
2900
+ *
2901
+ * // Relative URL with base
2902
+ * const url3 = safeParseUrl('/path', 'https://example.com')
2903
+ * if (url3) {
2904
+ * console.log(url3.href) // "https://example.com/path"
2905
+ * }
2906
+ *
2907
+ * // Error handling
2908
+ * function handleUserUrl(input: string) {
2909
+ * const url = safeParseUrl(input)
2910
+ * if (url) {
2911
+ * return url
2912
+ * } else {
2913
+ * console.log('Invalid URL provided')
2914
+ * return null
2915
+ * }
2916
+ * }
2917
+ * ```
2918
+ *
2919
+ * @public
2920
+ */
2921
+ declare const safeParseUrl: (url: string, baseUrl?: string | URL) => URL | undefined;
2922
+
2923
+ /**
2924
+ * Get whether a value is not undefined.
2925
+ *
2926
+ * @param value - The value to check.
2927
+ * @returns True if the value is not undefined, with proper type narrowing.
2928
+ * @example
2929
+ * ```ts
2930
+ * const maybeString: string | undefined = getValue()
2931
+ *
2932
+ * if (isDefined(maybeString)) {
2933
+ * // TypeScript knows maybeString is string, not undefined
2934
+ * console.log(maybeString.toUpperCase())
2935
+ * }
2936
+ *
2937
+ * // Filter undefined values from arrays
2938
+ * const values = [1, undefined, 2, undefined, 3]
2939
+ * const definedValues = values.filter(isDefined) // [1, 2, 3]
2940
+ * ```
2941
+ * @public
2942
+ */
2943
+ declare function isDefined<T>(value: T): value is typeof value extends undefined ? never : T;
2944
+ /**
2945
+ * Get whether a value is not null.
2946
+ *
2947
+ * @param value - The value to check.
2948
+ * @returns True if the value is not null, with proper type narrowing.
2949
+ * @example
2950
+ * ```ts
2951
+ * const maybeString: string | null = getValue()
2952
+ *
2953
+ * if (isNonNull(maybeString)) {
2954
+ * // TypeScript knows maybeString is string, not null
2955
+ * console.log(maybeString.length)
2956
+ * }
2957
+ *
2958
+ * // Filter null values from arrays
2959
+ * const values = ["a", null, "b", null, "c"]
2960
+ * const nonNullValues = values.filter(isNonNull) // ["a", "b", "c"]
2961
+ * ```
2962
+ * @public
2963
+ */
2964
+ declare function isNonNull<T>(value: T): value is typeof value extends null ? never : T;
2965
+ /**
2966
+ * Get whether a value is not nullish (not null and not undefined).
2967
+ *
2968
+ * @param value - The value to check.
2969
+ * @returns True if the value is neither null nor undefined, with proper type narrowing.
2970
+ * @example
2971
+ * ```ts
2972
+ * const maybeString: string | null | undefined = getValue()
2973
+ *
2974
+ * if (isNonNullish(maybeString)) {
2975
+ * // TypeScript knows maybeString is string, not null or undefined
2976
+ * console.log(maybeString.charAt(0))
2977
+ * }
2978
+ *
2979
+ * // Filter nullish values from arrays
2980
+ * const values = ["hello", null, "world", undefined, "!"]
2981
+ * const cleanValues = values.filter(isNonNullish) // ["hello", "world", "!"]
2982
+ * ```
2983
+ * @public
2984
+ */
2985
+ declare function isNonNullish<T>(value: T): value is typeof value extends undefined ? never : typeof value extends null ? never : T;
2986
+ /**
2987
+ * Create a deep copy of a value. Uses the structuredClone API if available, otherwise uses JSON.parse(JSON.stringify()).
2988
+ *
2989
+ * @param i - The value to clone.
2990
+ * @returns A deep copy of the input value.
2991
+ * @example
2992
+ * ```ts
2993
+ * const original = { a: 1, b: { c: 2 } }
2994
+ * const copy = structuredClone(original)
2995
+ *
2996
+ * copy.b.c = 3
2997
+ * console.log(original.b.c) // 2 (unchanged)
2998
+ * console.log(copy.b.c) // 3
2999
+ *
3000
+ * // Works with complex objects
3001
+ * const complexObject = {
3002
+ * date: new Date(),
3003
+ * array: [1, 2, 3],
3004
+ * nested: { deep: { value: "test" } }
3005
+ * }
3006
+ * const cloned = structuredClone(complexObject)
3007
+ * ```
3008
+ * @public
3009
+ */
3010
+ declare const structuredClone: <T>(i: T) => T;
3011
+ /**
3012
+ * Whether the current environment has native structuredClone support.
3013
+ * @returns True if using native structuredClone, false if using JSON fallback.
3014
+ * @internal
3015
+ */
3016
+ declare const isNativeStructuredClone: boolean;
3017
+ /**
3018
+ * The prototype object used by structuredClone for cloned objects.
3019
+ * When we patch structuredClone in jsdom for testing (see https://github.com/jsdom/jsdom/issues/3363),
3020
+ * the Object that is used as a prototype for the cloned object is not the same as the Object in
3021
+ * the code under test (that comes from jsdom's fake global context). This constant is used in
3022
+ * our code to work around this case.
3023
+ *
3024
+ * This is also the case for Array prototype, but that problem can be worked around with an
3025
+ * Array.isArray() check.
3026
+ * @internal
3027
+ */
3028
+ declare const STRUCTURED_CLONE_OBJECT_PROTOTYPE: any;
3029
+
3030
+ /**
3031
+ * Registers a tldraw library version for conflict detection.
3032
+ * This function tracks different tldraw library versions to warn about potential conflicts
3033
+ * when multiple versions are loaded simultaneously.
3034
+ * @param name - The name of the tldraw library package (e.g., '\@ibodr/editor').
3035
+ * @param version - The semantic version string (e.g., '2.0.0').
3036
+ * @param modules - The module system being used ('esm' or 'cjs').
3037
+ * @returns void
3038
+ * @example
3039
+ * ```ts
3040
+ * // Register a library version during package initialization
3041
+ * registerDrawLibraryVersion('@ibodr/editor', '2.0.0', 'esm')
3042
+ * registerDrawLibraryVersion('@ibodr/tldraw', '2.0.0', 'esm')
3043
+ *
3044
+ * // If conflicting versions are detected, warnings will be logged:
3045
+ * registerDrawLibraryVersion('@ibodr/editor', '1.9.0', 'cjs')
3046
+ * // Console warning about version mismatch will appear
3047
+ * ```
3048
+ * @internal
3049
+ */
3050
+ declare function registerDrawLibraryVersion(name?: string, version?: string, modules?: string): void;
3051
+
3052
+ /**
3053
+ * Issues a deprecation warning for deprecated getter properties, advising users to use
3054
+ * the equivalent getter method instead. The warning is shown only once per property name.
3055
+ *
3056
+ * @param name - The name of the deprecated property (e.g., 'viewport')
3057
+ *
3058
+ * @example
3059
+ * ```ts
3060
+ * // Inside a class with deprecated property access
3061
+ * get viewport() {
3062
+ * warnDeprecatedGetter('viewport')
3063
+ * return this.getViewport()
3064
+ * }
3065
+ *
3066
+ * // Usage will show: "[tldraw] Using 'viewport' is deprecated and will be removed..."
3067
+ * // But only the first time it's accessed
3068
+ * ```
3069
+ *
3070
+ * @internal
3071
+ */
3072
+ declare function warnDeprecatedGetter(name: string): void;
3073
+ /**
3074
+ * Issues a warning message to the console, but only once per unique message.
3075
+ * Subsequent calls with the same message are ignored, preventing console spam.
3076
+ * All messages are prefixed with "[tldraw]".
3077
+ *
3078
+ * @param message - The warning message to display
3079
+ *
3080
+ * @example
3081
+ * ```ts
3082
+ * // Warn about deprecated usage
3083
+ * function oldFunction() {
3084
+ * warnOnce('oldFunction is deprecated, use newFunction instead')
3085
+ * // Continue with implementation...
3086
+ * }
3087
+ *
3088
+ * // First call logs: "[tldraw] oldFunction is deprecated, use newFunction instead"
3089
+ * oldFunction() // Shows warning
3090
+ * oldFunction() // No warning (already shown)
3091
+ * oldFunction() // No warning (already shown)
3092
+ * ```
3093
+ *
3094
+ * @internal
3095
+ */
3096
+ declare function warnOnce(message: string): void;
3097
+
3098
+ export { type Awaitable, DEFAULT_SUPPORTED_IMAGE_TYPES, DEFAULT_SUPPORTED_MEDIA_TYPES, DEFAULT_SUPPORTED_MEDIA_TYPE_LIST, DEFAULT_SUPPORT_VIDEO_TYPES, type ErrorAnnotations, type ErrorResult, ExecutionQueue, type Expand, FileHelpers, FpsScheduler, Image, type IndexKey, type JsonArray, type JsonObject, type JsonPrimitive, type JsonValue, LruCache, type MakeUndefinedOptional, MediaHelpers, type OkResult, PerformanceTracker, PngHelpers, type RecursivePartial, type Required, Result, STRUCTURED_CLONE_OBJECT_PROTOTYPE, Timers, WeakCache, ZERO_INDEX_KEY, annotateError, areArraysShallowEqual, areObjectsShallowEqual, assert, assertExists, bind, clearLocalStorage, clearSessionStorage, compact, debounce, dedupe, deleteFromLocalStorage, deleteFromSessionStorage, exhaustiveSwitchError, fetch, filterEntries, fpsThrottle, getChangedKeys, getErrorAnnotations, getFirstFromIterable, getFromLocalStorage, getFromSessionStorage, getHashForBuffer, getHashForObject, getHashForString, getIndexAbove, getIndexBelow, getIndexBetween, getIndices, getIndicesAbove, getIndicesBelow, getIndicesBetween, getOwnProperty, groupBy, hasOwnProperty, invLerp, isDefined, isEqualAllowingForFloatingPointErrors, isNativeStructuredClone, isNonNull, isNonNullish, last, lerp, lns, mapObjectMapValues, maxBy, measureAverageDuration, measureCbDuration, measureDuration, mergeArraysAndReplaceDefaults, minBy, mockUniqueId, modulate, noop, objectMapEntries, objectMapEntriesIterable, objectMapFromEntries, objectMapKeys, objectMapValues, omit, omitFromStackTrace, partition, promiseWithResolve, registerDrawLibraryVersion, restoreUniqueId, retry, rng, rotateArray, safeParseUrl, setInLocalStorage, setInSessionStorage, sleep, sortById, sortByIndex, sortByMaybeIndex, stringEnum, structuredClone, throttleToNextFrame, uniqueId, validateIndexKey, warnDeprecatedGetter, warnOnce };