@dxos/util 0.8.4-main.74a063c4e0 → 0.8.4-main.765dc60934

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 (88) hide show
  1. package/LICENSE +102 -5
  2. package/dist/lib/browser/index.mjs +239 -149
  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 +239 -149
  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.map +1 -1
  19. package/dist/types/src/clear-undefined.d.ts.map +1 -1
  20. package/dist/types/src/complex.d.ts +15 -0
  21. package/dist/types/src/complex.d.ts.map +1 -1
  22. package/dist/types/src/composite-key.d.ts.map +1 -1
  23. package/dist/types/src/deep.d.ts.map +1 -1
  24. package/dist/types/src/defer-function.d.ts.map +1 -1
  25. package/dist/types/src/defer.d.ts.map +1 -1
  26. package/dist/types/src/di-container.d.ts.map +1 -1
  27. package/dist/types/src/di-key.d.ts +7 -5
  28. package/dist/types/src/di-key.d.ts.map +1 -1
  29. package/dist/types/src/entry.d.ts.map +1 -1
  30. package/dist/types/src/error-format.d.ts.map +1 -1
  31. package/dist/types/src/filename.d.ts.map +1 -1
  32. package/dist/types/src/for-each-async.d.ts.map +1 -1
  33. package/dist/types/src/human-hash.d.ts.map +1 -1
  34. package/dist/types/src/id.d.ts +30 -0
  35. package/dist/types/src/id.d.ts.map +1 -0
  36. package/dist/types/src/id.test.d.ts +2 -0
  37. package/dist/types/src/id.test.d.ts.map +1 -0
  38. package/dist/types/src/index.d.ts +4 -2
  39. package/dist/types/src/index.d.ts.map +1 -1
  40. package/dist/types/src/instance-id.d.ts.map +1 -1
  41. package/dist/types/src/interval.d.ts.map +1 -1
  42. package/dist/types/src/join-tables.d.ts.map +1 -1
  43. package/dist/types/src/json.d.ts.map +1 -1
  44. package/dist/types/src/map-values.d.ts.map +1 -1
  45. package/dist/types/src/map.d.ts.map +1 -1
  46. package/dist/types/src/object.d.ts.map +1 -1
  47. package/dist/types/src/order-keys.d.ts.map +1 -1
  48. package/dist/types/src/order.d.ts.map +1 -1
  49. package/dist/types/src/pick.d.ts.map +1 -1
  50. package/dist/types/src/platform.d.ts +1 -1
  51. package/dist/types/src/position.d.ts +1 -1
  52. package/dist/types/src/position.d.ts.map +1 -1
  53. package/dist/types/src/random.d.ts.map +1 -1
  54. package/dist/types/src/range.d.ts.map +1 -1
  55. package/dist/types/src/reducers.d.ts.map +1 -1
  56. package/dist/types/src/remove-undefined-keys.d.ts.map +1 -1
  57. package/dist/types/src/retry.d.ts.map +1 -1
  58. package/dist/types/src/safe-await.d.ts.map +1 -1
  59. package/dist/types/src/safe-instanceof.d.ts.map +1 -1
  60. package/dist/types/src/safe-parse.d.ts.map +1 -1
  61. package/dist/types/src/safe-stringify.d.ts.map +1 -1
  62. package/dist/types/src/sliding-window-summary.d.ts.map +1 -1
  63. package/dist/types/src/sort.d.ts.map +1 -1
  64. package/dist/types/src/string.d.ts.map +1 -1
  65. package/dist/types/src/sum.d.ts.map +1 -1
  66. package/dist/types/src/throw-unhandled-error.d.ts.map +1 -1
  67. package/dist/types/src/to-fallback.d.ts +4 -4
  68. package/dist/types/src/to-fallback.d.ts.map +1 -1
  69. package/dist/types/src/tracer.d.ts.map +1 -1
  70. package/dist/types/src/tree.d.ts.map +1 -1
  71. package/dist/types/src/types.d.ts.map +1 -1
  72. package/dist/types/src/uint8array.d.ts.map +1 -1
  73. package/dist/types/src/unit.d.ts.map +1 -1
  74. package/dist/types/src/url.d.ts.map +1 -1
  75. package/dist/types/src/weak.d.ts +15 -0
  76. package/dist/types/src/weak.d.ts.map +1 -1
  77. package/dist/types/tsconfig.tsbuildinfo +1 -1
  78. package/package.json +7 -10
  79. package/src/browser-storage.ts +60 -0
  80. package/src/complex.ts +32 -0
  81. package/src/di-key.ts +10 -8
  82. package/src/error-format.ts +3 -1
  83. package/src/id.test.ts +109 -0
  84. package/src/id.ts +48 -0
  85. package/src/index.ts +4 -2
  86. package/src/string.ts +6 -2
  87. package/src/unit.ts +6 -2
  88. package/src/weak.ts +52 -14
package/LICENSE CHANGED
@@ -1,8 +1,105 @@
1
- MIT License
2
- Copyright (c) 2022 DXOS
1
+ # Functional Source License, Version 1.1, ALv2 Future License
3
2
 
4
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
3
+ ## Abbreviation
5
4
 
6
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
5
+ FSL-1.1-Apache-2.0
7
6
 
8
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
7
+ ## Notice
8
+
9
+ Copyright 2026 DXOS
10
+
11
+ ## Terms and Conditions
12
+
13
+ ### Licensor ("We")
14
+
15
+ The party offering the Software under these Terms and Conditions.
16
+
17
+ ### The Software
18
+
19
+ The "Software" is each version of the software that we make available under
20
+ these Terms and Conditions, as indicated by our inclusion of these Terms and
21
+ Conditions with the Software.
22
+
23
+ ### License Grant
24
+
25
+ Subject to your compliance with this License Grant and the Patents,
26
+ Redistribution and Trademark clauses below, we hereby grant you the right to
27
+ use, copy, modify, create derivative works, publicly perform, publicly display
28
+ and redistribute the Software for any Permitted Purpose identified below.
29
+
30
+ ### Permitted Purpose
31
+
32
+ A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
33
+ means making the Software available to others in a commercial product or
34
+ service that:
35
+
36
+ 1. substitutes for the Software;
37
+
38
+ 2. substitutes for any other product or service we offer using the Software
39
+ that exists as of the date we make the Software available; or
40
+
41
+ 3. offers the same or substantially similar functionality as the Software.
42
+
43
+ Permitted Purposes specifically include using the Software:
44
+
45
+ 1. for your internal use and access;
46
+
47
+ 2. for non-commercial education;
48
+
49
+ 3. for non-commercial research; and
50
+
51
+ 4. in connection with professional services that you provide to a licensee
52
+ using the Software in accordance with these Terms and Conditions.
53
+
54
+ ### Patents
55
+
56
+ To the extent your use for a Permitted Purpose would necessarily infringe our
57
+ patents, the license grant above includes a license under our patents. If you
58
+ make a claim against any party that the Software infringes or contributes to
59
+ the infringement of any patent, then your patent license to the Software ends
60
+ immediately.
61
+
62
+ ### Redistribution
63
+
64
+ The Terms and Conditions apply to all copies, modifications and derivatives of
65
+ the Software.
66
+
67
+ If you redistribute any copies, modifications or derivatives of the Software,
68
+ you must include a copy of or a link to these Terms and Conditions and not
69
+ remove any copyright notices provided in or with the Software.
70
+
71
+ ### Disclaimer
72
+
73
+ THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
74
+ IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
75
+ PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
76
+
77
+ IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
78
+ SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
79
+ EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
80
+
81
+ ### Trademarks
82
+
83
+ Except for displaying the License Details and identifying us as the origin of
84
+ the Software, you have no right under these Terms and Conditions to use our
85
+ trademarks, trade names, service marks or product names.
86
+
87
+ ## Grant of Future License
88
+
89
+ We hereby irrevocably grant you an additional license to use the Software under
90
+ the Apache License, Version 2.0 that is effective on the second anniversary of
91
+ the date we make the Software available. On or after that date, you may use the
92
+ Software under the Apache License, Version 2.0, in which case the following
93
+ will apply:
94
+
95
+ Licensed under the Apache License, Version 2.0 (the "License"); you may not use
96
+ this file except in compliance with the License.
97
+
98
+ You may obtain a copy of the License at
99
+
100
+ http://www.apache.org/licenses/LICENSE-2.0
101
+
102
+ Unless required by applicable law or agreed to in writing, software distributed
103
+ under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
104
+ CONDITIONS OF ANY KIND, either express or implied. See the License for the
105
+ specific language governing permissions and limitations under the License.
@@ -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) {
@@ -532,6 +540,36 @@ var ComplexMap = class _ComplexMap {
532
540
  this._values.set(primitive, value);
533
541
  return this;
534
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
+ }
535
573
  get size() {
536
574
  return this._keys.size;
537
575
  }
@@ -578,17 +616,8 @@ var splitCompositeKey = (key) => key.split(SEPARATOR);
578
616
 
579
617
  // src/deep.ts
580
618
  import { invariant as invariant4 } from "@dxos/invariant";
581
- var __dxlog_file4 = "/__w/dxos/dxos/packages/common/util/src/deep.ts";
582
619
  var setDeep = (obj, path, value) => {
583
- invariant4(path.length > 0, void 0, {
584
- F: __dxlog_file4,
585
- L: 12,
586
- S: void 0,
587
- A: [
588
- "path.length > 0",
589
- ""
590
- ]
591
- });
620
+ invariant4(path.length > 0);
592
621
  let parent = obj;
593
622
  for (const key of path.slice(0, -1)) {
594
623
  if (parent[key] === void 0) {
@@ -673,6 +702,23 @@ var MapEntry = class {
673
702
  }
674
703
  };
675
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
+
676
722
  // src/filename.ts
677
723
  var createFilename = ({ parts = [], ext, date = /* @__PURE__ */ new Date() }) => [
678
724
  date.toISOString().replace(/[:.]/g, "-"),
@@ -1014,6 +1060,19 @@ var humanize = (value) => {
1014
1060
  return hasher.humanize(value);
1015
1061
  };
1016
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
+
1017
1076
  // src/map.ts
1018
1077
  var defaultMap = (map, key, def) => {
1019
1078
  let value = map.get(key);
@@ -1033,12 +1092,12 @@ var getPrototypeSpecificInstanceId = (instance) => {
1033
1092
  nextId: 0,
1034
1093
  instanceIds: /* @__PURE__ */ new WeakMap()
1035
1094
  }));
1036
- let id = instanceCtx.instanceIds.get(instance);
1037
- if (id === void 0) {
1038
- id = instanceCtx.nextId++;
1039
- 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);
1040
1099
  }
1041
- return id;
1100
+ return id2;
1042
1101
  };
1043
1102
  var getDebugName = (instance) => {
1044
1103
  if (instance == null) {
@@ -1319,27 +1378,27 @@ var orderKeys = (obj, order) => {
1319
1378
 
1320
1379
  // src/order.ts
1321
1380
  var inferObjectOrder = (objectMap, order = []) => {
1322
- const orderedObjects = order.reduce((acc, id) => {
1323
- if (id in objectMap) {
1324
- acc.objects.push(objectMap[id]);
1325
- 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);
1326
1385
  }
1327
1386
  return acc;
1328
1387
  }, {
1329
1388
  objects: [],
1330
1389
  ids: /* @__PURE__ */ new Set()
1331
1390
  });
1332
- const { objects } = Object.keys(objectMap).reduce((acc, id) => {
1333
- if (!acc.ids.has(id)) {
1334
- 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]);
1335
1394
  }
1336
1395
  return acc;
1337
1396
  }, orderedObjects);
1338
1397
  return objects;
1339
1398
  };
1340
1399
  var inferRecordOrder = (objectMap, order = []) => {
1341
- return Object.assign(order.filter((id) => id in objectMap).reduce((acc, id) => {
1342
- acc[id] = null;
1400
+ return Object.assign(order.filter((id2) => id2 in objectMap).reduce((acc, id2) => {
1401
+ acc[id2] = null;
1343
1402
  return acc;
1344
1403
  }, {}), objectMap);
1345
1404
  };
@@ -1583,6 +1642,43 @@ var removeProperties = (root, condition) => {
1583
1642
  return result;
1584
1643
  };
1585
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
+
1586
1682
  // src/safe-await.ts
1587
1683
  var safeAwaitAll = async (source, taskFactory, onError) => {
1588
1684
  const failedItems = [];
@@ -1739,7 +1835,6 @@ var defaultFilter = createReplacer();
1739
1835
 
1740
1836
  // src/sliding-window-summary.ts
1741
1837
  import { invariant as invariant5 } from "@dxos/invariant";
1742
- var __dxlog_file5 = "/__w/dxos/dxos/packages/common/util/src/sliding-window-summary.ts";
1743
1838
  var SlidingWindowSummary = class {
1744
1839
  _buffer;
1745
1840
  _sum = 0;
@@ -1747,15 +1842,7 @@ var SlidingWindowSummary = class {
1747
1842
  constructor(options) {
1748
1843
  this._buffer = new CircularBuffer(options.dataPoints);
1749
1844
  if (options.precision != null) {
1750
- invariant5(options.precision >= 0, void 0, {
1751
- F: __dxlog_file5,
1752
- L: 26,
1753
- S: this,
1754
- A: [
1755
- "options.precision >= 0",
1756
- ""
1757
- ]
1758
- });
1845
+ invariant5(options.precision >= 0);
1759
1846
  this._precision = Math.pow(10, options.precision);
1760
1847
  }
1761
1848
  }
@@ -1836,8 +1923,12 @@ function trim(strings, ...values) {
1836
1923
  return out;
1837
1924
  }, "");
1838
1925
  const lines = raw.split("\n");
1839
- while (lines.length && !lines[0].trim()) lines.shift();
1840
- 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
+ }
1841
1932
  const minIndent = Math.min(...lines.filter((l) => l.trim()).map((l) => l.match(/^[ \t]*/)?.[0].length ?? 0));
1842
1933
  return lines.map((l) => l.slice(minIndent)).join("\n");
1843
1934
  }
@@ -2040,8 +2131,8 @@ var Tracer = class {
2040
2131
  keys() {
2041
2132
  return Array.from(this._events.keys());
2042
2133
  }
2043
- get(id, filter) {
2044
- const events = this._events.get(id);
2134
+ get(id2, filter) {
2135
+ const events = this._events.get(id2);
2045
2136
  if (filter) {
2046
2137
  return events?.filter((event) => Object.entries(filter).every(([key, value]) => event?.value[key] === value));
2047
2138
  }
@@ -2058,11 +2149,11 @@ var Tracer = class {
2058
2149
  this._recording = false;
2059
2150
  return this;
2060
2151
  }
2061
- emit(id, value) {
2062
- this._post(this._createEvent(id, value));
2152
+ emit(id2, value) {
2153
+ this._post(this._createEvent(id2, value));
2063
2154
  }
2064
- mark(id, value) {
2065
- const event = this._createEvent(id, value);
2155
+ mark(id2, value) {
2156
+ const event = this._createEvent(id2, value);
2066
2157
  const start = performance.now();
2067
2158
  return {
2068
2159
  start,
@@ -2072,9 +2163,9 @@ var Tracer = class {
2072
2163
  }
2073
2164
  };
2074
2165
  }
2075
- _createEvent(id, value) {
2166
+ _createEvent(id2, value) {
2076
2167
  const event = {
2077
- id,
2168
+ id: id2,
2078
2169
  timestamp: Date.now()
2079
2170
  };
2080
2171
  if (value !== void 0) {
@@ -2172,11 +2263,15 @@ function arraySwap(array, from, to) {
2172
2263
  var createFormat = (unit) => {
2173
2264
  return (n, precision = unit.precision ?? 0) => {
2174
2265
  const value = n / unit.quotient;
2266
+ const formattedValue = value.toLocaleString("en-US", {
2267
+ minimumFractionDigits: precision,
2268
+ maximumFractionDigits: precision
2269
+ });
2175
2270
  return {
2176
2271
  unit,
2177
2272
  value,
2178
- formattedValue: value.toFixed(precision),
2179
- toString: () => `${value.toFixed(precision)}${unit.symbol}`
2273
+ formattedValue,
2274
+ toString: () => `${formattedValue}${unit.symbol}`
2180
2275
  };
2181
2276
  };
2182
2277
  };
@@ -2281,15 +2376,19 @@ var createUrl = (url, search) => {
2281
2376
  // src/weak.ts
2282
2377
  var WeakDictionary = class {
2283
2378
  _internal = /* @__PURE__ */ new Map();
2284
- _finalization = new FinalizationRegistry((cleanUpCallback) => {
2285
- cleanUpCallback();
2379
+ _finalization = new FinalizationRegistry(({ key, ref }) => {
2380
+ if (this._internal.get(key) === ref) {
2381
+ this._internal.delete(key);
2382
+ }
2286
2383
  });
2287
2384
  constructor(entries2) {
2288
- this._internal = new Map(entries2?.map(([key, value]) => [
2289
- key,
2290
- new WeakRef(value)
2291
- ]));
2292
- 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
+ }
2293
2392
  }
2294
2393
  *entries() {
2295
2394
  for (const [key, value] of this._internal) {
@@ -2329,10 +2428,45 @@ var WeakDictionary = class {
2329
2428
  return this._internal.get(key)?.deref();
2330
2429
  }
2331
2430
  set(key, value) {
2332
- this._internal.set(key, new WeakRef(value));
2333
- 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);
2334
2438
  return this;
2335
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
+ }
2336
2470
  has(key) {
2337
2471
  return this._internal.has(key) && this._internal.get(key).deref() !== void 0;
2338
2472
  }
@@ -2363,67 +2497,16 @@ var WeakDictionary = class {
2363
2497
  }
2364
2498
  });
2365
2499
  }
2366
- _register(key, value) {
2367
- this._finalization.register(value, () => {
2368
- this._internal.delete(key);
2500
+ _register(key, value, ref) {
2501
+ this._finalization.register(value, {
2502
+ key,
2503
+ ref
2369
2504
  }, value);
2370
2505
  }
2371
2506
  _unregister(value) {
2372
2507
  this._finalization.unregister(value);
2373
2508
  }
2374
2509
  };
2375
-
2376
- // src/error-format.ts
2377
- var formatErrorWithCauses = (error) => {
2378
- const lines = [];
2379
- let current = error;
2380
- let level = 0;
2381
- while (current) {
2382
- const prefix = level === 0 ? "" : `Caused by: `;
2383
- lines.push(prefix + (current.stack ?? String(current)));
2384
- if (!(current.cause instanceof Error)) break;
2385
- current = current.cause;
2386
- level += 1;
2387
- }
2388
- return lines.join("\n\n");
2389
- };
2390
-
2391
- // src/retry.ts
2392
- var DEFAULT_RETRY_OPTIONS = {
2393
- count: 3,
2394
- delayMs: 100,
2395
- exponent: 2,
2396
- retryOnError: async () => true,
2397
- retryOnValue: async () => false
2398
- };
2399
- var retry = async (options, cb) => {
2400
- const fullOptions = {
2401
- ...DEFAULT_RETRY_OPTIONS,
2402
- ...options
2403
- };
2404
- let numRetries = 0, currentDelay = fullOptions.delayMs;
2405
- while (true) {
2406
- let result;
2407
- try {
2408
- result = await cb();
2409
- } catch (err) {
2410
- if (numRetries > fullOptions.count || !await fullOptions.retryOnError(err)) {
2411
- throw err;
2412
- }
2413
- await new Promise((resolve) => setTimeout(resolve, currentDelay));
2414
- currentDelay *= fullOptions.exponent;
2415
- numRetries++;
2416
- continue;
2417
- }
2418
- if (!await fullOptions.retryOnValue(result)) {
2419
- return result;
2420
- }
2421
- await new Promise((resolve) => setTimeout(resolve, currentDelay));
2422
- currentDelay *= fullOptions.exponent;
2423
- numRetries++;
2424
- continue;
2425
- }
2426
- };
2427
2510
  export {
2428
2511
  BitField,
2429
2512
  Callback,
@@ -2451,6 +2534,10 @@ export {
2451
2534
  capitalize,
2452
2535
  chunkArray,
2453
2536
  clamp,
2537
+ clearCaches,
2538
+ clearIndexedDB,
2539
+ clearOPFS,
2540
+ clearServiceWorkers,
2454
2541
  clearUndefined,
2455
2542
  coerceArray,
2456
2543
  compareMulti,
@@ -2493,6 +2580,7 @@ export {
2493
2580
  hexToHue,
2494
2581
  humanize,
2495
2582
  hyphenize,
2583
+ id,
2496
2584
  idEmoji,
2497
2585
  idHue,
2498
2586
  inferObjectOrder,
@@ -2507,6 +2595,8 @@ export {
2507
2595
  isNonNullable,
2508
2596
  isTauri,
2509
2597
  isTruthy,
2598
+ isWellFormedId,
2599
+ isWellFormedIdPart,
2510
2600
  joinTables,
2511
2601
  jsonKeyReplacer,
2512
2602
  jsonReplacer,