@dxos/echo-pipeline 0.4.9 → 0.4.10-main.068c3d8

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 (69) hide show
  1. package/dist/lib/browser/{chunk-RTEEJ723.mjs → chunk-SYE4EK33.mjs} +30 -35
  2. package/dist/lib/browser/chunk-SYE4EK33.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +593 -217
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +8 -2
  7. package/dist/lib/browser/testing/index.mjs.map +4 -4
  8. package/dist/lib/node/{chunk-7VZVCCNF.cjs → chunk-WCTX6RNS.cjs} +35 -40
  9. package/dist/lib/node/chunk-WCTX6RNS.cjs.map +7 -0
  10. package/dist/lib/node/index.cjs +611 -237
  11. package/dist/lib/node/index.cjs.map +4 -4
  12. package/dist/lib/node/meta.json +1 -1
  13. package/dist/lib/node/testing/index.cjs +18 -13
  14. package/dist/lib/node/testing/index.cjs.map +4 -4
  15. package/dist/types/src/automerge/automerge-doc-loader.d.ts +66 -0
  16. package/dist/types/src/automerge/automerge-doc-loader.d.ts.map +1 -0
  17. package/dist/types/src/automerge/automerge-doc-loader.test.d.ts +2 -0
  18. package/dist/types/src/automerge/automerge-doc-loader.test.d.ts.map +1 -0
  19. package/dist/types/src/automerge/automerge-host.d.ts +21 -18
  20. package/dist/types/src/automerge/automerge-host.d.ts.map +1 -1
  21. package/dist/types/src/automerge/automerge-repo.test.d.ts +2 -0
  22. package/dist/types/src/automerge/automerge-repo.test.d.ts.map +1 -0
  23. package/dist/types/src/automerge/index.d.ts +4 -0
  24. package/dist/types/src/automerge/index.d.ts.map +1 -1
  25. package/dist/types/src/automerge/level.test.d.ts +2 -0
  26. package/dist/types/src/automerge/level.test.d.ts.map +1 -0
  27. package/dist/types/src/automerge/leveldb-storage-adapter.d.ts +30 -0
  28. package/dist/types/src/automerge/leveldb-storage-adapter.d.ts.map +1 -0
  29. package/dist/types/src/automerge/local-host-network-adapter.d.ts +8 -1
  30. package/dist/types/src/automerge/local-host-network-adapter.d.ts.map +1 -1
  31. package/dist/types/src/automerge/migrations.d.ts +7 -0
  32. package/dist/types/src/automerge/migrations.d.ts.map +1 -0
  33. package/dist/types/src/automerge/reference.d.ts +15 -0
  34. package/dist/types/src/automerge/reference.d.ts.map +1 -0
  35. package/dist/types/src/automerge/storage-adapter.test.d.ts +2 -0
  36. package/dist/types/src/automerge/storage-adapter.test.d.ts.map +1 -0
  37. package/dist/types/src/automerge/types.d.ts +73 -0
  38. package/dist/types/src/automerge/types.d.ts.map +1 -0
  39. package/dist/types/src/metadata/metadata-store.d.ts +2 -1
  40. package/dist/types/src/metadata/metadata-store.d.ts.map +1 -1
  41. package/dist/types/src/space/space.d.ts +4 -8
  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 +2 -2
  48. package/package.json +33 -30
  49. package/src/automerge/automerge-doc-loader.test.ts +97 -0
  50. package/src/automerge/automerge-doc-loader.ts +241 -0
  51. package/src/automerge/automerge-host.test.ts +22 -8
  52. package/src/automerge/automerge-host.ts +65 -118
  53. package/src/automerge/automerge-repo.test.ts +29 -0
  54. package/src/automerge/index.ts +4 -0
  55. package/src/automerge/level.test.ts +64 -0
  56. package/src/automerge/leveldb-storage-adapter.ts +117 -0
  57. package/src/automerge/local-host-network-adapter.ts +19 -13
  58. package/src/automerge/migrations.ts +41 -0
  59. package/src/automerge/reference.ts +31 -0
  60. package/src/automerge/storage-adapter.test.ts +90 -0
  61. package/src/automerge/types.ts +86 -0
  62. package/src/db-host/data-service.ts +1 -1
  63. package/src/metadata/metadata-store.ts +17 -8
  64. package/src/space/space.test.ts +7 -7
  65. package/src/space/space.ts +6 -21
  66. package/src/testing/index.ts +1 -0
  67. package/src/testing/level.ts +11 -0
  68. package/dist/lib/browser/chunk-RTEEJ723.mjs.map +0 -7
  69. package/dist/lib/node/chunk-7VZVCCNF.cjs.map +0 -7
@@ -18,162 +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_7VZVCCNF.AuthExtension,
22
- AuthStatus: () => import_chunk_7VZVCCNF.AuthStatus,
21
+ AuthExtension: () => import_chunk_WCTX6RNS.AuthExtension,
22
+ AuthStatus: () => import_chunk_WCTX6RNS.AuthStatus,
23
+ AutomergeDocumentLoaderImpl: () => AutomergeDocumentLoaderImpl,
23
24
  AutomergeHost: () => AutomergeHost,
24
25
  AutomergeStorageAdapter: () => AutomergeStorageAdapter,
25
- DataServiceImpl: () => import_chunk_7VZVCCNF.DataServiceImpl,
26
+ DataServiceImpl: () => import_chunk_WCTX6RNS.DataServiceImpl,
27
+ LevelDBStorageAdapter: () => LevelDBStorageAdapter,
26
28
  LocalHostNetworkAdapter: () => LocalHostNetworkAdapter,
27
- MOCK_AUTH_PROVIDER: () => import_chunk_7VZVCCNF.MOCK_AUTH_PROVIDER,
28
- MOCK_AUTH_VERIFIER: () => import_chunk_7VZVCCNF.MOCK_AUTH_VERIFIER,
29
+ MOCK_AUTH_PROVIDER: () => import_chunk_WCTX6RNS.MOCK_AUTH_PROVIDER,
30
+ MOCK_AUTH_VERIFIER: () => import_chunk_WCTX6RNS.MOCK_AUTH_VERIFIER,
29
31
  MeshNetworkAdapter: () => MeshNetworkAdapter,
30
- MetadataStore: () => import_chunk_7VZVCCNF.MetadataStore,
31
- Pipeline: () => import_chunk_7VZVCCNF.Pipeline,
32
- SnapshotManager: () => import_chunk_7VZVCCNF.SnapshotManager,
33
- SnapshotStore: () => import_chunk_7VZVCCNF.SnapshotStore,
34
- Space: () => import_chunk_7VZVCCNF.Space,
35
- SpaceManager: () => import_chunk_7VZVCCNF.SpaceManager,
36
- SpaceProtocol: () => import_chunk_7VZVCCNF.SpaceProtocol,
37
- SpaceProtocolSession: () => import_chunk_7VZVCCNF.SpaceProtocolSession,
38
- TimeframeClock: () => import_chunk_7VZVCCNF.TimeframeClock,
39
- codec: () => import_chunk_7VZVCCNF.codec,
40
- createMappedFeedWriter: () => import_chunk_7VZVCCNF.createMappedFeedWriter,
32
+ MetadataStore: () => import_chunk_WCTX6RNS.MetadataStore,
33
+ Pipeline: () => import_chunk_WCTX6RNS.Pipeline,
34
+ REFERENCE_TYPE_TAG: () => REFERENCE_TYPE_TAG,
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,
44
+ decodeReference: () => decodeReference,
45
+ encodeReference: () => encodeReference,
46
+ encodingOptions: () => encodingOptions,
41
47
  getSpaceKeyFromDoc: () => getSpaceKeyFromDoc,
42
- mapFeedIndexesToTimeframe: () => import_chunk_7VZVCCNF.mapFeedIndexesToTimeframe,
43
- mapTimeframeToFeedIndexes: () => import_chunk_7VZVCCNF.mapTimeframeToFeedIndexes,
44
- startAfter: () => import_chunk_7VZVCCNF.startAfter,
45
- valueEncoding: () => import_chunk_7VZVCCNF.valueEncoding
48
+ hasInvitationExpired: () => import_chunk_WCTX6RNS.hasInvitationExpired,
49
+ isEncodedReferenceObject: () => isEncodedReferenceObject,
50
+ mapFeedIndexesToTimeframe: () => import_chunk_WCTX6RNS.mapFeedIndexesToTimeframe,
51
+ mapTimeframeToFeedIndexes: () => import_chunk_WCTX6RNS.mapTimeframeToFeedIndexes,
52
+ startAfter: () => import_chunk_WCTX6RNS.startAfter,
53
+ valueEncoding: () => import_chunk_WCTX6RNS.valueEncoding
46
54
  });
47
55
  module.exports = __toCommonJS(node_exports);
48
- var import_chunk_7VZVCCNF = require("./chunk-7VZVCCNF.cjs");
56
+ var import_chunk_WCTX6RNS = require("./chunk-WCTX6RNS.cjs");
57
+ var import_async = require("@dxos/async");
49
58
  var import_automerge = require("@dxos/automerge/automerge");
50
59
  var import_automerge_repo = require("@dxos/automerge/automerge-repo");
51
- var import_automerge_repo_storage_indexeddb = require("@dxos/automerge/automerge-repo-storage-indexeddb");
52
60
  var import_context = require("@dxos/context");
53
61
  var import_keys = require("@dxos/keys");
54
62
  var import_log = require("@dxos/log");
55
- var import_protocols = require("@dxos/protocols");
56
- var import_random_access_storage = require("@dxos/random-access-storage");
57
63
  var import_tracing = require("@dxos/tracing");
58
64
  var import_util = require("@dxos/util");
59
- var import_util2 = require("@dxos/util");
60
- var import_async = require("@dxos/async");
65
+ var import_context2 = require("@dxos/context");
66
+ var import_async2 = require("@dxos/async");
61
67
  var import_automerge_repo2 = require("@dxos/automerge/automerge-repo");
62
68
  var import_codec_protobuf = require("@dxos/codec-protobuf");
63
69
  var import_invariant = require("@dxos/invariant");
64
- var import_log2 = require("@dxos/log");
65
- var import_async2 = require("@dxos/async");
70
+ var import_async3 = require("@dxos/async");
66
71
  var import_automerge_repo3 = require("@dxos/automerge/automerge-repo");
67
72
  var import_invariant2 = require("@dxos/invariant");
68
- var import_log3 = require("@dxos/log");
73
+ var import_log2 = require("@dxos/log");
69
74
  var import_teleport_extension_automerge_replicator = require("@dxos/teleport-extension-automerge-replicator");
70
- var AutomergeStorageAdapter = class {
71
- constructor(_directory) {
72
- this._directory = _directory;
73
- this._state = "opened";
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");
81
+ var import_debug = require("@dxos/debug");
82
+ var import_invariant3 = require("@dxos/invariant");
83
+ var import_log4 = require("@dxos/log");
84
+ var import_echo_db = require("@dxos/echo-db");
85
+ var LevelDBStorageAdapter = class extends import_context2.Resource {
86
+ constructor(_params) {
87
+ super();
88
+ this._params = _params;
74
89
  }
75
- async load(key) {
76
- if (this._state !== "opened") {
77
- return void 0;
78
- }
79
- const filename = this._getFilename(key);
80
- const file = this._directory.getOrCreateFile(filename);
81
- const { size } = await file.stat();
82
- if (!size || size === 0) {
83
- 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;
84
103
  }
85
- const buffer = await file.read(0, size);
86
- return (0, import_util2.bufferToArray)(buffer);
87
104
  }
88
- async save(key, data) {
89
- if (this._state !== "opened") {
105
+ async save(keyArray, binary) {
106
+ if (this._lifecycleState !== import_context2.LifecycleState.OPEN) {
90
107
  return void 0;
91
108
  }
92
- const filename = this._getFilename(key);
93
- const file = this._directory.getOrCreateFile(filename);
94
- await file.write(0, (0, import_util2.arrayToBuffer)(data));
95
- await file.truncate?.(data.length);
96
- 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);
97
119
  }
98
- async remove(key) {
99
- if (this._state !== "opened") {
120
+ async remove(keyArray) {
121
+ if (this._lifecycleState !== import_context2.LifecycleState.OPEN) {
100
122
  return void 0;
101
123
  }
102
- const filename = this._getFilename(key);
103
- const file = this._directory.getOrCreateFile(filename);
104
- await file.destroy();
124
+ await this._params.db.del(keyArray, {
125
+ ...encodingOptions
126
+ });
105
127
  }
106
128
  async loadRange(keyPrefix) {
107
- if (this._state !== "opened") {
129
+ if (this._lifecycleState !== import_context2.LifecycleState.OPEN) {
108
130
  return [];
109
131
  }
110
- const filename = this._getFilename(keyPrefix);
111
- const entries = await this._directory.list();
112
- return Promise.all(entries.filter((entry) => entry.startsWith(filename)).map(async (entry) => {
113
- const file = this._directory.getOrCreateFile(entry);
114
- const { size } = await file.stat();
115
- const buffer = await file.read(0, size);
116
- return {
117
- key: this._getKeyFromFilename(entry),
118
- data: (0, import_util2.bufferToArray)(buffer)
119
- };
120
- }));
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;
121
147
  }
122
148
  async removeRange(keyPrefix) {
123
- if (this._state !== "opened") {
149
+ if (this._lifecycleState !== import_context2.LifecycleState.OPEN) {
124
150
  return void 0;
125
151
  }
126
- const filename = this._getFilename(keyPrefix);
127
- const entries = await this._directory.list();
128
- await Promise.all(entries.filter((entry) => entry.startsWith(filename)).map(async (entry) => {
129
- const file = this._directory.getOrCreateFile(entry);
130
- await file.destroy();
131
- }));
132
- }
133
- async close() {
134
- this._state = "closed";
135
- }
136
- _getFilename(key) {
137
- return key.map((k) => k.replaceAll("%", "%25").replaceAll("-", "%2D")).join("-");
138
- }
139
- _getKeyFromFilename(filename) {
140
- return filename.split("-").map((k) => k.replaceAll("%2D", "-").replaceAll("%25", "%"));
141
- }
142
- };
143
- var AutomergeStorageWrapper = class {
144
- constructor({ storage, callbacks }) {
145
- this._storage = storage;
146
- this._callbacks = callbacks;
147
- }
148
- async load(key) {
149
- return this._storage.load(key);
150
- }
151
- async save(key, value) {
152
- await this._callbacks.beforeSave?.(key);
153
- await this._storage.save(key, value);
154
- await this._callbacks.afterSave?.(key);
155
- }
156
- async remove(key) {
157
- return this._storage.remove(key);
158
- }
159
- async loadRange(keyPrefix) {
160
- return this._storage.loadRange(keyPrefix);
161
- }
162
- async removeRange(keyPrefix) {
163
- return this._storage.removeRange(keyPrefix);
164
- }
165
- async close() {
166
- if (this._storage instanceof AutomergeStorageAdapter) {
167
- 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
+ });
168
164
  }
165
+ await batch.write();
169
166
  }
170
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";
171
177
  var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/local-host-network-adapter.ts";
172
178
  var LocalHostNetworkAdapter = class extends import_automerge_repo2.NetworkAdapter {
173
179
  constructor() {
174
180
  super(...arguments);
175
181
  this._peers = /* @__PURE__ */ new Map();
176
- this._connected = new import_async.Trigger();
182
+ this._connected = new import_async2.Trigger();
183
+ this._isConnected = false;
177
184
  }
178
185
  /**
179
186
  * Emits `ready` event. That signals to `Repo` that it can start using the adapter.
@@ -183,15 +190,21 @@ var LocalHostNetworkAdapter = class extends import_automerge_repo2.NetworkAdapte
183
190
  network: this
184
191
  });
185
192
  }
193
+ /**
194
+ * Called by `Repo` to connect to the network.
195
+ *
196
+ * @param peerId Our peer Id.
197
+ */
186
198
  connect(peerId) {
187
199
  this.peerId = peerId;
200
+ this._isConnected = true;
188
201
  this._connected.wake();
189
202
  }
190
203
  send(message) {
191
204
  const peer = this._peers.get(message.targetId);
192
205
  (0, import_invariant.invariant)(peer, "Peer not found.", {
193
206
  F: __dxlog_file,
194
- L: 45,
207
+ L: 51,
195
208
  S: this,
196
209
  A: [
197
210
  "peer",
@@ -206,12 +219,17 @@ var LocalHostNetworkAdapter = class extends import_automerge_repo2.NetworkAdapte
206
219
  }
207
220
  disconnect() {
208
221
  }
222
+ async whenConnected() {
223
+ await this._connected.wait({
224
+ timeout: 1e4
225
+ });
226
+ }
209
227
  syncRepo({ id, syncMessage }) {
210
228
  const peerId = this._getPeerId(id);
211
229
  return new import_codec_protobuf.Stream(({ next, close }) => {
212
230
  (0, import_invariant.invariant)(!this._peers.has(peerId), "Peer already connected.", {
213
231
  F: __dxlog_file,
214
- L: 63,
232
+ L: 73,
215
233
  S: this,
216
234
  A: [
217
235
  "!this._peers.has(peerId)",
@@ -233,35 +251,47 @@ var LocalHostNetworkAdapter = class extends import_automerge_repo2.NetworkAdapte
233
251
  });
234
252
  }
235
253
  });
236
- this._connected.wait({
237
- timeout: 1e3
238
- }).then(() => {
239
- this.emit("peer-candidate", {
240
- peerMetadata: {},
241
- peerId
242
- });
243
- }).catch((err) => import_log2.log.catch(err, void 0, {
254
+ (0, import_invariant.invariant)(this._isConnected, void 0, {
244
255
  F: __dxlog_file,
245
- L: 88,
256
+ L: 90,
246
257
  S: this,
247
- C: (f, a) => f(...a)
248
- }));
258
+ A: [
259
+ "this._isConnected",
260
+ ""
261
+ ]
262
+ });
263
+ this.emit("peer-candidate", {
264
+ peerMetadata: {},
265
+ peerId
266
+ });
249
267
  });
250
268
  }
251
269
  async sendSyncMessage({ id, syncMessage }) {
252
- await this._connected.wait({
253
- 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
+ ]
254
278
  });
255
279
  const message = import_automerge_repo2.cbor.decode(syncMessage);
256
280
  this.emit("message", message);
257
281
  }
258
282
  async getHostInfo() {
259
- await this._connected.wait({
260
- 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
+ ]
261
291
  });
262
292
  (0, import_invariant.invariant)(this.peerId, "Peer id not set.", {
263
293
  F: __dxlog_file,
264
- L: 100,
294
+ L: 106,
265
295
  S: this,
266
296
  A: [
267
297
  "this.peerId",
@@ -281,7 +311,7 @@ var MeshNetworkAdapter = class extends import_automerge_repo3.NetworkAdapter {
281
311
  constructor() {
282
312
  super(...arguments);
283
313
  this._extensions = /* @__PURE__ */ new Map();
284
- this._connected = new import_async2.Trigger();
314
+ this._connected = new import_async3.Trigger();
285
315
  }
286
316
  /**
287
317
  * Emits `ready` event. That signals to `Repo` that it can start using the adapter.
@@ -309,7 +339,7 @@ var MeshNetworkAdapter = class extends import_automerge_repo3.NetworkAdapter {
309
339
  });
310
340
  extension.sendSyncMessage({
311
341
  payload: import_automerge_repo3.cbor.encode(message)
312
- }).catch((err) => import_log3.log.catch(err, void 0, {
342
+ }).catch((err) => import_log2.log.catch(err, void 0, {
313
343
  F: __dxlog_file2,
314
344
  L: 39,
315
345
  S: this,
@@ -334,7 +364,7 @@ var MeshNetworkAdapter = class extends import_automerge_repo3.NetworkAdapter {
334
364
  }, {
335
365
  onStartReplication: async (info, remotePeerId) => {
336
366
  await this._connected.wait();
337
- (0, import_log3.log)("onStartReplication", {
367
+ (0, import_log2.log)("onStartReplication", {
338
368
  id: info.id,
339
369
  thisPeerId: this.peerId,
340
370
  remotePeerId: remotePeerId.toHex()
@@ -347,7 +377,7 @@ var MeshNetworkAdapter = class extends import_automerge_repo3.NetworkAdapter {
347
377
  if (!this._extensions.has(info.id)) {
348
378
  peerInfo = info;
349
379
  this._extensions.set(info.id, extension);
350
- (0, import_log3.log)("peer-candidate", {
380
+ (0, import_log2.log)("peer-candidate", {
351
381
  id: info.id,
352
382
  thisPeerId: this.peerId,
353
383
  remotePeerId: remotePeerId.toHex()
@@ -386,6 +416,108 @@ var MeshNetworkAdapter = class extends import_automerge_repo3.NetworkAdapter {
386
416
  return extension;
387
417
  }
388
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
+ };
389
521
  function _ts_decorate(decorators, target, key, desc) {
390
522
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
391
523
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
@@ -396,26 +528,29 @@ function _ts_decorate(decorators, target, key, desc) {
396
528
  r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
397
529
  return c > 3 && r && Object.defineProperty(target, key, r), r;
398
530
  }
399
- 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";
400
532
  var AutomergeHost = class {
401
- constructor({ directory, metadata }) {
533
+ constructor({ directory, db, storageCallbacks }) {
402
534
  this._ctx = new import_context.Context();
403
535
  this._authorizedDevices = new import_util.ComplexMap(import_keys.PublicKey.hash);
404
- this._updatingMetadata = /* @__PURE__ */ new Map();
405
536
  this._requestedDocs = /* @__PURE__ */ new Set();
406
- this._metadata = metadata;
407
- this._meshNetwork = new MeshNetworkAdapter();
408
- this._clientNetwork = new LocalHostNetworkAdapter();
409
- this._storage = new AutomergeStorageWrapper({
410
- storage: (
411
- // TODO(mykola): Delete specific handling of IDB storage.
412
- directory.type === import_random_access_storage.StorageType.IDB ? new import_automerge_repo_storage_indexeddb.IndexedDBStorageAdapter(directory.path, "data") : new AutomergeStorageAdapter(directory)
413
- ),
414
- callbacks: {
415
- beforeSave: (params) => this._beforeSave(params)
416
- }
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
417
545
  });
546
+ this._storage = new LevelDBStorageAdapter({
547
+ db: this._db,
548
+ callbacks: this._storageCallbacks
549
+ });
550
+ await this._storage.open?.();
418
551
  this._peerId = `host-${import_keys.PublicKey.random().toHex()}`;
552
+ this._meshNetwork = new MeshNetworkAdapter();
553
+ this._clientNetwork = new LocalHostNetworkAdapter();
419
554
  this._repo = new import_automerge_repo.Repo({
420
555
  peerId: this._peerId,
421
556
  network: [
@@ -440,8 +575,8 @@ var AutomergeHost = class {
440
575
  documentId,
441
576
  isRequested
442
577
  }, {
443
- F: __dxlog_file3,
444
- L: 96,
578
+ F: __dxlog_file4,
579
+ L: 99,
445
580
  S: this,
446
581
  C: (f, a) => f(...a)
447
582
  });
@@ -454,8 +589,8 @@ var AutomergeHost = class {
454
589
  peerId,
455
590
  documentId
456
591
  }, {
457
- F: __dxlog_file3,
458
- L: 103,
592
+ F: __dxlog_file4,
593
+ L: 106,
459
594
  S: this,
460
595
  C: (f, a) => f(...a)
461
596
  });
@@ -468,8 +603,8 @@ var AutomergeHost = class {
468
603
  peerId,
469
604
  documentId
470
605
  }, {
471
- F: __dxlog_file3,
472
- L: 112,
606
+ F: __dxlog_file4,
607
+ L: 115,
473
608
  S: this,
474
609
  C: (f, a) => f(...a)
475
610
  });
@@ -485,16 +620,16 @@ var AutomergeHost = class {
485
620
  spaceKey,
486
621
  isAuthorized
487
622
  }, {
488
- F: __dxlog_file3,
489
- L: 118,
623
+ F: __dxlog_file4,
624
+ L: 121,
490
625
  S: this,
491
626
  C: (f, a) => f(...a)
492
627
  });
493
628
  return isAuthorized;
494
629
  } catch (err) {
495
630
  import_log.log.catch(err, void 0, {
496
- F: __dxlog_file3,
497
- L: 128,
631
+ F: __dxlog_file4,
632
+ L: 131,
498
633
  S: this,
499
634
  C: (f, a) => f(...a)
500
635
  });
@@ -504,69 +639,22 @@ var AutomergeHost = class {
504
639
  });
505
640
  this._clientNetwork.ready();
506
641
  this._meshNetwork.ready();
507
- {
508
- const listener = ({ handle }) => this._onDocument(handle);
509
- this._repo.on("document", listener);
510
- this._ctx.onDispose(() => {
511
- this._repo.off("document", listener);
512
- });
513
- }
642
+ await this._clientNetwork.whenConnected();
643
+ }
644
+ async close() {
645
+ await this._storage.close?.();
646
+ await this._clientNetwork.close();
647
+ await this._ctx.dispose();
514
648
  }
515
649
  get repo() {
516
650
  return this._repo;
517
651
  }
518
- async _beforeSave(path) {
519
- const id = path[0];
520
- if (this._updatingMetadata.has(id)) {
521
- return this._updatingMetadata.get(id);
522
- }
523
- }
524
- _onDocument(handle) {
525
- const listener = (event) => this._onUpdate(event);
526
- handle.on("change", listener);
527
- this._ctx.onDispose(() => {
528
- handle.off("change", listener);
529
- });
530
- }
531
- _onUpdate(event) {
532
- if (this._metadata == null) {
533
- return;
534
- }
535
- const objectIds = getInlineChanges(event);
536
- if (objectIds.length === 0) {
537
- return;
538
- }
539
- const heads = (0, import_automerge.getHeads)(event.doc);
540
- const lastAvailableHash = heads.join("");
541
- if (!lastAvailableHash) {
542
- return;
543
- }
544
- const encodedIds = objectIds.map((objectId) => import_protocols.idCodec.encode({
545
- documentId: event.handle.documentId,
546
- objectId
547
- }));
548
- const idToLastHash = new Map(encodedIds.map((id) => [
549
- id,
550
- lastAvailableHash
551
- ]));
552
- const markingDirtyPromise = this._metadata.markDirty(idToLastHash).then(() => {
553
- this._updatingMetadata.delete(event.handle.documentId);
554
- }).catch((err) => {
555
- this._ctx.disposed && import_log.log.catch(err, void 0, {
556
- F: __dxlog_file3,
557
- L: 188,
558
- S: this,
559
- C: (f, a) => f(...a)
560
- });
561
- });
562
- this._updatingMetadata.set(event.handle.documentId, markingDirtyPromise);
563
- }
564
652
  _automergeDocs() {
565
653
  return (0, import_util.mapValues)(this._repo.handles, (handle) => ({
566
654
  state: handle.state,
567
655
  hasDoc: !!handle.docSync(),
568
656
  heads: handle.docSync() ? import_automerge.next.getHeads(handle.docSync()) : null,
569
- data: handle.docSync()?.doc && (0, import_util.mapValues)(handle.docSync()?.doc, (value, key) => {
657
+ data: handle.docSync() && (0, import_util.mapValues)(handle.docSync(), (value, key) => {
570
658
  try {
571
659
  switch (key) {
572
660
  case "access":
@@ -586,14 +674,25 @@ var AutomergeHost = class {
586
674
  _automergePeers() {
587
675
  return this._repo.peers;
588
676
  }
589
- async close() {
590
- await this._storage.close();
591
- await this._clientNetwork.close();
592
- await this._ctx.dispose();
593
- }
594
677
  //
595
678
  // Methods for client-services.
596
679
  //
680
+ async flush({ documentIds }) {
681
+ await Promise.all(documentIds?.map((id) => this._repo.find(id).whenReady()) ?? []);
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
+ }
695
+ }
597
696
  syncRepo(request) {
598
697
  return this._clientNetwork.syncRepo(request);
599
698
  }
@@ -614,8 +713,8 @@ var AutomergeHost = class {
614
713
  spaceKey,
615
714
  deviceKey
616
715
  }, {
617
- F: __dxlog_file3,
618
- L: 255,
716
+ F: __dxlog_file4,
717
+ L: 220,
619
718
  S: this,
620
719
  C: (f, a) => f(...a)
621
720
  });
@@ -638,24 +737,6 @@ _ts_decorate([
638
737
  AutomergeHost = _ts_decorate([
639
738
  import_tracing.trace.resource()
640
739
  ], AutomergeHost);
641
- var getInlineChanges = (event) => {
642
- const inlineChangedObjectIds = /* @__PURE__ */ new Set();
643
- for (const { path } of event.patches) {
644
- if (path.length < 2) {
645
- continue;
646
- }
647
- switch (path[0]) {
648
- case "objects":
649
- if (path.length >= 2) {
650
- inlineChangedObjectIds.add(path[1]);
651
- }
652
- break;
653
- }
654
- }
655
- return [
656
- ...inlineChangedObjectIds
657
- ];
658
- };
659
740
  var getSpaceKeyFromDoc = (doc) => {
660
741
  const rawSpaceKey = doc.access?.spaceKey ?? doc.experimental_spaceKey;
661
742
  if (rawSpaceKey == null) {
@@ -663,19 +744,307 @@ var getSpaceKeyFromDoc = (doc) => {
663
744
  }
664
745
  return String(rawSpaceKey);
665
746
  };
747
+ var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/automerge-doc-loader.ts";
748
+ var AutomergeDocumentLoaderImpl = class {
749
+ constructor(_spaceKey, _repo) {
750
+ this._spaceKey = _spaceKey;
751
+ this._repo = _repo;
752
+ this._spaceRootDocHandle = null;
753
+ this._objectDocumentHandles = /* @__PURE__ */ new Map();
754
+ this._objectsPendingDocumentLoad = /* @__PURE__ */ new Set();
755
+ this.onObjectDocumentLoaded = new import_async4.Event();
756
+ }
757
+ getAllHandles() {
758
+ return [
759
+ ...new Set(this._objectDocumentHandles.values())
760
+ ];
761
+ }
762
+ async loadSpaceRootDocHandle(ctx, spaceState) {
763
+ if (this._spaceRootDocHandle != null) {
764
+ return;
765
+ }
766
+ if (!spaceState.rootUrl) {
767
+ import_log4.log.error("Database opened with no rootUrl", {
768
+ spaceKey: this._spaceKey
769
+ }, {
770
+ F: __dxlog_file5,
771
+ L: 66,
772
+ S: this,
773
+ C: (f, a) => f(...a)
774
+ });
775
+ this._createContextBoundSpaceRootDocument(ctx);
776
+ } else {
777
+ const existingDocHandle = await this._initDocHandle(ctx, spaceState.rootUrl);
778
+ const doc = existingDocHandle.docSync();
779
+ (0, import_invariant3.invariant)(doc, void 0, {
780
+ F: __dxlog_file5,
781
+ L: 71,
782
+ S: this,
783
+ A: [
784
+ "doc",
785
+ ""
786
+ ]
787
+ });
788
+ if (doc.access == null) {
789
+ this._initDocAccess(existingDocHandle);
790
+ }
791
+ this._spaceRootDocHandle = existingDocHandle;
792
+ }
793
+ }
794
+ loadObjectDocument(objectId) {
795
+ (0, import_invariant3.invariant)(this._spaceRootDocHandle, void 0, {
796
+ F: __dxlog_file5,
797
+ L: 80,
798
+ S: this,
799
+ A: [
800
+ "this._spaceRootDocHandle",
801
+ ""
802
+ ]
803
+ });
804
+ if (this._objectDocumentHandles.has(objectId) || this._objectsPendingDocumentLoad.has(objectId)) {
805
+ return;
806
+ }
807
+ const spaceRootDoc = this._spaceRootDocHandle.docSync();
808
+ (0, import_invariant3.invariant)(spaceRootDoc, void 0, {
809
+ F: __dxlog_file5,
810
+ L: 85,
811
+ S: this,
812
+ A: [
813
+ "spaceRootDoc",
814
+ ""
815
+ ]
816
+ });
817
+ const documentUrl = (spaceRootDoc.links ?? {})[objectId];
818
+ if (documentUrl == null) {
819
+ this._objectsPendingDocumentLoad.add(objectId);
820
+ import_log4.log.info("loading delayed until object links are initialized", {
821
+ objectId
822
+ }, {
823
+ F: __dxlog_file5,
824
+ L: 89,
825
+ S: this,
826
+ C: (f, a) => f(...a)
827
+ });
828
+ return;
829
+ }
830
+ this._loadLinkedObjects({
831
+ [objectId]: documentUrl
832
+ });
833
+ }
834
+ onObjectLinksUpdated(links) {
835
+ if (!links) {
836
+ return;
837
+ }
838
+ const linksAwaitingLoad = Object.entries(links).filter(([objectId]) => this._objectsPendingDocumentLoad.has(objectId));
839
+ this._loadLinkedObjects(Object.fromEntries(linksAwaitingLoad));
840
+ linksAwaitingLoad.forEach(([objectId]) => this._objectsPendingDocumentLoad.delete(objectId));
841
+ }
842
+ getSpaceRootDocHandle() {
843
+ (0, import_invariant3.invariant)(this._spaceRootDocHandle, void 0, {
844
+ F: __dxlog_file5,
845
+ L: 107,
846
+ S: this,
847
+ A: [
848
+ "this._spaceRootDocHandle",
849
+ ""
850
+ ]
851
+ });
852
+ return this._spaceRootDocHandle;
853
+ }
854
+ createDocumentForObject(objectId) {
855
+ (0, import_invariant3.invariant)(this._spaceRootDocHandle, void 0, {
856
+ F: __dxlog_file5,
857
+ L: 112,
858
+ S: this,
859
+ A: [
860
+ "this._spaceRootDocHandle",
861
+ ""
862
+ ]
863
+ });
864
+ const spaceDocHandle = this._repo.create();
865
+ this._initDocAccess(spaceDocHandle);
866
+ this.onObjectBoundToDocument(spaceDocHandle, objectId);
867
+ this._spaceRootDocHandle.change((newDoc) => {
868
+ newDoc.links ??= {};
869
+ newDoc.links[objectId] = spaceDocHandle.url;
870
+ });
871
+ return spaceDocHandle;
872
+ }
873
+ onObjectBoundToDocument(handle, objectId) {
874
+ this._objectDocumentHandles.set(objectId, handle);
875
+ }
876
+ clearHandleReferences() {
877
+ const objectsWithHandles = [
878
+ ...this._objectDocumentHandles.keys()
879
+ ];
880
+ this._objectDocumentHandles.clear();
881
+ this._spaceRootDocHandle = null;
882
+ return objectsWithHandles;
883
+ }
884
+ _loadLinkedObjects(links) {
885
+ if (!links) {
886
+ return;
887
+ }
888
+ for (const [objectId, automergeUrl] of Object.entries(links)) {
889
+ const logMeta = {
890
+ objectId,
891
+ automergeUrl
892
+ };
893
+ const objectDocumentHandle = this._objectDocumentHandles.get(objectId);
894
+ if (objectDocumentHandle != null && objectDocumentHandle.url !== automergeUrl) {
895
+ import_log4.log.warn("object already inlined in a different document, ignoring the link", {
896
+ ...logMeta,
897
+ actualDocumentUrl: objectDocumentHandle.url
898
+ }, {
899
+ F: __dxlog_file5,
900
+ L: 142,
901
+ S: this,
902
+ C: (f, a) => f(...a)
903
+ });
904
+ continue;
905
+ }
906
+ if (objectDocumentHandle?.url === automergeUrl) {
907
+ import_log4.log.warn("object document was already loaded", logMeta, {
908
+ F: __dxlog_file5,
909
+ L: 149,
910
+ S: this,
911
+ C: (f, a) => f(...a)
912
+ });
913
+ continue;
914
+ }
915
+ const handle = this._repo.find(automergeUrl);
916
+ import_log4.log.debug("document loading triggered", logMeta, {
917
+ F: __dxlog_file5,
918
+ L: 153,
919
+ S: this,
920
+ C: (f, a) => f(...a)
921
+ });
922
+ this._objectDocumentHandles.set(objectId, handle);
923
+ void this._createObjectOnDocumentLoad(handle, objectId);
924
+ }
925
+ }
926
+ async _initDocHandle(ctx, url) {
927
+ const docHandle = this._repo.find(url);
928
+ while (true) {
929
+ try {
930
+ await (0, import_debug.warnAfterTimeout)(5e3, "Automerge root doc load timeout (AutomergeDb)", async () => {
931
+ await (0, import_context3.cancelWithContext)(ctx, docHandle.whenReady());
932
+ });
933
+ break;
934
+ } catch (err) {
935
+ if (`${err}`.includes("Timeout")) {
936
+ import_log4.log.info("wraparound", {
937
+ id: docHandle.documentId,
938
+ state: docHandle.state
939
+ }, {
940
+ F: __dxlog_file5,
941
+ L: 169,
942
+ S: this,
943
+ C: (f, a) => f(...a)
944
+ });
945
+ continue;
946
+ }
947
+ throw err;
948
+ }
949
+ }
950
+ if (docHandle.state === "unavailable") {
951
+ throw new Error("Automerge document is unavailable");
952
+ }
953
+ return docHandle;
954
+ }
955
+ _createContextBoundSpaceRootDocument(ctx) {
956
+ const docHandle = this._repo.create();
957
+ this._spaceRootDocHandle = docHandle;
958
+ ctx.onDispose(() => {
959
+ docHandle.delete();
960
+ this._spaceRootDocHandle = null;
961
+ });
962
+ }
963
+ _initDocAccess(handle) {
964
+ handle.change((newDoc) => {
965
+ newDoc.access ??= {
966
+ spaceKey: this._spaceKey.toHex()
967
+ };
968
+ newDoc.access.spaceKey = this._spaceKey.toHex();
969
+ });
970
+ }
971
+ async _createObjectOnDocumentLoad(handle, objectId) {
972
+ try {
973
+ await handle.doc([
974
+ "ready"
975
+ ]);
976
+ const logMeta = {
977
+ objectId,
978
+ docUrl: handle.url
979
+ };
980
+ if (this.onObjectDocumentLoaded.listenerCount() === 0) {
981
+ import_log4.log.info("document loaded after all listeners were removed", logMeta, {
982
+ F: __dxlog_file5,
983
+ L: 205,
984
+ S: this,
985
+ C: (f, a) => f(...a)
986
+ });
987
+ return;
988
+ }
989
+ const objectDocHandle = this._objectDocumentHandles.get(objectId);
990
+ if (objectDocHandle?.url !== handle.url) {
991
+ import_log4.log.warn("object was rebound while a document was loading, discarding handle", logMeta, {
992
+ F: __dxlog_file5,
993
+ L: 210,
994
+ S: this,
995
+ C: (f, a) => f(...a)
996
+ });
997
+ return;
998
+ }
999
+ this.onObjectDocumentLoaded.emit({
1000
+ handle,
1001
+ objectId
1002
+ });
1003
+ } catch (err) {
1004
+ const shouldRetryLoading = this.onObjectDocumentLoaded.listenerCount() > 0;
1005
+ import_log4.log.warn("failed to load a document", {
1006
+ objectId,
1007
+ automergeUrl: handle.url,
1008
+ retryLoading: shouldRetryLoading,
1009
+ err
1010
+ }, {
1011
+ F: __dxlog_file5,
1012
+ L: 216,
1013
+ S: this,
1014
+ C: (f, a) => f(...a)
1015
+ });
1016
+ if (shouldRetryLoading) {
1017
+ await this._createObjectOnDocumentLoad(handle, objectId);
1018
+ }
1019
+ }
1020
+ }
1021
+ };
1022
+ var REFERENCE_TYPE_TAG = "dxos.echo.model.document.Reference";
1023
+ var encodeReference = (reference) => ({
1024
+ "@type": REFERENCE_TYPE_TAG,
1025
+ // NOTE: Automerge do not support undefined values, so we need to use null instead.
1026
+ itemId: reference.itemId ?? null,
1027
+ protocol: reference.protocol ?? null,
1028
+ host: reference.host ?? null
1029
+ });
1030
+ var decodeReference = (value) => new import_echo_db.Reference(value.itemId, value.protocol ?? void 0, value.host ?? void 0);
1031
+ var isEncodedReferenceObject = (value) => typeof value === "object" && value !== null && value["@type"] === REFERENCE_TYPE_TAG;
666
1032
  // Annotate the CommonJS export names for ESM import in node:
667
1033
  0 && (module.exports = {
668
1034
  AuthExtension,
669
1035
  AuthStatus,
1036
+ AutomergeDocumentLoaderImpl,
670
1037
  AutomergeHost,
671
1038
  AutomergeStorageAdapter,
672
1039
  DataServiceImpl,
1040
+ LevelDBStorageAdapter,
673
1041
  LocalHostNetworkAdapter,
674
1042
  MOCK_AUTH_PROVIDER,
675
1043
  MOCK_AUTH_VERIFIER,
676
1044
  MeshNetworkAdapter,
677
1045
  MetadataStore,
678
1046
  Pipeline,
1047
+ REFERENCE_TYPE_TAG,
679
1048
  SnapshotManager,
680
1049
  SnapshotStore,
681
1050
  Space,
@@ -685,7 +1054,12 @@ var getSpaceKeyFromDoc = (doc) => {
685
1054
  TimeframeClock,
686
1055
  codec,
687
1056
  createMappedFeedWriter,
1057
+ decodeReference,
1058
+ encodeReference,
1059
+ encodingOptions,
688
1060
  getSpaceKeyFromDoc,
1061
+ hasInvitationExpired,
1062
+ isEncodedReferenceObject,
689
1063
  mapFeedIndexesToTimeframe,
690
1064
  mapTimeframeToFeedIndexes,
691
1065
  startAfter,