@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.
- package/dist/lib/browser/{chunk-RTEEJ723.mjs → chunk-SYE4EK33.mjs} +30 -35
- package/dist/lib/browser/chunk-SYE4EK33.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +593 -217
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +8 -2
- package/dist/lib/browser/testing/index.mjs.map +4 -4
- package/dist/lib/node/{chunk-7VZVCCNF.cjs → chunk-WCTX6RNS.cjs} +35 -40
- package/dist/lib/node/chunk-WCTX6RNS.cjs.map +7 -0
- package/dist/lib/node/index.cjs +611 -237
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/testing/index.cjs +18 -13
- package/dist/lib/node/testing/index.cjs.map +4 -4
- package/dist/types/src/automerge/automerge-doc-loader.d.ts +66 -0
- package/dist/types/src/automerge/automerge-doc-loader.d.ts.map +1 -0
- package/dist/types/src/automerge/automerge-doc-loader.test.d.ts +2 -0
- package/dist/types/src/automerge/automerge-doc-loader.test.d.ts.map +1 -0
- package/dist/types/src/automerge/automerge-host.d.ts +21 -18
- package/dist/types/src/automerge/automerge-host.d.ts.map +1 -1
- package/dist/types/src/automerge/automerge-repo.test.d.ts +2 -0
- package/dist/types/src/automerge/automerge-repo.test.d.ts.map +1 -0
- package/dist/types/src/automerge/index.d.ts +4 -0
- package/dist/types/src/automerge/index.d.ts.map +1 -1
- package/dist/types/src/automerge/level.test.d.ts +2 -0
- package/dist/types/src/automerge/level.test.d.ts.map +1 -0
- package/dist/types/src/automerge/leveldb-storage-adapter.d.ts +30 -0
- package/dist/types/src/automerge/leveldb-storage-adapter.d.ts.map +1 -0
- package/dist/types/src/automerge/local-host-network-adapter.d.ts +8 -1
- package/dist/types/src/automerge/local-host-network-adapter.d.ts.map +1 -1
- package/dist/types/src/automerge/migrations.d.ts +7 -0
- package/dist/types/src/automerge/migrations.d.ts.map +1 -0
- package/dist/types/src/automerge/reference.d.ts +15 -0
- package/dist/types/src/automerge/reference.d.ts.map +1 -0
- package/dist/types/src/automerge/storage-adapter.test.d.ts +2 -0
- package/dist/types/src/automerge/storage-adapter.test.d.ts.map +1 -0
- package/dist/types/src/automerge/types.d.ts +73 -0
- package/dist/types/src/automerge/types.d.ts.map +1 -0
- package/dist/types/src/metadata/metadata-store.d.ts +2 -1
- package/dist/types/src/metadata/metadata-store.d.ts.map +1 -1
- package/dist/types/src/space/space.d.ts +4 -8
- package/dist/types/src/space/space.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +1 -0
- package/dist/types/src/testing/index.d.ts.map +1 -1
- package/dist/types/src/testing/level.d.ts +3 -0
- package/dist/types/src/testing/level.d.ts.map +1 -0
- package/dist/types/src/testing/test-agent-builder.d.ts +2 -2
- package/package.json +33 -30
- package/src/automerge/automerge-doc-loader.test.ts +97 -0
- package/src/automerge/automerge-doc-loader.ts +241 -0
- package/src/automerge/automerge-host.test.ts +22 -8
- package/src/automerge/automerge-host.ts +65 -118
- package/src/automerge/automerge-repo.test.ts +29 -0
- package/src/automerge/index.ts +4 -0
- package/src/automerge/level.test.ts +64 -0
- package/src/automerge/leveldb-storage-adapter.ts +117 -0
- package/src/automerge/local-host-network-adapter.ts +19 -13
- package/src/automerge/migrations.ts +41 -0
- package/src/automerge/reference.ts +31 -0
- package/src/automerge/storage-adapter.test.ts +90 -0
- package/src/automerge/types.ts +86 -0
- package/src/db-host/data-service.ts +1 -1
- package/src/metadata/metadata-store.ts +17 -8
- package/src/space/space.test.ts +7 -7
- package/src/space/space.ts +6 -21
- package/src/testing/index.ts +1 -0
- package/src/testing/level.ts +11 -0
- package/dist/lib/browser/chunk-RTEEJ723.mjs.map +0 -7
- package/dist/lib/node/chunk-7VZVCCNF.cjs.map +0 -7
|
@@ -2,6 +2,7 @@ import "@dxos/node-std/globals";
|
|
|
2
2
|
import {
|
|
3
3
|
AuthExtension,
|
|
4
4
|
AuthStatus,
|
|
5
|
+
Buffer,
|
|
5
6
|
DataServiceImpl,
|
|
6
7
|
MOCK_AUTH_PROVIDER,
|
|
7
8
|
MOCK_AUTH_VERIFIER,
|
|
@@ -16,142 +17,130 @@ import {
|
|
|
16
17
|
TimeframeClock,
|
|
17
18
|
codec,
|
|
18
19
|
createMappedFeedWriter,
|
|
20
|
+
hasInvitationExpired,
|
|
19
21
|
mapFeedIndexesToTimeframe,
|
|
20
22
|
mapTimeframeToFeedIndexes,
|
|
21
23
|
startAfter,
|
|
22
24
|
valueEncoding
|
|
23
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-SYE4EK33.mjs";
|
|
24
26
|
|
|
25
27
|
// packages/core/echo/echo-pipeline/src/automerge/automerge-host.ts
|
|
26
|
-
import {
|
|
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/
|
|
38
|
-
import {
|
|
39
|
-
var
|
|
40
|
-
constructor(
|
|
41
|
-
|
|
42
|
-
this.
|
|
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(
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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(
|
|
58
|
-
if (this.
|
|
59
|
+
async save(keyArray, binary) {
|
|
60
|
+
if (this._lifecycleState !== LifecycleState.OPEN) {
|
|
59
61
|
return void 0;
|
|
60
62
|
}
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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(
|
|
68
|
-
if (this.
|
|
74
|
+
async remove(keyArray) {
|
|
75
|
+
if (this._lifecycleState !== LifecycleState.OPEN) {
|
|
69
76
|
return void 0;
|
|
70
77
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
78
|
+
await this._params.db.del(keyArray, {
|
|
79
|
+
...encodingOptions
|
|
80
|
+
});
|
|
74
81
|
}
|
|
75
82
|
async loadRange(keyPrefix) {
|
|
76
|
-
if (this.
|
|
83
|
+
if (this._lifecycleState !== LifecycleState.OPEN) {
|
|
77
84
|
return [];
|
|
78
85
|
}
|
|
79
|
-
const
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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.
|
|
103
|
+
if (this._lifecycleState !== LifecycleState.OPEN) {
|
|
93
104
|
return void 0;
|
|
94
105
|
}
|
|
95
|
-
const
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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:
|
|
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:
|
|
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.
|
|
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:
|
|
216
|
+
L: 90,
|
|
224
217
|
S: this,
|
|
225
|
-
|
|
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
|
-
|
|
231
|
-
|
|
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
|
-
|
|
238
|
-
|
|
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:
|
|
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
|
|
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) =>
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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,
|
|
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.
|
|
397
|
-
this.
|
|
398
|
-
this.
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
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:
|
|
434
|
-
L:
|
|
560
|
+
F: __dxlog_file4,
|
|
561
|
+
L: 99,
|
|
435
562
|
S: this,
|
|
436
563
|
C: (f, a) => f(...a)
|
|
437
564
|
});
|
|
@@ -444,8 +571,8 @@ var AutomergeHost = class {
|
|
|
444
571
|
peerId,
|
|
445
572
|
documentId
|
|
446
573
|
}, {
|
|
447
|
-
F:
|
|
448
|
-
L:
|
|
574
|
+
F: __dxlog_file4,
|
|
575
|
+
L: 106,
|
|
449
576
|
S: this,
|
|
450
577
|
C: (f, a) => f(...a)
|
|
451
578
|
});
|
|
@@ -458,8 +585,8 @@ var AutomergeHost = class {
|
|
|
458
585
|
peerId,
|
|
459
586
|
documentId
|
|
460
587
|
}, {
|
|
461
|
-
F:
|
|
462
|
-
L:
|
|
588
|
+
F: __dxlog_file4,
|
|
589
|
+
L: 115,
|
|
463
590
|
S: this,
|
|
464
591
|
C: (f, a) => f(...a)
|
|
465
592
|
});
|
|
@@ -475,16 +602,16 @@ var AutomergeHost = class {
|
|
|
475
602
|
spaceKey,
|
|
476
603
|
isAuthorized
|
|
477
604
|
}, {
|
|
478
|
-
F:
|
|
479
|
-
L:
|
|
605
|
+
F: __dxlog_file4,
|
|
606
|
+
L: 121,
|
|
480
607
|
S: this,
|
|
481
608
|
C: (f, a) => f(...a)
|
|
482
609
|
});
|
|
483
610
|
return isAuthorized;
|
|
484
611
|
} catch (err) {
|
|
485
612
|
log3.catch(err, void 0, {
|
|
486
|
-
F:
|
|
487
|
-
L:
|
|
613
|
+
F: __dxlog_file4,
|
|
614
|
+
L: 131,
|
|
488
615
|
S: this,
|
|
489
616
|
C: (f, a) => f(...a)
|
|
490
617
|
});
|
|
@@ -494,69 +621,22 @@ var AutomergeHost = class {
|
|
|
494
621
|
});
|
|
495
622
|
this._clientNetwork.ready();
|
|
496
623
|
this._meshNetwork.ready();
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
}
|
|
624
|
+
await this._clientNetwork.whenConnected();
|
|
625
|
+
}
|
|
626
|
+
async close() {
|
|
627
|
+
await this._storage.close?.();
|
|
628
|
+
await this._clientNetwork.close();
|
|
629
|
+
await this._ctx.dispose();
|
|
504
630
|
}
|
|
505
631
|
get repo() {
|
|
506
632
|
return this._repo;
|
|
507
633
|
}
|
|
508
|
-
async _beforeSave(path) {
|
|
509
|
-
const id = path[0];
|
|
510
|
-
if (this._updatingMetadata.has(id)) {
|
|
511
|
-
return this._updatingMetadata.get(id);
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
_onDocument(handle) {
|
|
515
|
-
const listener = (event) => this._onUpdate(event);
|
|
516
|
-
handle.on("change", listener);
|
|
517
|
-
this._ctx.onDispose(() => {
|
|
518
|
-
handle.off("change", listener);
|
|
519
|
-
});
|
|
520
|
-
}
|
|
521
|
-
_onUpdate(event) {
|
|
522
|
-
if (this._metadata == null) {
|
|
523
|
-
return;
|
|
524
|
-
}
|
|
525
|
-
const objectIds = getInlineChanges(event);
|
|
526
|
-
if (objectIds.length === 0) {
|
|
527
|
-
return;
|
|
528
|
-
}
|
|
529
|
-
const heads = getHeads(event.doc);
|
|
530
|
-
const lastAvailableHash = heads.join("");
|
|
531
|
-
if (!lastAvailableHash) {
|
|
532
|
-
return;
|
|
533
|
-
}
|
|
534
|
-
const encodedIds = objectIds.map((objectId) => idCodec.encode({
|
|
535
|
-
documentId: event.handle.documentId,
|
|
536
|
-
objectId
|
|
537
|
-
}));
|
|
538
|
-
const idToLastHash = new Map(encodedIds.map((id) => [
|
|
539
|
-
id,
|
|
540
|
-
lastAvailableHash
|
|
541
|
-
]));
|
|
542
|
-
const markingDirtyPromise = this._metadata.markDirty(idToLastHash).then(() => {
|
|
543
|
-
this._updatingMetadata.delete(event.handle.documentId);
|
|
544
|
-
}).catch((err) => {
|
|
545
|
-
this._ctx.disposed && log3.catch(err, void 0, {
|
|
546
|
-
F: __dxlog_file3,
|
|
547
|
-
L: 188,
|
|
548
|
-
S: this,
|
|
549
|
-
C: (f, a) => f(...a)
|
|
550
|
-
});
|
|
551
|
-
});
|
|
552
|
-
this._updatingMetadata.set(event.handle.documentId, markingDirtyPromise);
|
|
553
|
-
}
|
|
554
634
|
_automergeDocs() {
|
|
555
635
|
return mapValues(this._repo.handles, (handle) => ({
|
|
556
636
|
state: handle.state,
|
|
557
637
|
hasDoc: !!handle.docSync(),
|
|
558
638
|
heads: handle.docSync() ? automerge.getHeads(handle.docSync()) : null,
|
|
559
|
-
data: handle.docSync()
|
|
639
|
+
data: handle.docSync() && mapValues(handle.docSync(), (value, key) => {
|
|
560
640
|
try {
|
|
561
641
|
switch (key) {
|
|
562
642
|
case "access":
|
|
@@ -576,14 +656,25 @@ var AutomergeHost = class {
|
|
|
576
656
|
_automergePeers() {
|
|
577
657
|
return this._repo.peers;
|
|
578
658
|
}
|
|
579
|
-
async close() {
|
|
580
|
-
await this._storage.close();
|
|
581
|
-
await this._clientNetwork.close();
|
|
582
|
-
await this._ctx.dispose();
|
|
583
|
-
}
|
|
584
659
|
//
|
|
585
660
|
// Methods for client-services.
|
|
586
661
|
//
|
|
662
|
+
async flush({ documentIds }) {
|
|
663
|
+
await Promise.all(documentIds?.map((id) => this._repo.find(id).whenReady()) ?? []);
|
|
664
|
+
try {
|
|
665
|
+
await asyncTimeout(this._repo.flush(documentIds), 500);
|
|
666
|
+
} catch (err) {
|
|
667
|
+
log3.warn("flush error", {
|
|
668
|
+
documentIds,
|
|
669
|
+
err
|
|
670
|
+
}, {
|
|
671
|
+
F: __dxlog_file4,
|
|
672
|
+
L: 195,
|
|
673
|
+
S: this,
|
|
674
|
+
C: (f, a) => f(...a)
|
|
675
|
+
});
|
|
676
|
+
}
|
|
677
|
+
}
|
|
587
678
|
syncRepo(request) {
|
|
588
679
|
return this._clientNetwork.syncRepo(request);
|
|
589
680
|
}
|
|
@@ -604,8 +695,8 @@ var AutomergeHost = class {
|
|
|
604
695
|
spaceKey,
|
|
605
696
|
deviceKey
|
|
606
697
|
}, {
|
|
607
|
-
F:
|
|
608
|
-
L:
|
|
698
|
+
F: __dxlog_file4,
|
|
699
|
+
L: 220,
|
|
609
700
|
S: this,
|
|
610
701
|
C: (f, a) => f(...a)
|
|
611
702
|
});
|
|
@@ -628,24 +719,6 @@ _ts_decorate([
|
|
|
628
719
|
AutomergeHost = _ts_decorate([
|
|
629
720
|
trace.resource()
|
|
630
721
|
], AutomergeHost);
|
|
631
|
-
var getInlineChanges = (event) => {
|
|
632
|
-
const inlineChangedObjectIds = /* @__PURE__ */ new Set();
|
|
633
|
-
for (const { path } of event.patches) {
|
|
634
|
-
if (path.length < 2) {
|
|
635
|
-
continue;
|
|
636
|
-
}
|
|
637
|
-
switch (path[0]) {
|
|
638
|
-
case "objects":
|
|
639
|
-
if (path.length >= 2) {
|
|
640
|
-
inlineChangedObjectIds.add(path[1]);
|
|
641
|
-
}
|
|
642
|
-
break;
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
return [
|
|
646
|
-
...inlineChangedObjectIds
|
|
647
|
-
];
|
|
648
|
-
};
|
|
649
722
|
var getSpaceKeyFromDoc = (doc) => {
|
|
650
723
|
const rawSpaceKey = doc.access?.spaceKey ?? doc.experimental_spaceKey;
|
|
651
724
|
if (rawSpaceKey == null) {
|
|
@@ -653,18 +726,316 @@ var getSpaceKeyFromDoc = (doc) => {
|
|
|
653
726
|
}
|
|
654
727
|
return String(rawSpaceKey);
|
|
655
728
|
};
|
|
729
|
+
|
|
730
|
+
// packages/core/echo/echo-pipeline/src/automerge/automerge-doc-loader.ts
|
|
731
|
+
import { Event } from "@dxos/async";
|
|
732
|
+
import { cancelWithContext } from "@dxos/context";
|
|
733
|
+
import { warnAfterTimeout } from "@dxos/debug";
|
|
734
|
+
import { invariant as invariant3 } from "@dxos/invariant";
|
|
735
|
+
import { log as log4 } from "@dxos/log";
|
|
736
|
+
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/automerge-doc-loader.ts";
|
|
737
|
+
var AutomergeDocumentLoaderImpl = class {
|
|
738
|
+
constructor(_spaceKey, _repo) {
|
|
739
|
+
this._spaceKey = _spaceKey;
|
|
740
|
+
this._repo = _repo;
|
|
741
|
+
this._spaceRootDocHandle = null;
|
|
742
|
+
this._objectDocumentHandles = /* @__PURE__ */ new Map();
|
|
743
|
+
this._objectsPendingDocumentLoad = /* @__PURE__ */ new Set();
|
|
744
|
+
this.onObjectDocumentLoaded = new Event();
|
|
745
|
+
}
|
|
746
|
+
getAllHandles() {
|
|
747
|
+
return [
|
|
748
|
+
...new Set(this._objectDocumentHandles.values())
|
|
749
|
+
];
|
|
750
|
+
}
|
|
751
|
+
async loadSpaceRootDocHandle(ctx, spaceState) {
|
|
752
|
+
if (this._spaceRootDocHandle != null) {
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
755
|
+
if (!spaceState.rootUrl) {
|
|
756
|
+
log4.error("Database opened with no rootUrl", {
|
|
757
|
+
spaceKey: this._spaceKey
|
|
758
|
+
}, {
|
|
759
|
+
F: __dxlog_file5,
|
|
760
|
+
L: 66,
|
|
761
|
+
S: this,
|
|
762
|
+
C: (f, a) => f(...a)
|
|
763
|
+
});
|
|
764
|
+
this._createContextBoundSpaceRootDocument(ctx);
|
|
765
|
+
} else {
|
|
766
|
+
const existingDocHandle = await this._initDocHandle(ctx, spaceState.rootUrl);
|
|
767
|
+
const doc = existingDocHandle.docSync();
|
|
768
|
+
invariant3(doc, void 0, {
|
|
769
|
+
F: __dxlog_file5,
|
|
770
|
+
L: 71,
|
|
771
|
+
S: this,
|
|
772
|
+
A: [
|
|
773
|
+
"doc",
|
|
774
|
+
""
|
|
775
|
+
]
|
|
776
|
+
});
|
|
777
|
+
if (doc.access == null) {
|
|
778
|
+
this._initDocAccess(existingDocHandle);
|
|
779
|
+
}
|
|
780
|
+
this._spaceRootDocHandle = existingDocHandle;
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
loadObjectDocument(objectId) {
|
|
784
|
+
invariant3(this._spaceRootDocHandle, void 0, {
|
|
785
|
+
F: __dxlog_file5,
|
|
786
|
+
L: 80,
|
|
787
|
+
S: this,
|
|
788
|
+
A: [
|
|
789
|
+
"this._spaceRootDocHandle",
|
|
790
|
+
""
|
|
791
|
+
]
|
|
792
|
+
});
|
|
793
|
+
if (this._objectDocumentHandles.has(objectId) || this._objectsPendingDocumentLoad.has(objectId)) {
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
796
|
+
const spaceRootDoc = this._spaceRootDocHandle.docSync();
|
|
797
|
+
invariant3(spaceRootDoc, void 0, {
|
|
798
|
+
F: __dxlog_file5,
|
|
799
|
+
L: 85,
|
|
800
|
+
S: this,
|
|
801
|
+
A: [
|
|
802
|
+
"spaceRootDoc",
|
|
803
|
+
""
|
|
804
|
+
]
|
|
805
|
+
});
|
|
806
|
+
const documentUrl = (spaceRootDoc.links ?? {})[objectId];
|
|
807
|
+
if (documentUrl == null) {
|
|
808
|
+
this._objectsPendingDocumentLoad.add(objectId);
|
|
809
|
+
log4.info("loading delayed until object links are initialized", {
|
|
810
|
+
objectId
|
|
811
|
+
}, {
|
|
812
|
+
F: __dxlog_file5,
|
|
813
|
+
L: 89,
|
|
814
|
+
S: this,
|
|
815
|
+
C: (f, a) => f(...a)
|
|
816
|
+
});
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
this._loadLinkedObjects({
|
|
820
|
+
[objectId]: documentUrl
|
|
821
|
+
});
|
|
822
|
+
}
|
|
823
|
+
onObjectLinksUpdated(links) {
|
|
824
|
+
if (!links) {
|
|
825
|
+
return;
|
|
826
|
+
}
|
|
827
|
+
const linksAwaitingLoad = Object.entries(links).filter(([objectId]) => this._objectsPendingDocumentLoad.has(objectId));
|
|
828
|
+
this._loadLinkedObjects(Object.fromEntries(linksAwaitingLoad));
|
|
829
|
+
linksAwaitingLoad.forEach(([objectId]) => this._objectsPendingDocumentLoad.delete(objectId));
|
|
830
|
+
}
|
|
831
|
+
getSpaceRootDocHandle() {
|
|
832
|
+
invariant3(this._spaceRootDocHandle, void 0, {
|
|
833
|
+
F: __dxlog_file5,
|
|
834
|
+
L: 107,
|
|
835
|
+
S: this,
|
|
836
|
+
A: [
|
|
837
|
+
"this._spaceRootDocHandle",
|
|
838
|
+
""
|
|
839
|
+
]
|
|
840
|
+
});
|
|
841
|
+
return this._spaceRootDocHandle;
|
|
842
|
+
}
|
|
843
|
+
createDocumentForObject(objectId) {
|
|
844
|
+
invariant3(this._spaceRootDocHandle, void 0, {
|
|
845
|
+
F: __dxlog_file5,
|
|
846
|
+
L: 112,
|
|
847
|
+
S: this,
|
|
848
|
+
A: [
|
|
849
|
+
"this._spaceRootDocHandle",
|
|
850
|
+
""
|
|
851
|
+
]
|
|
852
|
+
});
|
|
853
|
+
const spaceDocHandle = this._repo.create();
|
|
854
|
+
this._initDocAccess(spaceDocHandle);
|
|
855
|
+
this.onObjectBoundToDocument(spaceDocHandle, objectId);
|
|
856
|
+
this._spaceRootDocHandle.change((newDoc) => {
|
|
857
|
+
newDoc.links ??= {};
|
|
858
|
+
newDoc.links[objectId] = spaceDocHandle.url;
|
|
859
|
+
});
|
|
860
|
+
return spaceDocHandle;
|
|
861
|
+
}
|
|
862
|
+
onObjectBoundToDocument(handle, objectId) {
|
|
863
|
+
this._objectDocumentHandles.set(objectId, handle);
|
|
864
|
+
}
|
|
865
|
+
clearHandleReferences() {
|
|
866
|
+
const objectsWithHandles = [
|
|
867
|
+
...this._objectDocumentHandles.keys()
|
|
868
|
+
];
|
|
869
|
+
this._objectDocumentHandles.clear();
|
|
870
|
+
this._spaceRootDocHandle = null;
|
|
871
|
+
return objectsWithHandles;
|
|
872
|
+
}
|
|
873
|
+
_loadLinkedObjects(links) {
|
|
874
|
+
if (!links) {
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
for (const [objectId, automergeUrl] of Object.entries(links)) {
|
|
878
|
+
const logMeta = {
|
|
879
|
+
objectId,
|
|
880
|
+
automergeUrl
|
|
881
|
+
};
|
|
882
|
+
const objectDocumentHandle = this._objectDocumentHandles.get(objectId);
|
|
883
|
+
if (objectDocumentHandle != null && objectDocumentHandle.url !== automergeUrl) {
|
|
884
|
+
log4.warn("object already inlined in a different document, ignoring the link", {
|
|
885
|
+
...logMeta,
|
|
886
|
+
actualDocumentUrl: objectDocumentHandle.url
|
|
887
|
+
}, {
|
|
888
|
+
F: __dxlog_file5,
|
|
889
|
+
L: 142,
|
|
890
|
+
S: this,
|
|
891
|
+
C: (f, a) => f(...a)
|
|
892
|
+
});
|
|
893
|
+
continue;
|
|
894
|
+
}
|
|
895
|
+
if (objectDocumentHandle?.url === automergeUrl) {
|
|
896
|
+
log4.warn("object document was already loaded", logMeta, {
|
|
897
|
+
F: __dxlog_file5,
|
|
898
|
+
L: 149,
|
|
899
|
+
S: this,
|
|
900
|
+
C: (f, a) => f(...a)
|
|
901
|
+
});
|
|
902
|
+
continue;
|
|
903
|
+
}
|
|
904
|
+
const handle = this._repo.find(automergeUrl);
|
|
905
|
+
log4.debug("document loading triggered", logMeta, {
|
|
906
|
+
F: __dxlog_file5,
|
|
907
|
+
L: 153,
|
|
908
|
+
S: this,
|
|
909
|
+
C: (f, a) => f(...a)
|
|
910
|
+
});
|
|
911
|
+
this._objectDocumentHandles.set(objectId, handle);
|
|
912
|
+
void this._createObjectOnDocumentLoad(handle, objectId);
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
async _initDocHandle(ctx, url) {
|
|
916
|
+
const docHandle = this._repo.find(url);
|
|
917
|
+
while (true) {
|
|
918
|
+
try {
|
|
919
|
+
await warnAfterTimeout(5e3, "Automerge root doc load timeout (AutomergeDb)", async () => {
|
|
920
|
+
await cancelWithContext(ctx, docHandle.whenReady());
|
|
921
|
+
});
|
|
922
|
+
break;
|
|
923
|
+
} catch (err) {
|
|
924
|
+
if (`${err}`.includes("Timeout")) {
|
|
925
|
+
log4.info("wraparound", {
|
|
926
|
+
id: docHandle.documentId,
|
|
927
|
+
state: docHandle.state
|
|
928
|
+
}, {
|
|
929
|
+
F: __dxlog_file5,
|
|
930
|
+
L: 169,
|
|
931
|
+
S: this,
|
|
932
|
+
C: (f, a) => f(...a)
|
|
933
|
+
});
|
|
934
|
+
continue;
|
|
935
|
+
}
|
|
936
|
+
throw err;
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
if (docHandle.state === "unavailable") {
|
|
940
|
+
throw new Error("Automerge document is unavailable");
|
|
941
|
+
}
|
|
942
|
+
return docHandle;
|
|
943
|
+
}
|
|
944
|
+
_createContextBoundSpaceRootDocument(ctx) {
|
|
945
|
+
const docHandle = this._repo.create();
|
|
946
|
+
this._spaceRootDocHandle = docHandle;
|
|
947
|
+
ctx.onDispose(() => {
|
|
948
|
+
docHandle.delete();
|
|
949
|
+
this._spaceRootDocHandle = null;
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
_initDocAccess(handle) {
|
|
953
|
+
handle.change((newDoc) => {
|
|
954
|
+
newDoc.access ??= {
|
|
955
|
+
spaceKey: this._spaceKey.toHex()
|
|
956
|
+
};
|
|
957
|
+
newDoc.access.spaceKey = this._spaceKey.toHex();
|
|
958
|
+
});
|
|
959
|
+
}
|
|
960
|
+
async _createObjectOnDocumentLoad(handle, objectId) {
|
|
961
|
+
try {
|
|
962
|
+
await handle.doc([
|
|
963
|
+
"ready"
|
|
964
|
+
]);
|
|
965
|
+
const logMeta = {
|
|
966
|
+
objectId,
|
|
967
|
+
docUrl: handle.url
|
|
968
|
+
};
|
|
969
|
+
if (this.onObjectDocumentLoaded.listenerCount() === 0) {
|
|
970
|
+
log4.info("document loaded after all listeners were removed", logMeta, {
|
|
971
|
+
F: __dxlog_file5,
|
|
972
|
+
L: 205,
|
|
973
|
+
S: this,
|
|
974
|
+
C: (f, a) => f(...a)
|
|
975
|
+
});
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
const objectDocHandle = this._objectDocumentHandles.get(objectId);
|
|
979
|
+
if (objectDocHandle?.url !== handle.url) {
|
|
980
|
+
log4.warn("object was rebound while a document was loading, discarding handle", logMeta, {
|
|
981
|
+
F: __dxlog_file5,
|
|
982
|
+
L: 210,
|
|
983
|
+
S: this,
|
|
984
|
+
C: (f, a) => f(...a)
|
|
985
|
+
});
|
|
986
|
+
return;
|
|
987
|
+
}
|
|
988
|
+
this.onObjectDocumentLoaded.emit({
|
|
989
|
+
handle,
|
|
990
|
+
objectId
|
|
991
|
+
});
|
|
992
|
+
} catch (err) {
|
|
993
|
+
const shouldRetryLoading = this.onObjectDocumentLoaded.listenerCount() > 0;
|
|
994
|
+
log4.warn("failed to load a document", {
|
|
995
|
+
objectId,
|
|
996
|
+
automergeUrl: handle.url,
|
|
997
|
+
retryLoading: shouldRetryLoading,
|
|
998
|
+
err
|
|
999
|
+
}, {
|
|
1000
|
+
F: __dxlog_file5,
|
|
1001
|
+
L: 216,
|
|
1002
|
+
S: this,
|
|
1003
|
+
C: (f, a) => f(...a)
|
|
1004
|
+
});
|
|
1005
|
+
if (shouldRetryLoading) {
|
|
1006
|
+
await this._createObjectOnDocumentLoad(handle, objectId);
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
};
|
|
1011
|
+
|
|
1012
|
+
// packages/core/echo/echo-pipeline/src/automerge/reference.ts
|
|
1013
|
+
import { Reference } from "@dxos/echo-db";
|
|
1014
|
+
var REFERENCE_TYPE_TAG = "dxos.echo.model.document.Reference";
|
|
1015
|
+
var encodeReference = (reference) => ({
|
|
1016
|
+
"@type": REFERENCE_TYPE_TAG,
|
|
1017
|
+
// NOTE: Automerge do not support undefined values, so we need to use null instead.
|
|
1018
|
+
itemId: reference.itemId ?? null,
|
|
1019
|
+
protocol: reference.protocol ?? null,
|
|
1020
|
+
host: reference.host ?? null
|
|
1021
|
+
});
|
|
1022
|
+
var decodeReference = (value) => new Reference(value.itemId, value.protocol ?? void 0, value.host ?? void 0);
|
|
1023
|
+
var isEncodedReferenceObject = (value) => typeof value === "object" && value !== null && value["@type"] === REFERENCE_TYPE_TAG;
|
|
656
1024
|
export {
|
|
657
1025
|
AuthExtension,
|
|
658
1026
|
AuthStatus,
|
|
1027
|
+
AutomergeDocumentLoaderImpl,
|
|
659
1028
|
AutomergeHost,
|
|
660
1029
|
AutomergeStorageAdapter,
|
|
661
1030
|
DataServiceImpl,
|
|
1031
|
+
LevelDBStorageAdapter,
|
|
662
1032
|
LocalHostNetworkAdapter,
|
|
663
1033
|
MOCK_AUTH_PROVIDER,
|
|
664
1034
|
MOCK_AUTH_VERIFIER,
|
|
665
1035
|
MeshNetworkAdapter,
|
|
666
1036
|
MetadataStore,
|
|
667
1037
|
Pipeline,
|
|
1038
|
+
REFERENCE_TYPE_TAG,
|
|
668
1039
|
SnapshotManager,
|
|
669
1040
|
SnapshotStore,
|
|
670
1041
|
Space,
|
|
@@ -674,7 +1045,12 @@ export {
|
|
|
674
1045
|
TimeframeClock,
|
|
675
1046
|
codec,
|
|
676
1047
|
createMappedFeedWriter,
|
|
1048
|
+
decodeReference,
|
|
1049
|
+
encodeReference,
|
|
1050
|
+
encodingOptions,
|
|
677
1051
|
getSpaceKeyFromDoc,
|
|
1052
|
+
hasInvitationExpired,
|
|
1053
|
+
isEncodedReferenceObject,
|
|
678
1054
|
mapFeedIndexesToTimeframe,
|
|
679
1055
|
mapTimeframeToFeedIndexes,
|
|
680
1056
|
startAfter,
|