@dxos/echo-pipeline 0.4.10-main.0302e13 → 0.4.10-main.05dbd64

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 (74) hide show
  1. package/dist/lib/browser/{chunk-RTEEJ723.mjs → chunk-KMWJLYEQ.mjs} +77 -57
  2. package/dist/lib/browser/chunk-KMWJLYEQ.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +368 -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 +10 -2
  7. package/dist/lib/browser/testing/index.mjs.map +4 -4
  8. package/dist/lib/node/{chunk-7VZVCCNF.cjs → chunk-YZA42CKA.cjs} +82 -62
  9. package/dist/lib/node/chunk-YZA42CKA.cjs.map +7 -0
  10. package/dist/lib/node/index.cjs +391 -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 +20 -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/control-pipeline.d.ts +3 -1
  40. package/dist/types/src/space/control-pipeline.d.ts.map +1 -1
  41. package/dist/types/src/space/space-manager.d.ts +3 -1
  42. package/dist/types/src/space/space-manager.d.ts.map +1 -1
  43. package/dist/types/src/space/space.d.ts +6 -9
  44. package/dist/types/src/space/space.d.ts.map +1 -1
  45. package/dist/types/src/testing/index.d.ts +1 -0
  46. package/dist/types/src/testing/index.d.ts.map +1 -1
  47. package/dist/types/src/testing/level.d.ts +3 -0
  48. package/dist/types/src/testing/level.d.ts.map +1 -0
  49. package/dist/types/src/testing/test-agent-builder.d.ts +2 -2
  50. package/dist/types/src/testing/test-agent-builder.d.ts.map +1 -1
  51. package/package.json +33 -30
  52. package/src/automerge/automerge-doc-loader.ts +9 -0
  53. package/src/automerge/automerge-host.test.ts +22 -8
  54. package/src/automerge/automerge-host.ts +66 -118
  55. package/src/automerge/automerge-repo.test.ts +29 -0
  56. package/src/automerge/index.ts +2 -0
  57. package/src/automerge/level.test.ts +82 -0
  58. package/src/automerge/leveldb-storage-adapter.ts +117 -0
  59. package/src/automerge/local-host-network-adapter.ts +19 -13
  60. package/src/automerge/migrations.ts +41 -0
  61. package/src/automerge/reference.ts +31 -0
  62. package/src/automerge/storage-adapter.test.ts +90 -0
  63. package/src/automerge/types.ts +8 -5
  64. package/src/db-host/data-service.ts +1 -1
  65. package/src/metadata/metadata-store.ts +17 -8
  66. package/src/space/control-pipeline.ts +11 -1
  67. package/src/space/space-manager.ts +4 -0
  68. package/src/space/space.test.ts +7 -7
  69. package/src/space/space.ts +17 -22
  70. package/src/testing/index.ts +1 -0
  71. package/src/testing/level.ts +11 -0
  72. package/src/testing/test-agent-builder.ts +1 -0
  73. package/dist/lib/browser/chunk-RTEEJ723.mjs.map +0 -7
  74. 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-KMWJLYEQ.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: 100,
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: 107,
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: 116,
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: 122,
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: 132,
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: 196,
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: 221,
609
700
  S: this,
610
701
  C: (f, a) => f(...a)
611
702
  });
@@ -625,27 +716,14 @@ _ts_decorate([
625
716
  depth: null
626
717
  })
627
718
  ], AutomergeHost.prototype, "_automergePeers", null);
719
+ _ts_decorate([
720
+ trace.span({
721
+ showInBrowserTimeline: true
722
+ })
723
+ ], AutomergeHost.prototype, "flush", null);
628
724
  AutomergeHost = _ts_decorate([
629
725
  trace.resource()
630
726
  ], 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
727
  var getSpaceKeyFromDoc = (doc) => {
650
728
  const rawSpaceKey = doc.access?.spaceKey ?? doc.experimental_spaceKey;
651
729
  if (rawSpaceKey == null) {
@@ -660,7 +738,18 @@ import { cancelWithContext } from "@dxos/context";
660
738
  import { warnAfterTimeout } from "@dxos/debug";
661
739
  import { invariant as invariant3 } from "@dxos/invariant";
662
740
  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";
741
+ import { trace as trace2 } from "@dxos/tracing";
742
+ function _ts_decorate2(decorators, target, key, desc) {
743
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
744
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
745
+ r = Reflect.decorate(decorators, target, key, desc);
746
+ else
747
+ for (var i = decorators.length - 1; i >= 0; i--)
748
+ if (d = decorators[i])
749
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
750
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
751
+ }
752
+ var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/automerge-doc-loader.ts";
664
753
  var AutomergeDocumentLoaderImpl = class {
665
754
  constructor(_spaceKey, _repo) {
666
755
  this._spaceKey = _spaceKey;
@@ -670,6 +759,11 @@ var AutomergeDocumentLoaderImpl = class {
670
759
  this._objectsPendingDocumentLoad = /* @__PURE__ */ new Set();
671
760
  this.onObjectDocumentLoaded = new Event();
672
761
  }
762
+ getAllHandles() {
763
+ return [
764
+ ...new Set(this._objectDocumentHandles.values())
765
+ ];
766
+ }
673
767
  async loadSpaceRootDocHandle(ctx, spaceState) {
674
768
  if (this._spaceRootDocHandle != null) {
675
769
  return;
@@ -678,8 +772,8 @@ var AutomergeDocumentLoaderImpl = class {
678
772
  log4.error("Database opened with no rootUrl", {
679
773
  spaceKey: this._spaceKey
680
774
  }, {
681
- F: __dxlog_file4,
682
- L: 60,
775
+ F: __dxlog_file5,
776
+ L: 69,
683
777
  S: this,
684
778
  C: (f, a) => f(...a)
685
779
  });
@@ -688,8 +782,8 @@ var AutomergeDocumentLoaderImpl = class {
688
782
  const existingDocHandle = await this._initDocHandle(ctx, spaceState.rootUrl);
689
783
  const doc = existingDocHandle.docSync();
690
784
  invariant3(doc, void 0, {
691
- F: __dxlog_file4,
692
- L: 65,
785
+ F: __dxlog_file5,
786
+ L: 74,
693
787
  S: this,
694
788
  A: [
695
789
  "doc",
@@ -704,8 +798,8 @@ var AutomergeDocumentLoaderImpl = class {
704
798
  }
705
799
  loadObjectDocument(objectId) {
706
800
  invariant3(this._spaceRootDocHandle, void 0, {
707
- F: __dxlog_file4,
708
- L: 74,
801
+ F: __dxlog_file5,
802
+ L: 83,
709
803
  S: this,
710
804
  A: [
711
805
  "this._spaceRootDocHandle",
@@ -717,8 +811,8 @@ var AutomergeDocumentLoaderImpl = class {
717
811
  }
718
812
  const spaceRootDoc = this._spaceRootDocHandle.docSync();
719
813
  invariant3(spaceRootDoc, void 0, {
720
- F: __dxlog_file4,
721
- L: 79,
814
+ F: __dxlog_file5,
815
+ L: 88,
722
816
  S: this,
723
817
  A: [
724
818
  "spaceRootDoc",
@@ -731,8 +825,8 @@ var AutomergeDocumentLoaderImpl = class {
731
825
  log4.info("loading delayed until object links are initialized", {
732
826
  objectId
733
827
  }, {
734
- F: __dxlog_file4,
735
- L: 83,
828
+ F: __dxlog_file5,
829
+ L: 92,
736
830
  S: this,
737
831
  C: (f, a) => f(...a)
738
832
  });
@@ -752,8 +846,8 @@ var AutomergeDocumentLoaderImpl = class {
752
846
  }
753
847
  getSpaceRootDocHandle() {
754
848
  invariant3(this._spaceRootDocHandle, void 0, {
755
- F: __dxlog_file4,
756
- L: 101,
849
+ F: __dxlog_file5,
850
+ L: 110,
757
851
  S: this,
758
852
  A: [
759
853
  "this._spaceRootDocHandle",
@@ -764,8 +858,8 @@ var AutomergeDocumentLoaderImpl = class {
764
858
  }
765
859
  createDocumentForObject(objectId) {
766
860
  invariant3(this._spaceRootDocHandle, void 0, {
767
- F: __dxlog_file4,
768
- L: 106,
861
+ F: __dxlog_file5,
862
+ L: 115,
769
863
  S: this,
770
864
  A: [
771
865
  "this._spaceRootDocHandle",
@@ -807,8 +901,8 @@ var AutomergeDocumentLoaderImpl = class {
807
901
  ...logMeta,
808
902
  actualDocumentUrl: objectDocumentHandle.url
809
903
  }, {
810
- F: __dxlog_file4,
811
- L: 136,
904
+ F: __dxlog_file5,
905
+ L: 145,
812
906
  S: this,
813
907
  C: (f, a) => f(...a)
814
908
  });
@@ -816,8 +910,8 @@ var AutomergeDocumentLoaderImpl = class {
816
910
  }
817
911
  if (objectDocumentHandle?.url === automergeUrl) {
818
912
  log4.warn("object document was already loaded", logMeta, {
819
- F: __dxlog_file4,
820
- L: 143,
913
+ F: __dxlog_file5,
914
+ L: 152,
821
915
  S: this,
822
916
  C: (f, a) => f(...a)
823
917
  });
@@ -825,8 +919,8 @@ var AutomergeDocumentLoaderImpl = class {
825
919
  }
826
920
  const handle = this._repo.find(automergeUrl);
827
921
  log4.debug("document loading triggered", logMeta, {
828
- F: __dxlog_file4,
829
- L: 147,
922
+ F: __dxlog_file5,
923
+ L: 156,
830
924
  S: this,
831
925
  C: (f, a) => f(...a)
832
926
  });
@@ -848,8 +942,8 @@ var AutomergeDocumentLoaderImpl = class {
848
942
  id: docHandle.documentId,
849
943
  state: docHandle.state
850
944
  }, {
851
- F: __dxlog_file4,
852
- L: 163,
945
+ F: __dxlog_file5,
946
+ L: 172,
853
947
  S: this,
854
948
  C: (f, a) => f(...a)
855
949
  });
@@ -890,8 +984,8 @@ var AutomergeDocumentLoaderImpl = class {
890
984
  };
891
985
  if (this.onObjectDocumentLoaded.listenerCount() === 0) {
892
986
  log4.info("document loaded after all listeners were removed", logMeta, {
893
- F: __dxlog_file4,
894
- L: 199,
987
+ F: __dxlog_file5,
988
+ L: 208,
895
989
  S: this,
896
990
  C: (f, a) => f(...a)
897
991
  });
@@ -900,8 +994,8 @@ var AutomergeDocumentLoaderImpl = class {
900
994
  const objectDocHandle = this._objectDocumentHandles.get(objectId);
901
995
  if (objectDocHandle?.url !== handle.url) {
902
996
  log4.warn("object was rebound while a document was loading, discarding handle", logMeta, {
903
- F: __dxlog_file4,
904
- L: 204,
997
+ F: __dxlog_file5,
998
+ L: 213,
905
999
  S: this,
906
1000
  C: (f, a) => f(...a)
907
1001
  });
@@ -919,8 +1013,8 @@ var AutomergeDocumentLoaderImpl = class {
919
1013
  retryLoading: shouldRetryLoading,
920
1014
  err
921
1015
  }, {
922
- F: __dxlog_file4,
923
- L: 210,
1016
+ F: __dxlog_file5,
1017
+ L: 219,
924
1018
  S: this,
925
1019
  C: (f, a) => f(...a)
926
1020
  });
@@ -930,6 +1024,27 @@ var AutomergeDocumentLoaderImpl = class {
930
1024
  }
931
1025
  }
932
1026
  };
1027
+ _ts_decorate2([
1028
+ trace2.span({
1029
+ showInBrowserTimeline: true
1030
+ })
1031
+ ], AutomergeDocumentLoaderImpl.prototype, "loadSpaceRootDocHandle", null);
1032
+ AutomergeDocumentLoaderImpl = _ts_decorate2([
1033
+ trace2.resource()
1034
+ ], AutomergeDocumentLoaderImpl);
1035
+
1036
+ // packages/core/echo/echo-pipeline/src/automerge/reference.ts
1037
+ import { Reference } from "@dxos/echo-schema";
1038
+ var REFERENCE_TYPE_TAG = "dxos.echo.model.document.Reference";
1039
+ var encodeReference = (reference) => ({
1040
+ "@type": REFERENCE_TYPE_TAG,
1041
+ // NOTE: Automerge do not support undefined values, so we need to use null instead.
1042
+ itemId: reference.itemId ?? null,
1043
+ protocol: reference.protocol ?? null,
1044
+ host: reference.host ?? null
1045
+ });
1046
+ var decodeReference = (value) => new Reference(value.itemId, value.protocol ?? void 0, value.host ?? void 0);
1047
+ var isEncodedReferenceObject = (value) => typeof value === "object" && value !== null && value["@type"] === REFERENCE_TYPE_TAG;
933
1048
  export {
934
1049
  AuthExtension,
935
1050
  AuthStatus,
@@ -937,12 +1052,14 @@ export {
937
1052
  AutomergeHost,
938
1053
  AutomergeStorageAdapter,
939
1054
  DataServiceImpl,
1055
+ LevelDBStorageAdapter,
940
1056
  LocalHostNetworkAdapter,
941
1057
  MOCK_AUTH_PROVIDER,
942
1058
  MOCK_AUTH_VERIFIER,
943
1059
  MeshNetworkAdapter,
944
1060
  MetadataStore,
945
1061
  Pipeline,
1062
+ REFERENCE_TYPE_TAG,
946
1063
  SnapshotManager,
947
1064
  SnapshotStore,
948
1065
  Space,
@@ -952,7 +1069,12 @@ export {
952
1069
  TimeframeClock,
953
1070
  codec,
954
1071
  createMappedFeedWriter,
1072
+ decodeReference,
1073
+ encodeReference,
1074
+ encodingOptions,
955
1075
  getSpaceKeyFromDoc,
1076
+ hasInvitationExpired,
1077
+ isEncodedReferenceObject,
956
1078
  mapFeedIndexesToTimeframe,
957
1079
  mapTimeframeToFeedIndexes,
958
1080
  startAfter,