@dxos/echo-pipeline 0.4.10-main.fd4f2a3 → 0.4.10-main.fd8ea31

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 (68) hide show
  1. package/dist/lib/browser/{chunk-RA6MLCZM.mjs → chunk-KMWJLYEQ.mjs} +68 -35
  2. package/dist/lib/browser/chunk-KMWJLYEQ.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +305 -231
  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-KGIYLJBT.cjs → chunk-YZA42CKA.cjs} +70 -37
  9. package/dist/lib/node/chunk-YZA42CKA.cjs.map +7 -0
  10. package/dist/lib/node/index.cjs +327 -256
  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-host.d.ts +19 -17
  16. package/dist/types/src/automerge/automerge-host.d.ts.map +1 -1
  17. package/dist/types/src/automerge/automerge-repo.test.d.ts +2 -0
  18. package/dist/types/src/automerge/automerge-repo.test.d.ts.map +1 -0
  19. package/dist/types/src/automerge/index.d.ts +1 -0
  20. package/dist/types/src/automerge/index.d.ts.map +1 -1
  21. package/dist/types/src/automerge/level.test.d.ts +2 -0
  22. package/dist/types/src/automerge/level.test.d.ts.map +1 -0
  23. package/dist/types/src/automerge/leveldb-storage-adapter.d.ts +30 -0
  24. package/dist/types/src/automerge/leveldb-storage-adapter.d.ts.map +1 -0
  25. package/dist/types/src/automerge/local-host-network-adapter.d.ts +8 -1
  26. package/dist/types/src/automerge/local-host-network-adapter.d.ts.map +1 -1
  27. package/dist/types/src/automerge/migrations.d.ts +7 -0
  28. package/dist/types/src/automerge/migrations.d.ts.map +1 -0
  29. package/dist/types/src/automerge/reference.d.ts +1 -1
  30. package/dist/types/src/automerge/reference.d.ts.map +1 -1
  31. package/dist/types/src/automerge/storage-adapter.test.d.ts +2 -0
  32. package/dist/types/src/automerge/storage-adapter.test.d.ts.map +1 -0
  33. package/dist/types/src/automerge/types.d.ts +6 -0
  34. package/dist/types/src/automerge/types.d.ts.map +1 -1
  35. package/dist/types/src/metadata/metadata-store.d.ts +2 -1
  36. package/dist/types/src/metadata/metadata-store.d.ts.map +1 -1
  37. package/dist/types/src/space/control-pipeline.d.ts +3 -1
  38. package/dist/types/src/space/control-pipeline.d.ts.map +1 -1
  39. package/dist/types/src/space/space-manager.d.ts +3 -1
  40. package/dist/types/src/space/space-manager.d.ts.map +1 -1
  41. package/dist/types/src/space/space.d.ts +2 -1
  42. package/dist/types/src/space/space.d.ts.map +1 -1
  43. package/dist/types/src/testing/index.d.ts +1 -0
  44. package/dist/types/src/testing/index.d.ts.map +1 -1
  45. package/dist/types/src/testing/level.d.ts +3 -0
  46. package/dist/types/src/testing/level.d.ts.map +1 -0
  47. package/dist/types/src/testing/test-agent-builder.d.ts.map +1 -1
  48. package/package.json +33 -30
  49. package/src/automerge/automerge-host.test.ts +22 -8
  50. package/src/automerge/automerge-host.ts +53 -114
  51. package/src/automerge/automerge-repo.test.ts +29 -0
  52. package/src/automerge/index.ts +1 -0
  53. package/src/automerge/level.test.ts +82 -0
  54. package/src/automerge/leveldb-storage-adapter.ts +117 -0
  55. package/src/automerge/local-host-network-adapter.ts +19 -13
  56. package/src/automerge/migrations.ts +41 -0
  57. package/src/automerge/reference.ts +1 -1
  58. package/src/automerge/storage-adapter.test.ts +90 -0
  59. package/src/automerge/types.ts +6 -3
  60. package/src/metadata/metadata-store.ts +17 -8
  61. package/src/space/control-pipeline.ts +11 -1
  62. package/src/space/space-manager.ts +4 -0
  63. package/src/space/space.ts +11 -1
  64. package/src/testing/index.ts +1 -0
  65. package/src/testing/level.ts +11 -0
  66. package/src/testing/test-agent-builder.ts +1 -0
  67. package/dist/lib/browser/chunk-RA6MLCZM.mjs.map +0 -7
  68. package/dist/lib/node/chunk-KGIYLJBT.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-RA6MLCZM.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: 101,
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: 108,
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: 117,
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: 123,
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: 133,
613
+ F: __dxlog_file4,
614
+ L: 132,
488
615
  S: this,
489
616
  C: (f, a) => f(...a)
490
617
  });
@@ -494,61 +621,16 @@ 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
- Object.values(this._repo.handles).forEach((handle) => handle.off("change"));
503
- });
504
- }
624
+ await this._clientNetwork.whenConnected();
625
+ }
626
+ async close() {
627
+ await this._storage.close?.();
628
+ await this._clientNetwork.close();
629
+ await this._ctx.dispose();
505
630
  }
506
631
  get repo() {
507
632
  return this._repo;
508
633
  }
509
- async _beforeSave(path) {
510
- const id = path[0];
511
- if (this._updatingMetadata.has(id)) {
512
- return this._updatingMetadata.get(id);
513
- }
514
- }
515
- _onDocument(handle) {
516
- const listener = (event) => this._onUpdate(event);
517
- handle.on("change", listener);
518
- }
519
- _onUpdate(event) {
520
- if (this._metadata == null) {
521
- return;
522
- }
523
- const objectIds = getInlineChanges(event);
524
- if (objectIds.length === 0) {
525
- return;
526
- }
527
- const heads = getHeads(event.doc);
528
- const lastAvailableHash = heads.join("");
529
- if (!lastAvailableHash) {
530
- return;
531
- }
532
- const encodedIds = objectIds.map((objectId) => idCodec.encode({
533
- documentId: event.handle.documentId,
534
- objectId
535
- }));
536
- const idToLastHash = new Map(encodedIds.map((id) => [
537
- id,
538
- lastAvailableHash
539
- ]));
540
- const markingDirtyPromise = this._metadata.markDirty(idToLastHash).then(() => {
541
- this._updatingMetadata.delete(event.handle.documentId);
542
- }).catch((err) => {
543
- this._ctx.disposed && log3.catch(err, void 0, {
544
- F: __dxlog_file3,
545
- L: 191,
546
- S: this,
547
- C: (f, a) => f(...a)
548
- });
549
- });
550
- this._updatingMetadata.set(event.handle.documentId, markingDirtyPromise);
551
- }
552
634
  _automergeDocs() {
553
635
  return mapValues(this._repo.handles, (handle) => ({
554
636
  state: handle.state,
@@ -574,17 +656,24 @@ var AutomergeHost = class {
574
656
  _automergePeers() {
575
657
  return this._repo.peers;
576
658
  }
577
- async close() {
578
- await this._storage.close();
579
- await this._clientNetwork.close();
580
- await this._ctx.dispose();
581
- }
582
659
  //
583
660
  // Methods for client-services.
584
661
  //
585
662
  async flush({ documentIds }) {
586
663
  await Promise.all(documentIds?.map((id) => this._repo.find(id).whenReady()) ?? []);
587
- await this._repo.flush(documentIds);
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
+ }
588
677
  }
589
678
  syncRepo(request) {
590
679
  return this._clientNetwork.syncRepo(request);
@@ -606,8 +695,8 @@ var AutomergeHost = class {
606
695
  spaceKey,
607
696
  deviceKey
608
697
  }, {
609
- F: __dxlog_file3,
610
- L: 264,
698
+ F: __dxlog_file4,
699
+ L: 221,
611
700
  S: this,
612
701
  C: (f, a) => f(...a)
613
702
  });
@@ -630,24 +719,6 @@ _ts_decorate([
630
719
  AutomergeHost = _ts_decorate([
631
720
  trace.resource()
632
721
  ], AutomergeHost);
633
- var getInlineChanges = (event) => {
634
- const inlineChangedObjectIds = /* @__PURE__ */ new Set();
635
- for (const { path } of event.patches) {
636
- if (path.length < 2) {
637
- continue;
638
- }
639
- switch (path[0]) {
640
- case "objects":
641
- if (path.length >= 2) {
642
- inlineChangedObjectIds.add(path[1]);
643
- }
644
- break;
645
- }
646
- }
647
- return [
648
- ...inlineChangedObjectIds
649
- ];
650
- };
651
722
  var getSpaceKeyFromDoc = (doc) => {
652
723
  const rawSpaceKey = doc.access?.spaceKey ?? doc.experimental_spaceKey;
653
724
  if (rawSpaceKey == null) {
@@ -662,7 +733,7 @@ import { cancelWithContext } from "@dxos/context";
662
733
  import { warnAfterTimeout } from "@dxos/debug";
663
734
  import { invariant as invariant3 } from "@dxos/invariant";
664
735
  import { log as log4 } from "@dxos/log";
665
- 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";
666
737
  var AutomergeDocumentLoaderImpl = class {
667
738
  constructor(_spaceKey, _repo) {
668
739
  this._spaceKey = _spaceKey;
@@ -685,7 +756,7 @@ var AutomergeDocumentLoaderImpl = class {
685
756
  log4.error("Database opened with no rootUrl", {
686
757
  spaceKey: this._spaceKey
687
758
  }, {
688
- F: __dxlog_file4,
759
+ F: __dxlog_file5,
689
760
  L: 66,
690
761
  S: this,
691
762
  C: (f, a) => f(...a)
@@ -695,7 +766,7 @@ var AutomergeDocumentLoaderImpl = class {
695
766
  const existingDocHandle = await this._initDocHandle(ctx, spaceState.rootUrl);
696
767
  const doc = existingDocHandle.docSync();
697
768
  invariant3(doc, void 0, {
698
- F: __dxlog_file4,
769
+ F: __dxlog_file5,
699
770
  L: 71,
700
771
  S: this,
701
772
  A: [
@@ -711,7 +782,7 @@ var AutomergeDocumentLoaderImpl = class {
711
782
  }
712
783
  loadObjectDocument(objectId) {
713
784
  invariant3(this._spaceRootDocHandle, void 0, {
714
- F: __dxlog_file4,
785
+ F: __dxlog_file5,
715
786
  L: 80,
716
787
  S: this,
717
788
  A: [
@@ -724,7 +795,7 @@ var AutomergeDocumentLoaderImpl = class {
724
795
  }
725
796
  const spaceRootDoc = this._spaceRootDocHandle.docSync();
726
797
  invariant3(spaceRootDoc, void 0, {
727
- F: __dxlog_file4,
798
+ F: __dxlog_file5,
728
799
  L: 85,
729
800
  S: this,
730
801
  A: [
@@ -738,7 +809,7 @@ var AutomergeDocumentLoaderImpl = class {
738
809
  log4.info("loading delayed until object links are initialized", {
739
810
  objectId
740
811
  }, {
741
- F: __dxlog_file4,
812
+ F: __dxlog_file5,
742
813
  L: 89,
743
814
  S: this,
744
815
  C: (f, a) => f(...a)
@@ -759,7 +830,7 @@ var AutomergeDocumentLoaderImpl = class {
759
830
  }
760
831
  getSpaceRootDocHandle() {
761
832
  invariant3(this._spaceRootDocHandle, void 0, {
762
- F: __dxlog_file4,
833
+ F: __dxlog_file5,
763
834
  L: 107,
764
835
  S: this,
765
836
  A: [
@@ -771,7 +842,7 @@ var AutomergeDocumentLoaderImpl = class {
771
842
  }
772
843
  createDocumentForObject(objectId) {
773
844
  invariant3(this._spaceRootDocHandle, void 0, {
774
- F: __dxlog_file4,
845
+ F: __dxlog_file5,
775
846
  L: 112,
776
847
  S: this,
777
848
  A: [
@@ -814,7 +885,7 @@ var AutomergeDocumentLoaderImpl = class {
814
885
  ...logMeta,
815
886
  actualDocumentUrl: objectDocumentHandle.url
816
887
  }, {
817
- F: __dxlog_file4,
888
+ F: __dxlog_file5,
818
889
  L: 142,
819
890
  S: this,
820
891
  C: (f, a) => f(...a)
@@ -823,7 +894,7 @@ var AutomergeDocumentLoaderImpl = class {
823
894
  }
824
895
  if (objectDocumentHandle?.url === automergeUrl) {
825
896
  log4.warn("object document was already loaded", logMeta, {
826
- F: __dxlog_file4,
897
+ F: __dxlog_file5,
827
898
  L: 149,
828
899
  S: this,
829
900
  C: (f, a) => f(...a)
@@ -832,7 +903,7 @@ var AutomergeDocumentLoaderImpl = class {
832
903
  }
833
904
  const handle = this._repo.find(automergeUrl);
834
905
  log4.debug("document loading triggered", logMeta, {
835
- F: __dxlog_file4,
906
+ F: __dxlog_file5,
836
907
  L: 153,
837
908
  S: this,
838
909
  C: (f, a) => f(...a)
@@ -855,7 +926,7 @@ var AutomergeDocumentLoaderImpl = class {
855
926
  id: docHandle.documentId,
856
927
  state: docHandle.state
857
928
  }, {
858
- F: __dxlog_file4,
929
+ F: __dxlog_file5,
859
930
  L: 169,
860
931
  S: this,
861
932
  C: (f, a) => f(...a)
@@ -897,7 +968,7 @@ var AutomergeDocumentLoaderImpl = class {
897
968
  };
898
969
  if (this.onObjectDocumentLoaded.listenerCount() === 0) {
899
970
  log4.info("document loaded after all listeners were removed", logMeta, {
900
- F: __dxlog_file4,
971
+ F: __dxlog_file5,
901
972
  L: 205,
902
973
  S: this,
903
974
  C: (f, a) => f(...a)
@@ -907,7 +978,7 @@ var AutomergeDocumentLoaderImpl = class {
907
978
  const objectDocHandle = this._objectDocumentHandles.get(objectId);
908
979
  if (objectDocHandle?.url !== handle.url) {
909
980
  log4.warn("object was rebound while a document was loading, discarding handle", logMeta, {
910
- F: __dxlog_file4,
981
+ F: __dxlog_file5,
911
982
  L: 210,
912
983
  S: this,
913
984
  C: (f, a) => f(...a)
@@ -926,7 +997,7 @@ var AutomergeDocumentLoaderImpl = class {
926
997
  retryLoading: shouldRetryLoading,
927
998
  err
928
999
  }, {
929
- F: __dxlog_file4,
1000
+ F: __dxlog_file5,
930
1001
  L: 216,
931
1002
  S: this,
932
1003
  C: (f, a) => f(...a)
@@ -939,7 +1010,7 @@ var AutomergeDocumentLoaderImpl = class {
939
1010
  };
940
1011
 
941
1012
  // packages/core/echo/echo-pipeline/src/automerge/reference.ts
942
- import { Reference } from "@dxos/echo-db";
1013
+ import { Reference } from "@dxos/echo-schema";
943
1014
  var REFERENCE_TYPE_TAG = "dxos.echo.model.document.Reference";
944
1015
  var encodeReference = (reference) => ({
945
1016
  "@type": REFERENCE_TYPE_TAG,
@@ -957,6 +1028,7 @@ export {
957
1028
  AutomergeHost,
958
1029
  AutomergeStorageAdapter,
959
1030
  DataServiceImpl,
1031
+ LevelDBStorageAdapter,
960
1032
  LocalHostNetworkAdapter,
961
1033
  MOCK_AUTH_PROVIDER,
962
1034
  MOCK_AUTH_VERIFIER,
@@ -975,7 +1047,9 @@ export {
975
1047
  createMappedFeedWriter,
976
1048
  decodeReference,
977
1049
  encodeReference,
1050
+ encodingOptions,
978
1051
  getSpaceKeyFromDoc,
1052
+ hasInvitationExpired,
979
1053
  isEncodedReferenceObject,
980
1054
  mapFeedIndexesToTimeframe,
981
1055
  mapTimeframeToFeedIndexes,