@dxos/client-services 0.1.0

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 (199) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +20 -0
  3. package/dist/src/errors.d.ts +8 -0
  4. package/dist/src/errors.d.ts.map +1 -0
  5. package/dist/src/errors.js +21 -0
  6. package/dist/src/errors.js.map +1 -0
  7. package/dist/src/index.d.ts +7 -0
  8. package/dist/src/index.d.ts.map +1 -0
  9. package/dist/src/index.js +26 -0
  10. package/dist/src/index.js.map +1 -0
  11. package/dist/src/packlets/devtools/devtools-host-events.d.ts +5 -0
  12. package/dist/src/packlets/devtools/devtools-host-events.d.ts.map +1 -0
  13. package/dist/src/packlets/devtools/devtools-host-events.js +14 -0
  14. package/dist/src/packlets/devtools/devtools-host-events.js.map +1 -0
  15. package/dist/src/packlets/devtools/feeds.d.ts +11 -0
  16. package/dist/src/packlets/devtools/feeds.d.ts.map +1 -0
  17. package/dist/src/packlets/devtools/feeds.js +72 -0
  18. package/dist/src/packlets/devtools/feeds.js.map +1 -0
  19. package/dist/src/packlets/devtools/index.d.ts +5 -0
  20. package/dist/src/packlets/devtools/index.d.ts.map +1 -0
  21. package/dist/src/packlets/devtools/index.js +24 -0
  22. package/dist/src/packlets/devtools/index.js.map +1 -0
  23. package/dist/src/packlets/devtools/network.d.ts +19 -0
  24. package/dist/src/packlets/devtools/network.d.ts.map +1 -0
  25. package/dist/src/packlets/devtools/network.js +79 -0
  26. package/dist/src/packlets/devtools/network.js.map +1 -0
  27. package/dist/src/packlets/devtools/spaces.d.ts +5 -0
  28. package/dist/src/packlets/devtools/spaces.d.ts.map +1 -0
  29. package/dist/src/packlets/devtools/spaces.js +38 -0
  30. package/dist/src/packlets/devtools/spaces.js.map +1 -0
  31. package/dist/src/packlets/identity/authenticator.d.ts +7 -0
  32. package/dist/src/packlets/identity/authenticator.d.ts.map +1 -0
  33. package/dist/src/packlets/identity/authenticator.js +40 -0
  34. package/dist/src/packlets/identity/authenticator.js.map +1 -0
  35. package/dist/src/packlets/identity/authenticator.test.d.ts +2 -0
  36. package/dist/src/packlets/identity/authenticator.test.d.ts.map +1 -0
  37. package/dist/src/packlets/identity/authenticator.test.js +32 -0
  38. package/dist/src/packlets/identity/authenticator.test.js.map +1 -0
  39. package/dist/src/packlets/identity/identity-manager.d.ts +35 -0
  40. package/dist/src/packlets/identity/identity-manager.d.ts.map +1 -0
  41. package/dist/src/packlets/identity/identity-manager.js +151 -0
  42. package/dist/src/packlets/identity/identity-manager.js.map +1 -0
  43. package/dist/src/packlets/identity/identity-manager.test.d.ts +2 -0
  44. package/dist/src/packlets/identity/identity-manager.test.d.ts.map +1 -0
  45. package/dist/src/packlets/identity/identity-manager.test.js +92 -0
  46. package/dist/src/packlets/identity/identity-manager.test.js.map +1 -0
  47. package/dist/src/packlets/identity/identity.d.ts +43 -0
  48. package/dist/src/packlets/identity/identity.d.ts.map +1 -0
  49. package/dist/src/packlets/identity/identity.js +74 -0
  50. package/dist/src/packlets/identity/identity.js.map +1 -0
  51. package/dist/src/packlets/identity/identity.test.d.ts +2 -0
  52. package/dist/src/packlets/identity/identity.test.d.ts.map +1 -0
  53. package/dist/src/packlets/identity/identity.test.js +258 -0
  54. package/dist/src/packlets/identity/identity.test.js.map +1 -0
  55. package/dist/src/packlets/identity/index.d.ts +4 -0
  56. package/dist/src/packlets/identity/index.d.ts.map +1 -0
  57. package/dist/src/packlets/identity/index.js +23 -0
  58. package/dist/src/packlets/identity/index.js.map +1 -0
  59. package/dist/src/packlets/invitations/common.d.ts +35 -0
  60. package/dist/src/packlets/invitations/common.d.ts.map +1 -0
  61. package/dist/src/packlets/invitations/common.js +12 -0
  62. package/dist/src/packlets/invitations/common.js.map +1 -0
  63. package/dist/src/packlets/invitations/halo-invitations.d.ts +23 -0
  64. package/dist/src/packlets/invitations/halo-invitations.d.ts.map +1 -0
  65. package/dist/src/packlets/invitations/halo-invitations.js +150 -0
  66. package/dist/src/packlets/invitations/halo-invitations.js.map +1 -0
  67. package/dist/src/packlets/invitations/index.d.ts +5 -0
  68. package/dist/src/packlets/invitations/index.d.ts.map +1 -0
  69. package/dist/src/packlets/invitations/index.js +24 -0
  70. package/dist/src/packlets/invitations/index.js.map +1 -0
  71. package/dist/src/packlets/invitations/invitation-wrapper.d.ts +36 -0
  72. package/dist/src/packlets/invitations/invitation-wrapper.d.ts.map +1 -0
  73. package/dist/src/packlets/invitations/invitation-wrapper.js +104 -0
  74. package/dist/src/packlets/invitations/invitation-wrapper.js.map +1 -0
  75. package/dist/src/packlets/invitations/observable.test.d.ts +2 -0
  76. package/dist/src/packlets/invitations/observable.test.d.ts.map +1 -0
  77. package/dist/src/packlets/invitations/observable.test.js +43 -0
  78. package/dist/src/packlets/invitations/observable.test.js.map +1 -0
  79. package/dist/src/packlets/invitations/space-invitations.d.ts +25 -0
  80. package/dist/src/packlets/invitations/space-invitations.d.ts.map +1 -0
  81. package/dist/src/packlets/invitations/space-invitations.js +136 -0
  82. package/dist/src/packlets/invitations/space-invitations.js.map +1 -0
  83. package/dist/src/packlets/services/impl/devtools.d.ts +34 -0
  84. package/dist/src/packlets/services/impl/devtools.d.ts.map +1 -0
  85. package/dist/src/packlets/services/impl/devtools.js +77 -0
  86. package/dist/src/packlets/services/impl/devtools.js.map +1 -0
  87. package/dist/src/packlets/services/impl/halo.d.ts +20 -0
  88. package/dist/src/packlets/services/impl/halo.d.ts.map +1 -0
  89. package/dist/src/packlets/services/impl/halo.js +93 -0
  90. package/dist/src/packlets/services/impl/halo.js.map +1 -0
  91. package/dist/src/packlets/services/impl/index.d.ts +6 -0
  92. package/dist/src/packlets/services/impl/index.d.ts.map +1 -0
  93. package/dist/src/packlets/services/impl/index.js +26 -0
  94. package/dist/src/packlets/services/impl/index.js.map +1 -0
  95. package/dist/src/packlets/services/impl/party.d.ts +25 -0
  96. package/dist/src/packlets/services/impl/party.d.ts.map +1 -0
  97. package/dist/src/packlets/services/impl/party.js +265 -0
  98. package/dist/src/packlets/services/impl/party.js.map +1 -0
  99. package/dist/src/packlets/services/impl/profile.d.ts +19 -0
  100. package/dist/src/packlets/services/impl/profile.d.ts.map +1 -0
  101. package/dist/src/packlets/services/impl/profile.js +120 -0
  102. package/dist/src/packlets/services/impl/profile.js.map +1 -0
  103. package/dist/src/packlets/services/impl/system.d.ts +9 -0
  104. package/dist/src/packlets/services/impl/system.d.ts.map +1 -0
  105. package/dist/src/packlets/services/impl/system.js +20 -0
  106. package/dist/src/packlets/services/impl/system.js.map +1 -0
  107. package/dist/src/packlets/services/impl/tracing.d.ts +12 -0
  108. package/dist/src/packlets/services/impl/tracing.d.ts.map +1 -0
  109. package/dist/src/packlets/services/impl/tracing.js +22 -0
  110. package/dist/src/packlets/services/impl/tracing.js.map +1 -0
  111. package/dist/src/packlets/services/index.d.ts +6 -0
  112. package/dist/src/packlets/services/index.d.ts.map +1 -0
  113. package/dist/src/packlets/services/index.js +25 -0
  114. package/dist/src/packlets/services/index.js.map +1 -0
  115. package/dist/src/packlets/services/service-context.d.ts +36 -0
  116. package/dist/src/packlets/services/service-context.d.ts.map +1 -0
  117. package/dist/src/packlets/services/service-context.js +112 -0
  118. package/dist/src/packlets/services/service-context.js.map +1 -0
  119. package/dist/src/packlets/services/service-factory.d.ts +15 -0
  120. package/dist/src/packlets/services/service-factory.d.ts.map +1 -0
  121. package/dist/src/packlets/services/service-factory.js +25 -0
  122. package/dist/src/packlets/services/service-factory.js.map +1 -0
  123. package/dist/src/packlets/services/service-host.d.ts +27 -0
  124. package/dist/src/packlets/services/service-host.d.ts.map +1 -0
  125. package/dist/src/packlets/services/service-host.js +78 -0
  126. package/dist/src/packlets/services/service-host.js.map +1 -0
  127. package/dist/src/packlets/services/service-host.test.d.ts +2 -0
  128. package/dist/src/packlets/services/service-host.test.d.ts.map +1 -0
  129. package/dist/src/packlets/services/service-host.test.js +78 -0
  130. package/dist/src/packlets/services/service-host.test.js.map +1 -0
  131. package/dist/src/packlets/services/services.d.ts +19 -0
  132. package/dist/src/packlets/services/services.d.ts.map +1 -0
  133. package/dist/src/packlets/services/services.js +19 -0
  134. package/dist/src/packlets/services/services.js.map +1 -0
  135. package/dist/src/packlets/services/signer.d.ts +9 -0
  136. package/dist/src/packlets/services/signer.d.ts.map +1 -0
  137. package/dist/src/packlets/services/signer.js +6 -0
  138. package/dist/src/packlets/services/signer.js.map +1 -0
  139. package/dist/src/packlets/services/testing/halo.test.d.ts +2 -0
  140. package/dist/src/packlets/services/testing/halo.test.d.ts.map +1 -0
  141. package/dist/src/packlets/services/testing/halo.test.js +34 -0
  142. package/dist/src/packlets/services/testing/halo.test.js.map +1 -0
  143. package/dist/src/packlets/services/testing/spaces.test.d.ts +2 -0
  144. package/dist/src/packlets/services/testing/spaces.test.d.ts.map +1 -0
  145. package/dist/src/packlets/services/testing/spaces.test.js +68 -0
  146. package/dist/src/packlets/services/testing/spaces.test.js.map +1 -0
  147. package/dist/src/packlets/services/testing/testing.d.ts +8 -0
  148. package/dist/src/packlets/services/testing/testing.d.ts.map +1 -0
  149. package/dist/src/packlets/services/testing/testing.js +23 -0
  150. package/dist/src/packlets/services/testing/testing.js.map +1 -0
  151. package/dist/src/packlets/storage/index.d.ts +2 -0
  152. package/dist/src/packlets/storage/index.d.ts.map +1 -0
  153. package/dist/src/packlets/storage/index.js +21 -0
  154. package/dist/src/packlets/storage/index.js.map +1 -0
  155. package/dist/src/packlets/storage/storage.d.ts +7 -0
  156. package/dist/src/packlets/storage/storage.d.ts.map +1 -0
  157. package/dist/src/packlets/storage/storage.js +89 -0
  158. package/dist/src/packlets/storage/storage.js.map +1 -0
  159. package/package.json +61 -0
  160. package/src/errors.ts +19 -0
  161. package/src/index.ts +11 -0
  162. package/src/packlets/devtools/devtools-host-events.ts +8 -0
  163. package/src/packlets/devtools/feeds.ts +91 -0
  164. package/src/packlets/devtools/index.ts +8 -0
  165. package/src/packlets/devtools/network.ts +89 -0
  166. package/src/packlets/devtools/spaces.ts +50 -0
  167. package/src/packlets/identity/authenticator.test.ts +32 -0
  168. package/src/packlets/identity/authenticator.ts +49 -0
  169. package/src/packlets/identity/identity-manager.test.ts +121 -0
  170. package/src/packlets/identity/identity-manager.ts +207 -0
  171. package/src/packlets/identity/identity.test.ts +295 -0
  172. package/src/packlets/identity/identity.ts +109 -0
  173. package/src/packlets/identity/index.ts +7 -0
  174. package/src/packlets/invitations/common.ts +48 -0
  175. package/src/packlets/invitations/halo-invitations.ts +162 -0
  176. package/src/packlets/invitations/index.ts +8 -0
  177. package/src/packlets/invitations/invitation-wrapper.ts +140 -0
  178. package/src/packlets/invitations/observable.test.ts +67 -0
  179. package/src/packlets/invitations/space-invitations.ts +159 -0
  180. package/src/packlets/services/impl/devtools.ts +141 -0
  181. package/src/packlets/services/impl/halo.ts +107 -0
  182. package/src/packlets/services/impl/index.ts +11 -0
  183. package/src/packlets/services/impl/party.ts +305 -0
  184. package/src/packlets/services/impl/profile.ts +141 -0
  185. package/src/packlets/services/impl/system.ts +19 -0
  186. package/src/packlets/services/impl/tracing.ts +21 -0
  187. package/src/packlets/services/index.ts +9 -0
  188. package/src/packlets/services/service-context.ts +151 -0
  189. package/src/packlets/services/service-factory.ts +35 -0
  190. package/src/packlets/services/service-host.test.ts +88 -0
  191. package/src/packlets/services/service-host.ts +101 -0
  192. package/src/packlets/services/services.ts +39 -0
  193. package/src/packlets/services/signer.ts +13 -0
  194. package/src/packlets/services/testing/halo.test.ts +40 -0
  195. package/src/packlets/services/testing/spaces.test.ts +87 -0
  196. package/src/packlets/services/testing/testing.ts +28 -0
  197. package/src/packlets/storage/index.ts +5 -0
  198. package/src/packlets/storage/storage.ts +97 -0
  199. package/src/typings.d.ts +5 -0
@@ -0,0 +1,141 @@
1
+ //
2
+ // Copyright 2022 DXOS.org
3
+ //
4
+
5
+ import { Stream } from '@dxos/codec-protobuf';
6
+ import { Config } from '@dxos/config';
7
+ import { todo } from '@dxos/debug';
8
+ import {
9
+ ClearSnapshotsRequest,
10
+ DevtoolsHost,
11
+ EnableDebugLoggingRequest,
12
+ EnableDebugLoggingResponse,
13
+ Event,
14
+ GetConfigResponse,
15
+ GetNetworkPeersRequest,
16
+ GetNetworkPeersResponse,
17
+ GetPartySnapshotRequest,
18
+ GetPartySnapshotResponse,
19
+ ResetStorageRequest,
20
+ SavePartySnapshotRequest,
21
+ SavePartySnapshotResponse,
22
+ SubscribeToCredentialMessagesRequest,
23
+ SubscribeToCredentialMessagesResponse,
24
+ SubscribeToFeedBlocksRequest,
25
+ SubscribeToFeedBlocksResponse,
26
+ SubscribeToFeedsRequest,
27
+ SubscribeToFeedsResponse,
28
+ SubscribeToItemsRequest,
29
+ SubscribeToItemsResponse,
30
+ SubscribeToKeyringKeysRequest,
31
+ SubscribeToKeyringKeysResponse,
32
+ SubscribeToNetworkTopicsResponse,
33
+ SubscribeToPartiesRequest,
34
+ SubscribeToPartiesResponse,
35
+ SubscribeToSignalStatusResponse,
36
+ SubscribeToSignalTraceResponse,
37
+ SubscribeToSwarmInfoResponse
38
+ } from '@dxos/protocols/proto/dxos/devtools/host';
39
+
40
+ import {
41
+ DevtoolsHostEvents,
42
+ subscribeToNetworkStatus,
43
+ subscribeToSignalTrace,
44
+ subscribeToSwarmInfo,
45
+ subscribeToSpaces,
46
+ subscribeToFeedBlocks,
47
+ subscribeToFeeds
48
+ } from '../../devtools';
49
+ import { ServiceContext } from '../service-context';
50
+
51
+ export type DevtoolsServiceParams = {
52
+ events: DevtoolsHostEvents;
53
+ config: Config;
54
+ context: ServiceContext;
55
+ };
56
+
57
+ export class DevtoolsService implements DevtoolsHost {
58
+ constructor(private readonly params: DevtoolsServiceParams) {}
59
+
60
+ events(request: void): Stream<Event> {
61
+ return new Stream<Event>(({ next }) => {
62
+ this.params.events.ready.on(() => {
63
+ next({ ready: {} });
64
+ });
65
+ });
66
+ }
67
+
68
+ getConfig(request: void): Promise<GetConfigResponse> {
69
+ todo();
70
+ }
71
+
72
+ resetStorage(request: ResetStorageRequest): Promise<void> {
73
+ todo();
74
+ }
75
+
76
+ enableDebugLogging(request: EnableDebugLoggingRequest): Promise<EnableDebugLoggingResponse> {
77
+ todo();
78
+ }
79
+
80
+ disableDebugLogging(request: EnableDebugLoggingRequest): Promise<EnableDebugLoggingResponse> {
81
+ todo();
82
+ }
83
+
84
+ subscribeToKeyringKeys(request: SubscribeToKeyringKeysRequest): Stream<SubscribeToKeyringKeysResponse> {
85
+ todo();
86
+ }
87
+
88
+ subscribeToCredentialMessages(
89
+ request: SubscribeToCredentialMessagesRequest
90
+ ): Stream<SubscribeToCredentialMessagesResponse> {
91
+ todo();
92
+ }
93
+
94
+ subscribeToParties(request: SubscribeToPartiesRequest): Stream<SubscribeToPartiesResponse> {
95
+ return subscribeToSpaces(this.params.context, request);
96
+ }
97
+
98
+ subscribeToItems(request: SubscribeToItemsRequest): Stream<SubscribeToItemsResponse> {
99
+ todo();
100
+ }
101
+
102
+ subscribeToFeeds(request: SubscribeToFeedsRequest): Stream<SubscribeToFeedsResponse> {
103
+ return subscribeToFeeds({ feedStore: this.params.context.feedStore }, request);
104
+ }
105
+
106
+ subscribeToFeedBlocks(request: SubscribeToFeedBlocksRequest): Stream<SubscribeToFeedBlocksResponse> {
107
+ return subscribeToFeedBlocks({ feedStore: this.params.context.feedStore }, request);
108
+ }
109
+
110
+ getPartySnapshot(request: GetPartySnapshotRequest): Promise<GetPartySnapshotResponse> {
111
+ todo();
112
+ }
113
+
114
+ savePartySnapshot(request: SavePartySnapshotRequest): Promise<SavePartySnapshotResponse> {
115
+ todo();
116
+ }
117
+
118
+ clearSnapshots(request: ClearSnapshotsRequest): Promise<void> {
119
+ todo();
120
+ }
121
+
122
+ getNetworkPeers(request: GetNetworkPeersRequest): Promise<GetNetworkPeersResponse> {
123
+ todo();
124
+ }
125
+
126
+ subscribeToNetworkTopics(request: void): Stream<SubscribeToNetworkTopicsResponse> {
127
+ todo();
128
+ }
129
+
130
+ subscribeToSignalStatus(request: void): Stream<SubscribeToSignalStatusResponse> {
131
+ return subscribeToNetworkStatus({ networkManager: this.params.context.networkManager });
132
+ }
133
+
134
+ subscribeToSignalTrace(): Stream<SubscribeToSignalTraceResponse> {
135
+ return subscribeToSignalTrace({ networkManager: this.params.context.networkManager });
136
+ }
137
+
138
+ subscribeToSwarmInfo(): Stream<SubscribeToSwarmInfoResponse> {
139
+ return subscribeToSwarmInfo({ networkManager: this.params.context.networkManager });
140
+ }
141
+ }
@@ -0,0 +1,107 @@
1
+ //
2
+ // Copyright 2022 DXOS.org
3
+ //
4
+
5
+ import assert from 'node:assert';
6
+
7
+ import { EventSubscriptions } from '@dxos/async';
8
+ import { Stream } from '@dxos/codec-protobuf';
9
+ import { ObjectModel } from '@dxos/object-model';
10
+ import {
11
+ AddKeyRecordRequest,
12
+ Contacts,
13
+ HaloService as HaloServiceRpc,
14
+ SignRequest,
15
+ SignResponse,
16
+ SetPreferenceRequest,
17
+ GetPreferenceRequest,
18
+ GetPreferenceResponse
19
+ } from '@dxos/protocols/proto/dxos/client';
20
+
21
+ import { HaloSigner } from '../signer';
22
+
23
+ /**
24
+ * HALO service implementation.
25
+ */
26
+ export class HaloService implements HaloServiceRpc {
27
+ constructor(
28
+ private readonly echo: any, // TODO(burdon): Remove.
29
+ private readonly signer?: HaloSigner
30
+ ) {}
31
+
32
+ // TODO(burdon): Rename signMessage? (in interface).
33
+ // TODO(burdon): Why is this part of the interface? (Can it be factored out completely?)
34
+ async sign(request: SignRequest): Promise<SignResponse> {
35
+ assert(this.signer, 'Signer not set.');
36
+ assert(request.publicKey, 'Provide a public_key of the key that should be used for signing.');
37
+ const key = await this.echo.halo.keyring.getFullKey(request.publicKey);
38
+ assert(key, `Key not found: ${request.publicKey.toHex()}`);
39
+ return this.signer.sign(request, key);
40
+ }
41
+
42
+ async addKeyRecord(request: AddKeyRecordRequest): Promise<void> {
43
+ assert(request.keyRecord && request.keyRecord.publicKey, 'Missing key record.');
44
+ await this.echo.halo.keyring.addKeyRecord(request.keyRecord);
45
+ assert(await this.echo.halo.keyring.getKey(request.keyRecord.publicKey), 'Key not inserted correctly.');
46
+ }
47
+
48
+ // TODO(burdon): subscribeToContacts or just query/contacts with subscription object.
49
+ // ResultSet vs Stream?
50
+ subscribeContacts(): Stream<Contacts> {
51
+ return new Stream(({ next }) => {
52
+ next({ contacts: [] });
53
+ });
54
+ if (this.echo.halo.identity) {
55
+ // return resultSetToStream(this.echo.halo.queryContacts(), (contacts): Contacts => ({ contacts }));
56
+ }
57
+
58
+ // TODO(burdon): Explain non-initialized path.
59
+ return new Stream(({ next }) => {
60
+ // If profile does not exist, send an empty array.
61
+ if (!this.echo.halo.identity) {
62
+ next({ contacts: [] });
63
+ }
64
+
65
+ const subscriptions = new EventSubscriptions();
66
+ setTimeout(async () => {
67
+ await this.echo.halo.identityReady.waitForCondition(() => !!this.echo.halo.identity);
68
+
69
+ const resultSet = this.echo.halo.queryContacts();
70
+ next({ contacts: resultSet.value });
71
+ subscriptions.add(resultSet.update.on(() => next({ contacts: resultSet.value })));
72
+ });
73
+
74
+ return () => subscriptions.clear();
75
+ });
76
+ }
77
+
78
+ async setGlobalPreference(request: SetPreferenceRequest): Promise<void> {
79
+ assert(request.key, 'Missing key of property.');
80
+ const preferences: ObjectModel | undefined = this.echo.halo.identity?.preferences?.getGlobalPreferences()?.model;
81
+ assert(preferences, 'Preferences failed to load.');
82
+ await preferences.setProperty(request.key, request.value);
83
+ }
84
+
85
+ async getGlobalPreference(request: GetPreferenceRequest): Promise<GetPreferenceResponse> {
86
+ assert(request.key, 'Missing key of property.');
87
+ const preferences: ObjectModel | undefined = this.echo.halo.identity?.preferences?.getGlobalPreferences()?.model;
88
+ return {
89
+ value: preferences?.getProperty(request.key)
90
+ };
91
+ }
92
+
93
+ async setDevicePreference(request: SetPreferenceRequest): Promise<void> {
94
+ assert(request.key, 'Missing key of property.');
95
+ const preferences: ObjectModel | undefined = this.echo.halo.identity?.preferences?.getDevicePreferences()?.model;
96
+ assert(preferences, 'Preferences failed to load.');
97
+ await preferences.setProperty(request.key, request.value);
98
+ }
99
+
100
+ async getDevicePreference(request: GetPreferenceRequest): Promise<GetPreferenceResponse> {
101
+ assert(request.key, 'Missing key of property.');
102
+ const preferences: ObjectModel | undefined = this.echo.halo.identity?.preferences?.getDevicePreferences()?.model;
103
+ return {
104
+ value: preferences?.getProperty(request.key)
105
+ };
106
+ }
107
+ }
@@ -0,0 +1,11 @@
1
+ //
2
+ // Copyright 2020 DXOS.org
3
+ //
4
+
5
+ // TODO(burdon): Add data service here.
6
+
7
+ export * from './halo';
8
+ export * from './party';
9
+ export * from './profile';
10
+ export * from './system';
11
+ export * from './tracing';
@@ -0,0 +1,305 @@
1
+ //
2
+ // Copyright 2022 DXOS.org
3
+ //
4
+
5
+ import assert from 'node:assert';
6
+ import { v4 } from 'uuid';
7
+
8
+ import { latch } from '@dxos/async';
9
+ import { Stream } from '@dxos/codec-protobuf';
10
+ import { todo } from '@dxos/debug';
11
+ import {
12
+ AuthenticateInvitationRequest,
13
+ CreateInvitationRequest,
14
+ CreateSnapshotRequest,
15
+ GetPartyDetailsRequest,
16
+ InvitationRequest,
17
+ InvitationState,
18
+ Party,
19
+ PartyDetails,
20
+ PartyService as PartyServiceRpc,
21
+ RedeemedInvitation,
22
+ SetPartyStateRequest,
23
+ SubscribeMembersRequest,
24
+ SubscribeMembersResponse,
25
+ SubscribePartiesResponse,
26
+ SubscribePartyRequest,
27
+ SubscribePartyResponse
28
+ } from '@dxos/protocols/proto/dxos/client';
29
+ import { PartySnapshot } from '@dxos/protocols/proto/dxos/echo/snapshot';
30
+ import { InvitationDescriptor } from '@dxos/protocols/proto/dxos/halo/invitations';
31
+
32
+ import { InvitationWrapper, InviteeInvitation, InviteeInvitations } from '../../invitations';
33
+ import { ServiceContext } from '../service-context';
34
+
35
+ /**
36
+ * Party service implementation.
37
+ */
38
+ // TODO(burdon): Rename Space.
39
+ export class PartyService implements PartyServiceRpc {
40
+ private inviteeInvitations: InviteeInvitations = new Map();
41
+
42
+ constructor(private readonly serviceContext: ServiceContext) {}
43
+
44
+ subscribeToParty(request: SubscribePartyRequest): Stream<SubscribePartyResponse> {
45
+ return new Stream(({ next }) => {
46
+ next({
47
+ party: {
48
+ publicKey: request.partyKey,
49
+ isOpen: true,
50
+ isActive: true,
51
+ members: []
52
+ }
53
+ });
54
+ });
55
+ // const update = (next: (message: SubscribePartyResponse) => void) => {
56
+ // try {
57
+ // const party = this.echo.getParty(request.party_key);
58
+ // next({
59
+ // party: party && {
60
+ // public_key: party.key,
61
+ // is_open: party.is_open,
62
+ // is_active: party.is_active,
63
+ // members: party.queryMembers().value
64
+ // }
65
+ // });
66
+ // } catch (err) {
67
+ // if (err instanceof InvalidStateError) {
68
+ // // Do nothing.
69
+ // } else {
70
+ // throw err;
71
+ // }
72
+ // }
73
+ // };
74
+
75
+ // const party = this.serviceContext.brane.getParty(request.party_key);
76
+ // if (party) {
77
+ // return new Stream(({ next }) => party.update.on(() => update(next)));
78
+ // } else {
79
+ // return new Stream(({ next }) => {
80
+ // let unsubscribeParty: () => void;
81
+ // const unsubscribeParties = this.echo.queryParties().subscribe((parties) => {
82
+ // const party = parties.find((party) => party.key.equals(request.party_key));
83
+ // if (party && !unsubscribeParty) {
84
+ // unsubscribeParty = party.update.on(() => update(next));
85
+ // }
86
+ // });
87
+
88
+ // update(next);
89
+
90
+ // return () => {
91
+ // unsubscribeParties();
92
+ // unsubscribeParty?.();
93
+ // };
94
+ // });
95
+ // }
96
+ }
97
+
98
+ subscribeParties() {
99
+ return new Stream<SubscribePartiesResponse>(({ next }) => {
100
+ const update = () => {
101
+ next({
102
+ parties: Array.from(this.serviceContext.spaceManager!.spaces.values()).map((space) => ({
103
+ publicKey: space.key,
104
+ isOpen: true,
105
+ isActive: true
106
+ }))
107
+ });
108
+ };
109
+
110
+ setTimeout(async () => {
111
+ if (!this.serviceContext.spaceManager) {
112
+ next({ parties: [] });
113
+ }
114
+
115
+ await this.serviceContext.initialized.wait();
116
+
117
+ update();
118
+ return this.serviceContext.spaceManager!.update.on(update);
119
+ });
120
+ });
121
+ }
122
+
123
+ async getPartyDetails(request: GetPartyDetailsRequest): Promise<PartyDetails> {
124
+ return todo();
125
+ // const party = this.echo.getParty(request.party_key) ?? raise(new SpaceNotFoundError(request.party_key));
126
+ // return {
127
+ // processedTimeframe: party.timeframe
128
+ // };
129
+ }
130
+
131
+ async createParty(): Promise<Party> {
132
+ await this.serviceContext.initialized.wait();
133
+ const space = await this.serviceContext.spaceManager!.createSpace();
134
+ return {
135
+ publicKey: space.key,
136
+ isOpen: true,
137
+ isActive: true
138
+ };
139
+ }
140
+
141
+ async cloneParty(snapshot: PartySnapshot): Promise<Party> {
142
+ return todo();
143
+ // const party = await this.echo.cloneParty(snapshot);
144
+ // return {
145
+ // public_key: party.key,
146
+ // is_open: party.is_open,
147
+ // is_active: party.is_active
148
+ // };
149
+ }
150
+
151
+ async setPartyState(request: SetPartyStateRequest) {
152
+ return todo();
153
+ // const party = this.echo.getParty(request.party_key);
154
+ // if (!party) {
155
+ // throw new Error('Party not found');
156
+ // }
157
+
158
+ // if (request.open === true) {
159
+ // await party.open();
160
+ // } else if (request.open === false) {
161
+ // await party.close();
162
+ // } // Undefined preserves previous state.
163
+
164
+ // if (request.active_global === true) {
165
+ // await party.activate({ global: true });
166
+ // } else if (request.active_global === false) {
167
+ // await party.deactivate({ global: true });
168
+ // } // Undefined preserves previous state.
169
+
170
+ // if (request.active_device === true) {
171
+ // await party.activate({ device: true });
172
+ // } else if (request.active_device === false) {
173
+ // await party.deactivate({ device: true });
174
+ // } // Undefined preserves previous state.
175
+ // return {
176
+ // public_key: party.key,
177
+ // is_open: party.is_open,
178
+ // is_active: party.is_active
179
+ // };
180
+ }
181
+
182
+ createInvitation(request: CreateInvitationRequest): Stream<InvitationRequest> {
183
+ return new Stream(({ next, close }) => {
184
+ setTimeout(async () => {
185
+ try {
186
+ let invitation: InvitationWrapper;
187
+ if (!request.inviteeKey) {
188
+ // const secret = Buffer.from(generatePasscode());
189
+ // const secretProvider = async () => {
190
+ // next({ state: InvitationState.CONNECTED });
191
+ // return Buffer.from(secret);
192
+ // };
193
+ invitation = await this.serviceContext.createInvitation(request.partyKey, () => {
194
+ next({ state: InvitationState.SUCCESS });
195
+ close();
196
+ });
197
+
198
+ assert(invitation.type === InvitationDescriptor.Type.INTERACTIVE);
199
+ // invitation.secret = Buffer.from(secret);
200
+ } else {
201
+ todo();
202
+ // invitation = await party.invitationManager.createOfflineInvitation(request.invitee_key);
203
+ }
204
+
205
+ // TODO(burdon): Change stream type.
206
+ next({
207
+ state: InvitationState.WAITING_FOR_CONNECTION,
208
+ descriptor: invitation!.toProto()
209
+ });
210
+
211
+ // if (invitation.type === InvitationDescriptor.Type.OFFLINE) {
212
+ // close();
213
+ // }
214
+ } catch (err: any) {
215
+ next({ state: InvitationState.ERROR, error: err.message });
216
+ close();
217
+ }
218
+ });
219
+ });
220
+ }
221
+
222
+ acceptInvitation(request: InvitationDescriptor): Stream<RedeemedInvitation> {
223
+ return new Stream(({ next, close }) => {
224
+ const id = v4();
225
+ const [, secretTrigger] = latch();
226
+ const inviteeInvitation: InviteeInvitation = { secretTrigger };
227
+
228
+ // Secret will be provided separately (in AuthenticateInvitation).
229
+ // Process will continue when `secretLatch` resolves, triggered by `secretTrigger`.
230
+ // const secretProvider: SecretProvider = async () => {
231
+ // await secretLatch;
232
+ // const secret = inviteeInvitation.secret;
233
+ // if (!secret) {
234
+ // throw new Error('Secret not provided.');
235
+ // }
236
+
237
+ // return Buffer.from(secret);
238
+ // };
239
+
240
+ // Joining process is kicked off, and will await authentication with a secret.
241
+ const partyPromise = this.serviceContext.acceptInvitation(InvitationWrapper.fromProto(request));
242
+ this.inviteeInvitations.set(id, inviteeInvitation);
243
+ next({ id, state: InvitationState.CONNECTED });
244
+
245
+ partyPromise
246
+ .then((party) => {
247
+ next({ id, state: InvitationState.SUCCESS, partyKey: party.key });
248
+ })
249
+ .catch((err) => {
250
+ console.error(err);
251
+ next({ id, state: InvitationState.ERROR, error: String(err) });
252
+ })
253
+ .finally(() => {
254
+ close();
255
+ });
256
+ });
257
+ }
258
+
259
+ async authenticateInvitation(request: AuthenticateInvitationRequest) {
260
+ assert(request.processId, 'Process ID is missing.');
261
+ const invitation = this.inviteeInvitations.get(request.processId);
262
+ assert(invitation, 'Invitation not found.');
263
+ assert(request.secret, 'Secret not provided.');
264
+
265
+ // Supply the secret, and move the internal invitation process by triggering the secretTrigger.
266
+ invitation.secret = request.secret;
267
+ invitation.secretTrigger?.();
268
+ }
269
+
270
+ subscribeMembers(request: SubscribeMembersRequest): Stream<SubscribeMembersResponse> {
271
+ return new Stream(({ next }) => {
272
+ next({
273
+ members: []
274
+ });
275
+ });
276
+ // const party = this.echo.getParty(request.party_key);
277
+ // if (party) {
278
+ // return resultSetToStream(party.queryMembers(), (members): SubscribeMembersResponse => ({ members }));
279
+ // } else {
280
+ // return new Stream(({ next }) => {
281
+ // let unsubscribeMembers: () => void;
282
+ // const unsubscribeParties = this.echo.queryParties().subscribe((parties) => {
283
+ // const party = parties.find((party) => party.key.equals(request.party_key));
284
+ // if (!unsubscribeMembers && party) {
285
+ // const resultSet = party.queryMembers();
286
+ // next({ members: resultSet.value });
287
+ // unsubscribeMembers = resultSet.update.on(() => next({ members: resultSet.value }));
288
+ // }
289
+ // });
290
+
291
+ // return () => {
292
+ // unsubscribeParties();
293
+ // unsubscribeMembers();
294
+ // };
295
+ // });
296
+ // }
297
+ }
298
+
299
+ async createSnapshot(request: CreateSnapshotRequest): Promise<PartySnapshot> {
300
+ return todo();
301
+ // assert(request.party_key);
302
+ // const party = this.echo.getParty(request.party_key) ?? raise(new SpaceNotFoundError(request.party_key));
303
+ // return party.createSnapshot();
304
+ }
305
+ }