@dxos/echo-pipeline 0.4.10-main.fd4f2a3 → 0.4.10-main.fd8ea31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/browser/{chunk-RA6MLCZM.mjs → chunk-KMWJLYEQ.mjs} +68 -35
- package/dist/lib/browser/chunk-KMWJLYEQ.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +305 -231
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +10 -2
- package/dist/lib/browser/testing/index.mjs.map +4 -4
- package/dist/lib/node/{chunk-KGIYLJBT.cjs → chunk-YZA42CKA.cjs} +70 -37
- package/dist/lib/node/chunk-YZA42CKA.cjs.map +7 -0
- package/dist/lib/node/index.cjs +327 -256
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/testing/index.cjs +20 -13
- package/dist/lib/node/testing/index.cjs.map +4 -4
- package/dist/types/src/automerge/automerge-host.d.ts +19 -17
- 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 +1 -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 +1 -1
- package/dist/types/src/automerge/reference.d.ts.map +1 -1
- 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 +6 -0
- package/dist/types/src/automerge/types.d.ts.map +1 -1
- 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/control-pipeline.d.ts +3 -1
- package/dist/types/src/space/control-pipeline.d.ts.map +1 -1
- package/dist/types/src/space/space-manager.d.ts +3 -1
- package/dist/types/src/space/space-manager.d.ts.map +1 -1
- package/dist/types/src/space/space.d.ts +2 -1
- 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.map +1 -1
- package/package.json +33 -30
- package/src/automerge/automerge-host.test.ts +22 -8
- package/src/automerge/automerge-host.ts +53 -114
- package/src/automerge/automerge-repo.test.ts +29 -0
- package/src/automerge/index.ts +1 -0
- package/src/automerge/level.test.ts +82 -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 +1 -1
- package/src/automerge/storage-adapter.test.ts +90 -0
- package/src/automerge/types.ts +6 -3
- package/src/metadata/metadata-store.ts +17 -8
- package/src/space/control-pipeline.ts +11 -1
- package/src/space/space-manager.ts +4 -0
- package/src/space/space.ts +11 -1
- package/src/testing/index.ts +1 -0
- package/src/testing/level.ts +11 -0
- package/src/testing/test-agent-builder.ts +1 -0
- package/dist/lib/browser/chunk-RA6MLCZM.mjs.map +0 -7
- package/dist/lib/node/chunk-KGIYLJBT.cjs.map +0 -7
|
@@ -6,7 +6,6 @@ import { Trigger } from '@dxos/async';
|
|
|
6
6
|
import { NetworkAdapter, type Message, type PeerId, cbor } from '@dxos/automerge/automerge-repo';
|
|
7
7
|
import { Stream } from '@dxos/codec-protobuf';
|
|
8
8
|
import { invariant } from '@dxos/invariant';
|
|
9
|
-
import { log } from '@dxos/log';
|
|
10
9
|
import { type HostInfo, type SyncRepoRequest, type SyncRepoResponse } from '@dxos/protocols/proto/dxos/echo/service';
|
|
11
10
|
|
|
12
11
|
type ClientSyncState = {
|
|
@@ -32,10 +31,17 @@ export class LocalHostNetworkAdapter extends NetworkAdapter {
|
|
|
32
31
|
});
|
|
33
32
|
}
|
|
34
33
|
|
|
35
|
-
private _connected = new Trigger();
|
|
34
|
+
private readonly _connected = new Trigger();
|
|
35
|
+
private _isConnected: boolean = false;
|
|
36
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Called by `Repo` to connect to the network.
|
|
39
|
+
*
|
|
40
|
+
* @param peerId Our peer Id.
|
|
41
|
+
*/
|
|
37
42
|
override connect(peerId: PeerId): void {
|
|
38
43
|
this.peerId = peerId;
|
|
44
|
+
this._isConnected = true;
|
|
39
45
|
this._connected.wake();
|
|
40
46
|
// No-op. Client always connects first
|
|
41
47
|
}
|
|
@@ -56,6 +62,10 @@ export class LocalHostNetworkAdapter extends NetworkAdapter {
|
|
|
56
62
|
// No-op
|
|
57
63
|
}
|
|
58
64
|
|
|
65
|
+
async whenConnected(): Promise<void> {
|
|
66
|
+
await this._connected.wait({ timeout: 10_000 });
|
|
67
|
+
}
|
|
68
|
+
|
|
59
69
|
syncRepo({ id, syncMessage }: SyncRepoRequest): Stream<SyncRepoResponse> {
|
|
60
70
|
const peerId = this._getPeerId(id);
|
|
61
71
|
|
|
@@ -77,26 +87,22 @@ export class LocalHostNetworkAdapter extends NetworkAdapter {
|
|
|
77
87
|
},
|
|
78
88
|
});
|
|
79
89
|
|
|
80
|
-
this.
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
peerId,
|
|
86
|
-
});
|
|
87
|
-
})
|
|
88
|
-
.catch((err) => log.catch(err));
|
|
90
|
+
invariant(this._isConnected);
|
|
91
|
+
this.emit('peer-candidate', {
|
|
92
|
+
peerMetadata: {},
|
|
93
|
+
peerId,
|
|
94
|
+
});
|
|
89
95
|
});
|
|
90
96
|
}
|
|
91
97
|
|
|
92
98
|
async sendSyncMessage({ id, syncMessage }: SyncRepoRequest): Promise<void> {
|
|
93
|
-
|
|
99
|
+
invariant(this._isConnected);
|
|
94
100
|
const message = cbor.decode(syncMessage!) as Message;
|
|
95
101
|
this.emit('message', message);
|
|
96
102
|
}
|
|
97
103
|
|
|
98
104
|
async getHostInfo(): Promise<HostInfo> {
|
|
99
|
-
|
|
105
|
+
invariant(this._isConnected);
|
|
100
106
|
invariant(this.peerId, 'Peer id not set.');
|
|
101
107
|
return {
|
|
102
108
|
peerId: this.peerId,
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type StorageKey } from '@dxos/automerge/automerge-repo';
|
|
6
|
+
import { IndexedDBStorageAdapter } from '@dxos/automerge/automerge-repo-storage-indexeddb';
|
|
7
|
+
import { log } from '@dxos/log';
|
|
8
|
+
import { StorageType, type Directory } from '@dxos/random-access-storage';
|
|
9
|
+
|
|
10
|
+
import { AutomergeStorageAdapter } from './automerge-storage-adapter';
|
|
11
|
+
import { encodingOptions } from './leveldb-storage-adapter';
|
|
12
|
+
import { type SubLevelDB } from './types';
|
|
13
|
+
|
|
14
|
+
export const levelMigration = async ({ db, directory }: { db: SubLevelDB; directory: Directory }) => {
|
|
15
|
+
// Note: Make automigration from previous storage to leveldb here.
|
|
16
|
+
const isNewLevel = !(await db
|
|
17
|
+
.iterator<StorageKey, Uint8Array>({
|
|
18
|
+
...encodingOptions,
|
|
19
|
+
})
|
|
20
|
+
.next());
|
|
21
|
+
|
|
22
|
+
if (!isNewLevel) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const oldStorageAdapter =
|
|
27
|
+
directory.type === StorageType.IDB
|
|
28
|
+
? new IndexedDBStorageAdapter(directory.path, 'data')
|
|
29
|
+
: new AutomergeStorageAdapter(directory);
|
|
30
|
+
|
|
31
|
+
const chunks = await oldStorageAdapter.loadRange([]);
|
|
32
|
+
if (chunks.length === 0) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const batch = db.batch();
|
|
36
|
+
log.info('found chunks on old storage adapter', { chunks: chunks.length });
|
|
37
|
+
for (const { key, data } of await oldStorageAdapter.loadRange([])) {
|
|
38
|
+
data && batch.put<StorageKey, Uint8Array>(key, data, { ...encodingOptions });
|
|
39
|
+
}
|
|
40
|
+
await batch.write();
|
|
41
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { expect } from 'chai';
|
|
6
|
+
|
|
7
|
+
import { type StorageAdapterInterface } from '@dxos/automerge/automerge-repo';
|
|
8
|
+
import { PublicKey } from '@dxos/keys';
|
|
9
|
+
import { StorageType, createStorage } from '@dxos/random-access-storage';
|
|
10
|
+
import { afterTest, describe, openAndClose, test } from '@dxos/test';
|
|
11
|
+
import { type MaybePromise } from '@dxos/util';
|
|
12
|
+
|
|
13
|
+
import { AutomergeStorageAdapter } from './automerge-storage-adapter';
|
|
14
|
+
import { LevelDBStorageAdapter } from './leveldb-storage-adapter';
|
|
15
|
+
import { createTestLevel } from '../testing';
|
|
16
|
+
|
|
17
|
+
const runTests = (
|
|
18
|
+
testNamespace: string,
|
|
19
|
+
/** Run per test. Expects automatic clean-up with `afterTest`. */ createAdapter: () => MaybePromise<StorageAdapterInterface>,
|
|
20
|
+
) => {
|
|
21
|
+
describe(testNamespace, () => {
|
|
22
|
+
const chunks = [
|
|
23
|
+
{ key: ['a', 'b', 'c', '1'], data: PublicKey.random().asUint8Array() },
|
|
24
|
+
{ key: ['a', 'b', 'c', '2'], data: PublicKey.random().asUint8Array() },
|
|
25
|
+
{ key: ['a', 'b', 'd', '3'], data: PublicKey.random().asUint8Array() },
|
|
26
|
+
{ key: ['a', 'b', 'd', '4'], data: PublicKey.random().asUint8Array() },
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
test('should store and retrieve data', async () => {
|
|
30
|
+
const adapter = await createAdapter();
|
|
31
|
+
|
|
32
|
+
await adapter.save(chunks[0].key, chunks[0].data);
|
|
33
|
+
expect(await adapter.load(chunks[0].key)).to.deep.equal(chunks[0].data);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('loadRange return inputs with correct prefixes', async () => {
|
|
37
|
+
const adapter = await createAdapter();
|
|
38
|
+
|
|
39
|
+
for (const chunk of chunks) {
|
|
40
|
+
await adapter.save(chunk.key, chunk.data);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
expect((await adapter.loadRange(['a', 'b'])).length).to.equal(4);
|
|
44
|
+
expect((await adapter.loadRange(['a', 'b', 'c']))[0]).to.deep.equal(chunks[0]);
|
|
45
|
+
expect((await adapter.loadRange(['a', 'b', 'c'])).length).to.equal(2);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test('deletion works', async () => {
|
|
49
|
+
const adapter = await createAdapter();
|
|
50
|
+
|
|
51
|
+
for (const chunk of chunks) {
|
|
52
|
+
await adapter.save(chunk.key, chunk.data);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
await adapter.remove(['a', 'b', 'c', '1']);
|
|
56
|
+
|
|
57
|
+
expect((await adapter.loadRange(['a', 'b'])).length).to.equal(3);
|
|
58
|
+
expect((await adapter.loadRange(['a', 'b', 'c'])).length).to.equal(1);
|
|
59
|
+
|
|
60
|
+
await adapter.removeRange(['a', 'b', 'd']);
|
|
61
|
+
|
|
62
|
+
expect((await adapter.loadRange(['a', 'b'])).length).to.equal(1);
|
|
63
|
+
expect((await adapter.loadRange(['a', 'b']))[0]).to.deep.equal(chunks[1]);
|
|
64
|
+
expect(await adapter.load(['a', 'b', 'c', '2'])).to.deep.equal(chunks[1].data);
|
|
65
|
+
expect(await adapter.load(['a', 'b', 'd', '3'])).to.be.undefined;
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Run tests for AutomergeStorageAdapter.
|
|
72
|
+
*/
|
|
73
|
+
runTests('AutomergeStorageAdapter', () => {
|
|
74
|
+
const storage = createStorage({ type: StorageType.RAM });
|
|
75
|
+
afterTest(() => storage.close());
|
|
76
|
+
const dir = storage.createDirectory('automerge');
|
|
77
|
+
const adapter = new AutomergeStorageAdapter(dir);
|
|
78
|
+
afterTest(() => adapter.close());
|
|
79
|
+
return adapter;
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Run tests for LevelDBStorageAdapter.
|
|
84
|
+
*/
|
|
85
|
+
runTests('LevelDBStorageAdapter', async () => {
|
|
86
|
+
const level = createTestLevel();
|
|
87
|
+
const adapter = new LevelDBStorageAdapter({ db: level.sublevel('automerge') });
|
|
88
|
+
await openAndClose(level, adapter as any);
|
|
89
|
+
return adapter;
|
|
90
|
+
});
|
package/src/automerge/types.ts
CHANGED
|
@@ -2,9 +2,8 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
//
|
|
5
|
+
import { type AbstractChainedBatch, type AbstractSublevel } from 'abstract-level';
|
|
6
|
+
import { type Level } from 'level';
|
|
8
7
|
|
|
9
8
|
import { type EncodedReferenceObject } from './reference';
|
|
10
9
|
|
|
@@ -81,3 +80,7 @@ export type ObjectSystem = {
|
|
|
81
80
|
*/
|
|
82
81
|
type?: EncodedReferenceObject;
|
|
83
82
|
};
|
|
83
|
+
|
|
84
|
+
export type LevelDB = Level<string, string>;
|
|
85
|
+
export type SubLevelDB = AbstractSublevel<any, string | Buffer | Uint8Array, string, string>;
|
|
86
|
+
export type BatchLevel = AbstractChainedBatch<any, string, string>;
|
|
@@ -11,7 +11,7 @@ import { invariant } from '@dxos/invariant';
|
|
|
11
11
|
import { PublicKey } from '@dxos/keys';
|
|
12
12
|
import { log } from '@dxos/log';
|
|
13
13
|
import { DataCorruptionError, STORAGE_VERSION, schema } from '@dxos/protocols';
|
|
14
|
-
import {
|
|
14
|
+
import { Invitation, SpaceState } from '@dxos/protocols/proto/dxos/client/services';
|
|
15
15
|
import {
|
|
16
16
|
type ControlPipelineSnapshot,
|
|
17
17
|
EchoMetadata,
|
|
@@ -174,13 +174,8 @@ export class MetadataStore {
|
|
|
174
174
|
scheduleTaskInterval(
|
|
175
175
|
this._invitationCleanupCtx,
|
|
176
176
|
async () => {
|
|
177
|
-
for (const invitation of this.
|
|
178
|
-
if (
|
|
179
|
-
invitation.created &&
|
|
180
|
-
invitation.lifetime &&
|
|
181
|
-
invitation.lifetime !== 0 &&
|
|
182
|
-
invitation.created.getTime() + invitation.lifetime * 1000 < Date.now()
|
|
183
|
-
) {
|
|
177
|
+
for (const invitation of this._metadata.invitations ?? []) {
|
|
178
|
+
if (hasInvitationExpired(invitation) || isLegacyInvitationFormat(invitation)) {
|
|
184
179
|
await this.removeInvitation(invitation.invitationId);
|
|
185
180
|
}
|
|
186
181
|
}
|
|
@@ -343,3 +338,17 @@ export class MetadataStore {
|
|
|
343
338
|
}
|
|
344
339
|
|
|
345
340
|
const fromBytesInt32 = (buf: Buffer) => buf.readInt32LE(0);
|
|
341
|
+
|
|
342
|
+
export const hasInvitationExpired = (invitation: Invitation): boolean => {
|
|
343
|
+
return Boolean(
|
|
344
|
+
invitation.created &&
|
|
345
|
+
invitation.lifetime &&
|
|
346
|
+
invitation.lifetime !== 0 &&
|
|
347
|
+
invitation.created.getTime() + invitation.lifetime * 1000 < Date.now(),
|
|
348
|
+
);
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
// TODO: remove once "multiuse" type invitations get removed from local metadata of existing profiles
|
|
352
|
+
const isLegacyInvitationFormat = (invitation: Invitation): boolean => {
|
|
353
|
+
return invitation.type === Invitation.Type.MULTIUSE;
|
|
354
|
+
};
|
|
@@ -4,7 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
import { DeferredTask, sleepWithContext, trackLeaks } from '@dxos/async';
|
|
6
6
|
import { Context } from '@dxos/context';
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
SpaceStateMachine,
|
|
9
|
+
type SpaceState,
|
|
10
|
+
type MemberInfo,
|
|
11
|
+
type FeedInfo,
|
|
12
|
+
type DelegateInvitationCredential,
|
|
13
|
+
} from '@dxos/credentials';
|
|
8
14
|
import { type FeedWrapper } from '@dxos/feed-store';
|
|
9
15
|
import { PublicKey } from '@dxos/keys';
|
|
10
16
|
import { log } from '@dxos/log';
|
|
@@ -50,6 +56,8 @@ export class ControlPipeline {
|
|
|
50
56
|
public readonly onFeedAdmitted = new Callback<AsyncCallback<FeedInfo>>();
|
|
51
57
|
public readonly onMemberAdmitted: Callback<AsyncCallback<MemberInfo>>;
|
|
52
58
|
public readonly onCredentialProcessed: Callback<AsyncCallback<Credential>>;
|
|
59
|
+
public readonly onDelegatedInvitation: Callback<AsyncCallback<DelegateInvitationCredential>>;
|
|
60
|
+
public readonly onDelegatedInvitationRemoved: Callback<AsyncCallback<DelegateInvitationCredential>>;
|
|
53
61
|
|
|
54
62
|
@trace.metricsCounter()
|
|
55
63
|
private _usage = new TimeUsageCounter();
|
|
@@ -92,6 +100,8 @@ export class ControlPipeline {
|
|
|
92
100
|
|
|
93
101
|
this.onMemberAdmitted = this._spaceStateMachine.onMemberAdmitted;
|
|
94
102
|
this.onCredentialProcessed = this._spaceStateMachine.onCredentialProcessed;
|
|
103
|
+
this.onDelegatedInvitation = this._spaceStateMachine.onDelegatedInvitation;
|
|
104
|
+
this.onDelegatedInvitationRemoved = this._spaceStateMachine.onDelegatedInvitationRemoved;
|
|
95
105
|
}
|
|
96
106
|
|
|
97
107
|
get spaceState(): SpaceState {
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { synchronized, trackLeaks } from '@dxos/async';
|
|
6
|
+
import { type DelegateInvitationCredential } from '@dxos/credentials';
|
|
6
7
|
import { failUndefined } from '@dxos/debug';
|
|
7
8
|
import { type FeedStore } from '@dxos/feed-store';
|
|
8
9
|
import { PublicKey } from '@dxos/keys';
|
|
@@ -42,6 +43,7 @@ export type ConstructSpaceParams = {
|
|
|
42
43
|
*/
|
|
43
44
|
onAuthorizedConnection: (session: Teleport) => void;
|
|
44
45
|
onAuthFailure?: (session: Teleport) => void;
|
|
46
|
+
onDelegatedInvitationStatusChange: (invitation: DelegateInvitationCredential, isActive: boolean) => Promise<void>;
|
|
45
47
|
};
|
|
46
48
|
|
|
47
49
|
/**
|
|
@@ -84,6 +86,7 @@ export class SpaceManager {
|
|
|
84
86
|
swarmIdentity,
|
|
85
87
|
onAuthorizedConnection,
|
|
86
88
|
onAuthFailure,
|
|
89
|
+
onDelegatedInvitationStatusChange,
|
|
87
90
|
memberKey,
|
|
88
91
|
}: ConstructSpaceParams) {
|
|
89
92
|
log.trace('dxos.echo.space-manager.construct-space', trace.begin({ id: this._instanceId }));
|
|
@@ -111,6 +114,7 @@ export class SpaceManager {
|
|
|
111
114
|
metadataStore: this._metadataStore,
|
|
112
115
|
snapshotManager,
|
|
113
116
|
memberKey,
|
|
117
|
+
onDelegatedInvitationStatusChange,
|
|
114
118
|
});
|
|
115
119
|
this._spaces.set(space.key, space);
|
|
116
120
|
|
package/src/space/space.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { Event, Mutex, synchronized, trackLeaks } from '@dxos/async';
|
|
6
6
|
import { Resource, type Context, LifecycleState } from '@dxos/context';
|
|
7
|
-
import { type FeedInfo } from '@dxos/credentials';
|
|
7
|
+
import { type FeedInfo, type DelegateInvitationCredential } from '@dxos/credentials';
|
|
8
8
|
import { type FeedOptions, type FeedWrapper } from '@dxos/feed-store';
|
|
9
9
|
import { invariant } from '@dxos/invariant';
|
|
10
10
|
import { type PublicKey } from '@dxos/keys';
|
|
@@ -35,6 +35,8 @@ export type SpaceParams = {
|
|
|
35
35
|
|
|
36
36
|
// TODO(dmaretskyi): Superseded by epochs.
|
|
37
37
|
snapshotId?: string | undefined;
|
|
38
|
+
|
|
39
|
+
onDelegatedInvitationStatusChange: (invitation: DelegateInvitationCredential, isActive: boolean) => Promise<void>;
|
|
38
40
|
};
|
|
39
41
|
|
|
40
42
|
export type CreatePipelineParams = {
|
|
@@ -99,6 +101,14 @@ export class Space extends Resource {
|
|
|
99
101
|
log('onCredentialProcessed', { credential });
|
|
100
102
|
this.stateUpdate.emit();
|
|
101
103
|
});
|
|
104
|
+
this._controlPipeline.onDelegatedInvitation.set(async (invitation) => {
|
|
105
|
+
log('onDelegatedInvitation', { invitation });
|
|
106
|
+
await params.onDelegatedInvitationStatusChange(invitation, true);
|
|
107
|
+
});
|
|
108
|
+
this._controlPipeline.onDelegatedInvitationRemoved.set(async (invitation) => {
|
|
109
|
+
log('onDelegatedInvitationRemoved', { invitation });
|
|
110
|
+
await params.onDelegatedInvitationStatusChange(invitation, false);
|
|
111
|
+
});
|
|
102
112
|
|
|
103
113
|
// Start replicating the genesis feed.
|
|
104
114
|
this.protocol = params.protocol;
|
package/src/testing/index.ts
CHANGED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Level } from 'level';
|
|
6
|
+
|
|
7
|
+
import { PublicKey } from '@dxos/keys';
|
|
8
|
+
|
|
9
|
+
import { type LevelDB } from '../automerge/types';
|
|
10
|
+
|
|
11
|
+
export const createTestLevel = (): LevelDB => new Level<string, string>(`/tmp/dxos-${PublicKey.random().toHex()}`);
|
|
@@ -190,6 +190,7 @@ export class TestAgent {
|
|
|
190
190
|
this.createGossip().createExtension({ remotePeerId: session.remotePeerId }),
|
|
191
191
|
);
|
|
192
192
|
},
|
|
193
|
+
onDelegatedInvitationStatusChange: async () => {},
|
|
193
194
|
});
|
|
194
195
|
await space.setControlFeed(controlFeed);
|
|
195
196
|
await space.setDataFeed(dataFeed);
|