@dxos/echo-db 2.33.8 → 2.33.9-dev.0cfaca1b
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/src/api/result-set.js +4 -4
- package/dist/src/api/result-set.js.map +1 -1
- package/dist/src/echo.js +2 -2
- package/dist/src/echo.js.map +1 -1
- package/dist/src/echo.test.js +3 -3
- package/dist/src/echo.test.js.map +1 -1
- package/dist/src/halo/halo-factory.d.ts +1 -1
- package/dist/src/halo/halo-factory.d.ts.map +1 -1
- package/dist/src/halo/halo-factory.js +15 -14
- package/dist/src/halo/halo-factory.js.map +1 -1
- package/dist/src/halo/halo-party.d.ts +4 -6
- package/dist/src/halo/halo-party.d.ts.map +1 -1
- package/dist/src/halo/halo-party.js +12 -6
- package/dist/src/halo/halo-party.js.map +1 -1
- package/dist/src/halo/halo.js +9 -9
- package/dist/src/halo/halo.js.map +1 -1
- package/dist/src/halo/identity-manager.d.ts.map +1 -1
- package/dist/src/halo/identity-manager.js +13 -7
- package/dist/src/halo/identity-manager.js.map +1 -1
- package/dist/src/halo/identity.js +2 -2
- package/dist/src/halo/identity.js.map +1 -1
- package/dist/src/halo/party-opener.d.ts.map +1 -1
- package/dist/src/halo/party-opener.js +2 -4
- package/dist/src/halo/party-opener.js.map +1 -1
- package/dist/src/halo/preferences.d.ts.map +1 -1
- package/dist/src/halo/preferences.js +9 -12
- package/dist/src/halo/preferences.js.map +1 -1
- package/dist/src/invitations/greeting-initiator.d.ts +5 -4
- package/dist/src/invitations/greeting-initiator.d.ts.map +1 -1
- package/dist/src/invitations/greeting-initiator.js +7 -7
- package/dist/src/invitations/greeting-initiator.js.map +1 -1
- package/dist/src/invitations/greeting-responder.d.ts +4 -7
- package/dist/src/invitations/greeting-responder.d.ts.map +1 -1
- package/dist/src/invitations/greeting-responder.js +9 -23
- package/dist/src/invitations/greeting-responder.js.map +1 -1
- package/dist/src/invitations/halo-recovery-initiator.js +6 -6
- package/dist/src/invitations/halo-recovery-initiator.js.map +1 -1
- package/dist/src/invitations/invitation-descriptor.js +9 -9
- package/dist/src/invitations/invitation-descriptor.js.map +1 -1
- package/dist/src/invitations/invitation-factory.d.ts +2 -1
- package/dist/src/invitations/invitation-factory.d.ts.map +1 -1
- package/dist/src/invitations/invitation-factory.js +6 -8
- package/dist/src/invitations/invitation-factory.js.map +1 -1
- package/dist/src/invitations/offline-invitation-claimer.js +7 -7
- package/dist/src/invitations/offline-invitation-claimer.js.map +1 -1
- package/dist/src/packlets/database/data-mirror.js +8 -8
- package/dist/src/packlets/database/data-mirror.js.map +1 -1
- package/dist/src/packlets/database/data-mirror.test.js +1 -1
- package/dist/src/packlets/database/data-mirror.test.js.map +1 -1
- package/dist/src/packlets/database/data-service-host.js +3 -3
- package/dist/src/packlets/database/data-service-host.js.map +1 -1
- package/dist/src/packlets/database/data-service-router.js +5 -5
- package/dist/src/packlets/database/data-service-router.js.map +1 -1
- package/dist/src/packlets/database/database-backend.js +3 -3
- package/dist/src/packlets/database/database-backend.js.map +1 -1
- package/dist/src/packlets/database/database.js +2 -2
- package/dist/src/packlets/database/database.js.map +1 -1
- package/dist/src/packlets/database/item-demuxer.js +14 -14
- package/dist/src/packlets/database/item-demuxer.js.map +1 -1
- package/dist/src/packlets/database/item-demuxer.test.js +1 -1
- package/dist/src/packlets/database/item-demuxer.test.js.map +1 -1
- package/dist/src/packlets/database/item-manager.js +18 -18
- package/dist/src/packlets/database/item-manager.js.map +1 -1
- package/dist/src/packlets/database/link.js +3 -3
- package/dist/src/packlets/database/link.js.map +1 -1
- package/dist/src/packlets/database/selection/result.js +2 -2
- package/dist/src/packlets/database/selection/result.js.map +1 -1
- package/dist/src/packlets/database/testing.js +1 -1
- package/dist/src/packlets/database/testing.js.map +1 -1
- package/dist/src/packlets/database/timeframe-clock.d.ts +2 -1
- package/dist/src/packlets/database/timeframe-clock.d.ts.map +1 -1
- package/dist/src/packlets/database/timeframe-clock.js +15 -5
- package/dist/src/packlets/database/timeframe-clock.js.map +1 -1
- package/dist/src/parties/data-party.d.ts +4 -3
- package/dist/src/parties/data-party.d.ts.map +1 -1
- package/dist/src/parties/data-party.js +18 -14
- package/dist/src/parties/data-party.js.map +1 -1
- package/dist/src/parties/data-party.test.js +12 -12
- package/dist/src/parties/data-party.test.js.map +1 -1
- package/dist/src/parties/party-factory.d.ts +2 -4
- package/dist/src/parties/party-factory.d.ts.map +1 -1
- package/dist/src/parties/party-factory.js +15 -12
- package/dist/src/parties/party-factory.js.map +1 -1
- package/dist/src/parties/party-manager.d.ts +1 -1
- package/dist/src/parties/party-manager.d.ts.map +1 -1
- package/dist/src/parties/party-manager.js +19 -19
- package/dist/src/parties/party-manager.js.map +1 -1
- package/dist/src/parties/party-manager.test.js +15 -12
- package/dist/src/parties/party-manager.test.js.map +1 -1
- package/dist/src/parties/party-preferences.js +2 -2
- package/dist/src/parties/party-preferences.js.map +1 -1
- package/dist/src/pipeline/feed-muxer.js +4 -4
- package/dist/src/pipeline/feed-muxer.js.map +1 -1
- package/dist/src/pipeline/feed-muxer.test.js +6 -4
- package/dist/src/pipeline/feed-muxer.test.js.map +1 -1
- package/dist/src/pipeline/message-selector.d.ts +1 -2
- package/dist/src/pipeline/message-selector.d.ts.map +1 -1
- package/dist/src/pipeline/message-selector.js +6 -33
- package/dist/src/pipeline/message-selector.js.map +1 -1
- package/dist/src/pipeline/metadata-store.d.ts +7 -2
- package/dist/src/pipeline/metadata-store.d.ts.map +1 -1
- package/dist/src/pipeline/metadata-store.js +43 -31
- package/dist/src/pipeline/metadata-store.js.map +1 -1
- package/dist/src/pipeline/party-feed-provider.d.ts +2 -2
- package/dist/src/pipeline/party-feed-provider.d.ts.map +1 -1
- package/dist/src/pipeline/party-feed-provider.js +5 -4
- package/dist/src/pipeline/party-feed-provider.js.map +1 -1
- package/dist/src/pipeline/party-pipeline.d.ts +5 -5
- package/dist/src/pipeline/party-pipeline.d.ts.map +1 -1
- package/dist/src/pipeline/party-pipeline.js +19 -20
- package/dist/src/pipeline/party-pipeline.js.map +1 -1
- package/dist/src/pipeline/party-pipeline.test.js +13 -18
- package/dist/src/pipeline/party-pipeline.test.js.map +1 -1
- package/dist/src/pipeline/party-processor.js +3 -3
- package/dist/src/pipeline/party-processor.js.map +1 -1
- package/dist/src/protocol/authenticator.test.js +53 -12
- package/dist/src/protocol/authenticator.test.js.map +1 -1
- package/dist/src/snapshots/snapshot-store.js +2 -2
- package/dist/src/snapshots/snapshot-store.js.map +1 -1
- package/dist/src/snapshots/snapshot-store.test.js +5 -1
- package/dist/src/snapshots/snapshot-store.test.js.map +1 -1
- package/dist/src/testing/testing-factories.js +2 -2
- package/dist/src/testing/testing-factories.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +21 -17
- package/src/api/result-set.ts +1 -1
- package/src/echo.test.ts +2 -2
- package/src/echo.ts +1 -1
- package/src/halo/halo-factory.ts +7 -7
- package/src/halo/halo-party.ts +15 -7
- package/src/halo/halo.ts +1 -1
- package/src/halo/identity-manager.ts +12 -3
- package/src/halo/identity.ts +1 -1
- package/src/halo/party-opener.ts +2 -4
- package/src/halo/preferences.ts +5 -9
- package/src/invitations/greeting-initiator.ts +9 -3
- package/src/invitations/greeting-responder.ts +8 -27
- package/src/invitations/halo-recovery-initiator.ts +1 -1
- package/src/invitations/invitation-descriptor.ts +1 -1
- package/src/invitations/invitation-factory.ts +3 -3
- package/src/invitations/offline-invitation-claimer.ts +1 -1
- package/src/packlets/database/data-mirror.test.ts +2 -2
- package/src/packlets/database/data-mirror.ts +1 -1
- package/src/packlets/database/data-service-host.ts +1 -1
- package/src/packlets/database/data-service-router.ts +1 -1
- package/src/packlets/database/database-backend.ts +1 -1
- package/src/packlets/database/database.ts +1 -1
- package/src/packlets/database/item-demuxer.test.ts +2 -2
- package/src/packlets/database/item-demuxer.ts +1 -1
- package/src/packlets/database/item-manager.ts +1 -1
- package/src/packlets/database/link.ts +1 -1
- package/src/packlets/database/selection/result.ts +1 -1
- package/src/packlets/database/testing.ts +2 -2
- package/src/packlets/database/timeframe-clock.ts +4 -1
- package/src/parties/data-party.test.ts +12 -12
- package/src/parties/data-party.ts +15 -7
- package/src/parties/party-factory.ts +18 -10
- package/src/parties/party-manager.test.ts +10 -7
- package/src/parties/party-manager.ts +15 -13
- package/src/parties/party-preferences.ts +1 -1
- package/src/pipeline/feed-muxer.test.ts +6 -4
- package/src/pipeline/feed-muxer.ts +3 -3
- package/src/pipeline/message-selector.ts +5 -36
- package/src/pipeline/metadata-store.ts +53 -31
- package/src/pipeline/party-feed-provider.ts +3 -3
- package/src/pipeline/party-pipeline.test.ts +13 -19
- package/src/pipeline/party-pipeline.ts +14 -13
- package/src/pipeline/party-processor.ts +1 -1
- package/src/protocol/authenticator.test.ts +102 -17
- package/src/snapshots/snapshot-store.test.ts +5 -1
- package/src/snapshots/snapshot-store.ts +1 -1
- package/src/testing/testing-factories.ts +1 -1
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { Event } from '@dxos/async';
|
|
6
|
-
import {
|
|
6
|
+
import { timed } from '@dxos/debug';
|
|
7
|
+
import { FeedKey } from '@dxos/echo-protocol';
|
|
8
|
+
import { Timeframe } from '@dxos/protocols';
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
11
|
* Keeps state of the last timeframe that was processed by ECHO.
|
|
@@ -29,6 +31,7 @@ export class TimeframeClock {
|
|
|
29
31
|
return !gaps.isEmpty();
|
|
30
32
|
}
|
|
31
33
|
|
|
34
|
+
@timed(5_000)
|
|
32
35
|
async waitUntilReached (target: Timeframe) {
|
|
33
36
|
await this.update.waitForCondition(() => Timeframe.dependencies(target, this._timeframe).isEmpty());
|
|
34
37
|
}
|
|
@@ -22,7 +22,7 @@ import { SnapshotStore } from '../snapshots';
|
|
|
22
22
|
import { DataParty } from './data-party';
|
|
23
23
|
|
|
24
24
|
describe('DataParty', () => {
|
|
25
|
-
const createParty = async (identity: IdentityCredentials, partyKey: PublicKey,
|
|
25
|
+
const createParty = async (identity: IdentityCredentials, partyKey: PublicKey, genesisFeedKey?: PublicKey) => {
|
|
26
26
|
|
|
27
27
|
const storage = createStorage('', StorageType.RAM);
|
|
28
28
|
const snapshotStore = new SnapshotStore(storage.directory('snapshots'));
|
|
@@ -43,7 +43,7 @@ describe('DataParty', () => {
|
|
|
43
43
|
identity.preferences,
|
|
44
44
|
networkManager
|
|
45
45
|
);
|
|
46
|
-
party.
|
|
46
|
+
party._setGenesisFeedKey(genesisFeedKey ?? writableFeed.key);
|
|
47
47
|
return party;
|
|
48
48
|
};
|
|
49
49
|
|
|
@@ -51,7 +51,7 @@ describe('DataParty', () => {
|
|
|
51
51
|
const keyring = new Keyring();
|
|
52
52
|
const identity = await createTestIdentityCredentials(keyring);
|
|
53
53
|
const partyKey = await keyring.createKeyRecord({ type: KeyType.PARTY });
|
|
54
|
-
const party = await createParty(identity, partyKey.publicKey
|
|
54
|
+
const party = await createParty(identity, partyKey.publicKey);
|
|
55
55
|
|
|
56
56
|
await party.open();
|
|
57
57
|
await party.close();
|
|
@@ -61,7 +61,7 @@ describe('DataParty', () => {
|
|
|
61
61
|
const keyring = new Keyring();
|
|
62
62
|
const identity = await createTestIdentityCredentials(keyring);
|
|
63
63
|
const partyKey = await keyring.createKeyRecord({ type: KeyType.PARTY });
|
|
64
|
-
const party = await createParty(identity, partyKey.publicKey
|
|
64
|
+
const party = await createParty(identity, partyKey.publicKey);
|
|
65
65
|
await party.open();
|
|
66
66
|
|
|
67
67
|
const feed = await party.getWriteFeed();
|
|
@@ -81,7 +81,7 @@ describe('DataParty', () => {
|
|
|
81
81
|
const keyring = new Keyring();
|
|
82
82
|
const identity = await createTestIdentityCredentials(keyring);
|
|
83
83
|
const partyKey = await keyring.createKeyRecord({ type: KeyType.PARTY });
|
|
84
|
-
const party = await createParty(identity, partyKey.publicKey
|
|
84
|
+
const party = await createParty(identity, partyKey.publicKey);
|
|
85
85
|
await party.open();
|
|
86
86
|
|
|
87
87
|
const feed = await party.getWriteFeed();
|
|
@@ -109,7 +109,7 @@ describe('DataParty', () => {
|
|
|
109
109
|
const identity = await createTestIdentityCredentials(keyring);
|
|
110
110
|
const partyKey = await keyring.createKeyRecord({ type: KeyType.PARTY });
|
|
111
111
|
|
|
112
|
-
const party = await createParty(identity, partyKey.publicKey
|
|
112
|
+
const party = await createParty(identity, partyKey.publicKey);
|
|
113
113
|
await party.open();
|
|
114
114
|
const feed = await party.getWriteFeed();
|
|
115
115
|
await party.credentialsWriter.write(createPartyGenesisMessage(
|
|
@@ -134,7 +134,7 @@ describe('DataParty', () => {
|
|
|
134
134
|
const identityA = await createTestIdentityCredentials(keyring);
|
|
135
135
|
const partyKey = await keyring.createKeyRecord({ type: KeyType.PARTY });
|
|
136
136
|
|
|
137
|
-
const party = await createParty(identityA, partyKey.publicKey
|
|
137
|
+
const party = await createParty(identityA, partyKey.publicKey);
|
|
138
138
|
await party.open();
|
|
139
139
|
const feed = await party.getWriteFeed();
|
|
140
140
|
await party.credentialsWriter.write(createPartyGenesisMessage(
|
|
@@ -161,7 +161,7 @@ describe('DataParty', () => {
|
|
|
161
161
|
const identityA = await createTestIdentityCredentials(keyring);
|
|
162
162
|
const partyKey = await keyring.createKeyRecord({ type: KeyType.PARTY });
|
|
163
163
|
|
|
164
|
-
const partyA = await createParty(identityA, partyKey.publicKey
|
|
164
|
+
const partyA = await createParty(identityA, partyKey.publicKey);
|
|
165
165
|
await partyA.open();
|
|
166
166
|
const feedA = await partyA.getWriteFeed();
|
|
167
167
|
await partyA.credentialsWriter.write(createPartyGenesisMessage(
|
|
@@ -178,7 +178,7 @@ describe('DataParty', () => {
|
|
|
178
178
|
));
|
|
179
179
|
|
|
180
180
|
const identityB = await deriveTestDeviceCredentials(identityA);
|
|
181
|
-
const partyB = await createParty(identityB, partyKey.publicKey,
|
|
181
|
+
const partyB = await createParty(identityB, partyKey.publicKey, feedA.key);
|
|
182
182
|
await partyB.open();
|
|
183
183
|
|
|
184
184
|
await partyA.database.createItem({ type: 'test:item-a' });
|
|
@@ -195,7 +195,7 @@ describe('DataParty', () => {
|
|
|
195
195
|
const identityA = await createTestIdentityCredentials(new Keyring());
|
|
196
196
|
const partyKeyA = await identityA.keyring.createKeyRecord({ type: KeyType.PARTY });
|
|
197
197
|
|
|
198
|
-
const partyA = await createParty(identityA, partyKeyA.publicKey
|
|
198
|
+
const partyA = await createParty(identityA, partyKeyA.publicKey);
|
|
199
199
|
await partyA.open();
|
|
200
200
|
const feedA = await partyA.getWriteFeed();
|
|
201
201
|
await partyA.credentialsWriter.write(createPartyGenesisMessage(
|
|
@@ -226,9 +226,9 @@ describe('DataParty', () => {
|
|
|
226
226
|
);
|
|
227
227
|
|
|
228
228
|
await initiator.connect();
|
|
229
|
-
const { partyKey: partyKeyB,
|
|
229
|
+
const { partyKey: partyKeyB, genesisFeedKey } = await initiator.redeemInvitation(defaultSecretProvider);
|
|
230
230
|
expect(partyKeyB.equals(partyKeyA.publicKey));
|
|
231
|
-
const partyB = await createParty(identityB, partyKeyB,
|
|
231
|
+
const partyB = await createParty(identityB, partyKeyB, genesisFeedKey);
|
|
232
232
|
await partyB.open();
|
|
233
233
|
await initiator.destroy();
|
|
234
234
|
|
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
// Copyright 2020 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import assert from 'assert';
|
|
5
|
+
import assert from 'node:assert';
|
|
6
6
|
|
|
7
7
|
import { synchronized, Event } from '@dxos/async';
|
|
8
8
|
import { timed } from '@dxos/debug';
|
|
9
|
-
import { PartyKey, PartySnapshot
|
|
9
|
+
import { PartyKey, PartySnapshot } from '@dxos/echo-protocol';
|
|
10
10
|
import { FeedDescriptor } from '@dxos/feed-store';
|
|
11
11
|
import { ModelFactory } from '@dxos/model-factory';
|
|
12
12
|
import { NetworkManager } from '@dxos/network-manager';
|
|
13
13
|
import { ObjectModel } from '@dxos/object-model';
|
|
14
|
-
import { PublicKey } from '@dxos/protocols';
|
|
14
|
+
import { PublicKey, Timeframe } from '@dxos/protocols';
|
|
15
15
|
|
|
16
16
|
import { ResultSet } from '../api';
|
|
17
17
|
import { ActivationOptions, PartyPreferences, Preferences } from '../halo';
|
|
@@ -46,7 +46,8 @@ export class DataParty {
|
|
|
46
46
|
private readonly _preferences?: PartyPreferences;
|
|
47
47
|
private _invitationManager?: InvitationFactory;
|
|
48
48
|
private _protocol?: PartyProtocolFactory;
|
|
49
|
-
|
|
49
|
+
|
|
50
|
+
private _genesisFeedKey?: PublicKey | undefined;
|
|
50
51
|
|
|
51
52
|
constructor (
|
|
52
53
|
partyKey: PartyKey,
|
|
@@ -141,11 +142,16 @@ export class DataParty {
|
|
|
141
142
|
await this._preferences?.setLastKnownTitle(title);
|
|
142
143
|
}
|
|
143
144
|
|
|
145
|
+
get genesisFeedKey () {
|
|
146
|
+
assert(this._genesisFeedKey);
|
|
147
|
+
return this._genesisFeedKey;
|
|
148
|
+
}
|
|
149
|
+
|
|
144
150
|
/**
|
|
145
151
|
* @internal
|
|
146
152
|
*/
|
|
147
|
-
|
|
148
|
-
this.
|
|
153
|
+
_setGenesisFeedKey (genesisFeedKey: PublicKey) {
|
|
154
|
+
this._genesisFeedKey = genesisFeedKey;
|
|
149
155
|
}
|
|
150
156
|
|
|
151
157
|
/**
|
|
@@ -161,8 +167,9 @@ export class DataParty {
|
|
|
161
167
|
// TODO(dmaretskyi): May be undefined in some tests.
|
|
162
168
|
const party = this._metadataStore.getParty(this._partyCore.key);
|
|
163
169
|
|
|
170
|
+
assert(this._genesisFeedKey);
|
|
164
171
|
await this._partyCore.open({
|
|
165
|
-
|
|
172
|
+
genesisFeedKey: this._genesisFeedKey,
|
|
166
173
|
initialTimeframe: this._initialTimeframe,
|
|
167
174
|
targetTimeframe: party?.latestTimeframe
|
|
168
175
|
});
|
|
@@ -175,6 +182,7 @@ export class DataParty {
|
|
|
175
182
|
|
|
176
183
|
this._invitationManager = new InvitationFactory(
|
|
177
184
|
this._partyCore.processor,
|
|
185
|
+
this._genesisFeedKey,
|
|
178
186
|
this._credentialsSigner,
|
|
179
187
|
this._partyCore.credentialsWriter,
|
|
180
188
|
this._networkManager
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
// Copyright 2020 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import assert from 'assert';
|
|
6
5
|
import debug from 'debug';
|
|
6
|
+
import assert from 'node:assert';
|
|
7
7
|
|
|
8
8
|
import {
|
|
9
9
|
createEnvelopeMessage,
|
|
@@ -14,11 +14,11 @@ import {
|
|
|
14
14
|
wrapMessage
|
|
15
15
|
} from '@dxos/credentials';
|
|
16
16
|
import { failUndefined, raise, timed } from '@dxos/debug';
|
|
17
|
-
import { createFeedWriter, FeedMessage, PartyKey, PartySnapshot
|
|
17
|
+
import { createFeedWriter, FeedMessage, PartyKey, PartySnapshot } from '@dxos/echo-protocol';
|
|
18
18
|
import { ModelFactory } from '@dxos/model-factory';
|
|
19
19
|
import { NetworkManager } from '@dxos/network-manager';
|
|
20
20
|
import { ObjectModel } from '@dxos/object-model';
|
|
21
|
-
import { PublicKey } from '@dxos/protocols';
|
|
21
|
+
import { PublicKey, Timeframe } from '@dxos/protocols';
|
|
22
22
|
import { humanize } from '@dxos/util';
|
|
23
23
|
|
|
24
24
|
import {
|
|
@@ -59,8 +59,10 @@ export class PartyFactory {
|
|
|
59
59
|
const party = await this.constructParty(partyKey.publicKey);
|
|
60
60
|
|
|
61
61
|
const writableFeed = await party.getWriteFeed();
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
party._setGenesisFeedKey(writableFeed.key);
|
|
63
|
+
|
|
64
|
+
await this._metadataStore.addParty(partyKey.publicKey);
|
|
65
|
+
await this._metadataStore.setGenesisFeed(partyKey.publicKey, writableFeed.key);
|
|
64
66
|
|
|
65
67
|
// Connect the pipeline.
|
|
66
68
|
await party.open();
|
|
@@ -111,8 +113,6 @@ export class PartyFactory {
|
|
|
111
113
|
|
|
112
114
|
/**
|
|
113
115
|
* Constructs a party object from an existing set of feeds.
|
|
114
|
-
* @param partyKey
|
|
115
|
-
* @param hints
|
|
116
116
|
*/
|
|
117
117
|
async constructParty (partyKey: PartyKey, initialTimeframe?: Timeframe) {
|
|
118
118
|
const identity = this._identityProvider() ?? raise(new IdentityNotInitializedError());
|
|
@@ -172,9 +172,14 @@ export class PartyFactory {
|
|
|
172
172
|
);
|
|
173
173
|
|
|
174
174
|
await initiator.connect();
|
|
175
|
-
const { partyKey,
|
|
175
|
+
const { partyKey, genesisFeedKey } = await initiator.redeemInvitation(secretProvider);
|
|
176
176
|
const party = await this.constructParty(partyKey);
|
|
177
|
-
|
|
177
|
+
|
|
178
|
+
await this._metadataStore.addParty(partyKey);
|
|
179
|
+
await this._metadataStore.setGenesisFeed(partyKey, genesisFeedKey);
|
|
180
|
+
|
|
181
|
+
party._setGenesisFeedKey(genesisFeedKey);
|
|
182
|
+
|
|
178
183
|
await party.open();
|
|
179
184
|
await initiator.destroy();
|
|
180
185
|
|
|
@@ -201,7 +206,10 @@ export class PartyFactory {
|
|
|
201
206
|
|
|
202
207
|
const writableFeed = await party.getWriteFeed();
|
|
203
208
|
// Hint at the newly created writable feed so that we can start replicating from it.
|
|
204
|
-
party.
|
|
209
|
+
party._setGenesisFeedKey(writableFeed.key);
|
|
210
|
+
|
|
211
|
+
await this._metadataStore.addParty(partyKey.publicKey);
|
|
212
|
+
await this._metadataStore.setGenesisFeed(partyKey.publicKey, writableFeed.key);
|
|
205
213
|
|
|
206
214
|
// Connect the pipeline.
|
|
207
215
|
await party.open();
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
/* eslint-disable jest/no-conditional-expect */
|
|
6
6
|
|
|
7
|
-
import assert from 'assert';
|
|
8
7
|
import debug from 'debug';
|
|
9
8
|
import expect from 'expect';
|
|
10
9
|
import { it as test } from 'mocha';
|
|
10
|
+
import assert from 'node:assert';
|
|
11
11
|
|
|
12
12
|
import { latch } from '@dxos/async';
|
|
13
13
|
import {
|
|
@@ -25,12 +25,12 @@ import {
|
|
|
25
25
|
verify
|
|
26
26
|
} from '@dxos/crypto';
|
|
27
27
|
import { checkType } from '@dxos/debug';
|
|
28
|
-
import { codec, EchoEnvelope
|
|
28
|
+
import { codec, EchoEnvelope } from '@dxos/echo-protocol';
|
|
29
29
|
import { createWritableFeedStream, FeedStore } from '@dxos/feed-store';
|
|
30
30
|
import { ModelFactory } from '@dxos/model-factory';
|
|
31
31
|
import { NetworkManager } from '@dxos/network-manager';
|
|
32
32
|
import { ObjectModel } from '@dxos/object-model';
|
|
33
|
-
import { PublicKey } from '@dxos/protocols';
|
|
33
|
+
import { PublicKey, Timeframe } from '@dxos/protocols';
|
|
34
34
|
import { createStorage, StorageType } from '@dxos/random-access-multi-storage';
|
|
35
35
|
import { afterTest, testTimeout } from '@dxos/testutils';
|
|
36
36
|
import { humanize } from '@dxos/util';
|
|
@@ -134,17 +134,19 @@ describe('Party manager', () => {
|
|
|
134
134
|
|
|
135
135
|
// TODO(burdon): Create multiple feeds.
|
|
136
136
|
const { publicKey, secretKey } = createKeyPair();
|
|
137
|
-
const
|
|
137
|
+
const feed = await feedStore.openReadWriteFeed(PublicKey.from(publicKey), secretKey);
|
|
138
138
|
const feedKey = await keyring.addKeyRecord({
|
|
139
139
|
publicKey: PublicKey.from(feed.key),
|
|
140
140
|
secretKey: feed.secretKey,
|
|
141
141
|
type: KeyType.FEED
|
|
142
142
|
});
|
|
143
143
|
|
|
144
|
-
|
|
145
|
-
|
|
144
|
+
await feed.append({
|
|
145
|
+
timeframe: new Timeframe(),
|
|
146
|
+
halo: createPartyGenesisMessage(keyring, partyKey, feedKey.publicKey, identityKey)
|
|
147
|
+
});
|
|
146
148
|
|
|
147
|
-
await partyManager.addParty(partyKey.publicKey,
|
|
149
|
+
await partyManager.addParty(partyKey.publicKey, feed.key);
|
|
148
150
|
|
|
149
151
|
await update;
|
|
150
152
|
});
|
|
@@ -185,6 +187,7 @@ describe('Party manager', () => {
|
|
|
185
187
|
assert(keyRecord, 'Key is not found in keyring');
|
|
186
188
|
assert(keyRecord.secretKey, 'Missing secret key');
|
|
187
189
|
await metadataStore.addPartyFeed(partyKey.publicKey, keyRecord.publicKey);
|
|
190
|
+
await metadataStore.setGenesisFeed(partyKey.publicKey, keyRecord.publicKey);
|
|
188
191
|
|
|
189
192
|
// TODO(burdon): Create multiple feeds.
|
|
190
193
|
const { feed } = await feedStore.openReadWriteFeed(keyRecord.publicKey, keyRecord.secretKey);
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
// Copyright 2020 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import assert from 'assert';
|
|
6
5
|
import debug from 'debug';
|
|
7
6
|
import unionWith from 'lodash.unionwith';
|
|
7
|
+
import assert from 'node:assert';
|
|
8
8
|
|
|
9
9
|
import { Event, synchronized } from '@dxos/async';
|
|
10
|
-
import {
|
|
10
|
+
import { SecretProvider } from '@dxos/credentials';
|
|
11
11
|
import { failUndefined, timed } from '@dxos/debug';
|
|
12
12
|
import { PartyKey, PartySnapshot } from '@dxos/echo-protocol';
|
|
13
13
|
import { PublicKey } from '@dxos/protocols';
|
|
@@ -96,11 +96,15 @@ export class PartyManager {
|
|
|
96
96
|
const snapshot = await this._snapshotStore.load(partyKey);
|
|
97
97
|
|
|
98
98
|
const metadata = this._metadataStore.getParty(partyKey) ?? failUndefined();
|
|
99
|
+
if (!metadata.genesisFeedKey) {
|
|
100
|
+
log(`Skipping loading party with missing genesis feed key: ${partyKey}`);
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
99
103
|
|
|
100
104
|
const party = snapshot
|
|
101
105
|
? await this._partyFactory.constructPartyFromSnapshot(snapshot)
|
|
102
106
|
: await this._partyFactory.constructParty(partyKey);
|
|
103
|
-
party.
|
|
107
|
+
party._setGenesisFeedKey(metadata.genesisFeedKey);
|
|
104
108
|
|
|
105
109
|
const isActive = identity?.preferences?.isPartyActive(partyKey) ?? true;
|
|
106
110
|
if (isActive) {
|
|
@@ -163,7 +167,7 @@ export class PartyManager {
|
|
|
163
167
|
* Construct a party object and start replicating with the remote peer that created that party.
|
|
164
168
|
*/
|
|
165
169
|
@synchronized
|
|
166
|
-
async addParty (partyKey: PartyKey,
|
|
170
|
+
async addParty (partyKey: PartyKey, genesisFeedKey: PublicKey) {
|
|
167
171
|
assert(this._open, 'PartyManager is not open.');
|
|
168
172
|
|
|
169
173
|
/*
|
|
@@ -176,11 +180,14 @@ export class PartyManager {
|
|
|
176
180
|
return this._parties.get(partyKey);
|
|
177
181
|
}
|
|
178
182
|
|
|
179
|
-
log(`Adding party partyKey=${partyKey.toHex()}
|
|
183
|
+
log(`Adding party partyKey=${partyKey.toHex()}`);
|
|
180
184
|
const party = await this._partyFactory.constructParty(partyKey);
|
|
181
|
-
party.
|
|
182
|
-
|
|
185
|
+
party._setGenesisFeedKey(genesisFeedKey);
|
|
186
|
+
|
|
183
187
|
await this._metadataStore.addParty(party.key);
|
|
188
|
+
await this._metadataStore.setGenesisFeed(party.key, genesisFeedKey);
|
|
189
|
+
|
|
190
|
+
await party.open();
|
|
184
191
|
this._setParty(party);
|
|
185
192
|
return party;
|
|
186
193
|
}
|
|
@@ -327,14 +334,9 @@ export class PartyManager {
|
|
|
327
334
|
return;
|
|
328
335
|
}
|
|
329
336
|
|
|
330
|
-
const keyHints: KeyHint[] = [
|
|
331
|
-
...party.processor.memberKeys.map(publicKey => ({ publicKey: publicKey, type: KeyType.UNKNOWN })),
|
|
332
|
-
...party.processor.feedKeys.map(publicKey => ({ publicKey: publicKey, type: KeyType.FEED }))
|
|
333
|
-
];
|
|
334
|
-
|
|
335
337
|
await identity.preferences.recordPartyJoining({
|
|
336
338
|
partyKey: party.key,
|
|
337
|
-
|
|
339
|
+
genesisFeed: party.genesisFeedKey
|
|
338
340
|
});
|
|
339
341
|
}
|
|
340
342
|
}
|
|
@@ -9,10 +9,10 @@ import { it as test } from 'mocha';
|
|
|
9
9
|
import { waitForCondition, latch } from '@dxos/async';
|
|
10
10
|
import { createPartyGenesisMessage, Keyring, KeyType } from '@dxos/credentials';
|
|
11
11
|
import { createId, createKeyPair } from '@dxos/crypto';
|
|
12
|
-
import { codec, createFeedWriter, FeedSelector, FeedStoreIterator, IEchoStream
|
|
12
|
+
import { codec, createFeedWriter, FeedSelector, FeedStoreIterator, IEchoStream } from '@dxos/echo-protocol';
|
|
13
13
|
import { FeedStore, createWritableFeedStream } from '@dxos/feed-store';
|
|
14
14
|
import { createSetPropertyMutation } from '@dxos/model-factory';
|
|
15
|
-
import { PublicKey } from '@dxos/protocols';
|
|
15
|
+
import { PublicKey, Timeframe } from '@dxos/protocols';
|
|
16
16
|
import { createStorage, StorageType } from '@dxos/random-access-multi-storage';
|
|
17
17
|
import { jsonReplacer } from '@dxos/util';
|
|
18
18
|
|
|
@@ -128,7 +128,8 @@ describe('FeedMuxer', () => {
|
|
|
128
128
|
await pipeline.outboundEchoStream!.write({
|
|
129
129
|
itemId: '123',
|
|
130
130
|
genesis: {
|
|
131
|
-
itemType: 'foo'
|
|
131
|
+
itemType: 'foo',
|
|
132
|
+
modelType: 'bar'
|
|
132
133
|
}
|
|
133
134
|
});
|
|
134
135
|
|
|
@@ -138,7 +139,8 @@ describe('FeedMuxer', () => {
|
|
|
138
139
|
expect((echoMessages[0] as any).data).toEqual({
|
|
139
140
|
itemId: '123',
|
|
140
141
|
genesis: {
|
|
141
|
-
itemType: 'foo'
|
|
142
|
+
itemType: 'foo',
|
|
143
|
+
modelType: 'bar'
|
|
142
144
|
}
|
|
143
145
|
});
|
|
144
146
|
});
|
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
// Copyright 2020 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import assert from 'assert';
|
|
6
5
|
import debug from 'debug';
|
|
6
|
+
import assert from 'node:assert';
|
|
7
7
|
|
|
8
8
|
import { Event } from '@dxos/async';
|
|
9
9
|
import { Message as HaloMessage } from '@dxos/credentials';
|
|
10
10
|
import { checkType } from '@dxos/debug';
|
|
11
11
|
import {
|
|
12
|
-
createFeedMeta, EchoEnvelope, FeedMessage, FeedStoreIterator, FeedWriter, IEchoStream, mapFeedWriter
|
|
12
|
+
createFeedMeta, EchoEnvelope, FeedMessage, FeedStoreIterator, FeedWriter, IEchoStream, mapFeedWriter
|
|
13
13
|
} from '@dxos/echo-protocol';
|
|
14
|
-
import { PublicKey } from '@dxos/protocols';
|
|
14
|
+
import { PublicKey, Timeframe } from '@dxos/protocols';
|
|
15
15
|
import { jsonReplacer } from '@dxos/util';
|
|
16
16
|
|
|
17
17
|
import { EchoProcessor, TimeframeClock } from '../packlets/database';
|
|
@@ -2,15 +2,12 @@
|
|
|
2
2
|
// Copyright 2020 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import assert from 'assert';
|
|
6
5
|
import debug from 'debug';
|
|
6
|
+
import assert from 'node:assert';
|
|
7
7
|
|
|
8
|
-
import { getPartyCredentialMessageType, PartyCredential } from '@dxos/credentials';
|
|
9
8
|
import { MessageSelector } from '@dxos/echo-protocol';
|
|
10
|
-
import { PublicKey } from '@dxos/protocols';
|
|
11
9
|
|
|
12
10
|
import { TimeframeClock } from '../packlets/database';
|
|
13
|
-
import { PartyStateProvider } from './party-processor';
|
|
14
11
|
|
|
15
12
|
const log = debug('dxos:echo-db:message-selector');
|
|
16
13
|
|
|
@@ -23,44 +20,16 @@ const log = debug('dxos:echo-db:message-selector');
|
|
|
23
20
|
* @param partyProcessor
|
|
24
21
|
* @param timeframeClock
|
|
25
22
|
*/
|
|
26
|
-
export const createMessageSelector = (
|
|
27
|
-
//
|
|
23
|
+
export const createMessageSelector = (timeframeClock: TimeframeClock): MessageSelector => candidates => {
|
|
24
|
+
// Pick the first candidate with a valid timeframe that has no gaps.
|
|
28
25
|
for (let i = 0; i < candidates.length; i++) {
|
|
29
|
-
const { data: { timeframe
|
|
30
|
-
const feedKey = PublicKey.from(candidates[i].key);
|
|
31
|
-
if (!echo) {
|
|
32
|
-
continue;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
assert(timeframe);
|
|
36
|
-
if (partyProcessor.isFeedAdmitted(feedKey) && !timeframeClock.hasGaps(timeframe)) {
|
|
37
|
-
return i;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Check HALO message candidates.
|
|
42
|
-
for (let i = 0; i < candidates.length; i++) {
|
|
43
|
-
const { data: { timeframe, halo } } = candidates[i];
|
|
44
|
-
const feedKey = PublicKey.from(candidates[i].key);
|
|
45
|
-
if (!halo) {
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
26
|
+
const { data: { timeframe } } = candidates[i];
|
|
48
27
|
|
|
49
28
|
assert(timeframe);
|
|
50
|
-
if (
|
|
29
|
+
if (!timeframeClock.hasGaps(timeframe)) {
|
|
51
30
|
return i;
|
|
52
31
|
}
|
|
53
|
-
|
|
54
|
-
if (partyProcessor.genesisRequired) {
|
|
55
|
-
try { // TODO(dmaretskyi): Get getPartyCredentialMessageType crashes for some reason.
|
|
56
|
-
// TODO(telackey): Add check that this is for the right Party.
|
|
57
|
-
if (getPartyCredentialMessageType(halo) === PartyCredential.Type.PARTY_GENESIS) {
|
|
58
|
-
return i;
|
|
59
|
-
}
|
|
60
|
-
} catch { }
|
|
61
|
-
}
|
|
62
32
|
}
|
|
63
|
-
|
|
64
33
|
// Not ready for this message yet.
|
|
65
34
|
log('Skipping...');
|
|
66
35
|
};
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
// Copyright 2021 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import assert from 'assert';
|
|
6
5
|
import debug from 'debug';
|
|
6
|
+
import assert from 'node:assert';
|
|
7
7
|
|
|
8
8
|
import { synchronized } from '@dxos/async';
|
|
9
9
|
import { failUndefined } from '@dxos/debug';
|
|
10
|
-
import { EchoMetadata, PartyMetadata, schema
|
|
11
|
-
import { PublicKey } from '@dxos/protocols';
|
|
10
|
+
import { EchoMetadata, PartyMetadata, schema } from '@dxos/echo-protocol';
|
|
11
|
+
import { PublicKey, Timeframe } from '@dxos/protocols';
|
|
12
12
|
import { Directory } from '@dxos/random-access-multi-storage';
|
|
13
13
|
|
|
14
14
|
/**
|
|
@@ -20,13 +20,20 @@ export const STORAGE_VERSION = 1;
|
|
|
20
20
|
|
|
21
21
|
const log = debug('dxos:snapshot-store');
|
|
22
22
|
|
|
23
|
+
export interface AddPartyOptions {
|
|
24
|
+
key: PublicKey
|
|
25
|
+
genesisFeed: PublicKey
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const emptyEchoMetadata = (): EchoMetadata => ({
|
|
29
|
+
version: STORAGE_VERSION,
|
|
30
|
+
parties: [],
|
|
31
|
+
created: new Date(),
|
|
32
|
+
updated: new Date()
|
|
33
|
+
});
|
|
34
|
+
|
|
23
35
|
export class MetadataStore {
|
|
24
|
-
private _metadata: EchoMetadata =
|
|
25
|
-
version: STORAGE_VERSION,
|
|
26
|
-
parties: [],
|
|
27
|
-
created: new Date(),
|
|
28
|
-
updated: new Date()
|
|
29
|
-
};
|
|
36
|
+
private _metadata: EchoMetadata = emptyEchoMetadata();
|
|
30
37
|
|
|
31
38
|
constructor (
|
|
32
39
|
private readonly _directory: Directory
|
|
@@ -51,19 +58,26 @@ export class MetadataStore {
|
|
|
51
58
|
async load (): Promise<void> {
|
|
52
59
|
const file = this._directory.createOrOpen('EchoMetadata');
|
|
53
60
|
try {
|
|
54
|
-
const { size } = await file.stat();
|
|
55
|
-
if (
|
|
61
|
+
const { size: fileLength } = await file.stat();
|
|
62
|
+
if (fileLength < 4) {
|
|
56
63
|
return;
|
|
57
64
|
}
|
|
65
|
+
// Loading file size from first 4 bytes.
|
|
66
|
+
const dataSize = fromBytesInt32(await file.read(0, 4));
|
|
67
|
+
log(`Load: data size ${dataSize}`);
|
|
68
|
+
|
|
69
|
+
// Sanity check.
|
|
70
|
+
{
|
|
71
|
+
if (fileLength < dataSize + 4) {
|
|
72
|
+
throw new Error('Metadata storage is corrupted');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
58
75
|
|
|
59
|
-
const data = await file.read(
|
|
76
|
+
const data = await file.read(4, dataSize);
|
|
60
77
|
this._metadata = schema.getCodecForType('dxos.echo.metadata.EchoMetadata').decode(data);
|
|
61
78
|
} catch (err: any) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
} else {
|
|
65
|
-
throw err;
|
|
66
|
-
}
|
|
79
|
+
log(`Error loading metadata: ${err}`);
|
|
80
|
+
this._metadata = emptyEchoMetadata();
|
|
67
81
|
} finally {
|
|
68
82
|
await file.close();
|
|
69
83
|
}
|
|
@@ -82,22 +96,14 @@ export class MetadataStore {
|
|
|
82
96
|
|
|
83
97
|
try {
|
|
84
98
|
const encoded = Buffer.from(schema.getCodecForType('dxos.echo.metadata.EchoMetadata').encode(data));
|
|
85
|
-
await file.write(0, encoded);
|
|
86
99
|
|
|
87
|
-
//
|
|
88
|
-
{
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
100
|
+
// Saving file size at first 4 bytes.
|
|
101
|
+
log(`Save: data size ${encoded.length}`);
|
|
102
|
+
await file.write(0, toBytesInt32(encoded.length));
|
|
103
|
+
|
|
104
|
+
// Saving data.
|
|
105
|
+
await file.write(4, encoded);
|
|
94
106
|
|
|
95
|
-
// Sanity check.
|
|
96
|
-
const { size } = await file.stat();
|
|
97
|
-
if (size !== encoded.length) {
|
|
98
|
-
console.log('SANITY!');
|
|
99
|
-
}
|
|
100
|
-
assert(size === encoded.length);
|
|
101
107
|
} finally {
|
|
102
108
|
await file.close();
|
|
103
109
|
}
|
|
@@ -147,6 +153,14 @@ export class MetadataStore {
|
|
|
147
153
|
await this._save();
|
|
148
154
|
}
|
|
149
155
|
|
|
156
|
+
async setGenesisFeed (partyKey: PublicKey, feedKey: PublicKey): Promise<void> {
|
|
157
|
+
assert(PublicKey.isPublicKey(feedKey));
|
|
158
|
+
await this.addPartyFeed(partyKey, feedKey);
|
|
159
|
+
const party = this.getParty(partyKey) ?? failUndefined();
|
|
160
|
+
party.genesisFeedKey = feedKey;
|
|
161
|
+
await this._save();
|
|
162
|
+
}
|
|
163
|
+
|
|
150
164
|
/**
|
|
151
165
|
* Sets the data feed key in the party specified by public key and saves updated data in persistent storage.
|
|
152
166
|
* Update party's feed list.
|
|
@@ -183,3 +197,11 @@ export class MetadataStore {
|
|
|
183
197
|
await this._save();
|
|
184
198
|
}
|
|
185
199
|
}
|
|
200
|
+
|
|
201
|
+
const toBytesInt32 = (num: number) => {
|
|
202
|
+
const buf = Buffer.alloc(4);
|
|
203
|
+
buf.writeInt32LE(num, 0);
|
|
204
|
+
return buf;
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
const fromBytesInt32 = (buf: Buffer) => buf.readInt32LE(0);
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
// Copyright 2021 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import assert from 'assert';
|
|
6
5
|
import debug from 'debug';
|
|
6
|
+
import assert from 'node:assert';
|
|
7
7
|
|
|
8
8
|
import { Event, synchronized } from '@dxos/async';
|
|
9
9
|
import { Keyring, KeyType } from '@dxos/credentials';
|
|
10
|
-
import { FeedSelector, FeedStoreIterator, MessageSelector
|
|
10
|
+
import { FeedSelector, FeedStoreIterator, MessageSelector } from '@dxos/echo-protocol';
|
|
11
11
|
import { FeedDescriptor, FeedStore } from '@dxos/feed-store';
|
|
12
|
-
import { PublicKey } from '@dxos/protocols';
|
|
12
|
+
import { PublicKey, Timeframe } from '@dxos/protocols';
|
|
13
13
|
import { ComplexMap } from '@dxos/util';
|
|
14
14
|
|
|
15
15
|
import { MetadataStore } from './metadata-store';
|