@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.
Files changed (164) hide show
  1. package/dist/lib/browser/{chunk-T73F4MV4.mjs → chunk-IHSMRQ3L.mjs} +985 -867
  2. package/dist/lib/browser/chunk-IHSMRQ3L.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +7 -3
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/lib/browser/packlets/testing/index.mjs +121 -297
  6. package/dist/lib/browser/packlets/testing/index.mjs.map +4 -4
  7. package/dist/lib/node/index.cjs +589 -469
  8. package/dist/lib/node/index.cjs.map +4 -4
  9. package/dist/lib/node/meta.json +1 -1
  10. package/dist/lib/node/packlets/testing/index.cjs +688 -740
  11. package/dist/lib/node/packlets/testing/index.cjs.map +4 -4
  12. package/dist/types/src/index.d.ts +1 -0
  13. package/dist/types/src/index.d.ts.map +1 -1
  14. package/dist/types/src/packlets/devices/devices-service.d.ts +1 -1
  15. package/dist/types/src/packlets/devices/devices-service.d.ts.map +1 -1
  16. package/dist/types/src/packlets/devtools/devtools.d.ts +4 -2
  17. package/dist/types/src/packlets/devtools/devtools.d.ts.map +1 -1
  18. package/dist/types/src/packlets/devtools/keys.d.ts.map +1 -1
  19. package/dist/types/src/packlets/devtools/network.d.ts +5 -4
  20. package/dist/types/src/packlets/devtools/network.d.ts.map +1 -1
  21. package/dist/types/src/packlets/identity/authenticator.d.ts +1 -1
  22. package/dist/types/src/packlets/identity/authenticator.d.ts.map +1 -1
  23. package/dist/types/src/packlets/identity/identity-manager.d.ts +2 -4
  24. package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
  25. package/dist/types/src/packlets/identity/identity.d.ts +1 -1
  26. package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
  27. package/dist/types/src/packlets/invitations/invitation-extension.d.ts +2 -3
  28. package/dist/types/src/packlets/invitations/invitation-extension.d.ts.map +1 -1
  29. package/dist/types/src/packlets/invitations/invitations-handler.d.ts +1 -3
  30. package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
  31. package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts +1 -2
  32. package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts.map +1 -1
  33. package/dist/types/src/packlets/network/network-service.d.ts +6 -4
  34. package/dist/types/src/packlets/network/network-service.d.ts.map +1 -1
  35. package/dist/types/src/packlets/services/client-rpc-server.d.ts +2 -2
  36. package/dist/types/src/packlets/services/client-rpc-server.d.ts.map +1 -1
  37. package/dist/types/src/packlets/services/index.d.ts +0 -1
  38. package/dist/types/src/packlets/services/index.d.ts.map +1 -1
  39. package/dist/types/src/packlets/services/local-client-services.d.ts +1 -1
  40. package/dist/types/src/packlets/services/local-client-services.d.ts.map +1 -1
  41. package/dist/types/src/packlets/services/service-context.d.ts +4 -2
  42. package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
  43. package/dist/types/src/packlets/services/service-host.d.ts +16 -9
  44. package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
  45. package/dist/types/src/packlets/spaces/data-space-manager.d.ts +12 -7
  46. package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
  47. package/dist/types/src/packlets/spaces/data-space.d.ts +15 -10
  48. package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
  49. package/dist/types/src/packlets/spaces/genesis.d.ts +5 -0
  50. package/dist/types/src/packlets/spaces/genesis.d.ts.map +1 -0
  51. package/dist/types/src/packlets/spaces/notarization-plugin.d.ts +4 -4
  52. package/dist/types/src/packlets/spaces/notarization-plugin.d.ts.map +1 -1
  53. package/dist/types/src/packlets/spaces/spaces-service.d.ts +2 -1
  54. package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
  55. package/dist/types/src/packlets/system/system-service.d.ts +1 -1
  56. package/dist/types/src/packlets/system/system-service.d.ts.map +1 -1
  57. package/dist/types/src/packlets/testing/credential-utils.d.ts +1 -1
  58. package/dist/types/src/packlets/testing/index.d.ts +0 -1
  59. package/dist/types/src/packlets/testing/index.d.ts.map +1 -1
  60. package/dist/types/src/packlets/testing/invitation-utils.d.ts +13 -7
  61. package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -1
  62. package/dist/types/src/packlets/testing/test-builder.d.ts +35 -32
  63. package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
  64. package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts +1 -1
  65. package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts.map +1 -1
  66. package/dist/types/src/packlets/vault/iframe-proxy-runtime.d.ts +5 -2
  67. package/dist/types/src/packlets/vault/iframe-proxy-runtime.d.ts.map +1 -1
  68. package/dist/types/src/packlets/vault/vault-resource-lock.d.ts +1 -1
  69. package/dist/types/src/packlets/vault/vault-resource-lock.d.ts.map +1 -1
  70. package/dist/types/src/packlets/vault/worker-runtime.d.ts +1 -1
  71. package/dist/types/src/packlets/vault/worker-runtime.d.ts.map +1 -1
  72. package/dist/types/src/packlets/vault/worker-session.d.ts +4 -7
  73. package/dist/types/src/packlets/vault/worker-session.d.ts.map +1 -1
  74. package/package.json +30 -31
  75. package/src/index.ts +1 -0
  76. package/src/packlets/devices/devices-service.ts +5 -5
  77. package/src/packlets/devtools/devtools.ts +25 -4
  78. package/src/packlets/devtools/feeds.ts +10 -10
  79. package/src/packlets/devtools/keys.ts +6 -6
  80. package/src/packlets/devtools/network.ts +14 -13
  81. package/src/packlets/devtools/spaces.ts +4 -4
  82. package/src/packlets/identity/authenticator.test.ts +1 -1
  83. package/src/packlets/identity/authenticator.ts +2 -2
  84. package/src/packlets/identity/identity-manager.test.ts +17 -13
  85. package/src/packlets/identity/identity-manager.ts +21 -22
  86. package/src/packlets/identity/identity-service.ts +3 -3
  87. package/src/packlets/identity/identity.test.ts +65 -36
  88. package/src/packlets/identity/identity.ts +17 -17
  89. package/src/packlets/invitations/device-invitation-protocol.test.ts +1 -1
  90. package/src/packlets/invitations/device-invitation-protocol.ts +7 -7
  91. package/src/packlets/invitations/invitation-extension.ts +16 -27
  92. package/src/packlets/invitations/invitations-handler.ts +17 -25
  93. package/src/packlets/invitations/invitations-service.ts +11 -11
  94. package/src/packlets/invitations/space-invitation-protocol.test.ts +9 -9
  95. package/src/packlets/invitations/space-invitation-protocol.ts +11 -12
  96. package/src/packlets/logging/logging-service.ts +8 -3
  97. package/src/packlets/network/network-service.test.ts +8 -8
  98. package/src/packlets/network/network-service.ts +20 -8
  99. package/src/packlets/services/client-rpc-server.ts +5 -5
  100. package/src/packlets/services/index.ts +0 -1
  101. package/src/packlets/services/local-client-services.ts +1 -1
  102. package/src/packlets/services/service-context.test.ts +3 -3
  103. package/src/packlets/services/service-context.ts +26 -24
  104. package/src/packlets/services/service-host.test.ts +6 -6
  105. package/src/packlets/services/service-host.ts +57 -31
  106. package/src/packlets/services/service-registry.test.ts +20 -38
  107. package/src/packlets/spaces/data-space-manager.test.ts +17 -29
  108. package/src/packlets/spaces/data-space-manager.ts +29 -35
  109. package/src/packlets/spaces/data-space.ts +73 -47
  110. package/src/packlets/spaces/genesis.ts +81 -0
  111. package/src/packlets/spaces/notarization-plugin.test.ts +2 -2
  112. package/src/packlets/spaces/notarization-plugin.ts +12 -12
  113. package/src/packlets/spaces/spaces-service.test.ts +2 -2
  114. package/src/packlets/spaces/spaces-service.ts +21 -10
  115. package/src/packlets/storage/storage.ts +3 -3
  116. package/src/packlets/system/system-service.test.ts +1 -1
  117. package/src/packlets/system/system-service.ts +1 -1
  118. package/src/packlets/testing/credential-utils.ts +4 -4
  119. package/src/packlets/testing/index.ts +0 -1
  120. package/src/packlets/testing/invitation-utils.ts +28 -33
  121. package/src/packlets/testing/test-builder.ts +132 -168
  122. package/src/packlets/vault/iframe-host-runtime.ts +8 -11
  123. package/src/packlets/vault/iframe-proxy-runtime.ts +25 -9
  124. package/src/packlets/vault/shell-runtime.ts +4 -4
  125. package/src/packlets/vault/vault-resource-lock.ts +2 -2
  126. package/src/packlets/vault/worker-runtime.ts +7 -9
  127. package/src/packlets/vault/worker-session.ts +24 -45
  128. package/dist/lib/browser/chunk-T73F4MV4.mjs.map +0 -7
  129. package/dist/types/src/packlets/services/utils.d.ts +0 -7
  130. package/dist/types/src/packlets/services/utils.d.ts.map +0 -1
  131. package/dist/types/src/packlets/testing/host-test-builder.d.ts +0 -43
  132. package/dist/types/src/packlets/testing/host-test-builder.d.ts.map +0 -1
  133. package/dist/types/src/packlets/tests/client-services.test.d.ts +0 -2
  134. package/dist/types/src/packlets/tests/client-services.test.d.ts.map +0 -1
  135. package/dist/types/src/packlets/tests/client.test.d.ts +0 -2
  136. package/dist/types/src/packlets/tests/client.test.d.ts.map +0 -1
  137. package/dist/types/src/packlets/tests/halo-credentials.test.d.ts +0 -2
  138. package/dist/types/src/packlets/tests/halo-credentials.test.d.ts.map +0 -1
  139. package/dist/types/src/packlets/tests/halo-persistent.test.d.ts +0 -2
  140. package/dist/types/src/packlets/tests/halo-persistent.test.d.ts.map +0 -1
  141. package/dist/types/src/packlets/tests/halo-profile.test.d.ts +0 -2
  142. package/dist/types/src/packlets/tests/halo-profile.test.d.ts.map +0 -1
  143. package/dist/types/src/packlets/tests/invitations.test.d.ts +0 -2
  144. package/dist/types/src/packlets/tests/invitations.test.d.ts.map +0 -1
  145. package/dist/types/src/packlets/tests/shared-worker.test.d.ts +0 -2
  146. package/dist/types/src/packlets/tests/shared-worker.test.d.ts.map +0 -1
  147. package/dist/types/src/packlets/tests/spaces-invitations.test.d.ts +0 -2
  148. package/dist/types/src/packlets/tests/spaces-invitations.test.d.ts.map +0 -1
  149. package/dist/types/src/packlets/tests/spaces.test.d.ts +0 -2
  150. package/dist/types/src/packlets/tests/spaces.test.d.ts.map +0 -1
  151. package/dist/types/src/packlets/tests/text.test.d.ts +0 -2
  152. package/dist/types/src/packlets/tests/text.test.d.ts.map +0 -1
  153. package/src/packlets/services/utils.ts +0 -53
  154. package/src/packlets/testing/host-test-builder.ts +0 -163
  155. package/src/packlets/tests/client-services.test.ts +0 -222
  156. package/src/packlets/tests/client.test.ts +0 -140
  157. package/src/packlets/tests/halo-credentials.test.ts +0 -94
  158. package/src/packlets/tests/halo-persistent.test.ts +0 -53
  159. package/src/packlets/tests/halo-profile.test.ts +0 -48
  160. package/src/packlets/tests/invitations.test.ts +0 -389
  161. package/src/packlets/tests/shared-worker.test.ts +0 -92
  162. package/src/packlets/tests/spaces-invitations.test.ts +0 -46
  163. package/src/packlets/tests/spaces.test.ts +0 -147
  164. 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 { SpaceState } from '@dxos/client';
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 { ModelFactory } from '@dxos/model-factory';
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._dataPipeline;
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._dataPipeline.open({
213
- openPipeline: async (start) => {
214
- const pipeline = await this._inner.createDataPipeline({ start });
215
- await pipeline.start();
216
- return pipeline;
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._dataPipeline.pipelineState!.waitUntilReachedTargetTimeframe({
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 { humanize, Provider } from '@dxos/util';
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
 
@@ -40,7 +40,7 @@ describe('SystemService', () => {
40
40
  },
41
41
  onReset: () => {
42
42
  reset.wake(true);
43
- }
43
+ },
44
44
  });
45
45
  });
46
46
 
@@ -9,7 +9,7 @@ import {
9
9
  SystemStatus,
10
10
  SystemStatusResponse,
11
11
  SystemService,
12
- UpdateSystemStatusRequest
12
+ UpdateSystemStatusRequest,
13
13
  } from '@dxos/protocols/proto/dxos/client/services';
14
14
  import { MaybePromise } from '@dxos/util';
15
15
 
@@ -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
  });
@@ -3,6 +3,5 @@
3
3
  //
4
4
 
5
5
  export * from './credential-utils';
6
- export * from './host-test-builder';
7
6
  export * from './invitation-utils';
8
7
  export * from './test-builder';