@dxos/client-services 0.1.26 → 0.1.27-next.a0dff21

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 (155) hide show
  1. package/dist/lib/browser/{chunk-R2FEBB66.mjs → chunk-OTSGRZZI.mjs} +796 -579
  2. package/dist/lib/browser/chunk-OTSGRZZI.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +19 -15
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/lib/browser/packlets/testing/index.mjs +46 -46
  6. package/dist/lib/browser/packlets/testing/index.mjs.map +4 -4
  7. package/dist/lib/node/index.cjs +864 -641
  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 +753 -631
  11. package/dist/lib/node/packlets/testing/index.cjs.map +4 -4
  12. package/dist/types/src/index.d.ts +0 -1
  13. package/dist/types/src/index.d.ts.map +1 -1
  14. package/dist/types/src/packlets/deprecated/index.d.ts +0 -3
  15. package/dist/types/src/packlets/deprecated/index.d.ts.map +1 -1
  16. package/dist/types/src/packlets/{identity/devices-service-impl.d.ts → devices/devices-service.d.ts} +4 -3
  17. package/dist/types/src/packlets/devices/devices-service.d.ts.map +1 -0
  18. package/dist/types/src/packlets/devices/index.d.ts +2 -0
  19. package/dist/types/src/packlets/devices/index.d.ts.map +1 -0
  20. package/dist/types/src/packlets/identity/authenticator.d.ts +1 -1
  21. package/dist/types/src/packlets/identity/authenticator.d.ts.map +1 -1
  22. package/dist/types/src/packlets/identity/identity-manager.d.ts +2 -2
  23. package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
  24. package/dist/types/src/packlets/identity/identity-service.d.ts +14 -0
  25. package/dist/types/src/packlets/identity/identity-service.d.ts.map +1 -0
  26. package/dist/types/src/packlets/identity/identity.d.ts +2 -2
  27. package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
  28. package/dist/types/src/packlets/identity/index.d.ts +1 -0
  29. package/dist/types/src/packlets/identity/index.d.ts.map +1 -1
  30. package/dist/types/src/packlets/invitations/{halo-invitations-handler.d.ts → device-invitations-handler.d.ts} +5 -5
  31. package/dist/types/src/packlets/invitations/device-invitations-handler.d.ts.map +1 -0
  32. package/dist/types/src/packlets/invitations/device-invitations-handler.test.d.ts +2 -0
  33. package/dist/types/src/packlets/invitations/device-invitations-handler.test.d.ts.map +1 -0
  34. package/dist/types/src/packlets/invitations/{halo-invitations-proxy.d.ts → device-invitations-proxy.d.ts} +2 -2
  35. package/dist/types/src/packlets/invitations/device-invitations-proxy.d.ts.map +1 -0
  36. package/dist/types/src/packlets/invitations/{halo-invitations-service.d.ts → device-invitations-service.d.ts} +2 -2
  37. package/dist/types/src/packlets/invitations/device-invitations-service.d.ts.map +1 -0
  38. package/dist/types/src/packlets/invitations/device-invitations-service.test.d.ts +2 -0
  39. package/dist/types/src/packlets/invitations/device-invitations-service.test.d.ts.map +1 -0
  40. package/dist/types/src/packlets/invitations/index.d.ts +3 -3
  41. package/dist/types/src/packlets/invitations/index.d.ts.map +1 -1
  42. package/dist/types/src/packlets/invitations/invitations-handler.d.ts +6 -0
  43. package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
  44. package/dist/types/src/packlets/invitations/space-invitations-handler.d.ts +1 -1
  45. package/dist/types/src/packlets/invitations/space-invitations-handler.d.ts.map +1 -1
  46. package/dist/types/src/packlets/services/index.d.ts +0 -1
  47. package/dist/types/src/packlets/services/index.d.ts.map +1 -1
  48. package/dist/types/src/packlets/services/service-context.d.ts +3 -3
  49. package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
  50. package/dist/types/src/packlets/services/service-definitions.d.ts +5 -7
  51. package/dist/types/src/packlets/services/service-definitions.d.ts.map +1 -1
  52. package/dist/types/src/packlets/services/service-host.d.ts +1 -0
  53. package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
  54. package/dist/types/src/packlets/spaces/data-space-manager.d.ts +1 -1
  55. package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
  56. package/dist/types/src/packlets/spaces/data-space.d.ts +1 -1
  57. package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
  58. package/dist/types/src/packlets/spaces/spaces-service.d.ts +12 -5
  59. package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
  60. package/dist/types/src/packlets/system/index.d.ts +2 -0
  61. package/dist/types/src/packlets/system/index.d.ts.map +1 -0
  62. package/dist/types/src/packlets/system/system-service.d.ts +28 -0
  63. package/dist/types/src/packlets/system/system-service.d.ts.map +1 -0
  64. package/dist/types/src/packlets/system/system-service.test.d.ts +2 -0
  65. package/dist/types/src/packlets/system/system-service.test.d.ts.map +1 -0
  66. package/dist/types/src/packlets/testing/index.d.ts +1 -1
  67. package/dist/types/src/packlets/testing/index.d.ts.map +1 -1
  68. package/dist/types/src/packlets/testing/test-builder.d.ts +1 -1
  69. package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
  70. package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts +11 -4
  71. package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts.map +1 -1
  72. package/dist/types/src/packlets/vault/iframe-proxy-runtime.d.ts +6 -1
  73. package/dist/types/src/packlets/vault/iframe-proxy-runtime.d.ts.map +1 -1
  74. package/dist/types/src/packlets/vault/index.d.ts +2 -0
  75. package/dist/types/src/packlets/vault/index.d.ts.map +1 -1
  76. package/dist/types/src/packlets/vault/services.d.ts +9 -1
  77. package/dist/types/src/packlets/vault/services.d.ts.map +1 -1
  78. package/dist/types/src/packlets/vault/shell-controller.d.ts +18 -0
  79. package/dist/types/src/packlets/vault/shell-controller.d.ts.map +1 -0
  80. package/dist/types/src/packlets/vault/shell-runtime.d.ts +45 -0
  81. package/dist/types/src/packlets/vault/shell-runtime.d.ts.map +1 -0
  82. package/dist/types/src/packlets/vault/worker-runtime.d.ts +2 -1
  83. package/dist/types/src/packlets/vault/worker-runtime.d.ts.map +1 -1
  84. package/dist/types/src/packlets/vault/worker-session.d.ts +4 -1
  85. package/dist/types/src/packlets/vault/worker-session.d.ts.map +1 -1
  86. package/package.json +29 -28
  87. package/src/index.ts +0 -1
  88. package/src/packlets/deprecated/index.ts +0 -3
  89. package/src/packlets/{identity/devices-service-impl.ts → devices/devices-service.ts} +10 -8
  90. package/src/packlets/devices/index.ts +5 -0
  91. package/src/packlets/devtools/spaces.ts +1 -1
  92. package/src/packlets/identity/authenticator.ts +1 -1
  93. package/src/packlets/identity/identity-manager.test.ts +1 -1
  94. package/src/packlets/identity/identity-manager.ts +2 -2
  95. package/src/packlets/identity/identity-service.ts +67 -0
  96. package/src/packlets/identity/identity.test.ts +1 -1
  97. package/src/packlets/identity/identity.ts +1 -1
  98. package/src/packlets/identity/index.ts +1 -0
  99. package/src/packlets/invitations/{halo-invitations-handler.test.ts → device-invitations-handler.test.ts} +2 -2
  100. package/src/packlets/invitations/{halo-invitations-handler.ts → device-invitations-handler.ts} +4 -4
  101. package/src/packlets/invitations/{halo-invitations-proxy.ts → device-invitations-proxy.ts} +1 -1
  102. package/src/packlets/invitations/{halo-invitations-service.test.ts → device-invitations-service.test.ts} +10 -10
  103. package/src/packlets/invitations/{halo-invitations-service.ts → device-invitations-service.ts} +1 -1
  104. package/src/packlets/invitations/index.ts +3 -3
  105. package/src/packlets/invitations/invitations-handler.ts +6 -0
  106. package/src/packlets/invitations/invitations-service.ts +2 -2
  107. package/src/packlets/invitations/space-invitations-handler.test.ts +1 -1
  108. package/src/packlets/invitations/space-invitations-handler.ts +55 -20
  109. package/src/packlets/services/index.ts +0 -1
  110. package/src/packlets/services/service-context.test.ts +3 -3
  111. package/src/packlets/services/service-context.ts +5 -5
  112. package/src/packlets/services/service-definitions.ts +14 -14
  113. package/src/packlets/services/service-host.test.ts +9 -9
  114. package/src/packlets/services/service-host.ts +40 -25
  115. package/src/packlets/spaces/data-space-manager.test.ts +1 -1
  116. package/src/packlets/spaces/data-space-manager.ts +4 -4
  117. package/src/packlets/spaces/data-space.ts +3 -3
  118. package/src/packlets/spaces/spaces-service.ts +93 -11
  119. package/src/packlets/system/index.ts +5 -0
  120. package/src/packlets/system/system-service.test.ts +80 -0
  121. package/src/packlets/system/system-service.ts +70 -0
  122. package/src/packlets/testing/index.ts +1 -1
  123. package/src/packlets/testing/test-builder.ts +3 -3
  124. package/src/packlets/vault/iframe-host-runtime.ts +28 -10
  125. package/src/packlets/vault/iframe-proxy-runtime.ts +16 -1
  126. package/src/packlets/vault/index.ts +2 -0
  127. package/src/packlets/vault/services.ts +17 -1
  128. package/src/packlets/vault/shell-controller.ts +56 -0
  129. package/src/packlets/vault/shell-runtime.ts +121 -0
  130. package/src/packlets/vault/worker-runtime.ts +3 -1
  131. package/src/packlets/vault/worker-session.ts +28 -19
  132. package/dist/lib/browser/chunk-R2FEBB66.mjs.map +0 -7
  133. package/dist/types/src/packlets/deprecated/invitations.d.ts +0 -47
  134. package/dist/types/src/packlets/deprecated/invitations.d.ts.map +0 -1
  135. package/dist/types/src/packlets/deprecated/profile.d.ts +0 -18
  136. package/dist/types/src/packlets/deprecated/profile.d.ts.map +0 -1
  137. package/dist/types/src/packlets/deprecated/space.d.ts +0 -23
  138. package/dist/types/src/packlets/deprecated/space.d.ts.map +0 -1
  139. package/dist/types/src/packlets/deprecated/system.d.ts +0 -24
  140. package/dist/types/src/packlets/deprecated/system.d.ts.map +0 -1
  141. package/dist/types/src/packlets/identity/devices-service-impl.d.ts.map +0 -1
  142. package/dist/types/src/packlets/invitations/halo-invitations-handler.d.ts.map +0 -1
  143. package/dist/types/src/packlets/invitations/halo-invitations-handler.test.d.ts +0 -2
  144. package/dist/types/src/packlets/invitations/halo-invitations-handler.test.d.ts.map +0 -1
  145. package/dist/types/src/packlets/invitations/halo-invitations-proxy.d.ts.map +0 -1
  146. package/dist/types/src/packlets/invitations/halo-invitations-service.d.ts.map +0 -1
  147. package/dist/types/src/packlets/invitations/halo-invitations-service.test.d.ts +0 -2
  148. package/dist/types/src/packlets/invitations/halo-invitations-service.test.d.ts.map +0 -1
  149. package/dist/types/src/packlets/services/signer.d.ts +0 -6
  150. package/dist/types/src/packlets/services/signer.d.ts.map +0 -1
  151. package/src/packlets/deprecated/invitations.ts +0 -63
  152. package/src/packlets/deprecated/profile.ts +0 -85
  153. package/src/packlets/deprecated/space.ts +0 -258
  154. package/src/packlets/deprecated/system.ts +0 -48
  155. package/src/packlets/services/signer.ts +0 -11
@@ -10,10 +10,10 @@ import {
10
10
  DataPipelineControllerImpl,
11
11
  MetadataStore,
12
12
  Space,
13
- SnapshotManager,
14
13
  SigningContext,
15
- createMappedFeedWriter
16
- } from '@dxos/echo-db';
14
+ createMappedFeedWriter,
15
+ SnapshotManager
16
+ } from '@dxos/echo-pipeline';
17
17
  import { FeedStore } from '@dxos/feed-store';
18
18
  import { Keyring } from '@dxos/keyring';
19
19
  import { PublicKey } from '@dxos/keys';
@@ -2,36 +2,98 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
- import { scheduleTask } from '@dxos/async';
5
+ import { EventSubscriptions, scheduleTask } from '@dxos/async';
6
6
  import { Stream } from '@dxos/codec-protobuf';
7
- import { raise } from '@dxos/debug';
8
- import { SpaceManager, SpaceNotFoundError } from '@dxos/echo-db';
7
+ import { raise, todo } from '@dxos/debug';
8
+ import { DataServiceSubscriptions, SpaceManager, SpaceNotFoundError } from '@dxos/echo-pipeline';
9
+ import { log } from '@dxos/log';
9
10
  import {
10
11
  QueryCredentialsRequest,
11
- QueryMembersRequest,
12
- QueryMembersResponse,
12
+ QuerySpacesResponse,
13
13
  Space,
14
+ SpaceMember,
14
15
  SpacesService,
16
+ SpaceStatus,
17
+ UpdateSpaceRequest,
15
18
  WriteCredentialsRequest
16
19
  } from '@dxos/protocols/proto/dxos/client/services';
17
20
  import { Credential } from '@dxos/protocols/proto/dxos/halo/credentials';
21
+ import { humanize, Provider } from '@dxos/util';
22
+
23
+ import { IdentityManager } from '../identity';
24
+ import { DataSpace } from './data-space';
25
+ import { DataSpaceManager } from './data-space-manager';
18
26
 
19
27
  /**
20
28
  *
21
29
  */
22
30
  export class SpacesServiceImpl implements SpacesService {
23
- constructor(private readonly _spaceManager: SpaceManager) {}
31
+ constructor(
32
+ private readonly _identityManager: IdentityManager,
33
+ private readonly _spaceManager: SpaceManager,
34
+ private readonly _dataServiceSubscriptions: DataServiceSubscriptions,
35
+ private readonly _getDataSpaceManager: Provider<Promise<DataSpaceManager>>
36
+ ) {}
24
37
 
25
38
  async createSpace(): Promise<Space> {
26
- throw new Error();
39
+ if (!this._identityManager.identity) {
40
+ throw new Error('This device has no HALO identity available. See https://docs.dxos.org/guide/halo');
41
+ }
42
+ const dataSpaceManager = await this._getDataSpaceManager();
43
+ const space = await dataSpaceManager.createSpace();
44
+ return this._transformSpace(space);
27
45
  }
28
46
 
29
- querySpaces(): Stream<Space> {
30
- throw new Error();
47
+ async updateSpace(request: UpdateSpaceRequest) {
48
+ todo();
31
49
  }
32
50
 
33
- queryMembers(query: QueryMembersRequest): Stream<QueryMembersResponse> {
34
- throw new Error();
51
+ querySpaces(): Stream<QuerySpacesResponse> {
52
+ return new Stream<QuerySpacesResponse>(({ next, ctx }) => {
53
+ const onUpdate = async () => {
54
+ const dataSpaceManager = await this._getDataSpaceManager();
55
+ const spaces = Array.from(dataSpaceManager.spaces.values())
56
+ // Skip spaces without data service available.
57
+ .filter((space) => this._dataServiceSubscriptions.getDataService(space.key))
58
+ .map((space) => this._transformSpace(space));
59
+ log('update', { spaces });
60
+ next({ spaces });
61
+ };
62
+
63
+ setTimeout(async () => {
64
+ const dataSpaceManager = await this._getDataSpaceManager();
65
+ const subscriptions = new EventSubscriptions();
66
+ // TODO(dmaretskyi): Create a pattern for subscribing to a set of objects.
67
+ const subscribeSpaces = () => {
68
+ subscriptions.clear();
69
+
70
+ for (const space of dataSpaceManager.spaces.values()) {
71
+ if (!this._dataServiceSubscriptions.getDataService(space.key)) {
72
+ // Skip spaces without data service available.
73
+ continue;
74
+ }
75
+
76
+ subscriptions.add(space.stateUpdate.on(ctx, onUpdate));
77
+ subscriptions.add(space.presence.updated.on(ctx, onUpdate));
78
+ }
79
+ };
80
+
81
+ dataSpaceManager.updated.on(ctx, () => {
82
+ subscribeSpaces();
83
+ void onUpdate();
84
+ });
85
+
86
+ ctx.onDispose(() => subscriptions.clear());
87
+ scheduleTask(ctx, () => {
88
+ subscribeSpaces();
89
+ void onUpdate();
90
+ });
91
+ });
92
+
93
+ if (!this._identityManager.identity) {
94
+ next({ spaces: [] });
95
+ }
96
+ });
35
97
  }
36
98
 
37
99
  queryCredentials({ spaceKey }: QueryCredentialsRequest): Stream<Credential> {
@@ -54,4 +116,24 @@ export class SpacesServiceImpl implements SpacesService {
54
116
  await space.controlPipeline.writer.write({ credential: { credential } });
55
117
  }
56
118
  }
119
+
120
+ private _transformSpace(space: DataSpace): Space {
121
+ return {
122
+ spaceKey: space.key,
123
+ status: space.isOpen ? SpaceStatus.ACTIVE : SpaceStatus.INACTIVE,
124
+ members: Array.from(space.inner.spaceState.members.values()).map((member) => ({
125
+ identity: {
126
+ identityKey: member.key,
127
+ profile: {
128
+ displayName: member.assertion.profile?.displayName ?? humanize(member.key)
129
+ }
130
+ },
131
+ presence:
132
+ this._identityManager.identity?.identityKey.equals(member.key) ||
133
+ space.presence.getPeersOnline().filter(({ identityKey }) => identityKey.equals(member.key)).length > 0
134
+ ? SpaceMember.PresenceState.ONLINE
135
+ : SpaceMember.PresenceState.OFFLINE
136
+ }))
137
+ };
138
+ }
57
139
  }
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ export * from './system-service';
@@ -0,0 +1,80 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { expect } from 'chai';
6
+
7
+ import { Event, Trigger } from '@dxos/async';
8
+ import { Config } from '@dxos/config';
9
+ import { SystemStatus, SystemStatusResponse, SystemService } from '@dxos/protocols/proto/dxos/client/services';
10
+ import { beforeEach, describe, test } from '@dxos/test';
11
+
12
+ import { SystemServiceImpl } from './system-service';
13
+
14
+ describe('SystemService', () => {
15
+ let systemService: SystemService;
16
+ let config: Config;
17
+ let statusUpdate: Event<void>;
18
+ let currentStatus: SystemStatus;
19
+ let updateStatus: Trigger<SystemStatus>;
20
+ let reset: Trigger<boolean>;
21
+
22
+ const changeStatus = (status: SystemStatus) => {
23
+ currentStatus = status;
24
+ statusUpdate.emit();
25
+ };
26
+
27
+ beforeEach(() => {
28
+ config = new Config({ runtime: { client: { log: { filter: 'system-service:debug' } } } });
29
+ statusUpdate = new Event<void>();
30
+ currentStatus = SystemStatus.ACTIVE;
31
+ updateStatus = new Trigger<SystemStatus>();
32
+ reset = new Trigger<boolean>();
33
+
34
+ systemService = new SystemServiceImpl({
35
+ config,
36
+ statusUpdate,
37
+ getCurrentStatus: () => currentStatus,
38
+ onUpdateStatus: (status) => {
39
+ updateStatus.wake(status);
40
+ },
41
+ onReset: () => {
42
+ reset.wake(true);
43
+ }
44
+ });
45
+ });
46
+
47
+ test('getConfig returns config', async () => {
48
+ expect(await systemService.getConfig()).to.deep.equal(config.values);
49
+ });
50
+
51
+ test('updateStatus triggers callback', async () => {
52
+ await systemService.updateStatus({ status: SystemStatus.INACTIVE });
53
+ const result = await updateStatus.wait();
54
+ expect(result).to.equal(SystemStatus.INACTIVE);
55
+ });
56
+
57
+ test('queryStatus returns initial status', async () => {
58
+ const status = new Trigger<SystemStatusResponse>();
59
+ systemService.queryStatus().subscribe((response) => {
60
+ status.wake(response);
61
+ });
62
+ expect(await status.wait()).to.deep.equal({ status: SystemStatus.ACTIVE });
63
+ });
64
+
65
+ test('queryStatus streams status changes', async () => {
66
+ const statuses: SystemStatus[] = [];
67
+ systemService.queryStatus().subscribe(({ status }) => {
68
+ statuses.push(status);
69
+ });
70
+ changeStatus(SystemStatus.INACTIVE);
71
+ changeStatus(SystemStatus.ACTIVE);
72
+ expect(statuses).to.deep.equal([SystemStatus.ACTIVE, SystemStatus.INACTIVE, SystemStatus.ACTIVE]);
73
+ });
74
+
75
+ test('reset triggers callback', async () => {
76
+ await systemService.reset();
77
+ const result = await reset.wait();
78
+ expect(result).to.be.true;
79
+ });
80
+ });
@@ -0,0 +1,70 @@
1
+ //
2
+ // Copyright 2022 DXOS.org
3
+ //
4
+
5
+ import { Event } from '@dxos/async';
6
+ import { Stream } from '@dxos/codec-protobuf';
7
+ import { Config } from '@dxos/config';
8
+ import {
9
+ SystemStatus,
10
+ SystemStatusResponse,
11
+ SystemService,
12
+ UpdateSystemStatusRequest
13
+ } from '@dxos/protocols/proto/dxos/client/services';
14
+ import { MaybePromise } from '@dxos/util';
15
+
16
+ export type SystemServiceOptions = {
17
+ config: Config;
18
+ statusUpdate: Event<void>;
19
+ getCurrentStatus: () => SystemStatus;
20
+ onUpdateStatus: (status: SystemStatus) => MaybePromise<void>;
21
+ onReset: () => MaybePromise<void>;
22
+ };
23
+
24
+ /**
25
+ *
26
+ */
27
+ export class SystemServiceImpl implements SystemService {
28
+ private readonly _config: SystemServiceOptions['config'];
29
+ private readonly _statusUpdate: SystemServiceOptions['statusUpdate'];
30
+ private readonly _getCurrentStatus: SystemServiceOptions['getCurrentStatus'];
31
+ private readonly _onUpdateStatus: SystemServiceOptions['onUpdateStatus'];
32
+ private readonly _onReset: SystemServiceOptions['onReset'];
33
+
34
+ constructor({ config, statusUpdate, onUpdateStatus, getCurrentStatus, onReset }: SystemServiceOptions) {
35
+ this._config = config;
36
+ this._statusUpdate = statusUpdate;
37
+ this._getCurrentStatus = getCurrentStatus;
38
+ this._onUpdateStatus = onUpdateStatus;
39
+ this._onReset = onReset;
40
+ }
41
+
42
+ async getConfig() {
43
+ return this._config.values;
44
+ }
45
+
46
+ async updateStatus({ status }: UpdateSystemStatusRequest) {
47
+ await this._onUpdateStatus(status);
48
+ }
49
+
50
+ queryStatus(): Stream<SystemStatusResponse> {
51
+ return new Stream(({ next }) => {
52
+ const update = () => {
53
+ next({ status: this._getCurrentStatus() });
54
+ };
55
+
56
+ update();
57
+ const unsubscribe = this._statusUpdate.on(() => update());
58
+ const interval = setInterval(update, 3000);
59
+
60
+ return () => {
61
+ clearInterval(interval);
62
+ unsubscribe();
63
+ };
64
+ });
65
+ }
66
+
67
+ async reset() {
68
+ await this._onReset();
69
+ }
70
+ }
@@ -3,5 +3,5 @@
3
3
  //
4
4
 
5
5
  export * from './credential-utils';
6
- export * from './test-builder';
7
6
  export * from './invitation-utils';
7
+ export * from './test-builder';
@@ -5,14 +5,14 @@
5
5
  import { Config } from '@dxos/config';
6
6
  import { createCredentialSignerWithChain, CredentialGenerator } from '@dxos/credentials';
7
7
  import {
8
+ SnapshotStore,
8
9
  DataPipelineControllerImpl,
9
10
  MetadataStore,
10
11
  SigningContext,
11
- SnapshotStore,
12
12
  SpaceManager,
13
13
  valueEncoding
14
- } from '@dxos/echo-db';
15
- import { testLocalDatabase } from '@dxos/echo-db/testing';
14
+ } from '@dxos/echo-pipeline';
15
+ import { testLocalDatabase } from '@dxos/echo-pipeline/testing';
16
16
  import { FeedFactory, FeedStore } from '@dxos/feed-store';
17
17
  import { Keyring } from '@dxos/keyring';
18
18
  import { MemorySignalManager, MemorySignalManagerContext } from '@dxos/messaging';
@@ -8,15 +8,17 @@ import { log, logInfo } from '@dxos/log';
8
8
  import { MemorySignalManager, MemorySignalManagerContext, WebsocketSignalManager } from '@dxos/messaging';
9
9
  import { createWebRTCTransportFactory, NetworkManager } from '@dxos/network-manager';
10
10
  import { createProtoRpcPeer, ProtoRpcPeer, RpcPort } from '@dxos/rpc';
11
- import { MaybePromise } from '@dxos/util';
11
+ import { getAsyncValue, Provider } from '@dxos/util';
12
12
 
13
13
  import { clientServiceBundle, ClientServices, ClientServicesHost } from '../services';
14
+ import { ShellRuntime, ShellRuntimeImpl } from './shell-runtime';
14
15
 
15
16
  const LOCK_KEY = 'DXOS_RESOURCE_LOCK';
16
17
 
17
18
  export type IFrameHostRuntimeParams = {
18
- configProvider: () => MaybePromise<Config>;
19
+ configProvider: Config | Provider<Promise<Config>>;
19
20
  appPort: RpcPort;
21
+ shellPort?: RpcPort;
20
22
  };
21
23
 
22
24
  /**
@@ -26,7 +28,7 @@ export type IFrameHostRuntimeParams = {
26
28
  * This should only be used when SharedWorker is not available.
27
29
  */
28
30
  export class IFrameHostRuntime {
29
- private readonly _configProvider: () => MaybePromise<Config>;
31
+ private readonly _configProvider: Config | Provider<Promise<Config>>;
30
32
  private readonly _transportFactory = createWebRTCTransportFactory();
31
33
  private readonly _ready = new Trigger<Error | undefined>();
32
34
  private readonly _getService: <Service>(
@@ -34,16 +36,20 @@ export class IFrameHostRuntime {
34
36
  ) => Promise<Service>;
35
37
 
36
38
  private readonly _appPort: RpcPort;
39
+ private readonly _shellPort?: RpcPort;
40
+ private _config!: Config;
37
41
  private _clientServices!: ClientServicesHost;
38
42
  private _clientRpc!: ProtoRpcPeer<ClientServices>;
39
- private _config!: Config;
43
+ private _shellRuntime?: ShellRuntimeImpl;
40
44
 
41
45
  @logInfo
42
46
  public origin?: string;
43
47
 
44
- constructor({ configProvider, appPort }: IFrameHostRuntimeParams) {
48
+ constructor({ configProvider, appPort, shellPort }: IFrameHostRuntimeParams) {
45
49
  this._configProvider = configProvider;
46
50
  this._appPort = appPort;
51
+ this._shellPort = shellPort;
52
+
47
53
  this._getService = async (find) => {
48
54
  const error = await this._ready.wait();
49
55
  if (error) {
@@ -57,12 +63,24 @@ export class IFrameHostRuntime {
57
63
 
58
64
  return service;
59
65
  };
66
+
67
+ if (this._shellPort) {
68
+ this._shellRuntime = new ShellRuntimeImpl(this._shellPort);
69
+ }
70
+ }
71
+
72
+ get services() {
73
+ return this._clientServices;
74
+ }
75
+
76
+ get shell(): ShellRuntime | undefined {
77
+ return this._shellRuntime;
60
78
  }
61
79
 
62
80
  async start() {
63
81
  log('starting...');
64
82
  try {
65
- this._config = await this._configProvider();
83
+ this._config = await getAsyncValue(this._configProvider);
66
84
  const signalServer = this._config.get('runtime.services.signal.server');
67
85
  this._clientServices = new ClientServicesHost({
68
86
  lockKey: LOCK_KEY,
@@ -80,13 +98,12 @@ export class IFrameHostRuntime {
80
98
  exposed: clientServiceBundle,
81
99
  handlers: {
82
100
  DataService: async () => await this._getService((services) => services.DataService),
101
+ DeviceInvitationsService: async () => await this._getService((services) => services.DeviceInvitationsService),
83
102
  DevicesService: async () => await this._getService((services) => services.DevicesService),
84
103
  DevtoolsHost: async () => await this._getService((services) => services.DevtoolsHost),
85
- HaloInvitationsService: async () => await this._getService((services) => services.HaloInvitationsService),
86
104
  NetworkService: async () => await this._getService((services) => services.NetworkService),
87
- ProfileService: async () => await this._getService((services) => services.ProfileService),
105
+ IdentityService: async () => await this._getService((services) => services.IdentityService),
88
106
  SpaceInvitationsService: async () => await this._getService((services) => services.SpaceInvitationsService),
89
- SpaceService: async () => await this._getService((services) => services.SpaceService),
90
107
  SpacesService: async () => await this._getService((services) => services.SpacesService),
91
108
  SystemService: async () => await this._getService((services) => services.SystemService),
92
109
  TracingService: async () => await this._getService((services) => services.TracingService)
@@ -94,7 +111,7 @@ export class IFrameHostRuntime {
94
111
  port: this._appPort
95
112
  });
96
113
 
97
- await Promise.all([this._clientServices.open(), this._clientRpc.open()]);
114
+ await Promise.all([this._clientServices.open(), this._clientRpc.open(), this._shellRuntime?.open()]);
98
115
  this._ready.wake(undefined);
99
116
  log('started');
100
117
  } catch (err: any) {
@@ -107,6 +124,7 @@ export class IFrameHostRuntime {
107
124
  log('stopping...');
108
125
  await this._clientRpc.close();
109
126
  await this._clientServices.close();
127
+ await this._shellRuntime?.close();
110
128
  log('stopped');
111
129
  }
112
130
  }
@@ -7,12 +7,14 @@ import { BridgeService } from '@dxos/protocols/proto/dxos/mesh/bridge';
7
7
  import { createProtoRpcPeer, ProtoRpcPeer, RpcPort } from '@dxos/rpc';
8
8
 
9
9
  import { iframeServiceBundle, WorkerServiceBundle, workerServiceBundle } from './services';
10
+ import { ShellRuntime, ShellRuntimeImpl } from './shell-runtime';
10
11
 
11
12
  // NOTE: Keep as RpcPorts to avoid dependency on @dxos/rpc-tunnel so we don't depend on browser-specific apis.
12
13
  export type IFrameProxyRuntimeParams = {
13
14
  systemPort: RpcPort;
14
15
  workerAppPort: RpcPort;
15
16
  windowAppPort: RpcPort;
17
+ shellPort?: RpcPort;
16
18
  };
17
19
 
18
20
  /**
@@ -22,13 +24,16 @@ export class IFrameProxyRuntime {
22
24
  private readonly _systemPort: RpcPort;
23
25
  private readonly _windowAppPort: RpcPort;
24
26
  private readonly _workerAppPort: RpcPort;
27
+ private readonly _shellPort?: RpcPort;
25
28
  private readonly _systemRpc: ProtoRpcPeer<WorkerServiceBundle>;
29
+ private readonly _shellRuntime?: ShellRuntimeImpl;
26
30
  private readonly _transportService = new WebRTCTransportService();
27
31
 
28
- constructor({ systemPort, workerAppPort, windowAppPort }: IFrameProxyRuntimeParams) {
32
+ constructor({ systemPort, workerAppPort, windowAppPort, shellPort }: IFrameProxyRuntimeParams) {
29
33
  this._systemPort = systemPort;
30
34
  this._windowAppPort = windowAppPort;
31
35
  this._workerAppPort = workerAppPort;
36
+ this._shellPort = shellPort;
32
37
 
33
38
  this._systemRpc = createProtoRpcPeer({
34
39
  requested: workerServiceBundle,
@@ -47,14 +52,24 @@ export class IFrameProxyRuntime {
47
52
 
48
53
  this._workerAppPort.subscribe((msg) => this._windowAppPort.send(msg));
49
54
  this._windowAppPort.subscribe((msg) => this._workerAppPort.send(msg));
55
+
56
+ if (this._shellPort) {
57
+ this._shellRuntime = new ShellRuntimeImpl(this._shellPort);
58
+ }
59
+ }
60
+
61
+ get shell(): ShellRuntime | undefined {
62
+ return this._shellRuntime;
50
63
  }
51
64
 
52
65
  async open(origin: string) {
53
66
  await this._systemRpc.open();
54
67
  await this._systemRpc.rpc.WorkerService.start({ origin });
68
+ await this._shellRuntime?.open();
55
69
  }
56
70
 
57
71
  async close() {
72
+ await this._shellRuntime?.close();
58
73
  await this._systemRpc.rpc.WorkerService.stop();
59
74
  await this._systemRpc.close();
60
75
  }
@@ -5,6 +5,8 @@
5
5
  export * from './iframe-host-runtime';
6
6
  export * from './iframe-proxy-runtime';
7
7
  export * from './services';
8
+ export * from './shell-controller';
9
+ export * from './shell-runtime';
8
10
  export * from './vault-resource-lock';
9
11
  export * from './worker-runtime';
10
12
  export * from './worker-session';
@@ -3,7 +3,7 @@
3
3
  //
4
4
 
5
5
  import { schema } from '@dxos/protocols';
6
- import type { IframeService, WorkerService } from '@dxos/protocols/proto/dxos/iframe';
6
+ import type { IframeService, AppService, ShellService, WorkerService } from '@dxos/protocols/proto/dxos/iframe';
7
7
  import type { BridgeService } from '@dxos/protocols/proto/dxos/mesh/bridge';
8
8
  import { ServiceBundle } from '@dxos/rpc';
9
9
 
@@ -24,3 +24,19 @@ export type WorkerServiceBundle = {
24
24
  export const workerServiceBundle: ServiceBundle<WorkerServiceBundle> = {
25
25
  WorkerService: schema.getService('dxos.iframe.WorkerService')
26
26
  };
27
+
28
+ export type AppServiceBundle = {
29
+ AppService: AppService;
30
+ };
31
+
32
+ export const appServiceBundle: ServiceBundle<AppServiceBundle> = {
33
+ AppService: schema.getService('dxos.iframe.AppService')
34
+ };
35
+
36
+ export type ShellServiceBundle = {
37
+ ShellService: ShellService;
38
+ };
39
+
40
+ export const shellServiceBundle: ServiceBundle<ShellServiceBundle> = {
41
+ ShellService: schema.getService('dxos.iframe.ShellService')
42
+ };
@@ -0,0 +1,56 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { Event } from '@dxos/async';
6
+ import { log } from '@dxos/log';
7
+ import { AppContextRequest, LayoutRequest, ShellDisplay, ShellLayout } from '@dxos/protocols/proto/dxos/iframe';
8
+ import { createProtoRpcPeer, ProtoRpcPeer, RpcPort } from '@dxos/rpc';
9
+
10
+ import { appServiceBundle, shellServiceBundle, ShellServiceBundle } from './services';
11
+
12
+ /**
13
+ * Provide access to the shell via RPC connection.
14
+ */
15
+ export class ShellController {
16
+ readonly contextUpdate = new Event<AppContextRequest>();
17
+ private _shellRpc?: ProtoRpcPeer<ShellServiceBundle>;
18
+ private _display = ShellDisplay.NONE;
19
+
20
+ constructor(private readonly _port: RpcPort) {}
21
+
22
+ get display() {
23
+ return this._display;
24
+ }
25
+
26
+ async setLayout(layout: ShellLayout, options: Omit<LayoutRequest, 'layout'> = {}) {
27
+ log('set layout', { layout, ...options });
28
+ this._display = ShellDisplay.FULLSCREEN;
29
+ this.contextUpdate.emit({ display: this._display });
30
+ await this._shellRpc?.rpc.ShellService.setLayout({ layout, ...options });
31
+ }
32
+
33
+ async open() {
34
+ this._shellRpc = createProtoRpcPeer({
35
+ requested: shellServiceBundle,
36
+ exposed: appServiceBundle,
37
+ handlers: {
38
+ AppService: {
39
+ setContext: async (request) => {
40
+ log('set context', request);
41
+ this._display = request.display;
42
+ this.contextUpdate.emit(request);
43
+ }
44
+ }
45
+ },
46
+ port: this._port
47
+ });
48
+
49
+ await this._shellRpc.open();
50
+ }
51
+
52
+ async close() {
53
+ await this._shellRpc?.close();
54
+ this._shellRpc = undefined;
55
+ }
56
+ }