@dxos/echo-pipeline 0.4.10-main.c32f430 → 0.4.10-main.c5e8686

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 (66) hide show
  1. package/dist/lib/browser/{chunk-RTEEJ723.mjs → chunk-SYE4EK33.mjs} +30 -35
  2. package/dist/lib/browser/chunk-SYE4EK33.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +344 -246
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +8 -2
  7. package/dist/lib/browser/testing/index.mjs.map +4 -4
  8. package/dist/lib/node/{chunk-7VZVCCNF.cjs → chunk-WCTX6RNS.cjs} +35 -40
  9. package/dist/lib/node/chunk-WCTX6RNS.cjs.map +7 -0
  10. package/dist/lib/node/index.cjs +367 -270
  11. package/dist/lib/node/index.cjs.map +4 -4
  12. package/dist/lib/node/meta.json +1 -1
  13. package/dist/lib/node/testing/index.cjs +18 -13
  14. package/dist/lib/node/testing/index.cjs.map +4 -4
  15. package/dist/types/src/automerge/automerge-doc-loader.d.ts +2 -0
  16. package/dist/types/src/automerge/automerge-doc-loader.d.ts.map +1 -1
  17. package/dist/types/src/automerge/automerge-host.d.ts +21 -18
  18. package/dist/types/src/automerge/automerge-host.d.ts.map +1 -1
  19. package/dist/types/src/automerge/automerge-repo.test.d.ts +2 -0
  20. package/dist/types/src/automerge/automerge-repo.test.d.ts.map +1 -0
  21. package/dist/types/src/automerge/index.d.ts +2 -0
  22. package/dist/types/src/automerge/index.d.ts.map +1 -1
  23. package/dist/types/src/automerge/level.test.d.ts +2 -0
  24. package/dist/types/src/automerge/level.test.d.ts.map +1 -0
  25. package/dist/types/src/automerge/leveldb-storage-adapter.d.ts +30 -0
  26. package/dist/types/src/automerge/leveldb-storage-adapter.d.ts.map +1 -0
  27. package/dist/types/src/automerge/local-host-network-adapter.d.ts +8 -1
  28. package/dist/types/src/automerge/local-host-network-adapter.d.ts.map +1 -1
  29. package/dist/types/src/automerge/migrations.d.ts +7 -0
  30. package/dist/types/src/automerge/migrations.d.ts.map +1 -0
  31. package/dist/types/src/automerge/reference.d.ts +15 -0
  32. package/dist/types/src/automerge/reference.d.ts.map +1 -0
  33. package/dist/types/src/automerge/storage-adapter.test.d.ts +2 -0
  34. package/dist/types/src/automerge/storage-adapter.test.d.ts.map +1 -0
  35. package/dist/types/src/automerge/types.d.ts +8 -2
  36. package/dist/types/src/automerge/types.d.ts.map +1 -1
  37. package/dist/types/src/metadata/metadata-store.d.ts +2 -1
  38. package/dist/types/src/metadata/metadata-store.d.ts.map +1 -1
  39. package/dist/types/src/space/space.d.ts +4 -8
  40. package/dist/types/src/space/space.d.ts.map +1 -1
  41. package/dist/types/src/testing/index.d.ts +1 -0
  42. package/dist/types/src/testing/index.d.ts.map +1 -1
  43. package/dist/types/src/testing/level.d.ts +3 -0
  44. package/dist/types/src/testing/level.d.ts.map +1 -0
  45. package/dist/types/src/testing/test-agent-builder.d.ts +2 -2
  46. package/package.json +33 -30
  47. package/src/automerge/automerge-doc-loader.ts +6 -0
  48. package/src/automerge/automerge-host.test.ts +22 -8
  49. package/src/automerge/automerge-host.ts +65 -118
  50. package/src/automerge/automerge-repo.test.ts +29 -0
  51. package/src/automerge/index.ts +2 -0
  52. package/src/automerge/level.test.ts +64 -0
  53. package/src/automerge/leveldb-storage-adapter.ts +117 -0
  54. package/src/automerge/local-host-network-adapter.ts +19 -13
  55. package/src/automerge/migrations.ts +41 -0
  56. package/src/automerge/reference.ts +31 -0
  57. package/src/automerge/storage-adapter.test.ts +90 -0
  58. package/src/automerge/types.ts +8 -5
  59. package/src/db-host/data-service.ts +1 -1
  60. package/src/metadata/metadata-store.ts +17 -8
  61. package/src/space/space.test.ts +7 -7
  62. package/src/space/space.ts +6 -21
  63. package/src/testing/index.ts +1 -0
  64. package/src/testing/level.ts +11 -0
  65. package/dist/lib/browser/chunk-RTEEJ723.mjs.map +0 -7
  66. package/dist/lib/node/chunk-7VZVCCNF.cjs.map +0 -7
@@ -2,6 +2,7 @@ import "@dxos/node-std/globals";
2
2
  import {
3
3
  AuthExtension,
4
4
  AuthStatus,
5
+ Buffer,
5
6
  DataServiceImpl,
6
7
  MOCK_AUTH_PROVIDER,
7
8
  MOCK_AUTH_VERIFIER,
@@ -16,142 +17,130 @@ import {
16
17
  TimeframeClock,
17
18
  codec,
18
19
  createMappedFeedWriter,
20
+ hasInvitationExpired,
19
21
  mapFeedIndexesToTimeframe,
20
22
  mapTimeframeToFeedIndexes,
21
23
  startAfter,
22
24
  valueEncoding
23
- } from "./chunk-RTEEJ723.mjs";
25
+ } from "./chunk-SYE4EK33.mjs";
24
26
 
25
27
  // packages/core/echo/echo-pipeline/src/automerge/automerge-host.ts
26
- import { next as automerge, getHeads } from "@dxos/automerge/automerge";
28
+ import { asyncTimeout } from "@dxos/async";
29
+ import { next as automerge } from "@dxos/automerge/automerge";
27
30
  import { Repo } from "@dxos/automerge/automerge-repo";
28
- import { IndexedDBStorageAdapter } from "@dxos/automerge/automerge-repo-storage-indexeddb";
29
31
  import { Context } from "@dxos/context";
30
32
  import { PublicKey } from "@dxos/keys";
31
33
  import { log as log3 } from "@dxos/log";
32
- import { idCodec } from "@dxos/protocols";
33
- import { StorageType } from "@dxos/random-access-storage";
34
34
  import { trace } from "@dxos/tracing";
35
35
  import { ComplexMap, ComplexSet, defaultMap, mapValues } from "@dxos/util";
36
36
 
37
- // packages/core/echo/echo-pipeline/src/automerge/automerge-storage-adapter.ts
38
- import { arrayToBuffer, bufferToArray } from "@dxos/util";
39
- var AutomergeStorageAdapter = class {
40
- constructor(_directory) {
41
- this._directory = _directory;
42
- this._state = "opened";
37
+ // packages/core/echo/echo-pipeline/src/automerge/leveldb-storage-adapter.ts
38
+ import { LifecycleState, Resource } from "@dxos/context";
39
+ var LevelDBStorageAdapter = class extends Resource {
40
+ constructor(_params) {
41
+ super();
42
+ this._params = _params;
43
43
  }
44
- async load(key) {
45
- if (this._state !== "opened") {
46
- return void 0;
47
- }
48
- const filename = this._getFilename(key);
49
- const file = this._directory.getOrCreateFile(filename);
50
- const { size } = await file.stat();
51
- if (!size || size === 0) {
52
- return void 0;
44
+ async load(keyArray) {
45
+ try {
46
+ if (this._lifecycleState !== LifecycleState.OPEN) {
47
+ return void 0;
48
+ }
49
+ return await this._params.db.get(keyArray, {
50
+ ...encodingOptions
51
+ });
52
+ } catch (err) {
53
+ if (isLevelDbNotFoundError(err)) {
54
+ return void 0;
55
+ }
56
+ throw err;
53
57
  }
54
- const buffer = await file.read(0, size);
55
- return bufferToArray(buffer);
56
58
  }
57
- async save(key, data) {
58
- if (this._state !== "opened") {
59
+ async save(keyArray, binary) {
60
+ if (this._lifecycleState !== LifecycleState.OPEN) {
59
61
  return void 0;
60
62
  }
61
- const filename = this._getFilename(key);
62
- const file = this._directory.getOrCreateFile(filename);
63
- await file.write(0, arrayToBuffer(data));
64
- await file.truncate?.(data.length);
65
- await file.flush?.();
63
+ const batch = this._params.db.batch();
64
+ await this._params.callbacks?.beforeSave?.({
65
+ path: keyArray,
66
+ batch
67
+ });
68
+ batch.put(keyArray, Buffer.from(binary), {
69
+ ...encodingOptions
70
+ });
71
+ await batch.write();
72
+ await this._params.callbacks?.afterSave?.(keyArray);
66
73
  }
67
- async remove(key) {
68
- if (this._state !== "opened") {
74
+ async remove(keyArray) {
75
+ if (this._lifecycleState !== LifecycleState.OPEN) {
69
76
  return void 0;
70
77
  }
71
- const filename = this._getFilename(key);
72
- const file = this._directory.getOrCreateFile(filename);
73
- await file.destroy();
78
+ await this._params.db.del(keyArray, {
79
+ ...encodingOptions
80
+ });
74
81
  }
75
82
  async loadRange(keyPrefix) {
76
- if (this._state !== "opened") {
83
+ if (this._lifecycleState !== LifecycleState.OPEN) {
77
84
  return [];
78
85
  }
79
- const filename = this._getFilename(keyPrefix);
80
- const entries = await this._directory.list();
81
- return Promise.all(entries.filter((entry) => entry.startsWith(filename)).map(async (entry) => {
82
- const file = this._directory.getOrCreateFile(entry);
83
- const { size } = await file.stat();
84
- const buffer = await file.read(0, size);
85
- return {
86
- key: this._getKeyFromFilename(entry),
87
- data: bufferToArray(buffer)
88
- };
89
- }));
86
+ const result = [];
87
+ for await (const [key, value] of this._params.db.iterator({
88
+ gte: keyPrefix,
89
+ lte: [
90
+ ...keyPrefix,
91
+ "\uFFFF"
92
+ ],
93
+ ...encodingOptions
94
+ })) {
95
+ result.push({
96
+ key,
97
+ data: value
98
+ });
99
+ }
100
+ return result;
90
101
  }
91
102
  async removeRange(keyPrefix) {
92
- if (this._state !== "opened") {
103
+ if (this._lifecycleState !== LifecycleState.OPEN) {
93
104
  return void 0;
94
105
  }
95
- const filename = this._getFilename(keyPrefix);
96
- const entries = await this._directory.list();
97
- await Promise.all(entries.filter((entry) => entry.startsWith(filename)).map(async (entry) => {
98
- const file = this._directory.getOrCreateFile(entry);
99
- await file.destroy();
100
- }));
101
- }
102
- async close() {
103
- this._state = "closed";
104
- }
105
- _getFilename(key) {
106
- return key.map((k) => k.replaceAll("%", "%25").replaceAll("-", "%2D")).join("-");
107
- }
108
- _getKeyFromFilename(filename) {
109
- return filename.split("-").map((k) => k.replaceAll("%2D", "-").replaceAll("%25", "%"));
110
- }
111
- };
112
-
113
- // packages/core/echo/echo-pipeline/src/automerge/automerge-storage–wrapper.ts
114
- var AutomergeStorageWrapper = class {
115
- constructor({ storage, callbacks }) {
116
- this._storage = storage;
117
- this._callbacks = callbacks;
118
- }
119
- async load(key) {
120
- return this._storage.load(key);
121
- }
122
- async save(key, value) {
123
- await this._callbacks.beforeSave?.(key);
124
- await this._storage.save(key, value);
125
- await this._callbacks.afterSave?.(key);
126
- }
127
- async remove(key) {
128
- return this._storage.remove(key);
129
- }
130
- async loadRange(keyPrefix) {
131
- return this._storage.loadRange(keyPrefix);
132
- }
133
- async removeRange(keyPrefix) {
134
- return this._storage.removeRange(keyPrefix);
135
- }
136
- async close() {
137
- if (this._storage instanceof AutomergeStorageAdapter) {
138
- return this._storage.close();
106
+ const batch = this._params.db.batch();
107
+ for await (const [key] of this._params.db.iterator({
108
+ gte: keyPrefix,
109
+ lte: [
110
+ ...keyPrefix,
111
+ "\uFFFF"
112
+ ],
113
+ ...encodingOptions
114
+ })) {
115
+ batch.del(key, {
116
+ ...encodingOptions
117
+ });
139
118
  }
119
+ await batch.write();
140
120
  }
141
121
  };
122
+ var keyEncoder = {
123
+ encode: (key) => Buffer.from(key.map((k) => k.replaceAll("%", "%25").replaceAll("-", "%2D")).join("-")),
124
+ decode: (key) => Buffer.from(key).toString().split("-").map((k) => k.replaceAll("%2D", "-").replaceAll("%25", "%"))
125
+ };
126
+ var encodingOptions = {
127
+ keyEncoding: keyEncoder,
128
+ valueEncoding: "buffer"
129
+ };
130
+ var isLevelDbNotFoundError = (err) => err.code === "LEVEL_NOT_FOUND";
142
131
 
143
132
  // packages/core/echo/echo-pipeline/src/automerge/local-host-network-adapter.ts
144
133
  import { Trigger } from "@dxos/async";
145
134
  import { NetworkAdapter, cbor } from "@dxos/automerge/automerge-repo";
146
135
  import { Stream } from "@dxos/codec-protobuf";
147
136
  import { invariant } from "@dxos/invariant";
148
- import { log } from "@dxos/log";
149
137
  var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/local-host-network-adapter.ts";
150
138
  var LocalHostNetworkAdapter = class extends NetworkAdapter {
151
139
  constructor() {
152
140
  super(...arguments);
153
141
  this._peers = /* @__PURE__ */ new Map();
154
142
  this._connected = new Trigger();
143
+ this._isConnected = false;
155
144
  }
156
145
  /**
157
146
  * Emits `ready` event. That signals to `Repo` that it can start using the adapter.
@@ -161,15 +150,21 @@ var LocalHostNetworkAdapter = class extends NetworkAdapter {
161
150
  network: this
162
151
  });
163
152
  }
153
+ /**
154
+ * Called by `Repo` to connect to the network.
155
+ *
156
+ * @param peerId Our peer Id.
157
+ */
164
158
  connect(peerId) {
165
159
  this.peerId = peerId;
160
+ this._isConnected = true;
166
161
  this._connected.wake();
167
162
  }
168
163
  send(message) {
169
164
  const peer = this._peers.get(message.targetId);
170
165
  invariant(peer, "Peer not found.", {
171
166
  F: __dxlog_file,
172
- L: 45,
167
+ L: 51,
173
168
  S: this,
174
169
  A: [
175
170
  "peer",
@@ -184,12 +179,17 @@ var LocalHostNetworkAdapter = class extends NetworkAdapter {
184
179
  }
185
180
  disconnect() {
186
181
  }
182
+ async whenConnected() {
183
+ await this._connected.wait({
184
+ timeout: 1e4
185
+ });
186
+ }
187
187
  syncRepo({ id, syncMessage }) {
188
188
  const peerId = this._getPeerId(id);
189
189
  return new Stream(({ next, close }) => {
190
190
  invariant(!this._peers.has(peerId), "Peer already connected.", {
191
191
  F: __dxlog_file,
192
- L: 63,
192
+ L: 73,
193
193
  S: this,
194
194
  A: [
195
195
  "!this._peers.has(peerId)",
@@ -211,35 +211,47 @@ var LocalHostNetworkAdapter = class extends NetworkAdapter {
211
211
  });
212
212
  }
213
213
  });
214
- this._connected.wait({
215
- timeout: 1e3
216
- }).then(() => {
217
- this.emit("peer-candidate", {
218
- peerMetadata: {},
219
- peerId
220
- });
221
- }).catch((err) => log.catch(err, void 0, {
214
+ invariant(this._isConnected, void 0, {
222
215
  F: __dxlog_file,
223
- L: 88,
216
+ L: 90,
224
217
  S: this,
225
- C: (f, a) => f(...a)
226
- }));
218
+ A: [
219
+ "this._isConnected",
220
+ ""
221
+ ]
222
+ });
223
+ this.emit("peer-candidate", {
224
+ peerMetadata: {},
225
+ peerId
226
+ });
227
227
  });
228
228
  }
229
229
  async sendSyncMessage({ id, syncMessage }) {
230
- await this._connected.wait({
231
- timeout: 1e3
230
+ invariant(this._isConnected, void 0, {
231
+ F: __dxlog_file,
232
+ L: 99,
233
+ S: this,
234
+ A: [
235
+ "this._isConnected",
236
+ ""
237
+ ]
232
238
  });
233
239
  const message = cbor.decode(syncMessage);
234
240
  this.emit("message", message);
235
241
  }
236
242
  async getHostInfo() {
237
- await this._connected.wait({
238
- timeout: 1e3
243
+ invariant(this._isConnected, void 0, {
244
+ F: __dxlog_file,
245
+ L: 105,
246
+ S: this,
247
+ A: [
248
+ "this._isConnected",
249
+ ""
250
+ ]
239
251
  });
240
252
  invariant(this.peerId, "Peer id not set.", {
241
253
  F: __dxlog_file,
242
- L: 100,
254
+ L: 106,
243
255
  S: this,
244
256
  A: [
245
257
  "this.peerId",
@@ -259,7 +271,7 @@ var LocalHostNetworkAdapter = class extends NetworkAdapter {
259
271
  import { Trigger as Trigger2 } from "@dxos/async";
260
272
  import { NetworkAdapter as NetworkAdapter2, cbor as cbor2 } from "@dxos/automerge/automerge-repo";
261
273
  import { invariant as invariant2 } from "@dxos/invariant";
262
- import { log as log2 } from "@dxos/log";
274
+ import { log } from "@dxos/log";
263
275
  import { AutomergeReplicator } from "@dxos/teleport-extension-automerge-replicator";
264
276
  var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/mesh-network-adapter.ts";
265
277
  var MeshNetworkAdapter = class extends NetworkAdapter2 {
@@ -294,7 +306,7 @@ var MeshNetworkAdapter = class extends NetworkAdapter2 {
294
306
  });
295
307
  extension.sendSyncMessage({
296
308
  payload: cbor2.encode(message)
297
- }).catch((err) => log2.catch(err, void 0, {
309
+ }).catch((err) => log.catch(err, void 0, {
298
310
  F: __dxlog_file2,
299
311
  L: 39,
300
312
  S: this,
@@ -319,7 +331,7 @@ var MeshNetworkAdapter = class extends NetworkAdapter2 {
319
331
  }, {
320
332
  onStartReplication: async (info, remotePeerId) => {
321
333
  await this._connected.wait();
322
- log2("onStartReplication", {
334
+ log("onStartReplication", {
323
335
  id: info.id,
324
336
  thisPeerId: this.peerId,
325
337
  remotePeerId: remotePeerId.toHex()
@@ -332,7 +344,7 @@ var MeshNetworkAdapter = class extends NetworkAdapter2 {
332
344
  if (!this._extensions.has(info.id)) {
333
345
  peerInfo = info;
334
346
  this._extensions.set(info.id, extension);
335
- log2("peer-candidate", {
347
+ log("peer-candidate", {
336
348
  id: info.id,
337
349
  thisPeerId: this.peerId,
338
350
  remotePeerId: remotePeerId.toHex()
@@ -372,6 +384,118 @@ var MeshNetworkAdapter = class extends NetworkAdapter2 {
372
384
  }
373
385
  };
374
386
 
387
+ // packages/core/echo/echo-pipeline/src/automerge/migrations.ts
388
+ import { IndexedDBStorageAdapter } from "@dxos/automerge/automerge-repo-storage-indexeddb";
389
+ import { log as log2 } from "@dxos/log";
390
+ import { StorageType } from "@dxos/random-access-storage";
391
+
392
+ // packages/core/echo/echo-pipeline/src/automerge/automerge-storage-adapter.ts
393
+ import { arrayToBuffer, bufferToArray } from "@dxos/util";
394
+ var AutomergeStorageAdapter = class {
395
+ constructor(_directory) {
396
+ this._directory = _directory;
397
+ this._state = "opened";
398
+ }
399
+ async load(key) {
400
+ if (this._state !== "opened") {
401
+ return void 0;
402
+ }
403
+ const filename = this._getFilename(key);
404
+ const file = this._directory.getOrCreateFile(filename);
405
+ const { size } = await file.stat();
406
+ if (!size || size === 0) {
407
+ return void 0;
408
+ }
409
+ const buffer = await file.read(0, size);
410
+ return bufferToArray(buffer);
411
+ }
412
+ async save(key, data) {
413
+ if (this._state !== "opened") {
414
+ return void 0;
415
+ }
416
+ const filename = this._getFilename(key);
417
+ const file = this._directory.getOrCreateFile(filename);
418
+ await file.write(0, arrayToBuffer(data));
419
+ await file.truncate?.(data.length);
420
+ await file.flush?.();
421
+ }
422
+ async remove(key) {
423
+ if (this._state !== "opened") {
424
+ return void 0;
425
+ }
426
+ const filename = this._getFilename(key);
427
+ const file = this._directory.getOrCreateFile(filename);
428
+ await file.destroy();
429
+ }
430
+ async loadRange(keyPrefix) {
431
+ if (this._state !== "opened") {
432
+ return [];
433
+ }
434
+ const filename = this._getFilename(keyPrefix);
435
+ const entries = await this._directory.list();
436
+ return Promise.all(entries.filter((entry) => entry.startsWith(filename)).map(async (entry) => {
437
+ const file = this._directory.getOrCreateFile(entry);
438
+ const { size } = await file.stat();
439
+ const buffer = await file.read(0, size);
440
+ return {
441
+ key: this._getKeyFromFilename(entry),
442
+ data: bufferToArray(buffer)
443
+ };
444
+ }));
445
+ }
446
+ async removeRange(keyPrefix) {
447
+ if (this._state !== "opened") {
448
+ return void 0;
449
+ }
450
+ const filename = this._getFilename(keyPrefix);
451
+ const entries = await this._directory.list();
452
+ await Promise.all(entries.filter((entry) => entry.startsWith(filename)).map(async (entry) => {
453
+ const file = this._directory.getOrCreateFile(entry);
454
+ await file.destroy();
455
+ }));
456
+ }
457
+ async close() {
458
+ this._state = "closed";
459
+ }
460
+ _getFilename(key) {
461
+ return key.map((k) => k.replaceAll("%", "%25").replaceAll("-", "%2D")).join("-");
462
+ }
463
+ _getKeyFromFilename(filename) {
464
+ return filename.split("-").map((k) => k.replaceAll("%2D", "-").replaceAll("%25", "%"));
465
+ }
466
+ };
467
+
468
+ // packages/core/echo/echo-pipeline/src/automerge/migrations.ts
469
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/migrations.ts";
470
+ var levelMigration = async ({ db, directory }) => {
471
+ const isNewLevel = !await db.iterator({
472
+ ...encodingOptions
473
+ }).next();
474
+ if (!isNewLevel) {
475
+ return;
476
+ }
477
+ const oldStorageAdapter = directory.type === StorageType.IDB ? new IndexedDBStorageAdapter(directory.path, "data") : new AutomergeStorageAdapter(directory);
478
+ const chunks = await oldStorageAdapter.loadRange([]);
479
+ if (chunks.length === 0) {
480
+ return;
481
+ }
482
+ const batch = db.batch();
483
+ log2.info("found chunks on old storage adapter", {
484
+ chunks: chunks.length
485
+ }, {
486
+ F: __dxlog_file3,
487
+ L: 36,
488
+ S: void 0,
489
+ C: (f, a) => f(...a)
490
+ });
491
+ for (const { key, data } of await oldStorageAdapter.loadRange([])) {
492
+ data && batch.put(key, data, {
493
+ ...encodingOptions
494
+ });
495
+ }
496
+ await batch.write();
497
+ };
498
+
375
499
  // packages/core/echo/echo-pipeline/src/automerge/automerge-host.ts
376
500
  function _ts_decorate(decorators, target, key, desc) {
377
501
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -383,29 +507,32 @@ function _ts_decorate(decorators, target, key, desc) {
383
507
  r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
384
508
  return c > 3 && r && Object.defineProperty(target, key, r), r;
385
509
  }
386
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/automerge-host.ts";
510
+ var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/automerge-host.ts";
387
511
  var AutomergeHost = class {
388
- constructor({ directory, metadata }) {
512
+ constructor({ directory, db, storageCallbacks }) {
389
513
  this._ctx = new Context();
390
514
  /**
391
515
  * spaceKey -> deviceKey[]
392
516
  */
393
517
  this._authorizedDevices = new ComplexMap(PublicKey.hash);
394
- this._updatingMetadata = /* @__PURE__ */ new Map();
395
518
  this._requestedDocs = /* @__PURE__ */ new Set();
396
- this._metadata = metadata;
397
- this._meshNetwork = new MeshNetworkAdapter();
398
- this._clientNetwork = new LocalHostNetworkAdapter();
399
- this._storage = new AutomergeStorageWrapper({
400
- storage: (
401
- // TODO(mykola): Delete specific handling of IDB storage.
402
- directory.type === StorageType.IDB ? new IndexedDBStorageAdapter(directory.path, "data") : new AutomergeStorageAdapter(directory)
403
- ),
404
- callbacks: {
405
- beforeSave: (params) => this._beforeSave(params)
406
- }
519
+ this._directory = directory;
520
+ this._db = db;
521
+ this._storageCallbacks = storageCallbacks;
522
+ }
523
+ async open() {
524
+ this._directory && await levelMigration({
525
+ db: this._db,
526
+ directory: this._directory
527
+ });
528
+ this._storage = new LevelDBStorageAdapter({
529
+ db: this._db,
530
+ callbacks: this._storageCallbacks
407
531
  });
532
+ await this._storage.open?.();
408
533
  this._peerId = `host-${PublicKey.random().toHex()}`;
534
+ this._meshNetwork = new MeshNetworkAdapter();
535
+ this._clientNetwork = new LocalHostNetworkAdapter();
409
536
  this._repo = new Repo({
410
537
  peerId: this._peerId,
411
538
  network: [
@@ -430,8 +557,8 @@ var AutomergeHost = class {
430
557
  documentId,
431
558
  isRequested
432
559
  }, {
433
- F: __dxlog_file3,
434
- L: 96,
560
+ F: __dxlog_file4,
561
+ L: 99,
435
562
  S: this,
436
563
  C: (f, a) => f(...a)
437
564
  });
@@ -444,8 +571,8 @@ var AutomergeHost = class {
444
571
  peerId,
445
572
  documentId
446
573
  }, {
447
- F: __dxlog_file3,
448
- L: 103,
574
+ F: __dxlog_file4,
575
+ L: 106,
449
576
  S: this,
450
577
  C: (f, a) => f(...a)
451
578
  });
@@ -458,8 +585,8 @@ var AutomergeHost = class {
458
585
  peerId,
459
586
  documentId
460
587
  }, {
461
- F: __dxlog_file3,
462
- L: 112,
588
+ F: __dxlog_file4,
589
+ L: 115,
463
590
  S: this,
464
591
  C: (f, a) => f(...a)
465
592
  });
@@ -475,16 +602,16 @@ var AutomergeHost = class {
475
602
  spaceKey,
476
603
  isAuthorized
477
604
  }, {
478
- F: __dxlog_file3,
479
- L: 118,
605
+ F: __dxlog_file4,
606
+ L: 121,
480
607
  S: this,
481
608
  C: (f, a) => f(...a)
482
609
  });
483
610
  return isAuthorized;
484
611
  } catch (err) {
485
612
  log3.catch(err, void 0, {
486
- F: __dxlog_file3,
487
- L: 128,
613
+ F: __dxlog_file4,
614
+ L: 131,
488
615
  S: this,
489
616
  C: (f, a) => f(...a)
490
617
  });
@@ -494,69 +621,22 @@ var AutomergeHost = class {
494
621
  });
495
622
  this._clientNetwork.ready();
496
623
  this._meshNetwork.ready();
497
- {
498
- const listener = ({ handle }) => this._onDocument(handle);
499
- this._repo.on("document", listener);
500
- this._ctx.onDispose(() => {
501
- this._repo.off("document", listener);
502
- });
503
- }
624
+ await this._clientNetwork.whenConnected();
625
+ }
626
+ async close() {
627
+ await this._storage.close?.();
628
+ await this._clientNetwork.close();
629
+ await this._ctx.dispose();
504
630
  }
505
631
  get repo() {
506
632
  return this._repo;
507
633
  }
508
- async _beforeSave(path) {
509
- const id = path[0];
510
- if (this._updatingMetadata.has(id)) {
511
- return this._updatingMetadata.get(id);
512
- }
513
- }
514
- _onDocument(handle) {
515
- const listener = (event) => this._onUpdate(event);
516
- handle.on("change", listener);
517
- this._ctx.onDispose(() => {
518
- handle.off("change", listener);
519
- });
520
- }
521
- _onUpdate(event) {
522
- if (this._metadata == null) {
523
- return;
524
- }
525
- const objectIds = getInlineChanges(event);
526
- if (objectIds.length === 0) {
527
- return;
528
- }
529
- const heads = getHeads(event.doc);
530
- const lastAvailableHash = heads.join("");
531
- if (!lastAvailableHash) {
532
- return;
533
- }
534
- const encodedIds = objectIds.map((objectId) => idCodec.encode({
535
- documentId: event.handle.documentId,
536
- objectId
537
- }));
538
- const idToLastHash = new Map(encodedIds.map((id) => [
539
- id,
540
- lastAvailableHash
541
- ]));
542
- const markingDirtyPromise = this._metadata.markDirty(idToLastHash).then(() => {
543
- this._updatingMetadata.delete(event.handle.documentId);
544
- }).catch((err) => {
545
- this._ctx.disposed && log3.catch(err, void 0, {
546
- F: __dxlog_file3,
547
- L: 188,
548
- S: this,
549
- C: (f, a) => f(...a)
550
- });
551
- });
552
- this._updatingMetadata.set(event.handle.documentId, markingDirtyPromise);
553
- }
554
634
  _automergeDocs() {
555
635
  return mapValues(this._repo.handles, (handle) => ({
556
636
  state: handle.state,
557
637
  hasDoc: !!handle.docSync(),
558
638
  heads: handle.docSync() ? automerge.getHeads(handle.docSync()) : null,
559
- data: handle.docSync()?.doc && mapValues(handle.docSync()?.doc, (value, key) => {
639
+ data: handle.docSync() && mapValues(handle.docSync(), (value, key) => {
560
640
  try {
561
641
  switch (key) {
562
642
  case "access":
@@ -576,14 +656,25 @@ var AutomergeHost = class {
576
656
  _automergePeers() {
577
657
  return this._repo.peers;
578
658
  }
579
- async close() {
580
- await this._storage.close();
581
- await this._clientNetwork.close();
582
- await this._ctx.dispose();
583
- }
584
659
  //
585
660
  // Methods for client-services.
586
661
  //
662
+ async flush({ documentIds }) {
663
+ await Promise.all(documentIds?.map((id) => this._repo.find(id).whenReady()) ?? []);
664
+ try {
665
+ await asyncTimeout(this._repo.flush(documentIds), 500);
666
+ } catch (err) {
667
+ log3.warn("flush error", {
668
+ documentIds,
669
+ err
670
+ }, {
671
+ F: __dxlog_file4,
672
+ L: 195,
673
+ S: this,
674
+ C: (f, a) => f(...a)
675
+ });
676
+ }
677
+ }
587
678
  syncRepo(request) {
588
679
  return this._clientNetwork.syncRepo(request);
589
680
  }
@@ -604,8 +695,8 @@ var AutomergeHost = class {
604
695
  spaceKey,
605
696
  deviceKey
606
697
  }, {
607
- F: __dxlog_file3,
608
- L: 255,
698
+ F: __dxlog_file4,
699
+ L: 220,
609
700
  S: this,
610
701
  C: (f, a) => f(...a)
611
702
  });
@@ -628,24 +719,6 @@ _ts_decorate([
628
719
  AutomergeHost = _ts_decorate([
629
720
  trace.resource()
630
721
  ], AutomergeHost);
631
- var getInlineChanges = (event) => {
632
- const inlineChangedObjectIds = /* @__PURE__ */ new Set();
633
- for (const { path } of event.patches) {
634
- if (path.length < 2) {
635
- continue;
636
- }
637
- switch (path[0]) {
638
- case "objects":
639
- if (path.length >= 2) {
640
- inlineChangedObjectIds.add(path[1]);
641
- }
642
- break;
643
- }
644
- }
645
- return [
646
- ...inlineChangedObjectIds
647
- ];
648
- };
649
722
  var getSpaceKeyFromDoc = (doc) => {
650
723
  const rawSpaceKey = doc.access?.spaceKey ?? doc.experimental_spaceKey;
651
724
  if (rawSpaceKey == null) {
@@ -660,7 +733,7 @@ import { cancelWithContext } from "@dxos/context";
660
733
  import { warnAfterTimeout } from "@dxos/debug";
661
734
  import { invariant as invariant3 } from "@dxos/invariant";
662
735
  import { log as log4 } from "@dxos/log";
663
- var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/automerge-doc-loader.ts";
736
+ var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/automerge-doc-loader.ts";
664
737
  var AutomergeDocumentLoaderImpl = class {
665
738
  constructor(_spaceKey, _repo) {
666
739
  this._spaceKey = _spaceKey;
@@ -670,6 +743,11 @@ var AutomergeDocumentLoaderImpl = class {
670
743
  this._objectsPendingDocumentLoad = /* @__PURE__ */ new Set();
671
744
  this.onObjectDocumentLoaded = new Event();
672
745
  }
746
+ getAllHandles() {
747
+ return [
748
+ ...new Set(this._objectDocumentHandles.values())
749
+ ];
750
+ }
673
751
  async loadSpaceRootDocHandle(ctx, spaceState) {
674
752
  if (this._spaceRootDocHandle != null) {
675
753
  return;
@@ -678,8 +756,8 @@ var AutomergeDocumentLoaderImpl = class {
678
756
  log4.error("Database opened with no rootUrl", {
679
757
  spaceKey: this._spaceKey
680
758
  }, {
681
- F: __dxlog_file4,
682
- L: 60,
759
+ F: __dxlog_file5,
760
+ L: 66,
683
761
  S: this,
684
762
  C: (f, a) => f(...a)
685
763
  });
@@ -688,8 +766,8 @@ var AutomergeDocumentLoaderImpl = class {
688
766
  const existingDocHandle = await this._initDocHandle(ctx, spaceState.rootUrl);
689
767
  const doc = existingDocHandle.docSync();
690
768
  invariant3(doc, void 0, {
691
- F: __dxlog_file4,
692
- L: 65,
769
+ F: __dxlog_file5,
770
+ L: 71,
693
771
  S: this,
694
772
  A: [
695
773
  "doc",
@@ -704,8 +782,8 @@ var AutomergeDocumentLoaderImpl = class {
704
782
  }
705
783
  loadObjectDocument(objectId) {
706
784
  invariant3(this._spaceRootDocHandle, void 0, {
707
- F: __dxlog_file4,
708
- L: 74,
785
+ F: __dxlog_file5,
786
+ L: 80,
709
787
  S: this,
710
788
  A: [
711
789
  "this._spaceRootDocHandle",
@@ -717,8 +795,8 @@ var AutomergeDocumentLoaderImpl = class {
717
795
  }
718
796
  const spaceRootDoc = this._spaceRootDocHandle.docSync();
719
797
  invariant3(spaceRootDoc, void 0, {
720
- F: __dxlog_file4,
721
- L: 79,
798
+ F: __dxlog_file5,
799
+ L: 85,
722
800
  S: this,
723
801
  A: [
724
802
  "spaceRootDoc",
@@ -731,8 +809,8 @@ var AutomergeDocumentLoaderImpl = class {
731
809
  log4.info("loading delayed until object links are initialized", {
732
810
  objectId
733
811
  }, {
734
- F: __dxlog_file4,
735
- L: 83,
812
+ F: __dxlog_file5,
813
+ L: 89,
736
814
  S: this,
737
815
  C: (f, a) => f(...a)
738
816
  });
@@ -752,8 +830,8 @@ var AutomergeDocumentLoaderImpl = class {
752
830
  }
753
831
  getSpaceRootDocHandle() {
754
832
  invariant3(this._spaceRootDocHandle, void 0, {
755
- F: __dxlog_file4,
756
- L: 101,
833
+ F: __dxlog_file5,
834
+ L: 107,
757
835
  S: this,
758
836
  A: [
759
837
  "this._spaceRootDocHandle",
@@ -764,8 +842,8 @@ var AutomergeDocumentLoaderImpl = class {
764
842
  }
765
843
  createDocumentForObject(objectId) {
766
844
  invariant3(this._spaceRootDocHandle, void 0, {
767
- F: __dxlog_file4,
768
- L: 106,
845
+ F: __dxlog_file5,
846
+ L: 112,
769
847
  S: this,
770
848
  A: [
771
849
  "this._spaceRootDocHandle",
@@ -807,8 +885,8 @@ var AutomergeDocumentLoaderImpl = class {
807
885
  ...logMeta,
808
886
  actualDocumentUrl: objectDocumentHandle.url
809
887
  }, {
810
- F: __dxlog_file4,
811
- L: 136,
888
+ F: __dxlog_file5,
889
+ L: 142,
812
890
  S: this,
813
891
  C: (f, a) => f(...a)
814
892
  });
@@ -816,8 +894,8 @@ var AutomergeDocumentLoaderImpl = class {
816
894
  }
817
895
  if (objectDocumentHandle?.url === automergeUrl) {
818
896
  log4.warn("object document was already loaded", logMeta, {
819
- F: __dxlog_file4,
820
- L: 143,
897
+ F: __dxlog_file5,
898
+ L: 149,
821
899
  S: this,
822
900
  C: (f, a) => f(...a)
823
901
  });
@@ -825,8 +903,8 @@ var AutomergeDocumentLoaderImpl = class {
825
903
  }
826
904
  const handle = this._repo.find(automergeUrl);
827
905
  log4.debug("document loading triggered", logMeta, {
828
- F: __dxlog_file4,
829
- L: 147,
906
+ F: __dxlog_file5,
907
+ L: 153,
830
908
  S: this,
831
909
  C: (f, a) => f(...a)
832
910
  });
@@ -848,8 +926,8 @@ var AutomergeDocumentLoaderImpl = class {
848
926
  id: docHandle.documentId,
849
927
  state: docHandle.state
850
928
  }, {
851
- F: __dxlog_file4,
852
- L: 163,
929
+ F: __dxlog_file5,
930
+ L: 169,
853
931
  S: this,
854
932
  C: (f, a) => f(...a)
855
933
  });
@@ -890,8 +968,8 @@ var AutomergeDocumentLoaderImpl = class {
890
968
  };
891
969
  if (this.onObjectDocumentLoaded.listenerCount() === 0) {
892
970
  log4.info("document loaded after all listeners were removed", logMeta, {
893
- F: __dxlog_file4,
894
- L: 199,
971
+ F: __dxlog_file5,
972
+ L: 205,
895
973
  S: this,
896
974
  C: (f, a) => f(...a)
897
975
  });
@@ -900,8 +978,8 @@ var AutomergeDocumentLoaderImpl = class {
900
978
  const objectDocHandle = this._objectDocumentHandles.get(objectId);
901
979
  if (objectDocHandle?.url !== handle.url) {
902
980
  log4.warn("object was rebound while a document was loading, discarding handle", logMeta, {
903
- F: __dxlog_file4,
904
- L: 204,
981
+ F: __dxlog_file5,
982
+ L: 210,
905
983
  S: this,
906
984
  C: (f, a) => f(...a)
907
985
  });
@@ -919,8 +997,8 @@ var AutomergeDocumentLoaderImpl = class {
919
997
  retryLoading: shouldRetryLoading,
920
998
  err
921
999
  }, {
922
- F: __dxlog_file4,
923
- L: 210,
1000
+ F: __dxlog_file5,
1001
+ L: 216,
924
1002
  S: this,
925
1003
  C: (f, a) => f(...a)
926
1004
  });
@@ -930,6 +1008,19 @@ var AutomergeDocumentLoaderImpl = class {
930
1008
  }
931
1009
  }
932
1010
  };
1011
+
1012
+ // packages/core/echo/echo-pipeline/src/automerge/reference.ts
1013
+ import { Reference } from "@dxos/echo-db";
1014
+ var REFERENCE_TYPE_TAG = "dxos.echo.model.document.Reference";
1015
+ var encodeReference = (reference) => ({
1016
+ "@type": REFERENCE_TYPE_TAG,
1017
+ // NOTE: Automerge do not support undefined values, so we need to use null instead.
1018
+ itemId: reference.itemId ?? null,
1019
+ protocol: reference.protocol ?? null,
1020
+ host: reference.host ?? null
1021
+ });
1022
+ var decodeReference = (value) => new Reference(value.itemId, value.protocol ?? void 0, value.host ?? void 0);
1023
+ var isEncodedReferenceObject = (value) => typeof value === "object" && value !== null && value["@type"] === REFERENCE_TYPE_TAG;
933
1024
  export {
934
1025
  AuthExtension,
935
1026
  AuthStatus,
@@ -937,12 +1028,14 @@ export {
937
1028
  AutomergeHost,
938
1029
  AutomergeStorageAdapter,
939
1030
  DataServiceImpl,
1031
+ LevelDBStorageAdapter,
940
1032
  LocalHostNetworkAdapter,
941
1033
  MOCK_AUTH_PROVIDER,
942
1034
  MOCK_AUTH_VERIFIER,
943
1035
  MeshNetworkAdapter,
944
1036
  MetadataStore,
945
1037
  Pipeline,
1038
+ REFERENCE_TYPE_TAG,
946
1039
  SnapshotManager,
947
1040
  SnapshotStore,
948
1041
  Space,
@@ -952,7 +1045,12 @@ export {
952
1045
  TimeframeClock,
953
1046
  codec,
954
1047
  createMappedFeedWriter,
1048
+ decodeReference,
1049
+ encodeReference,
1050
+ encodingOptions,
955
1051
  getSpaceKeyFromDoc,
1052
+ hasInvitationExpired,
1053
+ isEncodedReferenceObject,
956
1054
  mapFeedIndexesToTimeframe,
957
1055
  mapTimeframeToFeedIndexes,
958
1056
  startAfter,