@dxos/echo-pipeline 0.4.10-main.ef6fbc2 → 0.4.10-main.f635fb0

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 (54) hide show
  1. package/dist/lib/browser/{chunk-RA6MLCZM.mjs → chunk-SYE4EK33.mjs} +17 -9
  2. package/dist/lib/browser/chunk-SYE4EK33.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +304 -230
  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-KGIYLJBT.cjs → chunk-WCTX6RNS.cjs} +19 -11
  9. package/dist/lib/node/chunk-WCTX6RNS.cjs.map +7 -0
  10. package/dist/lib/node/index.cjs +325 -254
  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-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/storage-adapter.test.d.ts +2 -0
  30. package/dist/types/src/automerge/storage-adapter.test.d.ts.map +1 -0
  31. package/dist/types/src/automerge/types.d.ts +6 -0
  32. package/dist/types/src/automerge/types.d.ts.map +1 -1
  33. package/dist/types/src/metadata/metadata-store.d.ts +2 -1
  34. package/dist/types/src/metadata/metadata-store.d.ts.map +1 -1
  35. package/dist/types/src/testing/index.d.ts +1 -0
  36. package/dist/types/src/testing/index.d.ts.map +1 -1
  37. package/dist/types/src/testing/level.d.ts +3 -0
  38. package/dist/types/src/testing/level.d.ts.map +1 -0
  39. package/package.json +33 -30
  40. package/src/automerge/automerge-host.test.ts +22 -8
  41. package/src/automerge/automerge-host.ts +52 -114
  42. package/src/automerge/automerge-repo.test.ts +29 -0
  43. package/src/automerge/index.ts +1 -0
  44. package/src/automerge/level.test.ts +64 -0
  45. package/src/automerge/leveldb-storage-adapter.ts +117 -0
  46. package/src/automerge/local-host-network-adapter.ts +19 -13
  47. package/src/automerge/migrations.ts +41 -0
  48. package/src/automerge/storage-adapter.test.ts +90 -0
  49. package/src/automerge/types.ts +6 -3
  50. package/src/metadata/metadata-store.ts +17 -8
  51. package/src/testing/index.ts +1 -0
  52. package/src/testing/level.ts +11 -0
  53. package/dist/lib/browser/chunk-RA6MLCZM.mjs.map +0 -7
  54. package/dist/lib/node/chunk-KGIYLJBT.cjs.map +0 -7
@@ -18,173 +18,169 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var node_exports = {};
20
20
  __export(node_exports, {
21
- AuthExtension: () => import_chunk_KGIYLJBT.AuthExtension,
22
- AuthStatus: () => import_chunk_KGIYLJBT.AuthStatus,
21
+ AuthExtension: () => import_chunk_WCTX6RNS.AuthExtension,
22
+ AuthStatus: () => import_chunk_WCTX6RNS.AuthStatus,
23
23
  AutomergeDocumentLoaderImpl: () => AutomergeDocumentLoaderImpl,
24
24
  AutomergeHost: () => AutomergeHost,
25
25
  AutomergeStorageAdapter: () => AutomergeStorageAdapter,
26
- DataServiceImpl: () => import_chunk_KGIYLJBT.DataServiceImpl,
26
+ DataServiceImpl: () => import_chunk_WCTX6RNS.DataServiceImpl,
27
+ LevelDBStorageAdapter: () => LevelDBStorageAdapter,
27
28
  LocalHostNetworkAdapter: () => LocalHostNetworkAdapter,
28
- MOCK_AUTH_PROVIDER: () => import_chunk_KGIYLJBT.MOCK_AUTH_PROVIDER,
29
- MOCK_AUTH_VERIFIER: () => import_chunk_KGIYLJBT.MOCK_AUTH_VERIFIER,
29
+ MOCK_AUTH_PROVIDER: () => import_chunk_WCTX6RNS.MOCK_AUTH_PROVIDER,
30
+ MOCK_AUTH_VERIFIER: () => import_chunk_WCTX6RNS.MOCK_AUTH_VERIFIER,
30
31
  MeshNetworkAdapter: () => MeshNetworkAdapter,
31
- MetadataStore: () => import_chunk_KGIYLJBT.MetadataStore,
32
- Pipeline: () => import_chunk_KGIYLJBT.Pipeline,
32
+ MetadataStore: () => import_chunk_WCTX6RNS.MetadataStore,
33
+ Pipeline: () => import_chunk_WCTX6RNS.Pipeline,
33
34
  REFERENCE_TYPE_TAG: () => REFERENCE_TYPE_TAG,
34
- SnapshotManager: () => import_chunk_KGIYLJBT.SnapshotManager,
35
- SnapshotStore: () => import_chunk_KGIYLJBT.SnapshotStore,
36
- Space: () => import_chunk_KGIYLJBT.Space,
37
- SpaceManager: () => import_chunk_KGIYLJBT.SpaceManager,
38
- SpaceProtocol: () => import_chunk_KGIYLJBT.SpaceProtocol,
39
- SpaceProtocolSession: () => import_chunk_KGIYLJBT.SpaceProtocolSession,
40
- TimeframeClock: () => import_chunk_KGIYLJBT.TimeframeClock,
41
- codec: () => import_chunk_KGIYLJBT.codec,
42
- createMappedFeedWriter: () => import_chunk_KGIYLJBT.createMappedFeedWriter,
35
+ SnapshotManager: () => import_chunk_WCTX6RNS.SnapshotManager,
36
+ SnapshotStore: () => import_chunk_WCTX6RNS.SnapshotStore,
37
+ Space: () => import_chunk_WCTX6RNS.Space,
38
+ SpaceManager: () => import_chunk_WCTX6RNS.SpaceManager,
39
+ SpaceProtocol: () => import_chunk_WCTX6RNS.SpaceProtocol,
40
+ SpaceProtocolSession: () => import_chunk_WCTX6RNS.SpaceProtocolSession,
41
+ TimeframeClock: () => import_chunk_WCTX6RNS.TimeframeClock,
42
+ codec: () => import_chunk_WCTX6RNS.codec,
43
+ createMappedFeedWriter: () => import_chunk_WCTX6RNS.createMappedFeedWriter,
43
44
  decodeReference: () => decodeReference,
44
45
  encodeReference: () => encodeReference,
46
+ encodingOptions: () => encodingOptions,
45
47
  getSpaceKeyFromDoc: () => getSpaceKeyFromDoc,
48
+ hasInvitationExpired: () => import_chunk_WCTX6RNS.hasInvitationExpired,
46
49
  isEncodedReferenceObject: () => isEncodedReferenceObject,
47
- mapFeedIndexesToTimeframe: () => import_chunk_KGIYLJBT.mapFeedIndexesToTimeframe,
48
- mapTimeframeToFeedIndexes: () => import_chunk_KGIYLJBT.mapTimeframeToFeedIndexes,
49
- startAfter: () => import_chunk_KGIYLJBT.startAfter,
50
- valueEncoding: () => import_chunk_KGIYLJBT.valueEncoding
50
+ mapFeedIndexesToTimeframe: () => import_chunk_WCTX6RNS.mapFeedIndexesToTimeframe,
51
+ mapTimeframeToFeedIndexes: () => import_chunk_WCTX6RNS.mapTimeframeToFeedIndexes,
52
+ startAfter: () => import_chunk_WCTX6RNS.startAfter,
53
+ valueEncoding: () => import_chunk_WCTX6RNS.valueEncoding
51
54
  });
52
55
  module.exports = __toCommonJS(node_exports);
53
- var import_chunk_KGIYLJBT = require("./chunk-KGIYLJBT.cjs");
56
+ var import_chunk_WCTX6RNS = require("./chunk-WCTX6RNS.cjs");
57
+ var import_async = require("@dxos/async");
54
58
  var import_automerge = require("@dxos/automerge/automerge");
55
59
  var import_automerge_repo = require("@dxos/automerge/automerge-repo");
56
- var import_automerge_repo_storage_indexeddb = require("@dxos/automerge/automerge-repo-storage-indexeddb");
57
60
  var import_context = require("@dxos/context");
58
61
  var import_keys = require("@dxos/keys");
59
62
  var import_log = require("@dxos/log");
60
- var import_protocols = require("@dxos/protocols");
61
- var import_random_access_storage = require("@dxos/random-access-storage");
62
63
  var import_tracing = require("@dxos/tracing");
63
64
  var import_util = require("@dxos/util");
64
- var import_util2 = require("@dxos/util");
65
- var import_async = require("@dxos/async");
65
+ var import_context2 = require("@dxos/context");
66
+ var import_async2 = require("@dxos/async");
66
67
  var import_automerge_repo2 = require("@dxos/automerge/automerge-repo");
67
68
  var import_codec_protobuf = require("@dxos/codec-protobuf");
68
69
  var import_invariant = require("@dxos/invariant");
69
- var import_log2 = require("@dxos/log");
70
- var import_async2 = require("@dxos/async");
70
+ var import_async3 = require("@dxos/async");
71
71
  var import_automerge_repo3 = require("@dxos/automerge/automerge-repo");
72
72
  var import_invariant2 = require("@dxos/invariant");
73
- var import_log3 = require("@dxos/log");
73
+ var import_log2 = require("@dxos/log");
74
74
  var import_teleport_extension_automerge_replicator = require("@dxos/teleport-extension-automerge-replicator");
75
- var import_async3 = require("@dxos/async");
76
- var import_context2 = require("@dxos/context");
75
+ var import_automerge_repo_storage_indexeddb = require("@dxos/automerge/automerge-repo-storage-indexeddb");
76
+ var import_log3 = require("@dxos/log");
77
+ var import_random_access_storage = require("@dxos/random-access-storage");
78
+ var import_util2 = require("@dxos/util");
79
+ var import_async4 = require("@dxos/async");
80
+ var import_context3 = require("@dxos/context");
77
81
  var import_debug = require("@dxos/debug");
78
82
  var import_invariant3 = require("@dxos/invariant");
79
83
  var import_log4 = require("@dxos/log");
80
84
  var import_echo_db = require("@dxos/echo-db");
81
- var AutomergeStorageAdapter = class {
82
- constructor(_directory) {
83
- this._directory = _directory;
84
- this._state = "opened";
85
+ var LevelDBStorageAdapter = class extends import_context2.Resource {
86
+ constructor(_params) {
87
+ super();
88
+ this._params = _params;
85
89
  }
86
- async load(key) {
87
- if (this._state !== "opened") {
88
- return void 0;
89
- }
90
- const filename = this._getFilename(key);
91
- const file = this._directory.getOrCreateFile(filename);
92
- const { size } = await file.stat();
93
- if (!size || size === 0) {
94
- return void 0;
90
+ async load(keyArray) {
91
+ try {
92
+ if (this._lifecycleState !== import_context2.LifecycleState.OPEN) {
93
+ return void 0;
94
+ }
95
+ return await this._params.db.get(keyArray, {
96
+ ...encodingOptions
97
+ });
98
+ } catch (err) {
99
+ if (isLevelDbNotFoundError(err)) {
100
+ return void 0;
101
+ }
102
+ throw err;
95
103
  }
96
- const buffer = await file.read(0, size);
97
- return (0, import_util2.bufferToArray)(buffer);
98
104
  }
99
- async save(key, data) {
100
- if (this._state !== "opened") {
105
+ async save(keyArray, binary) {
106
+ if (this._lifecycleState !== import_context2.LifecycleState.OPEN) {
101
107
  return void 0;
102
108
  }
103
- const filename = this._getFilename(key);
104
- const file = this._directory.getOrCreateFile(filename);
105
- await file.write(0, (0, import_util2.arrayToBuffer)(data));
106
- await file.truncate?.(data.length);
107
- await file.flush?.();
109
+ const batch = this._params.db.batch();
110
+ await this._params.callbacks?.beforeSave?.({
111
+ path: keyArray,
112
+ batch
113
+ });
114
+ batch.put(keyArray, Buffer.from(binary), {
115
+ ...encodingOptions
116
+ });
117
+ await batch.write();
118
+ await this._params.callbacks?.afterSave?.(keyArray);
108
119
  }
109
- async remove(key) {
110
- if (this._state !== "opened") {
120
+ async remove(keyArray) {
121
+ if (this._lifecycleState !== import_context2.LifecycleState.OPEN) {
111
122
  return void 0;
112
123
  }
113
- const filename = this._getFilename(key);
114
- const file = this._directory.getOrCreateFile(filename);
115
- await file.destroy();
124
+ await this._params.db.del(keyArray, {
125
+ ...encodingOptions
126
+ });
116
127
  }
117
128
  async loadRange(keyPrefix) {
118
- if (this._state !== "opened") {
129
+ if (this._lifecycleState !== import_context2.LifecycleState.OPEN) {
119
130
  return [];
120
131
  }
121
- const filename = this._getFilename(keyPrefix);
122
- const entries = await this._directory.list();
123
- return Promise.all(entries.filter((entry) => entry.startsWith(filename)).map(async (entry) => {
124
- const file = this._directory.getOrCreateFile(entry);
125
- const { size } = await file.stat();
126
- const buffer = await file.read(0, size);
127
- return {
128
- key: this._getKeyFromFilename(entry),
129
- data: (0, import_util2.bufferToArray)(buffer)
130
- };
131
- }));
132
+ const result = [];
133
+ for await (const [key, value] of this._params.db.iterator({
134
+ gte: keyPrefix,
135
+ lte: [
136
+ ...keyPrefix,
137
+ "\uFFFF"
138
+ ],
139
+ ...encodingOptions
140
+ })) {
141
+ result.push({
142
+ key,
143
+ data: value
144
+ });
145
+ }
146
+ return result;
132
147
  }
133
148
  async removeRange(keyPrefix) {
134
- if (this._state !== "opened") {
149
+ if (this._lifecycleState !== import_context2.LifecycleState.OPEN) {
135
150
  return void 0;
136
151
  }
137
- const filename = this._getFilename(keyPrefix);
138
- const entries = await this._directory.list();
139
- await Promise.all(entries.filter((entry) => entry.startsWith(filename)).map(async (entry) => {
140
- const file = this._directory.getOrCreateFile(entry);
141
- await file.destroy();
142
- }));
143
- }
144
- async close() {
145
- this._state = "closed";
146
- }
147
- _getFilename(key) {
148
- return key.map((k) => k.replaceAll("%", "%25").replaceAll("-", "%2D")).join("-");
149
- }
150
- _getKeyFromFilename(filename) {
151
- return filename.split("-").map((k) => k.replaceAll("%2D", "-").replaceAll("%25", "%"));
152
- }
153
- };
154
- var AutomergeStorageWrapper = class {
155
- constructor({ storage, callbacks }) {
156
- this._storage = storage;
157
- this._callbacks = callbacks;
158
- }
159
- async load(key) {
160
- return this._storage.load(key);
161
- }
162
- async save(key, value) {
163
- await this._callbacks.beforeSave?.(key);
164
- await this._storage.save(key, value);
165
- await this._callbacks.afterSave?.(key);
166
- }
167
- async remove(key) {
168
- return this._storage.remove(key);
169
- }
170
- async loadRange(keyPrefix) {
171
- return this._storage.loadRange(keyPrefix);
172
- }
173
- async removeRange(keyPrefix) {
174
- return this._storage.removeRange(keyPrefix);
175
- }
176
- async close() {
177
- if (this._storage instanceof AutomergeStorageAdapter) {
178
- return this._storage.close();
152
+ const batch = this._params.db.batch();
153
+ for await (const [key] of this._params.db.iterator({
154
+ gte: keyPrefix,
155
+ lte: [
156
+ ...keyPrefix,
157
+ "\uFFFF"
158
+ ],
159
+ ...encodingOptions
160
+ })) {
161
+ batch.del(key, {
162
+ ...encodingOptions
163
+ });
179
164
  }
165
+ await batch.write();
180
166
  }
181
167
  };
168
+ var keyEncoder = {
169
+ encode: (key) => Buffer.from(key.map((k) => k.replaceAll("%", "%25").replaceAll("-", "%2D")).join("-")),
170
+ decode: (key) => Buffer.from(key).toString().split("-").map((k) => k.replaceAll("%2D", "-").replaceAll("%25", "%"))
171
+ };
172
+ var encodingOptions = {
173
+ keyEncoding: keyEncoder,
174
+ valueEncoding: "buffer"
175
+ };
176
+ var isLevelDbNotFoundError = (err) => err.code === "LEVEL_NOT_FOUND";
182
177
  var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/local-host-network-adapter.ts";
183
178
  var LocalHostNetworkAdapter = class extends import_automerge_repo2.NetworkAdapter {
184
179
  constructor() {
185
180
  super(...arguments);
186
181
  this._peers = /* @__PURE__ */ new Map();
187
- this._connected = new import_async.Trigger();
182
+ this._connected = new import_async2.Trigger();
183
+ this._isConnected = false;
188
184
  }
189
185
  /**
190
186
  * Emits `ready` event. That signals to `Repo` that it can start using the adapter.
@@ -194,15 +190,21 @@ var LocalHostNetworkAdapter = class extends import_automerge_repo2.NetworkAdapte
194
190
  network: this
195
191
  });
196
192
  }
193
+ /**
194
+ * Called by `Repo` to connect to the network.
195
+ *
196
+ * @param peerId Our peer Id.
197
+ */
197
198
  connect(peerId) {
198
199
  this.peerId = peerId;
200
+ this._isConnected = true;
199
201
  this._connected.wake();
200
202
  }
201
203
  send(message) {
202
204
  const peer = this._peers.get(message.targetId);
203
205
  (0, import_invariant.invariant)(peer, "Peer not found.", {
204
206
  F: __dxlog_file,
205
- L: 45,
207
+ L: 51,
206
208
  S: this,
207
209
  A: [
208
210
  "peer",
@@ -217,12 +219,17 @@ var LocalHostNetworkAdapter = class extends import_automerge_repo2.NetworkAdapte
217
219
  }
218
220
  disconnect() {
219
221
  }
222
+ async whenConnected() {
223
+ await this._connected.wait({
224
+ timeout: 1e4
225
+ });
226
+ }
220
227
  syncRepo({ id, syncMessage }) {
221
228
  const peerId = this._getPeerId(id);
222
229
  return new import_codec_protobuf.Stream(({ next, close }) => {
223
230
  (0, import_invariant.invariant)(!this._peers.has(peerId), "Peer already connected.", {
224
231
  F: __dxlog_file,
225
- L: 63,
232
+ L: 73,
226
233
  S: this,
227
234
  A: [
228
235
  "!this._peers.has(peerId)",
@@ -244,35 +251,47 @@ var LocalHostNetworkAdapter = class extends import_automerge_repo2.NetworkAdapte
244
251
  });
245
252
  }
246
253
  });
247
- this._connected.wait({
248
- timeout: 1e3
249
- }).then(() => {
250
- this.emit("peer-candidate", {
251
- peerMetadata: {},
252
- peerId
253
- });
254
- }).catch((err) => import_log2.log.catch(err, void 0, {
254
+ (0, import_invariant.invariant)(this._isConnected, void 0, {
255
255
  F: __dxlog_file,
256
- L: 88,
256
+ L: 90,
257
257
  S: this,
258
- C: (f, a) => f(...a)
259
- }));
258
+ A: [
259
+ "this._isConnected",
260
+ ""
261
+ ]
262
+ });
263
+ this.emit("peer-candidate", {
264
+ peerMetadata: {},
265
+ peerId
266
+ });
260
267
  });
261
268
  }
262
269
  async sendSyncMessage({ id, syncMessage }) {
263
- await this._connected.wait({
264
- timeout: 1e3
270
+ (0, import_invariant.invariant)(this._isConnected, void 0, {
271
+ F: __dxlog_file,
272
+ L: 99,
273
+ S: this,
274
+ A: [
275
+ "this._isConnected",
276
+ ""
277
+ ]
265
278
  });
266
279
  const message = import_automerge_repo2.cbor.decode(syncMessage);
267
280
  this.emit("message", message);
268
281
  }
269
282
  async getHostInfo() {
270
- await this._connected.wait({
271
- timeout: 1e3
283
+ (0, import_invariant.invariant)(this._isConnected, void 0, {
284
+ F: __dxlog_file,
285
+ L: 105,
286
+ S: this,
287
+ A: [
288
+ "this._isConnected",
289
+ ""
290
+ ]
272
291
  });
273
292
  (0, import_invariant.invariant)(this.peerId, "Peer id not set.", {
274
293
  F: __dxlog_file,
275
- L: 100,
294
+ L: 106,
276
295
  S: this,
277
296
  A: [
278
297
  "this.peerId",
@@ -292,7 +311,7 @@ var MeshNetworkAdapter = class extends import_automerge_repo3.NetworkAdapter {
292
311
  constructor() {
293
312
  super(...arguments);
294
313
  this._extensions = /* @__PURE__ */ new Map();
295
- this._connected = new import_async2.Trigger();
314
+ this._connected = new import_async3.Trigger();
296
315
  }
297
316
  /**
298
317
  * Emits `ready` event. That signals to `Repo` that it can start using the adapter.
@@ -320,7 +339,7 @@ var MeshNetworkAdapter = class extends import_automerge_repo3.NetworkAdapter {
320
339
  });
321
340
  extension.sendSyncMessage({
322
341
  payload: import_automerge_repo3.cbor.encode(message)
323
- }).catch((err) => import_log3.log.catch(err, void 0, {
342
+ }).catch((err) => import_log2.log.catch(err, void 0, {
324
343
  F: __dxlog_file2,
325
344
  L: 39,
326
345
  S: this,
@@ -345,7 +364,7 @@ var MeshNetworkAdapter = class extends import_automerge_repo3.NetworkAdapter {
345
364
  }, {
346
365
  onStartReplication: async (info, remotePeerId) => {
347
366
  await this._connected.wait();
348
- (0, import_log3.log)("onStartReplication", {
367
+ (0, import_log2.log)("onStartReplication", {
349
368
  id: info.id,
350
369
  thisPeerId: this.peerId,
351
370
  remotePeerId: remotePeerId.toHex()
@@ -358,7 +377,7 @@ var MeshNetworkAdapter = class extends import_automerge_repo3.NetworkAdapter {
358
377
  if (!this._extensions.has(info.id)) {
359
378
  peerInfo = info;
360
379
  this._extensions.set(info.id, extension);
361
- (0, import_log3.log)("peer-candidate", {
380
+ (0, import_log2.log)("peer-candidate", {
362
381
  id: info.id,
363
382
  thisPeerId: this.peerId,
364
383
  remotePeerId: remotePeerId.toHex()
@@ -397,6 +416,108 @@ var MeshNetworkAdapter = class extends import_automerge_repo3.NetworkAdapter {
397
416
  return extension;
398
417
  }
399
418
  };
419
+ var AutomergeStorageAdapter = class {
420
+ constructor(_directory) {
421
+ this._directory = _directory;
422
+ this._state = "opened";
423
+ }
424
+ async load(key) {
425
+ if (this._state !== "opened") {
426
+ return void 0;
427
+ }
428
+ const filename = this._getFilename(key);
429
+ const file = this._directory.getOrCreateFile(filename);
430
+ const { size } = await file.stat();
431
+ if (!size || size === 0) {
432
+ return void 0;
433
+ }
434
+ const buffer = await file.read(0, size);
435
+ return (0, import_util2.bufferToArray)(buffer);
436
+ }
437
+ async save(key, data) {
438
+ if (this._state !== "opened") {
439
+ return void 0;
440
+ }
441
+ const filename = this._getFilename(key);
442
+ const file = this._directory.getOrCreateFile(filename);
443
+ await file.write(0, (0, import_util2.arrayToBuffer)(data));
444
+ await file.truncate?.(data.length);
445
+ await file.flush?.();
446
+ }
447
+ async remove(key) {
448
+ if (this._state !== "opened") {
449
+ return void 0;
450
+ }
451
+ const filename = this._getFilename(key);
452
+ const file = this._directory.getOrCreateFile(filename);
453
+ await file.destroy();
454
+ }
455
+ async loadRange(keyPrefix) {
456
+ if (this._state !== "opened") {
457
+ return [];
458
+ }
459
+ const filename = this._getFilename(keyPrefix);
460
+ const entries = await this._directory.list();
461
+ return Promise.all(entries.filter((entry) => entry.startsWith(filename)).map(async (entry) => {
462
+ const file = this._directory.getOrCreateFile(entry);
463
+ const { size } = await file.stat();
464
+ const buffer = await file.read(0, size);
465
+ return {
466
+ key: this._getKeyFromFilename(entry),
467
+ data: (0, import_util2.bufferToArray)(buffer)
468
+ };
469
+ }));
470
+ }
471
+ async removeRange(keyPrefix) {
472
+ if (this._state !== "opened") {
473
+ return void 0;
474
+ }
475
+ const filename = this._getFilename(keyPrefix);
476
+ const entries = await this._directory.list();
477
+ await Promise.all(entries.filter((entry) => entry.startsWith(filename)).map(async (entry) => {
478
+ const file = this._directory.getOrCreateFile(entry);
479
+ await file.destroy();
480
+ }));
481
+ }
482
+ async close() {
483
+ this._state = "closed";
484
+ }
485
+ _getFilename(key) {
486
+ return key.map((k) => k.replaceAll("%", "%25").replaceAll("-", "%2D")).join("-");
487
+ }
488
+ _getKeyFromFilename(filename) {
489
+ return filename.split("-").map((k) => k.replaceAll("%2D", "-").replaceAll("%25", "%"));
490
+ }
491
+ };
492
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/migrations.ts";
493
+ var levelMigration = async ({ db, directory }) => {
494
+ const isNewLevel = !await db.iterator({
495
+ ...encodingOptions
496
+ }).next();
497
+ if (!isNewLevel) {
498
+ return;
499
+ }
500
+ const oldStorageAdapter = directory.type === import_random_access_storage.StorageType.IDB ? new import_automerge_repo_storage_indexeddb.IndexedDBStorageAdapter(directory.path, "data") : new AutomergeStorageAdapter(directory);
501
+ const chunks = await oldStorageAdapter.loadRange([]);
502
+ if (chunks.length === 0) {
503
+ return;
504
+ }
505
+ const batch = db.batch();
506
+ import_log3.log.info("found chunks on old storage adapter", {
507
+ chunks: chunks.length
508
+ }, {
509
+ F: __dxlog_file3,
510
+ L: 36,
511
+ S: void 0,
512
+ C: (f, a) => f(...a)
513
+ });
514
+ for (const { key, data } of await oldStorageAdapter.loadRange([])) {
515
+ data && batch.put(key, data, {
516
+ ...encodingOptions
517
+ });
518
+ }
519
+ await batch.write();
520
+ };
400
521
  function _ts_decorate(decorators, target, key, desc) {
401
522
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
402
523
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
@@ -407,26 +528,29 @@ function _ts_decorate(decorators, target, key, desc) {
407
528
  r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
408
529
  return c > 3 && r && Object.defineProperty(target, key, r), r;
409
530
  }
410
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/automerge-host.ts";
531
+ var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/automerge-host.ts";
411
532
  var AutomergeHost = class {
412
- constructor({ directory, metadata }) {
533
+ constructor({ directory, db, storageCallbacks }) {
413
534
  this._ctx = new import_context.Context();
414
535
  this._authorizedDevices = new import_util.ComplexMap(import_keys.PublicKey.hash);
415
- this._updatingMetadata = /* @__PURE__ */ new Map();
416
536
  this._requestedDocs = /* @__PURE__ */ new Set();
417
- this._metadata = metadata;
418
- this._meshNetwork = new MeshNetworkAdapter();
419
- this._clientNetwork = new LocalHostNetworkAdapter();
420
- this._storage = new AutomergeStorageWrapper({
421
- storage: (
422
- // TODO(mykola): Delete specific handling of IDB storage.
423
- directory.type === import_random_access_storage.StorageType.IDB ? new import_automerge_repo_storage_indexeddb.IndexedDBStorageAdapter(directory.path, "data") : new AutomergeStorageAdapter(directory)
424
- ),
425
- callbacks: {
426
- beforeSave: (params) => this._beforeSave(params)
427
- }
537
+ this._directory = directory;
538
+ this._db = db;
539
+ this._storageCallbacks = storageCallbacks;
540
+ }
541
+ async open() {
542
+ this._directory && await levelMigration({
543
+ db: this._db,
544
+ directory: this._directory
428
545
  });
546
+ this._storage = new LevelDBStorageAdapter({
547
+ db: this._db,
548
+ callbacks: this._storageCallbacks
549
+ });
550
+ await this._storage.open?.();
429
551
  this._peerId = `host-${import_keys.PublicKey.random().toHex()}`;
552
+ this._meshNetwork = new MeshNetworkAdapter();
553
+ this._clientNetwork = new LocalHostNetworkAdapter();
430
554
  this._repo = new import_automerge_repo.Repo({
431
555
  peerId: this._peerId,
432
556
  network: [
@@ -451,8 +575,8 @@ var AutomergeHost = class {
451
575
  documentId,
452
576
  isRequested
453
577
  }, {
454
- F: __dxlog_file3,
455
- L: 101,
578
+ F: __dxlog_file4,
579
+ L: 99,
456
580
  S: this,
457
581
  C: (f, a) => f(...a)
458
582
  });
@@ -465,8 +589,8 @@ var AutomergeHost = class {
465
589
  peerId,
466
590
  documentId
467
591
  }, {
468
- F: __dxlog_file3,
469
- L: 108,
592
+ F: __dxlog_file4,
593
+ L: 106,
470
594
  S: this,
471
595
  C: (f, a) => f(...a)
472
596
  });
@@ -479,8 +603,8 @@ var AutomergeHost = class {
479
603
  peerId,
480
604
  documentId
481
605
  }, {
482
- F: __dxlog_file3,
483
- L: 117,
606
+ F: __dxlog_file4,
607
+ L: 115,
484
608
  S: this,
485
609
  C: (f, a) => f(...a)
486
610
  });
@@ -496,16 +620,16 @@ var AutomergeHost = class {
496
620
  spaceKey,
497
621
  isAuthorized
498
622
  }, {
499
- F: __dxlog_file3,
500
- L: 123,
623
+ F: __dxlog_file4,
624
+ L: 121,
501
625
  S: this,
502
626
  C: (f, a) => f(...a)
503
627
  });
504
628
  return isAuthorized;
505
629
  } catch (err) {
506
630
  import_log.log.catch(err, void 0, {
507
- F: __dxlog_file3,
508
- L: 133,
631
+ F: __dxlog_file4,
632
+ L: 131,
509
633
  S: this,
510
634
  C: (f, a) => f(...a)
511
635
  });
@@ -515,61 +639,16 @@ var AutomergeHost = class {
515
639
  });
516
640
  this._clientNetwork.ready();
517
641
  this._meshNetwork.ready();
518
- {
519
- const listener = ({ handle }) => this._onDocument(handle);
520
- this._repo.on("document", listener);
521
- this._ctx.onDispose(() => {
522
- this._repo.off("document", listener);
523
- Object.values(this._repo.handles).forEach((handle) => handle.off("change"));
524
- });
525
- }
642
+ await this._clientNetwork.whenConnected();
643
+ }
644
+ async close() {
645
+ await this._storage.close?.();
646
+ await this._clientNetwork.close();
647
+ await this._ctx.dispose();
526
648
  }
527
649
  get repo() {
528
650
  return this._repo;
529
651
  }
530
- async _beforeSave(path) {
531
- const id = path[0];
532
- if (this._updatingMetadata.has(id)) {
533
- return this._updatingMetadata.get(id);
534
- }
535
- }
536
- _onDocument(handle) {
537
- const listener = (event) => this._onUpdate(event);
538
- handle.on("change", listener);
539
- }
540
- _onUpdate(event) {
541
- if (this._metadata == null) {
542
- return;
543
- }
544
- const objectIds = getInlineChanges(event);
545
- if (objectIds.length === 0) {
546
- return;
547
- }
548
- const heads = (0, import_automerge.getHeads)(event.doc);
549
- const lastAvailableHash = heads.join("");
550
- if (!lastAvailableHash) {
551
- return;
552
- }
553
- const encodedIds = objectIds.map((objectId) => import_protocols.idCodec.encode({
554
- documentId: event.handle.documentId,
555
- objectId
556
- }));
557
- const idToLastHash = new Map(encodedIds.map((id) => [
558
- id,
559
- lastAvailableHash
560
- ]));
561
- const markingDirtyPromise = this._metadata.markDirty(idToLastHash).then(() => {
562
- this._updatingMetadata.delete(event.handle.documentId);
563
- }).catch((err) => {
564
- this._ctx.disposed && import_log.log.catch(err, void 0, {
565
- F: __dxlog_file3,
566
- L: 191,
567
- S: this,
568
- C: (f, a) => f(...a)
569
- });
570
- });
571
- this._updatingMetadata.set(event.handle.documentId, markingDirtyPromise);
572
- }
573
652
  _automergeDocs() {
574
653
  return (0, import_util.mapValues)(this._repo.handles, (handle) => ({
575
654
  state: handle.state,
@@ -595,17 +674,24 @@ var AutomergeHost = class {
595
674
  _automergePeers() {
596
675
  return this._repo.peers;
597
676
  }
598
- async close() {
599
- await this._storage.close();
600
- await this._clientNetwork.close();
601
- await this._ctx.dispose();
602
- }
603
677
  //
604
678
  // Methods for client-services.
605
679
  //
606
680
  async flush({ documentIds }) {
607
681
  await Promise.all(documentIds?.map((id) => this._repo.find(id).whenReady()) ?? []);
608
- await this._repo.flush(documentIds);
682
+ try {
683
+ await (0, import_async.asyncTimeout)(this._repo.flush(documentIds), 500);
684
+ } catch (err) {
685
+ import_log.log.warn("flush error", {
686
+ documentIds,
687
+ err
688
+ }, {
689
+ F: __dxlog_file4,
690
+ L: 195,
691
+ S: this,
692
+ C: (f, a) => f(...a)
693
+ });
694
+ }
609
695
  }
610
696
  syncRepo(request) {
611
697
  return this._clientNetwork.syncRepo(request);
@@ -627,8 +713,8 @@ var AutomergeHost = class {
627
713
  spaceKey,
628
714
  deviceKey
629
715
  }, {
630
- F: __dxlog_file3,
631
- L: 264,
716
+ F: __dxlog_file4,
717
+ L: 220,
632
718
  S: this,
633
719
  C: (f, a) => f(...a)
634
720
  });
@@ -651,24 +737,6 @@ _ts_decorate([
651
737
  AutomergeHost = _ts_decorate([
652
738
  import_tracing.trace.resource()
653
739
  ], AutomergeHost);
654
- var getInlineChanges = (event) => {
655
- const inlineChangedObjectIds = /* @__PURE__ */ new Set();
656
- for (const { path } of event.patches) {
657
- if (path.length < 2) {
658
- continue;
659
- }
660
- switch (path[0]) {
661
- case "objects":
662
- if (path.length >= 2) {
663
- inlineChangedObjectIds.add(path[1]);
664
- }
665
- break;
666
- }
667
- }
668
- return [
669
- ...inlineChangedObjectIds
670
- ];
671
- };
672
740
  var getSpaceKeyFromDoc = (doc) => {
673
741
  const rawSpaceKey = doc.access?.spaceKey ?? doc.experimental_spaceKey;
674
742
  if (rawSpaceKey == null) {
@@ -676,7 +744,7 @@ var getSpaceKeyFromDoc = (doc) => {
676
744
  }
677
745
  return String(rawSpaceKey);
678
746
  };
679
- var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/automerge-doc-loader.ts";
747
+ var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/automerge-doc-loader.ts";
680
748
  var AutomergeDocumentLoaderImpl = class {
681
749
  constructor(_spaceKey, _repo) {
682
750
  this._spaceKey = _spaceKey;
@@ -684,7 +752,7 @@ var AutomergeDocumentLoaderImpl = class {
684
752
  this._spaceRootDocHandle = null;
685
753
  this._objectDocumentHandles = /* @__PURE__ */ new Map();
686
754
  this._objectsPendingDocumentLoad = /* @__PURE__ */ new Set();
687
- this.onObjectDocumentLoaded = new import_async3.Event();
755
+ this.onObjectDocumentLoaded = new import_async4.Event();
688
756
  }
689
757
  getAllHandles() {
690
758
  return [
@@ -699,7 +767,7 @@ var AutomergeDocumentLoaderImpl = class {
699
767
  import_log4.log.error("Database opened with no rootUrl", {
700
768
  spaceKey: this._spaceKey
701
769
  }, {
702
- F: __dxlog_file4,
770
+ F: __dxlog_file5,
703
771
  L: 66,
704
772
  S: this,
705
773
  C: (f, a) => f(...a)
@@ -709,7 +777,7 @@ var AutomergeDocumentLoaderImpl = class {
709
777
  const existingDocHandle = await this._initDocHandle(ctx, spaceState.rootUrl);
710
778
  const doc = existingDocHandle.docSync();
711
779
  (0, import_invariant3.invariant)(doc, void 0, {
712
- F: __dxlog_file4,
780
+ F: __dxlog_file5,
713
781
  L: 71,
714
782
  S: this,
715
783
  A: [
@@ -725,7 +793,7 @@ var AutomergeDocumentLoaderImpl = class {
725
793
  }
726
794
  loadObjectDocument(objectId) {
727
795
  (0, import_invariant3.invariant)(this._spaceRootDocHandle, void 0, {
728
- F: __dxlog_file4,
796
+ F: __dxlog_file5,
729
797
  L: 80,
730
798
  S: this,
731
799
  A: [
@@ -738,7 +806,7 @@ var AutomergeDocumentLoaderImpl = class {
738
806
  }
739
807
  const spaceRootDoc = this._spaceRootDocHandle.docSync();
740
808
  (0, import_invariant3.invariant)(spaceRootDoc, void 0, {
741
- F: __dxlog_file4,
809
+ F: __dxlog_file5,
742
810
  L: 85,
743
811
  S: this,
744
812
  A: [
@@ -752,7 +820,7 @@ var AutomergeDocumentLoaderImpl = class {
752
820
  import_log4.log.info("loading delayed until object links are initialized", {
753
821
  objectId
754
822
  }, {
755
- F: __dxlog_file4,
823
+ F: __dxlog_file5,
756
824
  L: 89,
757
825
  S: this,
758
826
  C: (f, a) => f(...a)
@@ -773,7 +841,7 @@ var AutomergeDocumentLoaderImpl = class {
773
841
  }
774
842
  getSpaceRootDocHandle() {
775
843
  (0, import_invariant3.invariant)(this._spaceRootDocHandle, void 0, {
776
- F: __dxlog_file4,
844
+ F: __dxlog_file5,
777
845
  L: 107,
778
846
  S: this,
779
847
  A: [
@@ -785,7 +853,7 @@ var AutomergeDocumentLoaderImpl = class {
785
853
  }
786
854
  createDocumentForObject(objectId) {
787
855
  (0, import_invariant3.invariant)(this._spaceRootDocHandle, void 0, {
788
- F: __dxlog_file4,
856
+ F: __dxlog_file5,
789
857
  L: 112,
790
858
  S: this,
791
859
  A: [
@@ -828,7 +896,7 @@ var AutomergeDocumentLoaderImpl = class {
828
896
  ...logMeta,
829
897
  actualDocumentUrl: objectDocumentHandle.url
830
898
  }, {
831
- F: __dxlog_file4,
899
+ F: __dxlog_file5,
832
900
  L: 142,
833
901
  S: this,
834
902
  C: (f, a) => f(...a)
@@ -837,7 +905,7 @@ var AutomergeDocumentLoaderImpl = class {
837
905
  }
838
906
  if (objectDocumentHandle?.url === automergeUrl) {
839
907
  import_log4.log.warn("object document was already loaded", logMeta, {
840
- F: __dxlog_file4,
908
+ F: __dxlog_file5,
841
909
  L: 149,
842
910
  S: this,
843
911
  C: (f, a) => f(...a)
@@ -846,7 +914,7 @@ var AutomergeDocumentLoaderImpl = class {
846
914
  }
847
915
  const handle = this._repo.find(automergeUrl);
848
916
  import_log4.log.debug("document loading triggered", logMeta, {
849
- F: __dxlog_file4,
917
+ F: __dxlog_file5,
850
918
  L: 153,
851
919
  S: this,
852
920
  C: (f, a) => f(...a)
@@ -860,7 +928,7 @@ var AutomergeDocumentLoaderImpl = class {
860
928
  while (true) {
861
929
  try {
862
930
  await (0, import_debug.warnAfterTimeout)(5e3, "Automerge root doc load timeout (AutomergeDb)", async () => {
863
- await (0, import_context2.cancelWithContext)(ctx, docHandle.whenReady());
931
+ await (0, import_context3.cancelWithContext)(ctx, docHandle.whenReady());
864
932
  });
865
933
  break;
866
934
  } catch (err) {
@@ -869,7 +937,7 @@ var AutomergeDocumentLoaderImpl = class {
869
937
  id: docHandle.documentId,
870
938
  state: docHandle.state
871
939
  }, {
872
- F: __dxlog_file4,
940
+ F: __dxlog_file5,
873
941
  L: 169,
874
942
  S: this,
875
943
  C: (f, a) => f(...a)
@@ -911,7 +979,7 @@ var AutomergeDocumentLoaderImpl = class {
911
979
  };
912
980
  if (this.onObjectDocumentLoaded.listenerCount() === 0) {
913
981
  import_log4.log.info("document loaded after all listeners were removed", logMeta, {
914
- F: __dxlog_file4,
982
+ F: __dxlog_file5,
915
983
  L: 205,
916
984
  S: this,
917
985
  C: (f, a) => f(...a)
@@ -921,7 +989,7 @@ var AutomergeDocumentLoaderImpl = class {
921
989
  const objectDocHandle = this._objectDocumentHandles.get(objectId);
922
990
  if (objectDocHandle?.url !== handle.url) {
923
991
  import_log4.log.warn("object was rebound while a document was loading, discarding handle", logMeta, {
924
- F: __dxlog_file4,
992
+ F: __dxlog_file5,
925
993
  L: 210,
926
994
  S: this,
927
995
  C: (f, a) => f(...a)
@@ -940,7 +1008,7 @@ var AutomergeDocumentLoaderImpl = class {
940
1008
  retryLoading: shouldRetryLoading,
941
1009
  err
942
1010
  }, {
943
- F: __dxlog_file4,
1011
+ F: __dxlog_file5,
944
1012
  L: 216,
945
1013
  S: this,
946
1014
  C: (f, a) => f(...a)
@@ -969,6 +1037,7 @@ var isEncodedReferenceObject = (value) => typeof value === "object" && value !==
969
1037
  AutomergeHost,
970
1038
  AutomergeStorageAdapter,
971
1039
  DataServiceImpl,
1040
+ LevelDBStorageAdapter,
972
1041
  LocalHostNetworkAdapter,
973
1042
  MOCK_AUTH_PROVIDER,
974
1043
  MOCK_AUTH_VERIFIER,
@@ -987,7 +1056,9 @@ var isEncodedReferenceObject = (value) => typeof value === "object" && value !==
987
1056
  createMappedFeedWriter,
988
1057
  decodeReference,
989
1058
  encodeReference,
1059
+ encodingOptions,
990
1060
  getSpaceKeyFromDoc,
1061
+ hasInvitationExpired,
991
1062
  isEncodedReferenceObject,
992
1063
  mapFeedIndexesToTimeframe,
993
1064
  mapTimeframeToFeedIndexes,