@dxos/echo-pipeline 0.5.0 → 0.5.1-main.2ed734f
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/index.mjs +47 -28
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +1 -1
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/node/index.cjs +53 -34
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/testing/index.cjs +1 -1
- package/dist/lib/node/testing/index.cjs.map +3 -3
- package/dist/types/src/automerge/automerge-host.d.ts +1 -1
- package/dist/types/src/automerge/automerge-host.d.ts.map +1 -1
- package/dist/types/src/testing/level.d.ts +1 -1
- package/dist/types/src/testing/level.d.ts.map +1 -1
- package/package.json +30 -30
- package/src/automerge/automerge-host.test.ts +22 -13
- package/src/automerge/automerge-host.ts +45 -13
- package/src/automerge/automerge-repo.test.ts +38 -6
- package/src/testing/level.ts +2 -1
|
@@ -2,11 +2,19 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import { next as automerge } from '@dxos/automerge/automerge';
|
|
7
|
-
import {
|
|
5
|
+
import { Event } from '@dxos/async';
|
|
6
|
+
import { type Doc, next as automerge, getBackend, type Heads } from '@dxos/automerge/automerge';
|
|
7
|
+
import {
|
|
8
|
+
type DocHandle,
|
|
9
|
+
Repo,
|
|
10
|
+
type DocumentId,
|
|
11
|
+
type PeerId,
|
|
12
|
+
type StorageAdapterInterface,
|
|
13
|
+
type DocHandleChangePayload,
|
|
14
|
+
} from '@dxos/automerge/automerge-repo';
|
|
8
15
|
import { type Stream } from '@dxos/codec-protobuf';
|
|
9
16
|
import { Context, type Lifecycle } from '@dxos/context';
|
|
17
|
+
import { invariant } from '@dxos/invariant';
|
|
10
18
|
import { PublicKey } from '@dxos/keys';
|
|
11
19
|
import { log } from '@dxos/log';
|
|
12
20
|
import {
|
|
@@ -24,7 +32,7 @@ import { LevelDBStorageAdapter, type StorageCallbacks } from './leveldb-storage-
|
|
|
24
32
|
import { LocalHostNetworkAdapter } from './local-host-network-adapter';
|
|
25
33
|
import { MeshNetworkAdapter } from './mesh-network-adapter';
|
|
26
34
|
import { levelMigration } from './migrations';
|
|
27
|
-
import { type SubLevelDB } from './types';
|
|
35
|
+
import { type SpaceDoc, type SubLevelDB } from './types';
|
|
28
36
|
|
|
29
37
|
// TODO: Remove
|
|
30
38
|
export type { DocumentId };
|
|
@@ -185,16 +193,17 @@ export class AutomergeHost {
|
|
|
185
193
|
// Methods for client-services.
|
|
186
194
|
//
|
|
187
195
|
@trace.span({ showInBrowserTimeline: true })
|
|
188
|
-
async flush({
|
|
196
|
+
async flush({ states }: FlushRequest): Promise<void> {
|
|
189
197
|
// Note: Wait for all requested documents to be loaded/synced from thin-client.
|
|
190
|
-
await Promise.all(
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
+
await Promise.all(
|
|
199
|
+
states?.map(async ({ heads, documentId }) => {
|
|
200
|
+
invariant(heads, 'heads are required for flush');
|
|
201
|
+
const handle = this.repo.handles[documentId as DocumentId] ?? this._repo.find(documentId as DocumentId);
|
|
202
|
+
await waitForHeads(handle, heads);
|
|
203
|
+
}) ?? [],
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
await this._repo.flush(states?.map(({ documentId }) => documentId as DocumentId));
|
|
198
207
|
}
|
|
199
208
|
|
|
200
209
|
syncRepo(request: SyncRepoRequest): Stream<SyncRepoResponse> {
|
|
@@ -232,3 +241,26 @@ export const getSpaceKeyFromDoc = (doc: any): string | null => {
|
|
|
232
241
|
|
|
233
242
|
return String(rawSpaceKey);
|
|
234
243
|
};
|
|
244
|
+
|
|
245
|
+
const waitForHeads = async (handle: DocHandle<SpaceDoc>, heads: Heads) => {
|
|
246
|
+
await handle.whenReady();
|
|
247
|
+
const unavailableHeads = new Set(heads);
|
|
248
|
+
|
|
249
|
+
await Event.wrap<DocHandleChangePayload<SpaceDoc>>(handle, 'change').waitForCondition(() => {
|
|
250
|
+
// Check if unavailable heads became available.
|
|
251
|
+
for (const changeHash of unavailableHeads.values()) {
|
|
252
|
+
if (changeIsPresentInDoc(handle.docSync(), changeHash)) {
|
|
253
|
+
unavailableHeads.delete(changeHash);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (unavailableHeads.size === 0) {
|
|
258
|
+
return true;
|
|
259
|
+
}
|
|
260
|
+
return false;
|
|
261
|
+
});
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
const changeIsPresentInDoc = (doc: Doc<any>, changeHash: string): boolean => {
|
|
265
|
+
return !!getBackend(doc).getChangeByHash(changeHash);
|
|
266
|
+
};
|
|
@@ -2,19 +2,25 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { expect } from 'chai';
|
|
6
|
+
|
|
7
|
+
import { change, clone, from, getBackend, getHeads } from '@dxos/automerge/automerge';
|
|
5
8
|
import { Repo } from '@dxos/automerge/automerge-repo';
|
|
6
9
|
import { randomBytes } from '@dxos/crypto';
|
|
7
|
-
import {
|
|
8
|
-
import { describe, test } from '@dxos/test';
|
|
10
|
+
import { describe, openAndClose, test } from '@dxos/test';
|
|
9
11
|
|
|
10
|
-
import {
|
|
12
|
+
import { LevelDBStorageAdapter } from './leveldb-storage-adapter';
|
|
13
|
+
import { createTestLevel } from '../testing';
|
|
11
14
|
|
|
12
15
|
describe('AutomergeRepo', () => {
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
test('flush', async () => {
|
|
17
|
+
const level = createTestLevel();
|
|
18
|
+
const storage = new LevelDBStorageAdapter({ db: level.sublevel('automerge') });
|
|
19
|
+
await openAndClose(level, storage);
|
|
20
|
+
|
|
15
21
|
const repo = new Repo({
|
|
16
22
|
network: [],
|
|
17
|
-
storage
|
|
23
|
+
storage,
|
|
18
24
|
});
|
|
19
25
|
const handle = repo.create<{ field?: string }>();
|
|
20
26
|
|
|
@@ -26,4 +32,30 @@ describe('AutomergeRepo', () => {
|
|
|
26
32
|
await p;
|
|
27
33
|
}
|
|
28
34
|
});
|
|
35
|
+
|
|
36
|
+
test('getChangeByHash', async () => {
|
|
37
|
+
const level = createTestLevel();
|
|
38
|
+
const storage = new LevelDBStorageAdapter({ db: level.sublevel('automerge') });
|
|
39
|
+
await openAndClose(level, storage);
|
|
40
|
+
|
|
41
|
+
const doc = from({ foo: 'bar' });
|
|
42
|
+
const copy = clone(doc);
|
|
43
|
+
const newDoc = change(copy, 'change', (doc: any) => {
|
|
44
|
+
doc.foo = 'baz';
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
{
|
|
48
|
+
const heads = getHeads(newDoc);
|
|
49
|
+
const changes = heads.map((hash) => getBackend(newDoc).getChangeByHash(hash));
|
|
50
|
+
expect(changes.length).to.equal(1);
|
|
51
|
+
expect(changes[0]).to.not.be.null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
{
|
|
55
|
+
const heads = getHeads(newDoc);
|
|
56
|
+
const changes = heads.map((hash) => getBackend(doc).getChangeByHash(hash));
|
|
57
|
+
expect(changes.length).to.equal(1);
|
|
58
|
+
expect(changes[0]).to.be.null;
|
|
59
|
+
}
|
|
60
|
+
});
|
|
29
61
|
});
|
package/src/testing/level.ts
CHANGED
|
@@ -8,4 +8,5 @@ import { PublicKey } from '@dxos/keys';
|
|
|
8
8
|
|
|
9
9
|
import { type LevelDB } from '../automerge/types';
|
|
10
10
|
|
|
11
|
-
export const createTestLevel = (
|
|
11
|
+
export const createTestLevel = (path = `/tmp/dxos-${PublicKey.random().toHex()}`): LevelDB =>
|
|
12
|
+
new Level<string, string>(path);
|