@dxos/echo-db 2.33.9-dev.d0ae5f95 → 2.33.9-dev.d0dce35f
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/index.d.ts +1 -0
- package/dist/src/api/index.d.ts.map +1 -1
- package/dist/src/api/index.js +1 -0
- package/dist/src/api/index.js.map +1 -1
- package/dist/src/api/subscription.d.ts +5 -0
- package/dist/src/api/subscription.d.ts.map +1 -0
- package/dist/src/api/subscription.js +25 -0
- package/dist/src/api/subscription.js.map +1 -0
- package/dist/src/echo-api.test.d.ts +2 -0
- package/dist/src/echo-api.test.d.ts.map +1 -0
- package/dist/src/echo-api.test.js +117 -0
- package/dist/src/echo-api.test.js.map +1 -0
- package/dist/src/echo.d.ts +3 -4
- package/dist/src/echo.d.ts.map +1 -1
- package/dist/src/echo.js +4 -6
- package/dist/src/echo.js.map +1 -1
- package/dist/src/echo.test.js.map +1 -1
- package/dist/src/halo/halo-party.d.ts +2 -2
- package/dist/src/halo/halo-party.d.ts.map +1 -1
- package/dist/src/halo/halo.test.js.map +1 -1
- package/dist/src/halo/identity-manager.d.ts.map +1 -1
- package/dist/src/halo/identity-manager.js +1 -4
- package/dist/src/halo/identity-manager.js.map +1 -1
- package/dist/src/halo/identity.d.ts +1 -1
- package/dist/src/halo/identity.d.ts.map +1 -1
- package/dist/src/halo/identity.js +2 -0
- package/dist/src/halo/identity.js.map +1 -1
- package/dist/src/halo/preferences.d.ts.map +1 -1
- package/dist/src/halo/preferences.js.map +1 -1
- package/dist/src/packlets/database/item-manager.d.ts.map +1 -1
- package/dist/src/parties/data-party.d.ts.map +1 -1
- package/dist/src/parties/data-party.test.js.map +1 -1
- package/dist/src/parties/party-factory.d.ts +3 -2
- package/dist/src/parties/party-factory.d.ts.map +1 -1
- package/dist/src/parties/party-factory.js.map +1 -1
- package/dist/src/parties/party-manager.d.ts +3 -3
- package/dist/src/parties/party-manager.d.ts.map +1 -1
- package/dist/src/parties/party-manager.js +0 -5
- package/dist/src/parties/party-manager.js.map +1 -1
- package/dist/src/parties/party-preferences.d.ts +1 -1
- package/dist/src/parties/party-preferences.d.ts.map +1 -1
- package/dist/src/parties/party-preferences.js +3 -3
- package/dist/src/parties/party-preferences.js.map +1 -1
- package/dist/src/pipeline/feed-muxer.test.js +4 -2
- package/dist/src/pipeline/feed-muxer.test.js.map +1 -1
- package/dist/src/pipeline/party-pipeline.d.ts +3 -1
- package/dist/src/pipeline/party-pipeline.d.ts.map +1 -1
- package/dist/src/pipeline/party-pipeline.js +7 -5
- package/dist/src/pipeline/party-pipeline.js.map +1 -1
- package/dist/src/pipeline/party-pipeline.test.js +10 -9
- package/dist/src/pipeline/party-pipeline.test.js.map +1 -1
- package/dist/src/protocol/identity-credentials.d.ts +0 -1
- package/dist/src/protocol/identity-credentials.d.ts.map +1 -1
- package/dist/src/protocol/identity-credentials.js.map +1 -1
- package/dist/src/protocol/index.d.ts +1 -0
- package/dist/src/protocol/index.d.ts.map +1 -1
- package/dist/src/protocol/index.js +1 -0
- package/dist/src/protocol/index.js.map +1 -1
- package/dist/src/protocol/party-protocol-factory.d.ts +1 -1
- package/dist/src/protocol/party-protocol-factory.d.ts.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/tsconfig.tsbuildinfo +1 -1
- package/package.json +19 -19
- package/src/api/index.ts +1 -0
- package/src/api/subscription.ts +24 -0
- package/src/echo-api.test.ts +162 -0
- package/src/echo.test.ts +1 -1
- package/src/echo.ts +11 -10
- package/src/halo/halo-party.ts +3 -3
- package/src/halo/halo.test.ts +1 -3
- package/src/halo/identity-manager.ts +1 -6
- package/src/halo/identity.ts +2 -2
- package/src/halo/preferences.ts +1 -0
- package/src/packlets/database/item-manager.ts +5 -5
- package/src/parties/data-party.test.ts +3 -1
- package/src/parties/data-party.ts +2 -2
- package/src/parties/party-factory.ts +3 -3
- package/src/parties/party-manager.ts +6 -13
- package/src/parties/party-preferences.ts +3 -3
- package/src/pipeline/feed-muxer.test.ts +4 -2
- package/src/pipeline/party-pipeline.test.ts +3 -2
- package/src/pipeline/party-pipeline.ts +9 -6
- package/src/protocol/identity-credentials.ts +0 -2
- package/src/protocol/index.ts +1 -0
- package/src/protocol/party-protocol-factory.ts +1 -1
- package/src/snapshots/snapshot-store.test.ts +5 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/echo-db",
|
|
3
|
-
"version": "2.33.9-dev.
|
|
3
|
+
"version": "2.33.9-dev.d0dce35f",
|
|
4
4
|
"description": "ECHO database.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -13,22 +13,22 @@
|
|
|
13
13
|
"src"
|
|
14
14
|
],
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@dxos/async": "2.33.9-dev.
|
|
17
|
-
"@dxos/codec-protobuf": "2.33.9-dev.
|
|
18
|
-
"@dxos/credentials": "2.33.9-dev.
|
|
19
|
-
"@dxos/crypto": "2.33.9-dev.
|
|
20
|
-
"@dxos/debug": "2.33.9-dev.
|
|
21
|
-
"@dxos/echo-protocol": "2.33.9-dev.
|
|
22
|
-
"@dxos/feed-store": "2.33.9-dev.
|
|
23
|
-
"@dxos/mesh-protocol": "2.33.9-dev.
|
|
24
|
-
"@dxos/model-factory": "2.33.9-dev.
|
|
25
|
-
"@dxos/network-manager": "2.33.9-dev.
|
|
26
|
-
"@dxos/object-model": "2.33.9-dev.
|
|
27
|
-
"@dxos/protocol-plugin-presence": "2.33.9-dev.
|
|
28
|
-
"@dxos/protocol-plugin-replicator": "2.33.9-dev.
|
|
29
|
-
"@dxos/protocols": "2.33.9-dev.
|
|
30
|
-
"@dxos/random-access-multi-storage": "2.33.9-dev.
|
|
31
|
-
"@dxos/util": "2.33.9-dev.
|
|
16
|
+
"@dxos/async": "2.33.9-dev.d0dce35f",
|
|
17
|
+
"@dxos/codec-protobuf": "2.33.9-dev.d0dce35f",
|
|
18
|
+
"@dxos/credentials": "2.33.9-dev.d0dce35f",
|
|
19
|
+
"@dxos/crypto": "2.33.9-dev.d0dce35f",
|
|
20
|
+
"@dxos/debug": "2.33.9-dev.d0dce35f",
|
|
21
|
+
"@dxos/echo-protocol": "2.33.9-dev.d0dce35f",
|
|
22
|
+
"@dxos/feed-store": "2.33.9-dev.d0dce35f",
|
|
23
|
+
"@dxos/mesh-protocol": "2.33.9-dev.d0dce35f",
|
|
24
|
+
"@dxos/model-factory": "2.33.9-dev.d0dce35f",
|
|
25
|
+
"@dxos/network-manager": "2.33.9-dev.d0dce35f",
|
|
26
|
+
"@dxos/object-model": "2.33.9-dev.d0dce35f",
|
|
27
|
+
"@dxos/protocol-plugin-presence": "2.33.9-dev.d0dce35f",
|
|
28
|
+
"@dxos/protocol-plugin-replicator": "2.33.9-dev.d0dce35f",
|
|
29
|
+
"@dxos/protocols": "2.33.9-dev.d0dce35f",
|
|
30
|
+
"@dxos/random-access-multi-storage": "2.33.9-dev.d0dce35f",
|
|
31
|
+
"@dxos/util": "2.33.9-dev.d0dce35f",
|
|
32
32
|
"assert": "^2.0.0",
|
|
33
33
|
"base-x": "~3.0.9",
|
|
34
34
|
"buffer-json-encoding": "^1.0.2",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"@types/lodash.defaultsdeep": "^4.6.6",
|
|
51
51
|
"@types/lodash.unionwith": "^4.6.6",
|
|
52
52
|
"@types/memdown": "^3.0.0",
|
|
53
|
-
"@types/mocha": "
|
|
53
|
+
"@types/mocha": "^8.2.2",
|
|
54
54
|
"@types/node": "^16.11.27",
|
|
55
55
|
"@types/pify": "^3.0.2",
|
|
56
56
|
"chalk": "^4.1.0",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"expect": "~27.0.2",
|
|
60
60
|
"faker": "^5.1.0",
|
|
61
61
|
"memdown": "^5.1.0",
|
|
62
|
-
"mocha": "
|
|
62
|
+
"mocha": "^8.4.0",
|
|
63
63
|
"typescript": "^4.7.2"
|
|
64
64
|
},
|
|
65
65
|
"publishConfig": {
|
package/src/api/index.ts
CHANGED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2021 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Event } from '@dxos/async';
|
|
6
|
+
import { Stream } from '@dxos/codec-protobuf';
|
|
7
|
+
|
|
8
|
+
import { ResultSet } from './result-set';
|
|
9
|
+
|
|
10
|
+
export const resultSetToStream = <T, U>(resultSet: ResultSet<T>, map: (arg: T[]) => U): Stream<U> => new Stream(({ next }) => {
|
|
11
|
+
next(map(resultSet.value));
|
|
12
|
+
return resultSet.update.on(() => next(map(resultSet.value)));
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export const streamToResultSet = <T, U>(stream: Stream<T>, map: (arg?: T) => U[]): ResultSet<U> => {
|
|
16
|
+
const event = new Event();
|
|
17
|
+
let lastItem: T | undefined;
|
|
18
|
+
stream.subscribe(data => {
|
|
19
|
+
lastItem = data;
|
|
20
|
+
event.emit();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
return new ResultSet(event, () => map(lastItem));
|
|
24
|
+
};
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2020 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import expect from 'expect';
|
|
6
|
+
import { it as test } from 'mocha';
|
|
7
|
+
|
|
8
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
|
|
9
|
+
// https://javascript.info/proxy
|
|
10
|
+
// https://www.javascripttutorial.net/es6/javascript-proxy
|
|
11
|
+
|
|
12
|
+
// TODO(burdon): Array-specific methods (e.g., push, replace, etc.)
|
|
13
|
+
// http://www.jomendez.com/2018/12/29/querying-arrays-with-more-readable-methods-using-javascript-proxy
|
|
14
|
+
// class ArrayHandler<T> extends Handler {}
|
|
15
|
+
|
|
16
|
+
type Mutation = [property: string, value: any]
|
|
17
|
+
|
|
18
|
+
interface Object {
|
|
19
|
+
// Special properties added by proto generator.
|
|
20
|
+
$id?: string
|
|
21
|
+
$type?: string
|
|
22
|
+
$mutations?: Mutation[]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
class Handler<T> {
|
|
26
|
+
_mutations: Mutation[] = [];
|
|
27
|
+
|
|
28
|
+
constructor (
|
|
29
|
+
private readonly _parent?: Handler<any>,
|
|
30
|
+
protected readonly _property?: string,
|
|
31
|
+
protected readonly _callback?: (value: T) => void
|
|
32
|
+
) {}
|
|
33
|
+
|
|
34
|
+
get mutations () {
|
|
35
|
+
return this._mutations;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
addMutation (mutation: Mutation) {
|
|
39
|
+
if (this._parent) {
|
|
40
|
+
this._parent.addMutation(mutation);
|
|
41
|
+
} else {
|
|
42
|
+
this._mutations.push(mutation);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
getMeta (p: string) {
|
|
47
|
+
switch (p) {
|
|
48
|
+
case '$mutations': {
|
|
49
|
+
return this._mutations;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
//
|
|
56
|
+
// TODO(burdon): Generated from proto.
|
|
57
|
+
//
|
|
58
|
+
|
|
59
|
+
interface Contact extends Object {
|
|
60
|
+
name?: {
|
|
61
|
+
first?: string
|
|
62
|
+
last?: string
|
|
63
|
+
}
|
|
64
|
+
age?: number
|
|
65
|
+
emails?: string[]
|
|
66
|
+
|
|
67
|
+
fullname?: string // TODO(burdon): Show how to add custom functions.
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
class ContactNameHandler extends Handler<Contact['name']> {
|
|
71
|
+
get (obj: any, p: string) {
|
|
72
|
+
switch (p) {
|
|
73
|
+
case 'first':
|
|
74
|
+
case 'last': {
|
|
75
|
+
return obj[p];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
set (obj: any, p: string, value: any) {
|
|
81
|
+
switch (p) {
|
|
82
|
+
case 'first':
|
|
83
|
+
case 'last': {
|
|
84
|
+
this.addMutation([`${this._property}.${p}`, value]);
|
|
85
|
+
obj[p] = value;
|
|
86
|
+
this._callback?.(obj);
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
class ContactHandler extends Handler<Contact> {
|
|
96
|
+
get (obj: any, p: string) {
|
|
97
|
+
const result = super.getMeta(p);
|
|
98
|
+
if (result !== undefined) {
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
switch (p) {
|
|
103
|
+
case 'name': {
|
|
104
|
+
return new Proxy(obj[p] ?? {}, new ContactNameHandler(this, p, value => {
|
|
105
|
+
obj[p] = value;
|
|
106
|
+
}));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return obj[p];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
set (obj: any, p: string, value: any) {
|
|
114
|
+
this.addMutation([p, value]);
|
|
115
|
+
obj[p] = value;
|
|
116
|
+
return true; // Throws TypeError if false.
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
type ItemType<T extends object> = [string, () => Handler<T>]
|
|
121
|
+
|
|
122
|
+
const ContactType: ItemType<Contact> = ['example.Contact', () => new ContactHandler()];
|
|
123
|
+
|
|
124
|
+
class Database {
|
|
125
|
+
private readonly _types = new Map<ItemType<any>, (value: any) => typeof Proxy>();
|
|
126
|
+
|
|
127
|
+
addType (type: ItemType<any>, constructor: (value: any) => any) {
|
|
128
|
+
this._types.set(type, constructor);
|
|
129
|
+
return this;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
create<T extends object> (type: ItemType<T>, value: T = {} as T): T {
|
|
133
|
+
const constructor = this._types.get(type)!;
|
|
134
|
+
return constructor(value) as any;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
describe('API', () => {
|
|
139
|
+
test('Pseudo-code', () => {
|
|
140
|
+
const db = new Database();
|
|
141
|
+
db.addType(ContactType, value => new Proxy<Contact>(value, new ContactHandler()));
|
|
142
|
+
|
|
143
|
+
// Create type-safe proxy.
|
|
144
|
+
const item = db.create(ContactType);
|
|
145
|
+
|
|
146
|
+
item.age = 64;
|
|
147
|
+
expect(item.$mutations).toHaveLength(1);
|
|
148
|
+
expect(item).toEqual({ age: 64 });
|
|
149
|
+
|
|
150
|
+
item.name!.first = 'Alice';
|
|
151
|
+
expect(item.name?.first).toBe('Alice');
|
|
152
|
+
expect(item.$mutations).toHaveLength(2);
|
|
153
|
+
expect(item).toEqual({ age: 64, name: { first: 'Alice' } });
|
|
154
|
+
|
|
155
|
+
expect(item.$mutations).toStrictEqual([
|
|
156
|
+
['age', 64],
|
|
157
|
+
['name.first', 'Alice']
|
|
158
|
+
]);
|
|
159
|
+
|
|
160
|
+
// TODO(burdon): Get item id, state, mutations, etc.
|
|
161
|
+
});
|
|
162
|
+
});
|
package/src/echo.test.ts
CHANGED
package/src/echo.ts
CHANGED
|
@@ -25,7 +25,7 @@ import { InvitationDescriptor, OfflineInvitationClaimer } from './invitations';
|
|
|
25
25
|
import { DataServiceRouter } from './packlets/database';
|
|
26
26
|
import { IdentityNotInitializedError, InvalidStorageVersionError } from './packlets/errors';
|
|
27
27
|
import { OpenProgress, PartyFactory, DataParty, PartyManager } from './parties';
|
|
28
|
-
import {
|
|
28
|
+
import { STORAGE_VERSION, MetadataStore, PartyFeedProvider } from './pipeline';
|
|
29
29
|
import { SnapshotStore } from './snapshots';
|
|
30
30
|
|
|
31
31
|
const log = debug('dxos:echo');
|
|
@@ -85,18 +85,19 @@ export interface EchoCreationOptions {
|
|
|
85
85
|
* Messages are streamed into the pipeline (from the `FeedStore`) in logical order, determined by the
|
|
86
86
|
* `Timeframe` (which implements a vector clock).
|
|
87
87
|
*/
|
|
88
|
-
// TODO(burdon): Create ECHOError class for public errors.
|
|
89
88
|
export class ECHO {
|
|
90
|
-
private readonly _halo: HALO;
|
|
91
89
|
private readonly _keyring: Keyring;
|
|
92
90
|
|
|
91
|
+
// TODO(burdon): Factor out.
|
|
92
|
+
private readonly _halo: HALO;
|
|
93
|
+
private readonly _partyManager: PartyManager;
|
|
94
|
+
private readonly _subscriptions = new SubscriptionGroup();
|
|
95
|
+
|
|
93
96
|
private readonly _storage: Storage;
|
|
94
97
|
private readonly _feedStore: FeedStore;
|
|
95
98
|
private readonly _modelFactory: ModelFactory;
|
|
96
99
|
private readonly _networkManager: NetworkManager;
|
|
97
100
|
private readonly _snapshotStore: SnapshotStore;
|
|
98
|
-
private readonly _partyManager: PartyManager;
|
|
99
|
-
private readonly _subs = new SubscriptionGroup();
|
|
100
101
|
private readonly _metadataStore: MetadataStore;
|
|
101
102
|
private readonly _dataServiceRouter: DataServiceRouter;
|
|
102
103
|
|
|
@@ -153,7 +154,7 @@ export class ECHO {
|
|
|
153
154
|
this._partyManager = new PartyManager(
|
|
154
155
|
this._metadataStore,
|
|
155
156
|
this._snapshotStore,
|
|
156
|
-
() => this.
|
|
157
|
+
() => this._halo.identity,
|
|
157
158
|
partyFactory
|
|
158
159
|
);
|
|
159
160
|
|
|
@@ -170,7 +171,7 @@ export class ECHO {
|
|
|
170
171
|
this._halo.identityReady.once(() => {
|
|
171
172
|
// It might be the case that halo gets closed before this has a chance to execute.
|
|
172
173
|
if (this.halo.identity?.halo.isOpen) {
|
|
173
|
-
this.
|
|
174
|
+
this._subscriptions.push(autoPartyOpener(this.halo.identity.preferences!, this._partyManager));
|
|
174
175
|
}
|
|
175
176
|
});
|
|
176
177
|
|
|
@@ -260,7 +261,7 @@ export class ECHO {
|
|
|
260
261
|
return;
|
|
261
262
|
}
|
|
262
263
|
|
|
263
|
-
this.
|
|
264
|
+
this._subscriptions.unsubscribe();
|
|
264
265
|
|
|
265
266
|
await this.halo.close();
|
|
266
267
|
|
|
@@ -272,7 +273,6 @@ export class ECHO {
|
|
|
272
273
|
|
|
273
274
|
/**
|
|
274
275
|
* Removes all data and closes this ECHO instance.
|
|
275
|
-
*
|
|
276
276
|
* The instance will be in an unusable state at this point and a page refresh is recommended.
|
|
277
277
|
*/
|
|
278
278
|
// TODO(burdon): Enable re-open.
|
|
@@ -371,7 +371,8 @@ export class ECHO {
|
|
|
371
371
|
assert(this._partyManager.isOpen, new InvalidStateError());
|
|
372
372
|
|
|
373
373
|
const actualSecretProvider =
|
|
374
|
-
secretProvider ?? OfflineInvitationClaimer.createSecretProvider(this.halo.identity?.createCredentialsSigner() ??
|
|
374
|
+
secretProvider ?? OfflineInvitationClaimer.createSecretProvider(this.halo.identity?.createCredentialsSigner() ??
|
|
375
|
+
raise(new IdentityNotInitializedError()));
|
|
375
376
|
|
|
376
377
|
return this._partyManager.joinParty(invitationDescriptor, actualSecretProvider);
|
|
377
378
|
}
|
package/src/halo/halo-party.ts
CHANGED
|
@@ -28,9 +28,9 @@ export const HALO_PARTY_DEVICE_PREFERENCES_TYPE = 'dxos:item/halo/device/prefere
|
|
|
28
28
|
/**
|
|
29
29
|
* A record in HALO party representing a party that user is currently a member of.
|
|
30
30
|
*/
|
|
31
|
-
export
|
|
32
|
-
partyKey: PublicKey
|
|
33
|
-
genesisFeed: PublicKey
|
|
31
|
+
export type JoinedParty = {
|
|
32
|
+
partyKey: PublicKey
|
|
33
|
+
genesisFeed: PublicKey
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
/**
|
package/src/halo/halo.test.ts
CHANGED
|
@@ -5,9 +5,7 @@
|
|
|
5
5
|
import expect from 'expect';
|
|
6
6
|
import { it as test } from 'mocha';
|
|
7
7
|
|
|
8
|
-
import {
|
|
9
|
-
defaultSecretProvider, generateSeedPhrase, keyPairFromSeedPhrase, Keyring
|
|
10
|
-
} from '@dxos/credentials';
|
|
8
|
+
import { defaultSecretProvider, generateSeedPhrase, keyPairFromSeedPhrase, Keyring } from '@dxos/credentials';
|
|
11
9
|
import { codec } from '@dxos/echo-protocol';
|
|
12
10
|
import { FeedStore } from '@dxos/feed-store';
|
|
13
11
|
import { ModelFactory } from '@dxos/model-factory';
|
|
@@ -39,15 +39,10 @@ export class IdentityManager {
|
|
|
39
39
|
assert(halo.isOpen, 'HALO must be open.');
|
|
40
40
|
|
|
41
41
|
// Wait for the minimum set of keys and messages we need for proper function:
|
|
42
|
-
//
|
|
43
42
|
// - KeyAdmit message for the current device so we can build the device KeyChain.
|
|
44
43
|
// - Identity genesis so it can be copied into newly joined parties.
|
|
45
|
-
//
|
|
46
44
|
const deviceKey = this._keyring.findKey(Keyring.signingFilter({ type: KeyType.DEVICE })) ?? failUndefined();
|
|
47
|
-
await waitForCondition(() =>
|
|
48
|
-
halo.processor.isMemberKey(deviceKey.publicKey) &&
|
|
49
|
-
halo.identityGenesis
|
|
50
|
-
);
|
|
45
|
+
await waitForCondition(() => halo.processor.isMemberKey(deviceKey.publicKey) && halo.identityGenesis);
|
|
51
46
|
|
|
52
47
|
this._identity = new Identity(this._keyring, halo);
|
|
53
48
|
this.ready.emit();
|
package/src/halo/identity.ts
CHANGED
|
@@ -27,6 +27,7 @@ export class Identity implements IdentityCredentials {
|
|
|
27
27
|
private readonly _deviceKeyChain: KeyChain;
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
|
+
* @param _keyring
|
|
30
31
|
* @param _halo HALO party. Must be open.
|
|
31
32
|
*/
|
|
32
33
|
constructor (
|
|
@@ -86,6 +87,7 @@ export class Identity implements IdentityCredentials {
|
|
|
86
87
|
/**
|
|
87
88
|
* HALO party. Must be open.
|
|
88
89
|
*/
|
|
90
|
+
// TODO(burdon): Remove.
|
|
89
91
|
get halo (): HaloParty {
|
|
90
92
|
return this._halo;
|
|
91
93
|
}
|
|
@@ -100,8 +102,6 @@ export class Identity implements IdentityCredentials {
|
|
|
100
102
|
}
|
|
101
103
|
}
|
|
102
104
|
|
|
103
|
-
export type IdentityProvider = () => Identity | undefined;
|
|
104
|
-
|
|
105
105
|
const getDeviceKeyChainFromHalo = (halo: HaloParty, deviceKey: KeyRecord) => {
|
|
106
106
|
try {
|
|
107
107
|
return Keyring.buildKeyChain(
|
package/src/halo/preferences.ts
CHANGED
|
@@ -26,14 +26,14 @@ export interface ModelConstructionOptions {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
export interface ItemConstructionOptions extends ModelConstructionOptions {
|
|
29
|
-
itemType: ItemType | undefined
|
|
30
|
-
parentId?: ItemID
|
|
29
|
+
itemType: ItemType | undefined
|
|
30
|
+
parentId?: ItemID
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
export interface LinkConstructionOptions extends ModelConstructionOptions {
|
|
34
|
-
itemType: ItemType | undefined
|
|
35
|
-
source: ItemID
|
|
36
|
-
target: ItemID
|
|
34
|
+
itemType: ItemType | undefined
|
|
35
|
+
source: ItemID
|
|
36
|
+
target: ItemID
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
/**
|
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
import expect from 'expect';
|
|
6
6
|
import { it as test } from 'mocha';
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
createKeyAdmitMessage, createPartyGenesisMessage, defaultSecretProvider, Keyring, KeyType, codec as haloCodec
|
|
10
|
+
} from '@dxos/credentials';
|
|
9
11
|
import { codec } from '@dxos/echo-protocol';
|
|
10
12
|
import { FeedStore } from '@dxos/feed-store';
|
|
11
13
|
import { ModelFactory } from '@dxos/model-factory';
|
|
@@ -30,7 +30,7 @@ export const PARTY_TITLE_PROPERTY = 'title'; // TODO(burdon): Remove (should not
|
|
|
30
30
|
|
|
31
31
|
// TODO(burdon): Factor out public API.
|
|
32
32
|
export interface PartyMember {
|
|
33
|
-
publicKey: PublicKey
|
|
33
|
+
publicKey: PublicKey
|
|
34
34
|
displayName?: string
|
|
35
35
|
}
|
|
36
36
|
|
|
@@ -142,7 +142,7 @@ export class DataParty {
|
|
|
142
142
|
await this._preferences?.setLastKnownTitle(title);
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
get genesisFeedKey () {
|
|
145
|
+
get genesisFeedKey (): PublicKey {
|
|
146
146
|
assert(this._genesisFeedKey);
|
|
147
147
|
return this._genesisFeedKey;
|
|
148
148
|
}
|
|
@@ -19,7 +19,7 @@ import { ModelFactory } from '@dxos/model-factory';
|
|
|
19
19
|
import { NetworkManager } from '@dxos/network-manager';
|
|
20
20
|
import { ObjectModel } from '@dxos/object-model';
|
|
21
21
|
import { PublicKey, Timeframe } from '@dxos/protocols';
|
|
22
|
-
import { humanize } from '@dxos/util';
|
|
22
|
+
import { humanize, Provider } from '@dxos/util';
|
|
23
23
|
|
|
24
24
|
import {
|
|
25
25
|
createDataPartyAdmissionMessages,
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
} from '../invitations';
|
|
28
28
|
import { IdentityNotInitializedError } from '../packlets/errors';
|
|
29
29
|
import { MetadataStore, PartyFeedProvider, PipelineOptions } from '../pipeline';
|
|
30
|
-
import {
|
|
30
|
+
import { IdentityCredentials } from '../protocol/identity-credentials';
|
|
31
31
|
import { SnapshotStore } from '../snapshots';
|
|
32
32
|
import { DataParty, PARTY_ITEM_TYPE } from './data-party';
|
|
33
33
|
|
|
@@ -38,7 +38,7 @@ const log = debug('dxos:echo-db:party-factory');
|
|
|
38
38
|
*/
|
|
39
39
|
export class PartyFactory {
|
|
40
40
|
constructor (
|
|
41
|
-
private readonly _identityProvider:
|
|
41
|
+
private readonly _identityProvider: Provider<IdentityCredentials | undefined>,
|
|
42
42
|
private readonly _networkManager: NetworkManager,
|
|
43
43
|
private readonly _modelFactory: ModelFactory,
|
|
44
44
|
private readonly _snapshotStore: SnapshotStore,
|
|
@@ -11,11 +11,11 @@ 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';
|
|
14
|
-
import { ComplexMap, boolGuard } from '@dxos/util';
|
|
14
|
+
import { ComplexMap, boolGuard, Provider } from '@dxos/util';
|
|
15
15
|
|
|
16
16
|
import { InvitationDescriptor } from '../invitations';
|
|
17
17
|
import { MetadataStore } from '../pipeline';
|
|
18
|
-
import {
|
|
18
|
+
import { IdentityCredentials } from '../protocol/identity-credentials';
|
|
19
19
|
import { SnapshotStore } from '../snapshots';
|
|
20
20
|
import { DataParty, PARTY_ITEM_TYPE, PARTY_TITLE_PROPERTY } from './data-party';
|
|
21
21
|
import { PartyFactory } from './party-factory';
|
|
@@ -25,9 +25,9 @@ export const CONTACT_DEBOUNCE_INTERVAL = 500;
|
|
|
25
25
|
const log = debug('dxos:echo-db:party-manager');
|
|
26
26
|
|
|
27
27
|
export interface OpenProgress {
|
|
28
|
-
haloOpened: boolean
|
|
29
|
-
partiesOpened?: number
|
|
30
|
-
totalParties?: number
|
|
28
|
+
haloOpened: boolean
|
|
29
|
+
partiesOpened?: number
|
|
30
|
+
totalParties?: number
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
/**
|
|
@@ -42,16 +42,12 @@ export class PartyManager {
|
|
|
42
42
|
// Map of parties by party key.
|
|
43
43
|
private readonly _parties = new ComplexMap<PublicKey, DataParty>(key => key.toHex());
|
|
44
44
|
|
|
45
|
-
// Unsubscribe handlers.
|
|
46
|
-
// TODO(burdon): Never used.
|
|
47
|
-
private readonly _onCloseHandlers: (() => void)[] = [];
|
|
48
|
-
|
|
49
45
|
private _open = false;
|
|
50
46
|
|
|
51
47
|
constructor (
|
|
52
48
|
private readonly _metadataStore: MetadataStore,
|
|
53
49
|
private readonly _snapshotStore: SnapshotStore,
|
|
54
|
-
private readonly _identityProvider:
|
|
50
|
+
private readonly _identityProvider: Provider<IdentityCredentials | undefined>,
|
|
55
51
|
private readonly _partyFactory: PartyFactory
|
|
56
52
|
) {}
|
|
57
53
|
|
|
@@ -129,9 +125,6 @@ export class PartyManager {
|
|
|
129
125
|
}
|
|
130
126
|
this._open = false;
|
|
131
127
|
|
|
132
|
-
// Clean-up.
|
|
133
|
-
this._onCloseHandlers.forEach(callback => callback());
|
|
134
|
-
|
|
135
128
|
// Close parties.
|
|
136
129
|
for (const party of this._parties.values()) {
|
|
137
130
|
if (party.isOpen) {
|
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
import assert from 'node:assert';
|
|
6
6
|
|
|
7
|
-
import { PARTY_TITLE_PROPERTY, DataParty } from '.';
|
|
8
7
|
import { Preferences } from '../halo/preferences';
|
|
8
|
+
import { PARTY_TITLE_PROPERTY, DataParty } from './data-party';
|
|
9
9
|
|
|
10
10
|
export interface ActivationOptions {
|
|
11
|
-
global?: boolean
|
|
12
|
-
device?: boolean
|
|
11
|
+
global?: boolean
|
|
12
|
+
device?: boolean
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
/**
|
|
@@ -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
|
});
|
|
@@ -18,9 +18,10 @@ import { PublicKey, Timeframe } from '@dxos/protocols';
|
|
|
18
18
|
import { createStorage, StorageType } from '@dxos/random-access-multi-storage';
|
|
19
19
|
import { afterTest } from '@dxos/testutils';
|
|
20
20
|
|
|
21
|
-
import {
|
|
22
|
-
import { createReplicatorPlugin } from '../protocol/replicator-plugin';
|
|
21
|
+
import { createReplicatorPlugin } from '../protocol';
|
|
23
22
|
import { SnapshotStore } from '../snapshots';
|
|
23
|
+
import { MetadataStore } from './metadata-store';
|
|
24
|
+
import { PartyFeedProvider } from './party-feed-provider';
|
|
24
25
|
import { PartyPipeline } from './party-pipeline';
|
|
25
26
|
|
|
26
27
|
describe('PartyPipeline', () => {
|
|
@@ -14,20 +14,23 @@ import { ModelFactory } from '@dxos/model-factory';
|
|
|
14
14
|
import { PublicKey, Timeframe } from '@dxos/protocols';
|
|
15
15
|
import { SubscriptionGroup } from '@dxos/util';
|
|
16
16
|
|
|
17
|
-
import { createMessageSelector, PartyProcessor, PartyFeedProvider, FeedMuxer } from '.';
|
|
18
17
|
import { Database, FeedDatabaseBackend, TimeframeClock } from '../packlets/database';
|
|
19
18
|
import { createAutomaticSnapshots, SnapshotStore } from '../snapshots';
|
|
19
|
+
import { FeedMuxer } from './feed-muxer';
|
|
20
|
+
import { createMessageSelector } from './message-selector';
|
|
21
|
+
import { PartyFeedProvider } from './party-feed-provider';
|
|
22
|
+
import { PartyProcessor } from './party-processor';
|
|
20
23
|
|
|
21
24
|
const DEFAULT_SNAPSHOT_INTERVAL = 100; // Every 100 messages.
|
|
22
25
|
|
|
23
26
|
export interface PipelineOptions {
|
|
24
|
-
readLogger?: (msg: any) => void
|
|
25
|
-
writeLogger?: (msg: any) => void
|
|
26
|
-
readOnly?: boolean
|
|
27
|
+
readLogger?: (msg: any) => void
|
|
28
|
+
writeLogger?: (msg: any) => void
|
|
29
|
+
readOnly?: boolean
|
|
27
30
|
// TODO(burdon): Hierarchical options.
|
|
28
31
|
// snapshots: { enabled: true, interval: 100 } }
|
|
29
|
-
snapshots?: boolean
|
|
30
|
-
snapshotInterval?: number
|
|
32
|
+
snapshots?: boolean
|
|
33
|
+
snapshotInterval?: number
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
export interface OpenOptions {
|
|
@@ -27,8 +27,6 @@ export interface IdentityCredentials {
|
|
|
27
27
|
contacts: ContactManager | undefined
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
export type IdentityCredentialsProvider = () => IdentityCredentials | undefined
|
|
31
|
-
|
|
32
30
|
export const createTestIdentityCredentials = async (keyring: Keyring): Promise<IdentityCredentials> => {
|
|
33
31
|
const identityKey = await keyring.createKeyRecord({ type: KeyType.IDENTITY });
|
|
34
32
|
const deviceKey = await keyring.createKeyRecord({ type: KeyType.DEVICE });
|
package/src/protocol/index.ts
CHANGED
|
@@ -11,7 +11,7 @@ import { MMSTTopology, NetworkManager, Plugin } from '@dxos/network-manager';
|
|
|
11
11
|
import { PresencePlugin } from '@dxos/protocol-plugin-presence';
|
|
12
12
|
import { PublicKey } from '@dxos/protocols';
|
|
13
13
|
|
|
14
|
-
import { CredentialsProvider } from '
|
|
14
|
+
import { CredentialsProvider } from './authenticator';
|
|
15
15
|
|
|
16
16
|
const log = debug('dxos:echo-db:party-protocol-factory');
|
|
17
17
|
|