@dxos/client-services 0.1.41 → 0.1.45-next.45667d4
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-T73F4MV4.mjs → chunk-IHSMRQ3L.mjs} +985 -867
- package/dist/lib/browser/chunk-IHSMRQ3L.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +7 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/packlets/testing/index.mjs +121 -297
- package/dist/lib/browser/packlets/testing/index.mjs.map +4 -4
- package/dist/lib/node/index.cjs +589 -469
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/packlets/testing/index.cjs +688 -740
- package/dist/lib/node/packlets/testing/index.cjs.map +4 -4
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/packlets/devices/devices-service.d.ts +1 -1
- package/dist/types/src/packlets/devices/devices-service.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/devtools.d.ts +4 -2
- package/dist/types/src/packlets/devtools/devtools.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/keys.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/network.d.ts +5 -4
- package/dist/types/src/packlets/devtools/network.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/authenticator.d.ts +1 -1
- package/dist/types/src/packlets/identity/authenticator.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-manager.d.ts +2 -4
- package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity.d.ts +1 -1
- package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitation-extension.d.ts +2 -3
- package/dist/types/src/packlets/invitations/invitation-extension.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitations-handler.d.ts +1 -3
- package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts +1 -2
- package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts.map +1 -1
- package/dist/types/src/packlets/network/network-service.d.ts +6 -4
- package/dist/types/src/packlets/network/network-service.d.ts.map +1 -1
- package/dist/types/src/packlets/services/client-rpc-server.d.ts +2 -2
- package/dist/types/src/packlets/services/client-rpc-server.d.ts.map +1 -1
- package/dist/types/src/packlets/services/index.d.ts +0 -1
- package/dist/types/src/packlets/services/index.d.ts.map +1 -1
- package/dist/types/src/packlets/services/local-client-services.d.ts +1 -1
- package/dist/types/src/packlets/services/local-client-services.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-context.d.ts +4 -2
- package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-host.d.ts +16 -9
- package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts +12 -7
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space.d.ts +15 -10
- package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/genesis.d.ts +5 -0
- package/dist/types/src/packlets/spaces/genesis.d.ts.map +1 -0
- package/dist/types/src/packlets/spaces/notarization-plugin.d.ts +4 -4
- package/dist/types/src/packlets/spaces/notarization-plugin.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/spaces-service.d.ts +2 -1
- package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
- package/dist/types/src/packlets/system/system-service.d.ts +1 -1
- package/dist/types/src/packlets/system/system-service.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/credential-utils.d.ts +1 -1
- package/dist/types/src/packlets/testing/index.d.ts +0 -1
- package/dist/types/src/packlets/testing/index.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/invitation-utils.d.ts +13 -7
- package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/test-builder.d.ts +35 -32
- package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts +1 -1
- package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/iframe-proxy-runtime.d.ts +5 -2
- package/dist/types/src/packlets/vault/iframe-proxy-runtime.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/vault-resource-lock.d.ts +1 -1
- package/dist/types/src/packlets/vault/vault-resource-lock.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/worker-runtime.d.ts +1 -1
- package/dist/types/src/packlets/vault/worker-runtime.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/worker-session.d.ts +4 -7
- package/dist/types/src/packlets/vault/worker-session.d.ts.map +1 -1
- package/package.json +30 -31
- package/src/index.ts +1 -0
- package/src/packlets/devices/devices-service.ts +5 -5
- package/src/packlets/devtools/devtools.ts +25 -4
- package/src/packlets/devtools/feeds.ts +10 -10
- package/src/packlets/devtools/keys.ts +6 -6
- package/src/packlets/devtools/network.ts +14 -13
- package/src/packlets/devtools/spaces.ts +4 -4
- package/src/packlets/identity/authenticator.test.ts +1 -1
- package/src/packlets/identity/authenticator.ts +2 -2
- package/src/packlets/identity/identity-manager.test.ts +17 -13
- package/src/packlets/identity/identity-manager.ts +21 -22
- package/src/packlets/identity/identity-service.ts +3 -3
- package/src/packlets/identity/identity.test.ts +65 -36
- package/src/packlets/identity/identity.ts +17 -17
- package/src/packlets/invitations/device-invitation-protocol.test.ts +1 -1
- package/src/packlets/invitations/device-invitation-protocol.ts +7 -7
- package/src/packlets/invitations/invitation-extension.ts +16 -27
- package/src/packlets/invitations/invitations-handler.ts +17 -25
- package/src/packlets/invitations/invitations-service.ts +11 -11
- package/src/packlets/invitations/space-invitation-protocol.test.ts +9 -9
- package/src/packlets/invitations/space-invitation-protocol.ts +11 -12
- package/src/packlets/logging/logging-service.ts +8 -3
- package/src/packlets/network/network-service.test.ts +8 -8
- package/src/packlets/network/network-service.ts +20 -8
- package/src/packlets/services/client-rpc-server.ts +5 -5
- package/src/packlets/services/index.ts +0 -1
- package/src/packlets/services/local-client-services.ts +1 -1
- package/src/packlets/services/service-context.test.ts +3 -3
- package/src/packlets/services/service-context.ts +26 -24
- package/src/packlets/services/service-host.test.ts +6 -6
- package/src/packlets/services/service-host.ts +57 -31
- package/src/packlets/services/service-registry.test.ts +20 -38
- package/src/packlets/spaces/data-space-manager.test.ts +17 -29
- package/src/packlets/spaces/data-space-manager.ts +29 -35
- package/src/packlets/spaces/data-space.ts +73 -47
- package/src/packlets/spaces/genesis.ts +81 -0
- package/src/packlets/spaces/notarization-plugin.test.ts +2 -2
- package/src/packlets/spaces/notarization-plugin.ts +12 -12
- package/src/packlets/spaces/spaces-service.test.ts +2 -2
- package/src/packlets/spaces/spaces-service.ts +21 -10
- package/src/packlets/storage/storage.ts +3 -3
- package/src/packlets/system/system-service.test.ts +1 -1
- package/src/packlets/system/system-service.ts +1 -1
- package/src/packlets/testing/credential-utils.ts +4 -4
- package/src/packlets/testing/index.ts +0 -1
- package/src/packlets/testing/invitation-utils.ts +28 -33
- package/src/packlets/testing/test-builder.ts +132 -168
- package/src/packlets/vault/iframe-host-runtime.ts +8 -11
- package/src/packlets/vault/iframe-proxy-runtime.ts +25 -9
- package/src/packlets/vault/shell-runtime.ts +4 -4
- package/src/packlets/vault/vault-resource-lock.ts +2 -2
- package/src/packlets/vault/worker-runtime.ts +7 -9
- package/src/packlets/vault/worker-session.ts +24 -45
- package/dist/lib/browser/chunk-T73F4MV4.mjs.map +0 -7
- package/dist/types/src/packlets/services/utils.d.ts +0 -7
- package/dist/types/src/packlets/services/utils.d.ts.map +0 -1
- package/dist/types/src/packlets/testing/host-test-builder.d.ts +0 -43
- package/dist/types/src/packlets/testing/host-test-builder.d.ts.map +0 -1
- package/dist/types/src/packlets/tests/client-services.test.d.ts +0 -2
- package/dist/types/src/packlets/tests/client-services.test.d.ts.map +0 -1
- package/dist/types/src/packlets/tests/client.test.d.ts +0 -2
- package/dist/types/src/packlets/tests/client.test.d.ts.map +0 -1
- package/dist/types/src/packlets/tests/halo-credentials.test.d.ts +0 -2
- package/dist/types/src/packlets/tests/halo-credentials.test.d.ts.map +0 -1
- package/dist/types/src/packlets/tests/halo-persistent.test.d.ts +0 -2
- package/dist/types/src/packlets/tests/halo-persistent.test.d.ts.map +0 -1
- package/dist/types/src/packlets/tests/halo-profile.test.d.ts +0 -2
- package/dist/types/src/packlets/tests/halo-profile.test.d.ts.map +0 -1
- package/dist/types/src/packlets/tests/invitations.test.d.ts +0 -2
- package/dist/types/src/packlets/tests/invitations.test.d.ts.map +0 -1
- package/dist/types/src/packlets/tests/shared-worker.test.d.ts +0 -2
- package/dist/types/src/packlets/tests/shared-worker.test.d.ts.map +0 -1
- package/dist/types/src/packlets/tests/spaces-invitations.test.d.ts +0 -2
- package/dist/types/src/packlets/tests/spaces-invitations.test.d.ts.map +0 -1
- package/dist/types/src/packlets/tests/spaces.test.d.ts +0 -2
- package/dist/types/src/packlets/tests/spaces.test.d.ts.map +0 -1
- package/dist/types/src/packlets/tests/text.test.d.ts +0 -2
- package/dist/types/src/packlets/tests/text.test.d.ts.map +0 -1
- package/src/packlets/services/utils.ts +0 -53
- package/src/packlets/testing/host-test-builder.ts +0 -163
- package/src/packlets/tests/client-services.test.ts +0 -222
- package/src/packlets/tests/client.test.ts +0 -140
- package/src/packlets/tests/halo-credentials.test.ts +0 -94
- package/src/packlets/tests/halo-persistent.test.ts +0 -53
- package/src/packlets/tests/halo-profile.test.ts +0 -48
- package/src/packlets/tests/invitations.test.ts +0 -389
- package/src/packlets/tests/shared-worker.test.ts +0 -92
- package/src/packlets/tests/spaces-invitations.test.ts +0 -46
- package/src/packlets/tests/spaces.test.ts +0 -147
- package/src/packlets/tests/text.test.ts +0 -206
|
@@ -3,31 +3,25 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { Event, scheduleTask, trackLeaks } from '@dxos/async';
|
|
6
|
-
import {
|
|
7
|
-
import { Context } from '@dxos/context';
|
|
6
|
+
import { cancelWithContext, Context } from '@dxos/context';
|
|
8
7
|
import { CredentialConsumer } from '@dxos/credentials';
|
|
9
8
|
import { timed } from '@dxos/debug';
|
|
10
|
-
import {
|
|
11
|
-
MetadataStore,
|
|
12
|
-
Space,
|
|
13
|
-
SigningContext,
|
|
14
|
-
createMappedFeedWriter,
|
|
15
|
-
SnapshotManager,
|
|
16
|
-
DataPipeline
|
|
17
|
-
} from '@dxos/echo-pipeline';
|
|
9
|
+
import { MetadataStore, Space, createMappedFeedWriter, DataPipeline } from '@dxos/echo-pipeline';
|
|
18
10
|
import { CancelledError, SystemError } from '@dxos/errors';
|
|
19
11
|
import { FeedStore } from '@dxos/feed-store';
|
|
20
12
|
import { Keyring } from '@dxos/keyring';
|
|
21
13
|
import { PublicKey } from '@dxos/keys';
|
|
22
14
|
import { log } from '@dxos/log';
|
|
23
|
-
import {
|
|
15
|
+
import { SpaceState, Space as SpaceProto } from '@dxos/protocols/proto/dxos/client/services';
|
|
24
16
|
import { FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
|
|
17
|
+
import { SpaceCache } from '@dxos/protocols/proto/dxos/echo/metadata';
|
|
25
18
|
import { AdmittedFeed, Credential } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
26
19
|
import { GossipMessage } from '@dxos/protocols/proto/dxos/mesh/teleport/gossip';
|
|
27
20
|
import { Gossip, Presence } from '@dxos/teleport-extension-gossip';
|
|
28
21
|
import { ComplexSet } from '@dxos/util';
|
|
29
22
|
|
|
30
23
|
import { TrustedKeySetAuthVerifier } from '../identity';
|
|
24
|
+
import { SigningContext } from './data-space-manager';
|
|
31
25
|
import { NotarizationPlugin } from './notarization-plugin';
|
|
32
26
|
|
|
33
27
|
const AUTH_TIMEOUT = 30000;
|
|
@@ -46,23 +40,19 @@ export type DataSpaceCallbacks = {
|
|
|
46
40
|
|
|
47
41
|
export type DataSpaceParams = {
|
|
48
42
|
inner: Space;
|
|
49
|
-
modelFactory: ModelFactory;
|
|
50
43
|
metadataStore: MetadataStore;
|
|
51
|
-
snapshotManager: SnapshotManager;
|
|
52
44
|
gossip: Gossip;
|
|
53
45
|
presence: Presence;
|
|
54
46
|
keyring: Keyring;
|
|
55
47
|
feedStore: FeedStore<FeedMessage>;
|
|
56
48
|
signingContext: SigningContext;
|
|
57
|
-
memberKey: PublicKey;
|
|
58
|
-
snapshotId?: string | undefined;
|
|
59
49
|
callbacks?: DataSpaceCallbacks;
|
|
50
|
+
cache?: SpaceCache;
|
|
60
51
|
};
|
|
61
52
|
|
|
62
53
|
@trackLeaks('open', 'close')
|
|
63
54
|
export class DataSpace {
|
|
64
55
|
private readonly _ctx = new Context();
|
|
65
|
-
private readonly _dataPipeline: DataPipeline;
|
|
66
56
|
private readonly _inner: Space;
|
|
67
57
|
private readonly _gossip: Gossip;
|
|
68
58
|
private readonly _presence: Presence;
|
|
@@ -72,12 +62,20 @@ export class DataSpace {
|
|
|
72
62
|
private readonly _signingContext: SigningContext;
|
|
73
63
|
private readonly _notarizationPluginConsumer: CredentialConsumer<NotarizationPlugin>;
|
|
74
64
|
private readonly _callbacks: DataSpaceCallbacks;
|
|
65
|
+
private readonly _cache?: SpaceCache;
|
|
75
66
|
|
|
76
67
|
private _state = SpaceState.CLOSED;
|
|
77
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Error for _state === SpaceState.ERROR.
|
|
71
|
+
*/
|
|
72
|
+
public error: Error | undefined = undefined;
|
|
73
|
+
|
|
78
74
|
public readonly authVerifier: TrustedKeySetAuthVerifier;
|
|
79
75
|
public readonly stateUpdate = new Event();
|
|
80
76
|
|
|
77
|
+
public metrics: SpaceProto.Metrics = {};
|
|
78
|
+
|
|
81
79
|
constructor(params: DataSpaceParams) {
|
|
82
80
|
this._inner = params.inner;
|
|
83
81
|
this._inner.stateUpdate.on(this._ctx, () => this.stateUpdate.emit());
|
|
@@ -89,23 +87,15 @@ export class DataSpace {
|
|
|
89
87
|
this._metadataStore = params.metadataStore;
|
|
90
88
|
this._signingContext = params.signingContext;
|
|
91
89
|
this._callbacks = params.callbacks ?? {};
|
|
92
|
-
this._dataPipeline = new DataPipeline({
|
|
93
|
-
modelFactory: params.modelFactory,
|
|
94
|
-
metadataStore: params.metadataStore,
|
|
95
|
-
snapshotManager: params.snapshotManager,
|
|
96
|
-
memberKey: params.memberKey,
|
|
97
|
-
spaceKey: this._inner.key,
|
|
98
|
-
feedInfoProvider: (feedKey) => this._inner.spaceState.feeds.get(feedKey),
|
|
99
|
-
snapshotId: params.snapshotId
|
|
100
|
-
});
|
|
101
90
|
|
|
102
91
|
this.authVerifier = new TrustedKeySetAuthVerifier({
|
|
103
92
|
trustedKeysProvider: () => new ComplexSet(PublicKey.hash, Array.from(this._inner.spaceState.members.keys())),
|
|
104
93
|
update: this._inner.stateUpdate,
|
|
105
|
-
authTimeout: AUTH_TIMEOUT
|
|
94
|
+
authTimeout: AUTH_TIMEOUT,
|
|
106
95
|
});
|
|
107
96
|
|
|
108
97
|
this._notarizationPluginConsumer = this._inner.spaceState.registerProcessor(new NotarizationPlugin());
|
|
98
|
+
this._cache = params.cache;
|
|
109
99
|
}
|
|
110
100
|
|
|
111
101
|
get key() {
|
|
@@ -126,7 +116,7 @@ export class DataSpace {
|
|
|
126
116
|
}
|
|
127
117
|
|
|
128
118
|
get dataPipeline(): DataPipeline {
|
|
129
|
-
return this.
|
|
119
|
+
return this._inner.dataPipeline;
|
|
130
120
|
}
|
|
131
121
|
|
|
132
122
|
get presence() {
|
|
@@ -137,18 +127,22 @@ export class DataSpace {
|
|
|
137
127
|
return this._notarizationPluginConsumer.processor;
|
|
138
128
|
}
|
|
139
129
|
|
|
130
|
+
get cache() {
|
|
131
|
+
return this._cache;
|
|
132
|
+
}
|
|
133
|
+
|
|
140
134
|
async open() {
|
|
141
135
|
await this.notarizationPlugin.open();
|
|
142
136
|
await this._notarizationPluginConsumer.open();
|
|
143
137
|
await this._inner.open();
|
|
144
138
|
this._state = SpaceState.INACTIVE;
|
|
139
|
+
this.metrics.open = new Date();
|
|
145
140
|
}
|
|
146
141
|
|
|
147
142
|
async close() {
|
|
148
143
|
this._state = SpaceState.CLOSED;
|
|
149
144
|
await this._ctx.dispose();
|
|
150
145
|
|
|
151
|
-
await this._dataPipeline.close();
|
|
152
146
|
await this.authVerifier.close();
|
|
153
147
|
|
|
154
148
|
await this._inner.close();
|
|
@@ -172,6 +166,7 @@ export class DataSpace {
|
|
|
172
166
|
initializeDataPipelineAsync() {
|
|
173
167
|
scheduleTask(this._ctx, async () => {
|
|
174
168
|
try {
|
|
169
|
+
this.metrics.pipelineInitBegin = new Date();
|
|
175
170
|
await this.initializeDataPipeline();
|
|
176
171
|
} catch (err) {
|
|
177
172
|
if (err instanceof CancelledError) {
|
|
@@ -180,6 +175,11 @@ export class DataSpace {
|
|
|
180
175
|
}
|
|
181
176
|
|
|
182
177
|
log.error('Error initializing data pipeline', err);
|
|
178
|
+
this._state = SpaceState.ERROR;
|
|
179
|
+
this.error = err as Error;
|
|
180
|
+
this.stateUpdate.emit();
|
|
181
|
+
} finally {
|
|
182
|
+
this.metrics.ready = new Date();
|
|
183
183
|
}
|
|
184
184
|
});
|
|
185
185
|
}
|
|
@@ -193,9 +193,11 @@ export class DataSpace {
|
|
|
193
193
|
// TODO(dmaretskyi): Cancel with context.
|
|
194
194
|
await this._inner.controlPipeline.state.waitUntilReachedTargetTimeframe({
|
|
195
195
|
ctx: this._ctx,
|
|
196
|
-
breakOnStall: false
|
|
196
|
+
breakOnStall: false,
|
|
197
197
|
});
|
|
198
198
|
|
|
199
|
+
this.metrics.controlPipelineReady = new Date();
|
|
200
|
+
|
|
199
201
|
await this._createWritableFeeds();
|
|
200
202
|
log('Writable feeds created');
|
|
201
203
|
this.stateUpdate.emit();
|
|
@@ -203,27 +205,28 @@ export class DataSpace {
|
|
|
203
205
|
this.notarizationPlugin.setWriter(
|
|
204
206
|
createMappedFeedWriter<Credential, FeedMessage.Payload>(
|
|
205
207
|
(credential) => ({
|
|
206
|
-
credential: { credential }
|
|
208
|
+
credential: { credential },
|
|
207
209
|
}),
|
|
208
|
-
this._inner.controlPipeline.writer
|
|
209
|
-
)
|
|
210
|
+
this._inner.controlPipeline.writer,
|
|
211
|
+
),
|
|
210
212
|
);
|
|
211
213
|
|
|
212
|
-
await this.
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
});
|
|
214
|
+
await this._inner.initializeDataPipeline();
|
|
215
|
+
|
|
216
|
+
this.metrics.dataPipelineOpen = new Date();
|
|
217
|
+
|
|
218
|
+
// Wait for the first epoch.
|
|
219
|
+
await cancelWithContext(this._ctx, this._inner.dataPipeline.ensureEpochInitialized());
|
|
219
220
|
|
|
220
221
|
log('waiting for data pipeline to reach target timeframe');
|
|
221
222
|
// Wait for the data pipeline to catch up to its desired timeframe.
|
|
222
|
-
await this.
|
|
223
|
+
await this._inner.dataPipeline.pipelineState!.waitUntilReachedTargetTimeframe({
|
|
223
224
|
ctx: this._ctx,
|
|
224
|
-
breakOnStall: false
|
|
225
|
+
breakOnStall: false,
|
|
225
226
|
});
|
|
226
227
|
|
|
228
|
+
this.metrics.dataPipelineReady = new Date();
|
|
229
|
+
|
|
227
230
|
log('data pipeline ready');
|
|
228
231
|
await this._callbacks.beforeReady?.();
|
|
229
232
|
|
|
@@ -248,9 +251,9 @@ export class DataSpace {
|
|
|
248
251
|
spaceKey: this.key,
|
|
249
252
|
deviceKey: this._signingContext.deviceKey,
|
|
250
253
|
identityKey: this._signingContext.identityKey,
|
|
251
|
-
designation: AdmittedFeed.Designation.CONTROL
|
|
252
|
-
}
|
|
253
|
-
})
|
|
254
|
+
designation: AdmittedFeed.Designation.CONTROL,
|
|
255
|
+
},
|
|
256
|
+
}),
|
|
254
257
|
);
|
|
255
258
|
}
|
|
256
259
|
if (!this.inner.dataFeedKey) {
|
|
@@ -265,9 +268,9 @@ export class DataSpace {
|
|
|
265
268
|
spaceKey: this.key,
|
|
266
269
|
deviceKey: this._signingContext.deviceKey,
|
|
267
270
|
identityKey: this._signingContext.identityKey,
|
|
268
|
-
designation: AdmittedFeed.Designation.DATA
|
|
269
|
-
}
|
|
270
|
-
})
|
|
271
|
+
designation: AdmittedFeed.Designation.DATA,
|
|
272
|
+
},
|
|
273
|
+
}),
|
|
271
274
|
);
|
|
272
275
|
}
|
|
273
276
|
|
|
@@ -279,4 +282,27 @@ export class DataSpace {
|
|
|
279
282
|
// Set this after credentials are notarized so that on failure we will retry.
|
|
280
283
|
await this._metadataStore.setWritableFeedKeys(this.key, this.inner.controlFeedKey!, this.inner.dataFeedKey!);
|
|
281
284
|
}
|
|
285
|
+
|
|
286
|
+
async createEpoch() {
|
|
287
|
+
const epoch = await this.dataPipeline.createEpoch();
|
|
288
|
+
|
|
289
|
+
await this.inner.controlPipeline.writer.write({
|
|
290
|
+
credential: {
|
|
291
|
+
credential: await this._signingContext.credentialSigner.createCredential({
|
|
292
|
+
subject: this.key,
|
|
293
|
+
assertion: {
|
|
294
|
+
'@type': 'dxos.halo.credentials.Epoch',
|
|
295
|
+
...epoch,
|
|
296
|
+
},
|
|
297
|
+
}),
|
|
298
|
+
},
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
for (const feed of this.inner.dataPipeline.pipelineState?.feeds ?? []) {
|
|
302
|
+
const indexBeforeEpoch = epoch.timeframe.get(feed.key);
|
|
303
|
+
if (indexBeforeEpoch) {
|
|
304
|
+
await feed.clear(0, indexBeforeEpoch + 1);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
282
308
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { createCredential } from '@dxos/credentials';
|
|
6
|
+
import { failUndefined } from '@dxos/debug';
|
|
7
|
+
import { Space } from '@dxos/echo-pipeline';
|
|
8
|
+
import { Keyring } from '@dxos/keyring';
|
|
9
|
+
import { AdmittedFeed, SpaceMember } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
10
|
+
import { Timeframe } from '@dxos/timeframe';
|
|
11
|
+
|
|
12
|
+
import { SigningContext } from './data-space-manager';
|
|
13
|
+
|
|
14
|
+
export const spaceGenesis = async (keyring: Keyring, signingContext: SigningContext, space: Space) => {
|
|
15
|
+
// TODO(dmaretskyi): Find a way to reconcile with credential generator.
|
|
16
|
+
const credentials = [
|
|
17
|
+
await createCredential({
|
|
18
|
+
signer: keyring,
|
|
19
|
+
issuer: space.key,
|
|
20
|
+
subject: space.key,
|
|
21
|
+
assertion: {
|
|
22
|
+
'@type': 'dxos.halo.credentials.SpaceGenesis',
|
|
23
|
+
spaceKey: space.key,
|
|
24
|
+
},
|
|
25
|
+
}),
|
|
26
|
+
|
|
27
|
+
await createCredential({
|
|
28
|
+
signer: keyring,
|
|
29
|
+
issuer: space.key,
|
|
30
|
+
subject: signingContext.identityKey,
|
|
31
|
+
assertion: {
|
|
32
|
+
'@type': 'dxos.halo.credentials.SpaceMember',
|
|
33
|
+
spaceKey: space.key,
|
|
34
|
+
role: SpaceMember.Role.ADMIN,
|
|
35
|
+
profile: signingContext.profile,
|
|
36
|
+
genesisFeedKey: space.controlFeedKey ?? failUndefined(),
|
|
37
|
+
},
|
|
38
|
+
}),
|
|
39
|
+
|
|
40
|
+
await signingContext.credentialSigner.createCredential({
|
|
41
|
+
subject: space.controlFeedKey ?? failUndefined(),
|
|
42
|
+
assertion: {
|
|
43
|
+
'@type': 'dxos.halo.credentials.AdmittedFeed',
|
|
44
|
+
spaceKey: space.key,
|
|
45
|
+
identityKey: signingContext.identityKey,
|
|
46
|
+
deviceKey: signingContext.deviceKey,
|
|
47
|
+
designation: AdmittedFeed.Designation.CONTROL,
|
|
48
|
+
},
|
|
49
|
+
}),
|
|
50
|
+
|
|
51
|
+
await signingContext.credentialSigner.createCredential({
|
|
52
|
+
subject: space.dataFeedKey ?? failUndefined(),
|
|
53
|
+
assertion: {
|
|
54
|
+
'@type': 'dxos.halo.credentials.AdmittedFeed',
|
|
55
|
+
spaceKey: space.key,
|
|
56
|
+
identityKey: signingContext.identityKey,
|
|
57
|
+
deviceKey: signingContext.deviceKey,
|
|
58
|
+
designation: AdmittedFeed.Designation.DATA,
|
|
59
|
+
},
|
|
60
|
+
}),
|
|
61
|
+
|
|
62
|
+
await signingContext.credentialSigner.createCredential({
|
|
63
|
+
subject: space.key ?? failUndefined(),
|
|
64
|
+
assertion: {
|
|
65
|
+
'@type': 'dxos.halo.credentials.Epoch',
|
|
66
|
+
number: 0,
|
|
67
|
+
previousId: undefined,
|
|
68
|
+
timeframe: new Timeframe(),
|
|
69
|
+
snapshotCid: undefined,
|
|
70
|
+
},
|
|
71
|
+
}),
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
for (const credential of credentials) {
|
|
75
|
+
await space.controlPipeline.writer.write({
|
|
76
|
+
credential: { credential },
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return credentials;
|
|
81
|
+
};
|
|
@@ -67,11 +67,11 @@ describe('NotarizationPlugin', () => {
|
|
|
67
67
|
const credential = await generator.createFeedAdmission(
|
|
68
68
|
await keyring.createKey(),
|
|
69
69
|
await keyring.createKey(),
|
|
70
|
-
AdmittedFeed.Designation.CONTROL
|
|
70
|
+
AdmittedFeed.Designation.CONTROL,
|
|
71
71
|
);
|
|
72
72
|
|
|
73
73
|
const notarized = peer2.notarizationPlugin.notarize({
|
|
74
|
-
credentials: [credential]
|
|
74
|
+
credentials: [credential],
|
|
75
75
|
});
|
|
76
76
|
|
|
77
77
|
await testBuilder.connect(peer1, peer2);
|
|
@@ -80,12 +80,12 @@ export class NotarizationPlugin implements CredentialProcessor {
|
|
|
80
80
|
credentials,
|
|
81
81
|
timeout = DEFAULT_NOTARIZE_TIMEOUT,
|
|
82
82
|
retryTimeout = DEFAULT_RETRY_TIMEOUT,
|
|
83
|
-
successDelay = DEFAULT_SUCCESS_DELAY
|
|
83
|
+
successDelay = DEFAULT_SUCCESS_DELAY,
|
|
84
84
|
}: NotarizeParams) {
|
|
85
85
|
log('notarize', { credentials });
|
|
86
86
|
assert(
|
|
87
87
|
credentials.every((credential) => credential.id),
|
|
88
|
-
'Credentials must have an id'
|
|
88
|
+
'Credentials must have an id',
|
|
89
89
|
);
|
|
90
90
|
|
|
91
91
|
const errors = new Trigger();
|
|
@@ -94,7 +94,7 @@ export class NotarizationPlugin implements CredentialProcessor {
|
|
|
94
94
|
log.warn('Notarization error', { err });
|
|
95
95
|
void ctx.dispose();
|
|
96
96
|
errors.throw(err);
|
|
97
|
-
}
|
|
97
|
+
},
|
|
98
98
|
});
|
|
99
99
|
opCtx?.onDispose(() => ctx.dispose());
|
|
100
100
|
|
|
@@ -105,12 +105,12 @@ export class NotarizationPlugin implements CredentialProcessor {
|
|
|
105
105
|
() => {
|
|
106
106
|
log.warn('Notarization timeout', {
|
|
107
107
|
timeout,
|
|
108
|
-
peers: Array.from(this._extensions).map((extension) => extension.remotePeerId)
|
|
108
|
+
peers: Array.from(this._extensions).map((extension) => extension.remotePeerId),
|
|
109
109
|
});
|
|
110
110
|
void ctx.dispose();
|
|
111
111
|
errors.throw(new TimeoutError(timeout, 'Notarization timed out'));
|
|
112
112
|
},
|
|
113
|
-
timeout
|
|
113
|
+
timeout,
|
|
114
114
|
);
|
|
115
115
|
}
|
|
116
116
|
|
|
@@ -137,7 +137,7 @@ export class NotarizationPlugin implements CredentialProcessor {
|
|
|
137
137
|
peersTried.add(peer);
|
|
138
138
|
log('try notarizing', { peer: peer.localPeerId, credentialId: credentials.map((credential) => credential.id) });
|
|
139
139
|
await peer.rpc.NotarizationService.notarize({
|
|
140
|
-
credentials: credentials.filter((credential) => !this._processedCredentials.has(credential.id!))
|
|
140
|
+
credentials: credentials.filter((credential) => !this._processedCredentials.has(credential.id!)),
|
|
141
141
|
});
|
|
142
142
|
log('success');
|
|
143
143
|
await sleep(successDelay); // wait before trying with a new peer
|
|
@@ -209,7 +209,7 @@ export class NotarizationPlugin implements CredentialProcessor {
|
|
|
209
209
|
log('extension closed', { peer: extension.localPeerId });
|
|
210
210
|
this._extensions.delete(extension);
|
|
211
211
|
},
|
|
212
|
-
onNotarize: this._onNotarize.bind(this)
|
|
212
|
+
onNotarize: this._onNotarize.bind(this),
|
|
213
213
|
});
|
|
214
214
|
return extension;
|
|
215
215
|
}
|
|
@@ -225,11 +225,11 @@ export class NotarizationTeleportExtension extends RpcExtension<Services, Servic
|
|
|
225
225
|
constructor(private readonly _params: NotarizationTeleportExtensionParams) {
|
|
226
226
|
super({
|
|
227
227
|
requested: {
|
|
228
|
-
NotarizationService: schema.getService('dxos.mesh.teleport.notarization.NotarizationService')
|
|
228
|
+
NotarizationService: schema.getService('dxos.mesh.teleport.notarization.NotarizationService'),
|
|
229
229
|
},
|
|
230
230
|
exposed: {
|
|
231
|
-
NotarizationService: schema.getService('dxos.mesh.teleport.notarization.NotarizationService')
|
|
232
|
-
}
|
|
231
|
+
NotarizationService: schema.getService('dxos.mesh.teleport.notarization.NotarizationService'),
|
|
232
|
+
},
|
|
233
233
|
});
|
|
234
234
|
}
|
|
235
235
|
|
|
@@ -238,8 +238,8 @@ export class NotarizationTeleportExtension extends RpcExtension<Services, Servic
|
|
|
238
238
|
NotarizationService: {
|
|
239
239
|
notarize: async (request) => {
|
|
240
240
|
await this._params.onNotarize(request);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
243
|
};
|
|
244
244
|
}
|
|
245
245
|
|
|
@@ -30,7 +30,7 @@ describe('SpacesService', () => {
|
|
|
30
30
|
async () => {
|
|
31
31
|
await serviceContext.initialized.wait();
|
|
32
32
|
return serviceContext.dataSpaceManager!;
|
|
33
|
-
}
|
|
33
|
+
},
|
|
34
34
|
);
|
|
35
35
|
});
|
|
36
36
|
|
|
@@ -69,7 +69,7 @@ describe('SpacesService', () => {
|
|
|
69
69
|
const existingSpaces = [
|
|
70
70
|
await spacesService.createSpace(),
|
|
71
71
|
await spacesService.createSpace(),
|
|
72
|
-
await spacesService.createSpace()
|
|
72
|
+
await spacesService.createSpace(),
|
|
73
73
|
];
|
|
74
74
|
|
|
75
75
|
const query = spacesService.querySpaces();
|
|
@@ -7,7 +7,9 @@ import { Stream } from '@dxos/codec-protobuf';
|
|
|
7
7
|
import { raise, todo } from '@dxos/debug';
|
|
8
8
|
import { DataServiceSubscriptions, SpaceManager, SpaceNotFoundError } from '@dxos/echo-pipeline';
|
|
9
9
|
import { log } from '@dxos/log';
|
|
10
|
+
import { encodeError } from '@dxos/protocols';
|
|
10
11
|
import {
|
|
12
|
+
CreateEpochRequest,
|
|
11
13
|
PostMessageRequest,
|
|
12
14
|
QueryCredentialsRequest,
|
|
13
15
|
QuerySpacesResponse,
|
|
@@ -16,11 +18,11 @@ import {
|
|
|
16
18
|
SpacesService,
|
|
17
19
|
SubscribeMessagesRequest,
|
|
18
20
|
UpdateSpaceRequest,
|
|
19
|
-
WriteCredentialsRequest
|
|
21
|
+
WriteCredentialsRequest,
|
|
20
22
|
} from '@dxos/protocols/proto/dxos/client/services';
|
|
21
23
|
import { Credential } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
22
24
|
import { GossipMessage } from '@dxos/protocols/proto/dxos/mesh/teleport/gossip';
|
|
23
|
-
import {
|
|
25
|
+
import { Provider, humanize } from '@dxos/util';
|
|
24
26
|
|
|
25
27
|
import { IdentityManager } from '../identity';
|
|
26
28
|
import { DataSpace } from './data-space';
|
|
@@ -36,7 +38,7 @@ export class SpacesServiceImpl implements SpacesService {
|
|
|
36
38
|
private readonly _identityManager: IdentityManager,
|
|
37
39
|
private readonly _spaceManager: SpaceManager,
|
|
38
40
|
private readonly _dataServiceSubscriptions: DataServiceSubscriptions,
|
|
39
|
-
private readonly _getDataSpaceManager: Provider<Promise<DataSpaceManager
|
|
41
|
+
private readonly _getDataSpaceManager: Provider<Promise<DataSpaceManager>>,
|
|
40
42
|
) {}
|
|
41
43
|
|
|
42
44
|
async createSpace(): Promise<Space> {
|
|
@@ -83,7 +85,7 @@ export class SpacesServiceImpl implements SpacesService {
|
|
|
83
85
|
subscriptions.add(
|
|
84
86
|
space.dataPipeline.pipelineState.timeframeUpdate
|
|
85
87
|
.debounce(TIMEFRAME_UPDATE_DEBOUNCE_TIME)
|
|
86
|
-
.on(ctx, onUpdate)
|
|
88
|
+
.on(ctx, onUpdate),
|
|
87
89
|
);
|
|
88
90
|
}
|
|
89
91
|
}
|
|
@@ -130,7 +132,7 @@ export class SpacesServiceImpl implements SpacesService {
|
|
|
130
132
|
const processor = space.spaceState.registerProcessor({
|
|
131
133
|
process: async (credential) => {
|
|
132
134
|
next(credential);
|
|
133
|
-
}
|
|
135
|
+
},
|
|
134
136
|
});
|
|
135
137
|
ctx.onDispose(() => processor.close());
|
|
136
138
|
scheduleTask(ctx, () => processor.open());
|
|
@@ -144,10 +146,17 @@ export class SpacesServiceImpl implements SpacesService {
|
|
|
144
146
|
}
|
|
145
147
|
}
|
|
146
148
|
|
|
149
|
+
async createEpoch({ spaceKey }: CreateEpochRequest) {
|
|
150
|
+
const dataSpaceManager = await this._getDataSpaceManager();
|
|
151
|
+
const space = dataSpaceManager.spaces.get(spaceKey) ?? raise(new SpaceNotFoundError(spaceKey));
|
|
152
|
+
await space.createEpoch();
|
|
153
|
+
}
|
|
154
|
+
|
|
147
155
|
private _transformSpace(space: DataSpace): Space {
|
|
148
156
|
return {
|
|
149
157
|
spaceKey: space.key,
|
|
150
158
|
state: space.state,
|
|
159
|
+
error: space.error ? encodeError(space.error) : undefined,
|
|
151
160
|
pipeline: {
|
|
152
161
|
controlFeeds: space.inner.controlPipeline.state.feeds.map((feed) => feed.key),
|
|
153
162
|
currentControlTimeframe: space.inner.controlPipeline.state.timeframe,
|
|
@@ -157,21 +166,23 @@ export class SpacesServiceImpl implements SpacesService {
|
|
|
157
166
|
dataFeeds: space.dataPipeline.pipelineState?.feeds.map((feed) => feed.key) ?? [],
|
|
158
167
|
currentDataTimeframe: space.dataPipeline.pipelineState?.timeframe,
|
|
159
168
|
targetDataTimeframe: space.dataPipeline.pipelineState?.targetTimeframe,
|
|
160
|
-
totalDataTimeframe: space.dataPipeline.pipelineState?.endTimeframe
|
|
169
|
+
totalDataTimeframe: space.dataPipeline.pipelineState?.endTimeframe,
|
|
161
170
|
},
|
|
162
171
|
members: Array.from(space.inner.spaceState.members.values()).map((member) => ({
|
|
163
172
|
identity: {
|
|
164
173
|
identityKey: member.key,
|
|
165
174
|
profile: {
|
|
166
|
-
displayName: member.assertion.profile?.displayName ?? humanize(member.key)
|
|
167
|
-
}
|
|
175
|
+
displayName: member.assertion.profile?.displayName ?? humanize(member.key),
|
|
176
|
+
},
|
|
168
177
|
},
|
|
169
178
|
presence:
|
|
170
179
|
this._identityManager.identity?.identityKey.equals(member.key) ||
|
|
171
180
|
space.presence.getPeersOnline().filter(({ identityKey }) => identityKey.equals(member.key)).length > 0
|
|
172
181
|
? SpaceMember.PresenceState.ONLINE
|
|
173
|
-
: SpaceMember.PresenceState.OFFLINE
|
|
174
|
-
}))
|
|
182
|
+
: SpaceMember.PresenceState.OFFLINE,
|
|
183
|
+
})),
|
|
184
|
+
cache: space.cache,
|
|
185
|
+
metrics: space.metrics,
|
|
175
186
|
};
|
|
176
187
|
}
|
|
177
188
|
}
|
|
@@ -16,7 +16,7 @@ export const createStorageObjects = (config: Runtime.Client.Storage) => {
|
|
|
16
16
|
path = 'dxos/storage', // TODO(burdon): Factor out const.
|
|
17
17
|
storageType,
|
|
18
18
|
keyStorage,
|
|
19
|
-
persistent = false
|
|
19
|
+
persistent = false,
|
|
20
20
|
} = config ?? {};
|
|
21
21
|
|
|
22
22
|
if (persistent && storageType === StorageDriver.RAM) {
|
|
@@ -35,8 +35,8 @@ export const createStorageObjects = (config: Runtime.Client.Storage) => {
|
|
|
35
35
|
return {
|
|
36
36
|
storage: createStorage({
|
|
37
37
|
type: persistent ? toStorageType(storageType) : StorageType.RAM,
|
|
38
|
-
root: `${path}
|
|
39
|
-
})
|
|
38
|
+
root: `${path}/`,
|
|
39
|
+
}),
|
|
40
40
|
};
|
|
41
41
|
};
|
|
42
42
|
|
|
@@ -9,7 +9,7 @@ import { Credential } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
|
9
9
|
|
|
10
10
|
export const createMockCredential = async ({
|
|
11
11
|
signer,
|
|
12
|
-
issuer
|
|
12
|
+
issuer,
|
|
13
13
|
}: {
|
|
14
14
|
signer: Signer;
|
|
15
15
|
issuer: PublicKey;
|
|
@@ -22,7 +22,7 @@ export const createMockCredential = async ({
|
|
|
22
22
|
'@type': 'example.testing.rpc.MessageWithAny',
|
|
23
23
|
payload: {
|
|
24
24
|
'@type': 'google.protobuf.Any',
|
|
25
|
-
value: Buffer.from('test')
|
|
26
|
-
}
|
|
27
|
-
}
|
|
25
|
+
value: Buffer.from('test'),
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
28
|
});
|