@dxos/util 0.8.4-main.ef1bc66f44 → 0.8.4-main.f466a3d56e

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/LICENSE +102 -5
  2. package/dist/lib/browser/index.mjs +281 -180
  3. package/dist/lib/browser/index.mjs.map +4 -4
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/lib/node-esm/index.mjs +281 -180
  6. package/dist/lib/node-esm/index.mjs.map +4 -4
  7. package/dist/lib/node-esm/meta.json +1 -1
  8. package/dist/types/src/array-to-hex.d.ts.map +1 -1
  9. package/dist/types/src/array.d.ts.map +1 -1
  10. package/dist/types/src/binder.d.ts.map +1 -1
  11. package/dist/types/src/bitfield.d.ts.map +1 -1
  12. package/dist/types/src/browser-storage.d.ts +9 -0
  13. package/dist/types/src/browser-storage.d.ts.map +1 -0
  14. package/dist/types/src/callback-collection.d.ts.map +1 -1
  15. package/dist/types/src/callback.d.ts.map +1 -1
  16. package/dist/types/src/case.d.ts.map +1 -1
  17. package/dist/types/src/chunk-array.d.ts.map +1 -1
  18. package/dist/types/src/circular-buffer.d.ts +1 -0
  19. package/dist/types/src/circular-buffer.d.ts.map +1 -1
  20. package/dist/types/src/clear-undefined.d.ts.map +1 -1
  21. package/dist/types/src/complex.d.ts +15 -0
  22. package/dist/types/src/complex.d.ts.map +1 -1
  23. package/dist/types/src/composite-key.d.ts +10 -0
  24. package/dist/types/src/composite-key.d.ts.map +1 -0
  25. package/dist/types/src/composite-key.test.d.ts +2 -0
  26. package/dist/types/src/composite-key.test.d.ts.map +1 -0
  27. package/dist/types/src/deep.d.ts +0 -3
  28. package/dist/types/src/deep.d.ts.map +1 -1
  29. package/dist/types/src/defer-function.d.ts.map +1 -1
  30. package/dist/types/src/defer.d.ts.map +1 -1
  31. package/dist/types/src/di-container.d.ts.map +1 -1
  32. package/dist/types/src/di-key.d.ts +7 -5
  33. package/dist/types/src/di-key.d.ts.map +1 -1
  34. package/dist/types/src/entry.d.ts.map +1 -1
  35. package/dist/types/src/error-format.d.ts.map +1 -1
  36. package/dist/types/src/filename.d.ts.map +1 -1
  37. package/dist/types/src/for-each-async.d.ts.map +1 -1
  38. package/dist/types/src/human-hash.d.ts.map +1 -1
  39. package/dist/types/src/id.d.ts +30 -0
  40. package/dist/types/src/id.d.ts.map +1 -0
  41. package/dist/types/src/id.test.d.ts +2 -0
  42. package/dist/types/src/id.test.d.ts.map +1 -0
  43. package/dist/types/src/index.d.ts +5 -2
  44. package/dist/types/src/index.d.ts.map +1 -1
  45. package/dist/types/src/instance-id.d.ts.map +1 -1
  46. package/dist/types/src/interval.d.ts.map +1 -1
  47. package/dist/types/src/join-tables.d.ts.map +1 -1
  48. package/dist/types/src/json.d.ts.map +1 -1
  49. package/dist/types/src/map-values.d.ts.map +1 -1
  50. package/dist/types/src/map.d.ts.map +1 -1
  51. package/dist/types/src/object.d.ts.map +1 -1
  52. package/dist/types/src/order-keys.d.ts.map +1 -1
  53. package/dist/types/src/order.d.ts.map +1 -1
  54. package/dist/types/src/pick.d.ts.map +1 -1
  55. package/dist/types/src/platform.d.ts +1 -1
  56. package/dist/types/src/platform.d.ts.map +1 -1
  57. package/dist/types/src/position.d.ts +5 -5
  58. package/dist/types/src/position.d.ts.map +1 -1
  59. package/dist/types/src/random.d.ts.map +1 -1
  60. package/dist/types/src/range.d.ts.map +1 -1
  61. package/dist/types/src/reducers.d.ts.map +1 -1
  62. package/dist/types/src/remove-undefined-keys.d.ts.map +1 -1
  63. package/dist/types/src/retry.d.ts.map +1 -1
  64. package/dist/types/src/safe-await.d.ts.map +1 -1
  65. package/dist/types/src/safe-instanceof.d.ts.map +1 -1
  66. package/dist/types/src/safe-parse.d.ts +1 -0
  67. package/dist/types/src/safe-parse.d.ts.map +1 -1
  68. package/dist/types/src/safe-stringify.d.ts +1 -1
  69. package/dist/types/src/safe-stringify.d.ts.map +1 -1
  70. package/dist/types/src/safe-stringify.test.d.ts +2 -0
  71. package/dist/types/src/safe-stringify.test.d.ts.map +1 -0
  72. package/dist/types/src/sliding-window-summary.d.ts.map +1 -1
  73. package/dist/types/src/sort.d.ts.map +1 -1
  74. package/dist/types/src/string.d.ts.map +1 -1
  75. package/dist/types/src/sum.d.ts.map +1 -1
  76. package/dist/types/src/throw-unhandled-error.d.ts.map +1 -1
  77. package/dist/types/src/to-fallback.d.ts +18 -4
  78. package/dist/types/src/to-fallback.d.ts.map +1 -1
  79. package/dist/types/src/tracer.d.ts.map +1 -1
  80. package/dist/types/src/tree.d.ts.map +1 -1
  81. package/dist/types/src/types.d.ts +1 -1
  82. package/dist/types/src/types.d.ts.map +1 -1
  83. package/dist/types/src/uint8array.d.ts.map +1 -1
  84. package/dist/types/src/unit.d.ts.map +1 -1
  85. package/dist/types/src/url.d.ts.map +1 -1
  86. package/dist/types/src/weak.d.ts +15 -0
  87. package/dist/types/src/weak.d.ts.map +1 -1
  88. package/dist/types/tsconfig.tsbuildinfo +1 -1
  89. package/package.json +7 -14
  90. package/src/browser-storage.ts +60 -0
  91. package/src/circular-buffer.test.ts +26 -0
  92. package/src/circular-buffer.ts +5 -0
  93. package/src/complex.ts +32 -0
  94. package/src/composite-key.test.ts +31 -0
  95. package/src/composite-key.ts +16 -0
  96. package/src/deep.ts +0 -6
  97. package/src/di-key.ts +10 -8
  98. package/src/error-format.ts +3 -1
  99. package/src/id.test.ts +109 -0
  100. package/src/id.ts +48 -0
  101. package/src/index.ts +5 -2
  102. package/src/platform.ts +27 -5
  103. package/src/position.test.ts +38 -44
  104. package/src/position.ts +7 -11
  105. package/src/safe-parse.ts +8 -0
  106. package/src/safe-stringify.test.ts +96 -0
  107. package/src/safe-stringify.ts +15 -8
  108. package/src/string.ts +6 -2
  109. package/src/to-fallback.ts +39 -156
  110. package/src/types.ts +1 -1
  111. package/src/unit.ts +6 -2
  112. package/src/weak.ts +52 -14
@@ -119,7 +119,6 @@ var createBinder = (obj) => ({
119
119
 
120
120
  // src/bitfield.ts
121
121
  import { invariant } from "@dxos/invariant";
122
- var __dxlog_file = "/__w/dxos/dxos/packages/common/util/src/bitfield.ts";
123
122
  var BitField = class _BitField {
124
123
  static get(data, idx) {
125
124
  const bit = data[idx >> 3] >> 7 - idx % 8 & 1;
@@ -151,15 +150,7 @@ var BitField = class _BitField {
151
150
  return result;
152
151
  }
153
152
  static and(first, second) {
154
- invariant(first.length === second.length, "Bitfields must be of the same length", {
155
- F: __dxlog_file,
156
- L: 52,
157
- S: this,
158
- A: [
159
- "first.length === second.length",
160
- "'Bitfields must be of the same length'"
161
- ]
162
- });
153
+ invariant(first.length === second.length, "Bitfields must be of the same length");
163
154
  const result = new Uint8Array(first.length);
164
155
  for (let i = 0; i < first.length; i++) {
165
156
  result[i] = first[i] & second[i];
@@ -187,6 +178,49 @@ var BitField = class _BitField {
187
178
  }
188
179
  };
189
180
 
181
+ // src/browser-storage.ts
182
+ var clearIndexedDB = async () => {
183
+ const dbs = await indexedDB.databases();
184
+ const results = await Promise.allSettled(dbs.filter((db) => db.name != null).map((db) => new Promise((resolve, reject) => {
185
+ const request = indexedDB.deleteDatabase(db.name);
186
+ request.onsuccess = () => resolve();
187
+ request.onerror = () => reject(request.error);
188
+ request.onblocked = () => reject(new Error(`IndexedDB deletion blocked: ${db.name}`));
189
+ })));
190
+ const failures = results.filter((r) => r.status === "rejected");
191
+ if (failures.length > 0) {
192
+ throw new AggregateError(failures.map((r) => r.reason), "Failed to delete some IndexedDB databases");
193
+ }
194
+ };
195
+ var clearOPFS = async () => {
196
+ const root = await navigator.storage.getDirectory();
197
+ const errors = [];
198
+ for await (const [name] of root.entries()) {
199
+ try {
200
+ await root.removeEntry(name, {
201
+ recursive: true
202
+ });
203
+ } catch (err) {
204
+ errors.push(err);
205
+ }
206
+ }
207
+ if (errors.length > 0) {
208
+ throw new AggregateError(errors, "Failed to remove some OPFS entries");
209
+ }
210
+ };
211
+ var clearServiceWorkers = async () => {
212
+ const regs = await navigator.serviceWorker.getRegistrations();
213
+ for (const reg of regs) {
214
+ await reg.unregister();
215
+ }
216
+ };
217
+ var clearCaches = async () => {
218
+ const keys2 = await caches.keys();
219
+ for (const key of keys2) {
220
+ await caches.delete(key);
221
+ }
222
+ };
223
+
190
224
  // src/callback-collection.ts
191
225
  var CallbackCollection = class {
192
226
  #callbacks = [];
@@ -213,34 +247,17 @@ var CallbackCollection = class {
213
247
 
214
248
  // src/callback.ts
215
249
  import { invariant as invariant2 } from "@dxos/invariant";
216
- var __dxlog_file2 = "/__w/dxos/dxos/packages/common/util/src/callback.ts";
217
250
  var Callback = class {
218
251
  _callback;
219
252
  call(...args) {
220
- invariant2(this._callback, "Callback not set", {
221
- F: __dxlog_file2,
222
- L: 20,
223
- S: this,
224
- A: [
225
- "this._callback",
226
- "'Callback not set'"
227
- ]
228
- });
253
+ invariant2(this._callback, "Callback not set");
229
254
  return this._callback(...args);
230
255
  }
231
256
  callIfSet(...args) {
232
257
  return this._callback?.(...args);
233
258
  }
234
259
  set(callback) {
235
- invariant2(!this._callback, "Callback already set", {
236
- F: __dxlog_file2,
237
- L: 29,
238
- S: this,
239
- A: [
240
- "!this._callback",
241
- "'Callback already set'"
242
- ]
243
- });
260
+ invariant2(!this._callback, "Callback already set");
244
261
  this._callback = callback;
245
262
  }
246
263
  isSet() {
@@ -308,21 +325,12 @@ var chunkArray = (array, size) => {
308
325
 
309
326
  // src/circular-buffer.ts
310
327
  import { invariant as invariant3 } from "@dxos/invariant";
311
- var __dxlog_file3 = "/__w/dxos/dxos/packages/common/util/src/circular-buffer.ts";
312
328
  var CircularBuffer = class {
313
329
  _buffer;
314
330
  _nextIndex = 0;
315
331
  _elementCount = 0;
316
332
  constructor(size) {
317
- invariant3(size >= 1, void 0, {
318
- F: __dxlog_file3,
319
- L: 13,
320
- S: this,
321
- A: [
322
- "size >= 1",
323
- ""
324
- ]
325
- });
333
+ invariant3(size >= 1);
326
334
  this._buffer = new Array(size);
327
335
  }
328
336
  push(element) {
@@ -335,6 +343,10 @@ var CircularBuffer = class {
335
343
  get elementCount() {
336
344
  return this._elementCount;
337
345
  }
346
+ clear() {
347
+ this._nextIndex = 0;
348
+ this._elementCount = 0;
349
+ }
338
350
  getLast() {
339
351
  if (this._elementCount === 0) {
340
352
  return void 0;
@@ -528,6 +540,36 @@ var ComplexMap = class _ComplexMap {
528
540
  this._values.set(primitive, value);
529
541
  return this;
530
542
  }
543
+ /**
544
+ * Returns the value for the given key if present, otherwise inserts and returns the default value.
545
+ * @param key - The key to look up or insert.
546
+ * @param defaultValue - The value to insert if the key is not present.
547
+ * @returns The existing or newly inserted value.
548
+ */
549
+ getOrInsert(key, defaultValue) {
550
+ const primitive = this._keyProjection(key);
551
+ if (this._values.has(primitive)) {
552
+ return this._values.get(primitive);
553
+ }
554
+ this.set(key, defaultValue);
555
+ return defaultValue;
556
+ }
557
+ /**
558
+ * Returns the value for the given key if present, otherwise computes, inserts, and returns a new value.
559
+ * The callback is only invoked when the key is missing.
560
+ * @param key - The key to look up or insert.
561
+ * @param callbackfn - Function to compute the value if the key is not present.
562
+ * @returns The existing or newly computed value.
563
+ */
564
+ getOrInsertComputed(key, callbackfn) {
565
+ const primitive = this._keyProjection(key);
566
+ if (this._values.has(primitive)) {
567
+ return this._values.get(primitive);
568
+ }
569
+ const value = callbackfn(key);
570
+ this.set(key, value);
571
+ return value;
572
+ }
531
573
  get size() {
532
574
  return this._keys.size;
533
575
  }
@@ -567,21 +609,15 @@ var makeMap = (keyProjection) => class BoundComplexMap extends ComplexMap {
567
609
  }
568
610
  };
569
611
 
612
+ // src/composite-key.ts
613
+ var SEPARATOR = ":";
614
+ var compositeKey = (...parts) => parts.join(SEPARATOR);
615
+ var splitCompositeKey = (key) => key.split(SEPARATOR);
616
+
570
617
  // src/deep.ts
571
- import get from "lodash.get";
572
- import set from "lodash.set";
573
618
  import { invariant as invariant4 } from "@dxos/invariant";
574
- var __dxlog_file4 = "/__w/dxos/dxos/packages/common/util/src/deep.ts";
575
619
  var setDeep = (obj, path, value) => {
576
- invariant4(path.length > 0, void 0, {
577
- F: __dxlog_file4,
578
- L: 18,
579
- S: void 0,
580
- A: [
581
- "path.length > 0",
582
- ""
583
- ]
584
- });
620
+ invariant4(path.length > 0);
585
621
  let parent = obj;
586
622
  for (const key of path.slice(0, -1)) {
587
623
  if (parent[key] === void 0) {
@@ -666,6 +702,23 @@ var MapEntry = class {
666
702
  }
667
703
  };
668
704
 
705
+ // src/error-format.ts
706
+ var formatErrorWithCauses = (error) => {
707
+ const lines = [];
708
+ let current = error;
709
+ let level = 0;
710
+ while (current) {
711
+ const prefix = level === 0 ? "" : `Caused by: `;
712
+ lines.push(prefix + (current.stack ?? String(current)));
713
+ if (!(current.cause instanceof Error)) {
714
+ break;
715
+ }
716
+ current = current.cause;
717
+ level += 1;
718
+ }
719
+ return lines.join("\n\n");
720
+ };
721
+
669
722
  // src/filename.ts
670
723
  var createFilename = ({ parts = [], ext, date = /* @__PURE__ */ new Date() }) => [
671
724
  date.toISOString().replace(/[:.]/g, "-"),
@@ -1007,6 +1060,19 @@ var humanize = (value) => {
1007
1060
  return hasher.humanize(value);
1008
1061
  };
1009
1062
 
1063
+ // src/id.ts
1064
+ var PART = /^[a-zA-Z][a-zA-Z0-9]{0,62}$/;
1065
+ var ID = /^[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(\.[a-zA-Z]([a-zA-Z0-9]{0,62})?)$/;
1066
+ function id(strings, ...values) {
1067
+ const raw = strings.reduce((out, str, i) => out + str + (i < values.length ? String(values[i]) : ""), "");
1068
+ if (!ID.test(raw)) {
1069
+ throw new Error(`Invalid id (expected AT Protocol NSID): ${JSON.stringify(raw)}`);
1070
+ }
1071
+ return raw;
1072
+ }
1073
+ var isWellFormedId = (value) => ID.test(value);
1074
+ var isWellFormedIdPart = (value) => PART.test(value);
1075
+
1010
1076
  // src/map.ts
1011
1077
  var defaultMap = (map, key, def) => {
1012
1078
  let value = map.get(key);
@@ -1018,7 +1084,7 @@ var defaultMap = (map, key, def) => {
1018
1084
  };
1019
1085
 
1020
1086
  // src/instance-id.ts
1021
- var symbol = Symbol.for("dxos.instance-contexts");
1087
+ var symbol = /* @__PURE__ */ Symbol.for("dxos.instance-contexts");
1022
1088
  var instanceContexts = globalThis[symbol] ??= /* @__PURE__ */ new WeakMap();
1023
1089
  var getPrototypeSpecificInstanceId = (instance) => {
1024
1090
  const prototype = Object.getPrototypeOf(instance);
@@ -1026,12 +1092,12 @@ var getPrototypeSpecificInstanceId = (instance) => {
1026
1092
  nextId: 0,
1027
1093
  instanceIds: /* @__PURE__ */ new WeakMap()
1028
1094
  }));
1029
- let id = instanceCtx.instanceIds.get(instance);
1030
- if (id === void 0) {
1031
- id = instanceCtx.nextId++;
1032
- instanceCtx.instanceIds.set(instance, id);
1095
+ let id2 = instanceCtx.instanceIds.get(instance);
1096
+ if (id2 === void 0) {
1097
+ id2 = instanceCtx.nextId++;
1098
+ instanceCtx.instanceIds.set(instance, id2);
1033
1099
  }
1034
- return id;
1100
+ return id2;
1035
1101
  };
1036
1102
  var getDebugName = (instance) => {
1037
1103
  if (instance == null) {
@@ -1312,27 +1378,27 @@ var orderKeys = (obj, order) => {
1312
1378
 
1313
1379
  // src/order.ts
1314
1380
  var inferObjectOrder = (objectMap, order = []) => {
1315
- const orderedObjects = order.reduce((acc, id) => {
1316
- if (id in objectMap) {
1317
- acc.objects.push(objectMap[id]);
1318
- acc.ids.add(id);
1381
+ const orderedObjects = order.reduce((acc, id2) => {
1382
+ if (id2 in objectMap) {
1383
+ acc.objects.push(objectMap[id2]);
1384
+ acc.ids.add(id2);
1319
1385
  }
1320
1386
  return acc;
1321
1387
  }, {
1322
1388
  objects: [],
1323
1389
  ids: /* @__PURE__ */ new Set()
1324
1390
  });
1325
- const { objects } = Object.keys(objectMap).reduce((acc, id) => {
1326
- if (!acc.ids.has(id)) {
1327
- acc.objects.push(objectMap[id]);
1391
+ const { objects } = Object.keys(objectMap).reduce((acc, id2) => {
1392
+ if (!acc.ids.has(id2)) {
1393
+ acc.objects.push(objectMap[id2]);
1328
1394
  }
1329
1395
  return acc;
1330
1396
  }, orderedObjects);
1331
1397
  return objects;
1332
1398
  };
1333
1399
  var inferRecordOrder = (objectMap, order = []) => {
1334
- return Object.assign(order.filter((id) => id in objectMap).reduce((acc, id) => {
1335
- acc[id] = null;
1400
+ return Object.assign(order.filter((id2) => id2 in objectMap).reduce((acc, id2) => {
1401
+ acc[id2] = null;
1336
1402
  return acc;
1337
1403
  }, {}), objectMap);
1338
1404
  };
@@ -1418,12 +1484,12 @@ var getHostPlatform = () => {
1418
1484
  };
1419
1485
 
1420
1486
  // src/position.ts
1421
- var byPosition = ({ position: a = "static" }, { position: b = "static" }) => {
1487
+ var byPosition = ({ position: a }, { position: b }) => {
1422
1488
  if (a === b) {
1423
1489
  return 0;
1424
- } else if (a === "hoist" || b === "fallback") {
1490
+ } else if (a === "first" || b === "last") {
1425
1491
  return -1;
1426
- } else if (b === "hoist" || a === "fallback") {
1492
+ } else if (b === "first" || a === "last") {
1427
1493
  return 1;
1428
1494
  } else {
1429
1495
  return 0;
@@ -1576,6 +1642,43 @@ var removeProperties = (root, condition) => {
1576
1642
  return result;
1577
1643
  };
1578
1644
 
1645
+ // src/retry.ts
1646
+ var DEFAULT_RETRY_OPTIONS = {
1647
+ count: 3,
1648
+ delayMs: 100,
1649
+ exponent: 2,
1650
+ retryOnError: async () => true,
1651
+ retryOnValue: async () => false
1652
+ };
1653
+ var retry = async (options, cb) => {
1654
+ const fullOptions = {
1655
+ ...DEFAULT_RETRY_OPTIONS,
1656
+ ...options
1657
+ };
1658
+ let numRetries = 0, currentDelay = fullOptions.delayMs;
1659
+ while (true) {
1660
+ let result;
1661
+ try {
1662
+ result = await cb();
1663
+ } catch (err) {
1664
+ if (numRetries > fullOptions.count || !await fullOptions.retryOnError(err)) {
1665
+ throw err;
1666
+ }
1667
+ await new Promise((resolve) => setTimeout(resolve, currentDelay));
1668
+ currentDelay *= fullOptions.exponent;
1669
+ numRetries++;
1670
+ continue;
1671
+ }
1672
+ if (!await fullOptions.retryOnValue(result)) {
1673
+ return result;
1674
+ }
1675
+ await new Promise((resolve) => setTimeout(resolve, currentDelay));
1676
+ currentDelay *= fullOptions.exponent;
1677
+ numRetries++;
1678
+ continue;
1679
+ }
1680
+ };
1681
+
1579
1682
  // src/safe-await.ts
1580
1683
  var safeAwaitAll = async (source, taskFactory, onError) => {
1581
1684
  const failedItems = [];
@@ -1595,7 +1698,7 @@ var safeAwaitAll = async (source, taskFactory, onError) => {
1595
1698
  };
1596
1699
 
1597
1700
  // src/safe-instanceof.ts
1598
- var instanceTag = Symbol("instanceTag");
1701
+ var instanceTag = /* @__PURE__ */ Symbol("instanceTag");
1599
1702
  var safeInstanceof = (tag) => (target) => {
1600
1703
  target.prototype[instanceTag] = tag;
1601
1704
  Object.defineProperty(target.prototype, Symbol.hasInstance, {
@@ -1632,6 +1735,13 @@ var safeParseJson = (str, defaultValue) => {
1632
1735
  }
1633
1736
  return defaultValue;
1634
1737
  };
1738
+ var safeUrl = (str) => {
1739
+ try {
1740
+ return new URL(str ?? "");
1741
+ } catch {
1742
+ return void 0;
1743
+ }
1744
+ };
1635
1745
 
1636
1746
  // src/safe-stringify.ts
1637
1747
  var SKIP = Object.freeze({});
@@ -1642,6 +1752,9 @@ function safeStringify(obj, filter = defaultFilter, indent = 2) {
1642
1752
  let path = key;
1643
1753
  if (!key) {
1644
1754
  path = "$";
1755
+ if (value != null && typeof value === "object") {
1756
+ seen.set(value, path);
1757
+ }
1645
1758
  return value;
1646
1759
  } else if (this) {
1647
1760
  const parentPath = seen.get(this);
@@ -1653,7 +1766,7 @@ function safeStringify(obj, filter = defaultFilter, indent = 2) {
1653
1766
  if (typeof value === "function") {
1654
1767
  return void 0;
1655
1768
  }
1656
- if (typeof value === "object" && Object.getPrototypeOf(value) !== Object.prototype) {
1769
+ if (typeof value === "object" && Object.getPrototypeOf(value) !== Object.prototype && !Array.isArray(value)) {
1657
1770
  return void 0;
1658
1771
  }
1659
1772
  if (typeof value === "object" && value !== null) {
@@ -1674,7 +1787,11 @@ function safeStringify(obj, filter = defaultFilter, indent = 2) {
1674
1787
  return `ERROR: ${error.message}`;
1675
1788
  }
1676
1789
  }
1677
- return JSON.stringify(obj, replacer, indent);
1790
+ try {
1791
+ return JSON.stringify(obj, replacer, indent);
1792
+ } catch (error) {
1793
+ return `ERROR: ${error.message}`;
1794
+ }
1678
1795
  }
1679
1796
  var createReplacer = ({ omit: omit2, parse, maxDepth, maxArrayLen, maxStringLen } = {}) => {
1680
1797
  let currentDepth = 0;
@@ -1689,6 +1806,9 @@ var createReplacer = ({ omit: omit2, parse, maxDepth, maxArrayLen, maxStringLen
1689
1806
  if (typeof value === "function") {
1690
1807
  return SKIP;
1691
1808
  }
1809
+ if (maxArrayLen != null && Array.isArray(value) && value.length > maxArrayLen) {
1810
+ return `[length: ${value.length}]`;
1811
+ }
1692
1812
  if (value && typeof value === "object") {
1693
1813
  depthMap.set(value, currentDepth);
1694
1814
  if (maxDepth != null && currentDepth >= maxDepth) {
@@ -1705,9 +1825,6 @@ var createReplacer = ({ omit: omit2, parse, maxDepth, maxArrayLen, maxStringLen
1705
1825
  return value;
1706
1826
  }
1707
1827
  }
1708
- if (maxArrayLen != null && Array.isArray(value) && value.length > maxArrayLen) {
1709
- return `[length: ${value.length}]`;
1710
- }
1711
1828
  if (maxStringLen != null && typeof value === "string" && value.length > maxStringLen) {
1712
1829
  return value.slice(0, maxStringLen) + "...";
1713
1830
  }
@@ -1718,7 +1835,6 @@ var defaultFilter = createReplacer();
1718
1835
 
1719
1836
  // src/sliding-window-summary.ts
1720
1837
  import { invariant as invariant5 } from "@dxos/invariant";
1721
- var __dxlog_file5 = "/__w/dxos/dxos/packages/common/util/src/sliding-window-summary.ts";
1722
1838
  var SlidingWindowSummary = class {
1723
1839
  _buffer;
1724
1840
  _sum = 0;
@@ -1726,15 +1842,7 @@ var SlidingWindowSummary = class {
1726
1842
  constructor(options) {
1727
1843
  this._buffer = new CircularBuffer(options.dataPoints);
1728
1844
  if (options.precision != null) {
1729
- invariant5(options.precision >= 0, void 0, {
1730
- F: __dxlog_file5,
1731
- L: 26,
1732
- S: this,
1733
- A: [
1734
- "options.precision >= 0",
1735
- ""
1736
- ]
1737
- });
1845
+ invariant5(options.precision >= 0);
1738
1846
  this._precision = Math.pow(10, options.precision);
1739
1847
  }
1740
1848
  }
@@ -1815,8 +1923,12 @@ function trim(strings, ...values) {
1815
1923
  return out;
1816
1924
  }, "");
1817
1925
  const lines = raw.split("\n");
1818
- while (lines.length && !lines[0].trim()) lines.shift();
1819
- while (lines.length && !lines[lines.length - 1].trim()) lines.pop();
1926
+ while (lines.length && !lines[0].trim()) {
1927
+ lines.shift();
1928
+ }
1929
+ while (lines.length && !lines[lines.length - 1].trim()) {
1930
+ lines.pop();
1931
+ }
1820
1932
  const minIndent = Math.min(...lines.filter((l) => l.trim()).map((l) => l.match(/^[ \t]*/)?.[0].length ?? 0));
1821
1933
  return lines.map((l) => l.slice(minIndent)).join("\n");
1822
1934
  }
@@ -1834,18 +1946,6 @@ var throwUnhandledError = (error) => {
1834
1946
 
1835
1947
  // src/to-fallback.ts
1836
1948
  var idEmoji = [
1837
- // When changing this set, please check the result in a console or e.g. RunKit (https://runkit.com/thure/642214441dd6ae000855a8de)
1838
- // Emoji sometimes use a combination of code points, and some code points aren't visible on their own, so by adding or deleting you may unintentionally create non-visible items.
1839
- // This set was chosen from the characters in Unicode Emoji v15.0 based on the following criteria:
1840
- // – not people or isolated anthropomorphic faces
1841
- // – not flags
1842
- // – more concrete than abstract
1843
- // – less culturally specific
1844
- // – less easily confused with another emoji in the set
1845
- // – requires less special knowledge to identify
1846
- // – less likely to evoke negative feelings (no meat, no drugs, no weapons, etc)
1847
- // – less common as a signifier in UX
1848
- // NOTE that this is intentionally an array of strings because of the way emoji graphemes work.
1849
1949
  "\u{1F47B}",
1850
1950
  "\u{1F479}",
1851
1951
  "\u{1F47D}",
@@ -1981,17 +2081,18 @@ var idEmoji = [
1981
2081
  ];
1982
2082
  var idHue = [
1983
2083
  "red",
1984
- // 'orange' as const, /* More shades in these palettes are considered “ugly” */
2084
+ "orange",
1985
2085
  "amber",
1986
- // 'yellow' as const, /* More shades in these palettes are considered “ugly” */
2086
+ "yellow",
1987
2087
  "lime",
1988
2088
  "green",
1989
2089
  "emerald",
1990
2090
  "teal",
1991
2091
  "cyan",
1992
- // 'sky' as const, /* Omitted since it is quite similar to the primary accent palette */
1993
- // 'blue' as const, /* Omitted since it is quite similar to the primary accent palette */
1994
- // 'indigo' as const, /* Omitted since it is quite similar to the primary accent palette */
2092
+ // Omit colors similar to primary accent.
2093
+ // 'sky' as const,
2094
+ // 'blue' as const,
2095
+ // 'indigo' as const,
1995
2096
  "violet",
1996
2097
  "purple",
1997
2098
  "fuchsia",
@@ -2030,8 +2131,8 @@ var Tracer = class {
2030
2131
  keys() {
2031
2132
  return Array.from(this._events.keys());
2032
2133
  }
2033
- get(id, filter) {
2034
- const events = this._events.get(id);
2134
+ get(id2, filter) {
2135
+ const events = this._events.get(id2);
2035
2136
  if (filter) {
2036
2137
  return events?.filter((event) => Object.entries(filter).every(([key, value]) => event?.value[key] === value));
2037
2138
  }
@@ -2048,11 +2149,11 @@ var Tracer = class {
2048
2149
  this._recording = false;
2049
2150
  return this;
2050
2151
  }
2051
- emit(id, value) {
2052
- this._post(this._createEvent(id, value));
2152
+ emit(id2, value) {
2153
+ this._post(this._createEvent(id2, value));
2053
2154
  }
2054
- mark(id, value) {
2055
- const event = this._createEvent(id, value);
2155
+ mark(id2, value) {
2156
+ const event = this._createEvent(id2, value);
2056
2157
  const start = performance.now();
2057
2158
  return {
2058
2159
  start,
@@ -2062,9 +2163,9 @@ var Tracer = class {
2062
2163
  }
2063
2164
  };
2064
2165
  }
2065
- _createEvent(id, value) {
2166
+ _createEvent(id2, value) {
2066
2167
  const event = {
2067
- id,
2168
+ id: id2,
2068
2169
  timestamp: Date.now()
2069
2170
  };
2070
2171
  if (value !== void 0) {
@@ -2162,11 +2263,15 @@ function arraySwap(array, from, to) {
2162
2263
  var createFormat = (unit) => {
2163
2264
  return (n, precision = unit.precision ?? 0) => {
2164
2265
  const value = n / unit.quotient;
2266
+ const formattedValue = value.toLocaleString("en-US", {
2267
+ minimumFractionDigits: precision,
2268
+ maximumFractionDigits: precision
2269
+ });
2165
2270
  return {
2166
2271
  unit,
2167
2272
  value,
2168
- formattedValue: value.toFixed(precision),
2169
- toString: () => `${value.toFixed(precision)}${unit.symbol}`
2273
+ formattedValue,
2274
+ toString: () => `${formattedValue}${unit.symbol}`
2170
2275
  };
2171
2276
  };
2172
2277
  };
@@ -2271,15 +2376,19 @@ var createUrl = (url, search) => {
2271
2376
  // src/weak.ts
2272
2377
  var WeakDictionary = class {
2273
2378
  _internal = /* @__PURE__ */ new Map();
2274
- _finalization = new FinalizationRegistry((cleanUpCallback) => {
2275
- cleanUpCallback();
2379
+ _finalization = new FinalizationRegistry(({ key, ref }) => {
2380
+ if (this._internal.get(key) === ref) {
2381
+ this._internal.delete(key);
2382
+ }
2276
2383
  });
2277
2384
  constructor(entries2) {
2278
- this._internal = new Map(entries2?.map(([key, value]) => [
2279
- key,
2280
- new WeakRef(value)
2281
- ]));
2282
- entries2?.forEach(([key, value]) => this._register(key, value));
2385
+ if (entries2) {
2386
+ for (const [key, value] of entries2) {
2387
+ const ref = new WeakRef(value);
2388
+ this._internal.set(key, ref);
2389
+ this._register(key, value, ref);
2390
+ }
2391
+ }
2283
2392
  }
2284
2393
  *entries() {
2285
2394
  for (const [key, value] of this._internal) {
@@ -2319,10 +2428,45 @@ var WeakDictionary = class {
2319
2428
  return this._internal.get(key)?.deref();
2320
2429
  }
2321
2430
  set(key, value) {
2322
- this._internal.set(key, new WeakRef(value));
2323
- this._register(key, value);
2431
+ const previous = this._internal.get(key)?.deref();
2432
+ if (previous) {
2433
+ this._unregister(previous);
2434
+ }
2435
+ const ref = new WeakRef(value);
2436
+ this._internal.set(key, ref);
2437
+ this._register(key, value, ref);
2324
2438
  return this;
2325
2439
  }
2440
+ /**
2441
+ * Returns the value for the given key if present, otherwise inserts and returns the default value.
2442
+ * @param key - The key to look up or insert.
2443
+ * @param defaultValue - The value to insert if the key is not present.
2444
+ * @returns The existing or newly inserted value.
2445
+ */
2446
+ getOrInsert(key, defaultValue) {
2447
+ const existing = this.get(key);
2448
+ if (existing !== void 0) {
2449
+ return existing;
2450
+ }
2451
+ this.set(key, defaultValue);
2452
+ return defaultValue;
2453
+ }
2454
+ /**
2455
+ * Returns the value for the given key if present, otherwise computes, inserts, and returns a new value.
2456
+ * The callback is only invoked when the key is missing.
2457
+ * @param key - The key to look up or insert.
2458
+ * @param callbackfn - Function to compute the value if the key is not present.
2459
+ * @returns The existing or newly computed value.
2460
+ */
2461
+ getOrInsertComputed(key, callbackfn) {
2462
+ const existing = this.get(key);
2463
+ if (existing !== void 0) {
2464
+ return existing;
2465
+ }
2466
+ const value = callbackfn(key);
2467
+ this.set(key, value);
2468
+ return value;
2469
+ }
2326
2470
  has(key) {
2327
2471
  return this._internal.has(key) && this._internal.get(key).deref() !== void 0;
2328
2472
  }
@@ -2353,67 +2497,16 @@ var WeakDictionary = class {
2353
2497
  }
2354
2498
  });
2355
2499
  }
2356
- _register(key, value) {
2357
- this._finalization.register(value, () => {
2358
- this._internal.delete(key);
2500
+ _register(key, value, ref) {
2501
+ this._finalization.register(value, {
2502
+ key,
2503
+ ref
2359
2504
  }, value);
2360
2505
  }
2361
2506
  _unregister(value) {
2362
2507
  this._finalization.unregister(value);
2363
2508
  }
2364
2509
  };
2365
-
2366
- // src/error-format.ts
2367
- var formatErrorWithCauses = (error) => {
2368
- const lines = [];
2369
- let current = error;
2370
- let level = 0;
2371
- while (current) {
2372
- const prefix = level === 0 ? "" : `Caused by: `;
2373
- lines.push(prefix + (current.stack ?? String(current)));
2374
- if (!(current.cause instanceof Error)) break;
2375
- current = current.cause;
2376
- level += 1;
2377
- }
2378
- return lines.join("\n\n");
2379
- };
2380
-
2381
- // src/retry.ts
2382
- var DEFAULT_RETRY_OPTIONS = {
2383
- count: 3,
2384
- delayMs: 100,
2385
- exponent: 2,
2386
- retryOnError: async () => true,
2387
- retryOnValue: async () => false
2388
- };
2389
- var retry = async (options, cb) => {
2390
- const fullOptions = {
2391
- ...DEFAULT_RETRY_OPTIONS,
2392
- ...options
2393
- };
2394
- let numRetries = 0, currentDelay = fullOptions.delayMs;
2395
- while (true) {
2396
- let result;
2397
- try {
2398
- result = await cb();
2399
- } catch (err) {
2400
- if (numRetries > fullOptions.count || !await fullOptions.retryOnError(err)) {
2401
- throw err;
2402
- }
2403
- await new Promise((resolve) => setTimeout(resolve, currentDelay));
2404
- currentDelay *= fullOptions.exponent;
2405
- numRetries++;
2406
- continue;
2407
- }
2408
- if (!await fullOptions.retryOnValue(result)) {
2409
- return result;
2410
- }
2411
- await new Promise((resolve) => setTimeout(resolve, currentDelay));
2412
- currentDelay *= fullOptions.exponent;
2413
- numRetries++;
2414
- continue;
2415
- }
2416
- };
2417
2510
  export {
2418
2511
  BitField,
2419
2512
  Callback,
@@ -2441,12 +2534,17 @@ export {
2441
2534
  capitalize,
2442
2535
  chunkArray,
2443
2536
  clamp,
2537
+ clearCaches,
2538
+ clearIndexedDB,
2539
+ clearOPFS,
2540
+ clearServiceWorkers,
2444
2541
  clearUndefined,
2445
2542
  coerceArray,
2446
2543
  compareMulti,
2447
2544
  compareObject,
2448
2545
  compareScalar,
2449
2546
  compareString,
2547
+ compositeKey,
2450
2548
  createBinder,
2451
2549
  createBucketReducer,
2452
2550
  createFilename,
@@ -2470,7 +2568,6 @@ export {
2470
2568
  exponentialBackoffInterval,
2471
2569
  forEachAsync,
2472
2570
  formatErrorWithCauses,
2473
- get,
2474
2571
  getAsyncProviderValue,
2475
2572
  getDate,
2476
2573
  getDebugName,
@@ -2483,6 +2580,7 @@ export {
2483
2580
  hexToHue,
2484
2581
  humanize,
2485
2582
  hyphenize,
2583
+ id,
2486
2584
  idEmoji,
2487
2585
  idHue,
2488
2586
  inferObjectOrder,
@@ -2497,6 +2595,8 @@ export {
2497
2595
  isNonNullable,
2498
2596
  isTauri,
2499
2597
  isTruthy,
2598
+ isWellFormedId,
2599
+ isWellFormedIdPart,
2500
2600
  joinTables,
2501
2601
  jsonKeyReplacer,
2502
2602
  jsonReplacer,
@@ -2534,9 +2634,10 @@ export {
2534
2634
  safeParseInt,
2535
2635
  safeParseJson,
2536
2636
  safeStringify,
2537
- set,
2637
+ safeUrl,
2538
2638
  setDeep,
2539
2639
  sortKeys,
2640
+ splitCompositeKey,
2540
2641
  stringToArray,
2541
2642
  stringifyTree,
2542
2643
  stripUndefined,