@dxos/util 0.8.4-main.40e3dcdf1b → 0.8.4-main.422d1c7879

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.
@@ -187,6 +187,49 @@ var BitField = class _BitField {
187
187
  }
188
188
  };
189
189
 
190
+ // src/browser-storage.ts
191
+ var clearIndexedDB = async () => {
192
+ const dbs = await indexedDB.databases();
193
+ const results = await Promise.allSettled(dbs.filter((db) => db.name != null).map((db) => new Promise((resolve, reject) => {
194
+ const request = indexedDB.deleteDatabase(db.name);
195
+ request.onsuccess = () => resolve();
196
+ request.onerror = () => reject(request.error);
197
+ request.onblocked = () => reject(new Error(`IndexedDB deletion blocked: ${db.name}`));
198
+ })));
199
+ const failures = results.filter((r) => r.status === "rejected");
200
+ if (failures.length > 0) {
201
+ throw new AggregateError(failures.map((r) => r.reason), "Failed to delete some IndexedDB databases");
202
+ }
203
+ };
204
+ var clearOPFS = async () => {
205
+ const root = await navigator.storage.getDirectory();
206
+ const errors = [];
207
+ for await (const [name] of root.entries()) {
208
+ try {
209
+ await root.removeEntry(name, {
210
+ recursive: true
211
+ });
212
+ } catch (err) {
213
+ errors.push(err);
214
+ }
215
+ }
216
+ if (errors.length > 0) {
217
+ throw new AggregateError(errors, "Failed to remove some OPFS entries");
218
+ }
219
+ };
220
+ var clearServiceWorkers = async () => {
221
+ const regs = await navigator.serviceWorker.getRegistrations();
222
+ for (const reg of regs) {
223
+ await reg.unregister();
224
+ }
225
+ };
226
+ var clearCaches = async () => {
227
+ const keys2 = await caches.keys();
228
+ for (const key of keys2) {
229
+ await caches.delete(key);
230
+ }
231
+ };
232
+
190
233
  // src/callback-collection.ts
191
234
  var CallbackCollection = class {
192
235
  #callbacks = [];
@@ -532,6 +575,36 @@ var ComplexMap = class _ComplexMap {
532
575
  this._values.set(primitive, value);
533
576
  return this;
534
577
  }
578
+ /**
579
+ * Returns the value for the given key if present, otherwise inserts and returns the default value.
580
+ * @param key - The key to look up or insert.
581
+ * @param defaultValue - The value to insert if the key is not present.
582
+ * @returns The existing or newly inserted value.
583
+ */
584
+ getOrInsert(key, defaultValue) {
585
+ const primitive = this._keyProjection(key);
586
+ if (this._values.has(primitive)) {
587
+ return this._values.get(primitive);
588
+ }
589
+ this.set(key, defaultValue);
590
+ return defaultValue;
591
+ }
592
+ /**
593
+ * Returns the value for the given key if present, otherwise computes, inserts, and returns a new value.
594
+ * The callback is only invoked when the key is missing.
595
+ * @param key - The key to look up or insert.
596
+ * @param callbackfn - Function to compute the value if the key is not present.
597
+ * @returns The existing or newly computed value.
598
+ */
599
+ getOrInsertComputed(key, callbackfn) {
600
+ const primitive = this._keyProjection(key);
601
+ if (this._values.has(primitive)) {
602
+ return this._values.get(primitive);
603
+ }
604
+ const value = callbackfn(key);
605
+ this.set(key, value);
606
+ return value;
607
+ }
535
608
  get size() {
536
609
  return this._keys.size;
537
610
  }
@@ -571,6 +644,11 @@ var makeMap = (keyProjection) => class BoundComplexMap extends ComplexMap {
571
644
  }
572
645
  };
573
646
 
647
+ // src/composite-key.ts
648
+ var SEPARATOR = ":";
649
+ var compositeKey = (...parts) => parts.join(SEPARATOR);
650
+ var splitCompositeKey = (key) => key.split(SEPARATOR);
651
+
574
652
  // src/deep.ts
575
653
  import { invariant as invariant4 } from "@dxos/invariant";
576
654
  var __dxlog_file4 = "/__w/dxos/dxos/packages/common/util/src/deep.ts";
@@ -668,6 +746,21 @@ var MapEntry = class {
668
746
  }
669
747
  };
670
748
 
749
+ // src/error-format.ts
750
+ var formatErrorWithCauses = (error) => {
751
+ const lines = [];
752
+ let current = error;
753
+ let level = 0;
754
+ while (current) {
755
+ const prefix = level === 0 ? "" : `Caused by: `;
756
+ lines.push(prefix + (current.stack ?? String(current)));
757
+ if (!(current.cause instanceof Error)) break;
758
+ current = current.cause;
759
+ level += 1;
760
+ }
761
+ return lines.join("\n\n");
762
+ };
763
+
671
764
  // src/filename.ts
672
765
  var createFilename = ({ parts = [], ext, date = /* @__PURE__ */ new Date() }) => [
673
766
  date.toISOString().replace(/[:.]/g, "-"),
@@ -1578,6 +1671,43 @@ var removeProperties = (root, condition) => {
1578
1671
  return result;
1579
1672
  };
1580
1673
 
1674
+ // src/retry.ts
1675
+ var DEFAULT_RETRY_OPTIONS = {
1676
+ count: 3,
1677
+ delayMs: 100,
1678
+ exponent: 2,
1679
+ retryOnError: async () => true,
1680
+ retryOnValue: async () => false
1681
+ };
1682
+ var retry = async (options, cb) => {
1683
+ const fullOptions = {
1684
+ ...DEFAULT_RETRY_OPTIONS,
1685
+ ...options
1686
+ };
1687
+ let numRetries = 0, currentDelay = fullOptions.delayMs;
1688
+ while (true) {
1689
+ let result;
1690
+ try {
1691
+ result = await cb();
1692
+ } catch (err) {
1693
+ if (numRetries > fullOptions.count || !await fullOptions.retryOnError(err)) {
1694
+ throw err;
1695
+ }
1696
+ await new Promise((resolve) => setTimeout(resolve, currentDelay));
1697
+ currentDelay *= fullOptions.exponent;
1698
+ numRetries++;
1699
+ continue;
1700
+ }
1701
+ if (!await fullOptions.retryOnValue(result)) {
1702
+ return result;
1703
+ }
1704
+ await new Promise((resolve) => setTimeout(resolve, currentDelay));
1705
+ currentDelay *= fullOptions.exponent;
1706
+ numRetries++;
1707
+ continue;
1708
+ }
1709
+ };
1710
+
1581
1711
  // src/safe-await.ts
1582
1712
  var safeAwaitAll = async (source, taskFactory, onError) => {
1583
1713
  const failedItems = [];
@@ -2276,15 +2406,19 @@ var createUrl = (url, search) => {
2276
2406
  // src/weak.ts
2277
2407
  var WeakDictionary = class {
2278
2408
  _internal = /* @__PURE__ */ new Map();
2279
- _finalization = new FinalizationRegistry((cleanUpCallback) => {
2280
- cleanUpCallback();
2409
+ _finalization = new FinalizationRegistry(({ key, ref }) => {
2410
+ if (this._internal.get(key) === ref) {
2411
+ this._internal.delete(key);
2412
+ }
2281
2413
  });
2282
2414
  constructor(entries2) {
2283
- this._internal = new Map(entries2?.map(([key, value]) => [
2284
- key,
2285
- new WeakRef(value)
2286
- ]));
2287
- entries2?.forEach(([key, value]) => this._register(key, value));
2415
+ if (entries2) {
2416
+ for (const [key, value] of entries2) {
2417
+ const ref = new WeakRef(value);
2418
+ this._internal.set(key, ref);
2419
+ this._register(key, value, ref);
2420
+ }
2421
+ }
2288
2422
  }
2289
2423
  *entries() {
2290
2424
  for (const [key, value] of this._internal) {
@@ -2324,10 +2458,45 @@ var WeakDictionary = class {
2324
2458
  return this._internal.get(key)?.deref();
2325
2459
  }
2326
2460
  set(key, value) {
2327
- this._internal.set(key, new WeakRef(value));
2328
- this._register(key, value);
2461
+ const previous = this._internal.get(key)?.deref();
2462
+ if (previous) {
2463
+ this._unregister(previous);
2464
+ }
2465
+ const ref = new WeakRef(value);
2466
+ this._internal.set(key, ref);
2467
+ this._register(key, value, ref);
2329
2468
  return this;
2330
2469
  }
2470
+ /**
2471
+ * Returns the value for the given key if present, otherwise inserts and returns the default value.
2472
+ * @param key - The key to look up or insert.
2473
+ * @param defaultValue - The value to insert if the key is not present.
2474
+ * @returns The existing or newly inserted value.
2475
+ */
2476
+ getOrInsert(key, defaultValue) {
2477
+ const existing = this.get(key);
2478
+ if (existing !== void 0) {
2479
+ return existing;
2480
+ }
2481
+ this.set(key, defaultValue);
2482
+ return defaultValue;
2483
+ }
2484
+ /**
2485
+ * Returns the value for the given key if present, otherwise computes, inserts, and returns a new value.
2486
+ * The callback is only invoked when the key is missing.
2487
+ * @param key - The key to look up or insert.
2488
+ * @param callbackfn - Function to compute the value if the key is not present.
2489
+ * @returns The existing or newly computed value.
2490
+ */
2491
+ getOrInsertComputed(key, callbackfn) {
2492
+ const existing = this.get(key);
2493
+ if (existing !== void 0) {
2494
+ return existing;
2495
+ }
2496
+ const value = callbackfn(key);
2497
+ this.set(key, value);
2498
+ return value;
2499
+ }
2331
2500
  has(key) {
2332
2501
  return this._internal.has(key) && this._internal.get(key).deref() !== void 0;
2333
2502
  }
@@ -2358,67 +2527,16 @@ var WeakDictionary = class {
2358
2527
  }
2359
2528
  });
2360
2529
  }
2361
- _register(key, value) {
2362
- this._finalization.register(value, () => {
2363
- this._internal.delete(key);
2530
+ _register(key, value, ref) {
2531
+ this._finalization.register(value, {
2532
+ key,
2533
+ ref
2364
2534
  }, value);
2365
2535
  }
2366
2536
  _unregister(value) {
2367
2537
  this._finalization.unregister(value);
2368
2538
  }
2369
2539
  };
2370
-
2371
- // src/error-format.ts
2372
- var formatErrorWithCauses = (error) => {
2373
- const lines = [];
2374
- let current = error;
2375
- let level = 0;
2376
- while (current) {
2377
- const prefix = level === 0 ? "" : `Caused by: `;
2378
- lines.push(prefix + (current.stack ?? String(current)));
2379
- if (!(current.cause instanceof Error)) break;
2380
- current = current.cause;
2381
- level += 1;
2382
- }
2383
- return lines.join("\n\n");
2384
- };
2385
-
2386
- // src/retry.ts
2387
- var DEFAULT_RETRY_OPTIONS = {
2388
- count: 3,
2389
- delayMs: 100,
2390
- exponent: 2,
2391
- retryOnError: async () => true,
2392
- retryOnValue: async () => false
2393
- };
2394
- var retry = async (options, cb) => {
2395
- const fullOptions = {
2396
- ...DEFAULT_RETRY_OPTIONS,
2397
- ...options
2398
- };
2399
- let numRetries = 0, currentDelay = fullOptions.delayMs;
2400
- while (true) {
2401
- let result;
2402
- try {
2403
- result = await cb();
2404
- } catch (err) {
2405
- if (numRetries > fullOptions.count || !await fullOptions.retryOnError(err)) {
2406
- throw err;
2407
- }
2408
- await new Promise((resolve) => setTimeout(resolve, currentDelay));
2409
- currentDelay *= fullOptions.exponent;
2410
- numRetries++;
2411
- continue;
2412
- }
2413
- if (!await fullOptions.retryOnValue(result)) {
2414
- return result;
2415
- }
2416
- await new Promise((resolve) => setTimeout(resolve, currentDelay));
2417
- currentDelay *= fullOptions.exponent;
2418
- numRetries++;
2419
- continue;
2420
- }
2421
- };
2422
2540
  export {
2423
2541
  BitField,
2424
2542
  Callback,
@@ -2446,12 +2564,17 @@ export {
2446
2564
  capitalize,
2447
2565
  chunkArray,
2448
2566
  clamp,
2567
+ clearCaches,
2568
+ clearIndexedDB,
2569
+ clearOPFS,
2570
+ clearServiceWorkers,
2449
2571
  clearUndefined,
2450
2572
  coerceArray,
2451
2573
  compareMulti,
2452
2574
  compareObject,
2453
2575
  compareScalar,
2454
2576
  compareString,
2577
+ compositeKey,
2455
2578
  createBinder,
2456
2579
  createBucketReducer,
2457
2580
  createFilename,
@@ -2541,6 +2664,7 @@ export {
2541
2664
  safeUrl,
2542
2665
  setDeep,
2543
2666
  sortKeys,
2667
+ splitCompositeKey,
2544
2668
  stringToArray,
2545
2669
  stringifyTree,
2546
2670
  stripUndefined,