@dxos/client 2.33.9-dev.9dc01397 → 2.33.9-dev.a2586ac4

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 (60) hide show
  1. package/dist/browser.js +846 -1717
  2. package/dist/src/packlets/proto/gen/dxos/client.d.ts +97 -0
  3. package/dist/src/packlets/proto/gen/dxos/client.d.ts.map +1 -1
  4. package/dist/src/packlets/proto/gen/dxos/client.js +21 -1
  5. package/dist/src/packlets/proto/gen/dxos/client.js.map +1 -1
  6. package/dist/src/packlets/proto/gen/dxos/config.d.ts +5 -0
  7. package/dist/src/packlets/proto/gen/dxos/config.d.ts.map +1 -1
  8. package/dist/src/packlets/proto/gen/dxos/config.js.map +1 -1
  9. package/dist/src/packlets/proto/gen/google/protobuf.d.ts +2 -2
  10. package/dist/src/packlets/proto/gen/google/protobuf.d.ts.map +1 -1
  11. package/dist/src/packlets/proto/gen/google/protobuf.js.map +1 -1
  12. package/dist/src/packlets/proto/gen/index.d.ts +11 -0
  13. package/dist/src/packlets/proto/gen/index.d.ts.map +1 -1
  14. package/dist/src/packlets/proto/gen/index.js +1 -1
  15. package/dist/src/packlets/proto/gen/index.js.map +1 -1
  16. package/dist/src/packlets/proxy/client-proxy.d.ts.map +1 -1
  17. package/dist/src/packlets/proxy/client-proxy.js +15 -11
  18. package/dist/src/packlets/proxy/client-proxy.js.map +1 -1
  19. package/dist/src/packlets/proxy/index.d.ts +1 -1
  20. package/dist/src/packlets/proxy/index.d.ts.map +1 -1
  21. package/dist/src/packlets/proxy/index.js +1 -1
  22. package/dist/src/packlets/proxy/index.js.map +1 -1
  23. package/dist/src/packlets/proxy/singleton-port.d.ts +3 -0
  24. package/dist/src/packlets/proxy/singleton-port.d.ts.map +1 -0
  25. package/dist/src/packlets/proxy/singleton-port.js +59 -0
  26. package/dist/src/packlets/proxy/singleton-port.js.map +1 -0
  27. package/dist/src/singleton/main.d.ts +2 -0
  28. package/dist/src/singleton/main.d.ts.map +1 -0
  29. package/dist/src/singleton/main.js +155 -0
  30. package/dist/src/singleton/main.js.map +1 -0
  31. package/dist/src/singleton/proxy-port.d.ts +10 -0
  32. package/dist/src/singleton/proxy-port.d.ts.map +1 -0
  33. package/dist/src/singleton/proxy-port.js +22 -0
  34. package/dist/src/singleton/proxy-port.js.map +1 -0
  35. package/dist/src/singleton/shared-worker.d.ts +2 -0
  36. package/dist/src/singleton/shared-worker.d.ts.map +1 -0
  37. package/dist/src/singleton/shared-worker.js +134 -0
  38. package/dist/src/singleton/shared-worker.js.map +1 -0
  39. package/dist/src/singleton/singleton.stories.d.ts +6 -0
  40. package/dist/src/singleton/singleton.stories.d.ts.map +1 -0
  41. package/dist/src/singleton/singleton.stories.js +52 -0
  42. package/dist/src/singleton/singleton.stories.js.map +1 -0
  43. package/dist/tsconfig.tsbuildinfo +1 -1
  44. package/package.json +27 -20
  45. package/src/packlets/proto/gen/dxos/client.ts +97 -0
  46. package/src/packlets/proto/gen/dxos/config.ts +5 -0
  47. package/src/packlets/proto/gen/google/protobuf.ts +2 -2
  48. package/src/packlets/proto/gen/index.ts +12 -1
  49. package/src/packlets/proxy/client-proxy.ts +21 -17
  50. package/src/packlets/proxy/index.ts +1 -1
  51. package/src/packlets/proxy/singleton-port.ts +60 -0
  52. package/src/singleton/main.ts +170 -0
  53. package/src/singleton/proxy-port.ts +23 -0
  54. package/src/singleton/shared-worker.ts +147 -0
  55. package/src/singleton/singleton.stories.tsx +36 -0
  56. package/dist/src/packlets/proxy/messages.d.ts +0 -3
  57. package/dist/src/packlets/proxy/messages.d.ts.map +0 -1
  58. package/dist/src/packlets/proxy/messages.js +0 -30
  59. package/dist/src/packlets/proxy/messages.js.map +0 -1
  60. package/src/packlets/proxy/messages.ts +0 -29
@@ -7,8 +7,8 @@ export * from './devtools';
7
7
  export * from './echo-proxy';
8
8
  export * from './halo-proxy';
9
9
  export * from './invitation-proxy';
10
- export * from './messages';
11
10
  export * from './party-proxy';
12
11
  export * from './serializer';
13
12
  export * from './service-proxy';
13
+ export * from './singleton-port';
14
14
  export * from './version';
@@ -0,0 +1,60 @@
1
+ //
2
+ // Copyright 2021 DXOS.org
3
+ //
4
+
5
+ import debug from 'debug';
6
+
7
+ import { RpcPort } from '@dxos/rpc';
8
+ import { isNode } from '@dxos/util';
9
+
10
+ import { SingletonMessage } from '../proto';
11
+
12
+ const log = debug('dxos:client:singleton-port');
13
+
14
+ const waitForClient = () => {
15
+ return new Promise<void>(resolve => {
16
+ const messageHandler = (event: MessageEvent<SingletonMessage>) => {
17
+ if (event.data?.type === SingletonMessage.Type.CLIENT_READY) {
18
+ window.removeEventListener('message', messageHandler);
19
+ resolve();
20
+ }
21
+ };
22
+
23
+ window.addEventListener('message', messageHandler);
24
+ });
25
+ };
26
+
27
+ export const createSingletonPort = async (singletonSource: string): Promise<RpcPort> => {
28
+ if (isNode()) {
29
+ throw new Error('Connecting to singleton client is not available in Node environment.');
30
+ }
31
+
32
+ const singleton = document.createElement('iframe') as HTMLIFrameElement;
33
+ singleton.id = 'dxos-client-singleton';
34
+ singleton.src = singletonSource;
35
+ singleton.setAttribute('style', 'display: none;');
36
+ document.body.appendChild(singleton);
37
+
38
+ await waitForClient();
39
+
40
+ return {
41
+ send: async message => singleton.contentWindow?.postMessage({
42
+ type: SingletonMessage.Type.WINDOW_MESSAGE,
43
+ data: Array.from(message)
44
+ }, '*'),
45
+ subscribe: callback => {
46
+ const handler = (event: MessageEvent<SingletonMessage>) => {
47
+ const message = event.data;
48
+ if (message?.type !== SingletonMessage.Type.WINDOW_MESSAGE) {
49
+ return;
50
+ }
51
+
52
+ log('Received message from singleton client:', message);
53
+ callback(new Uint8Array(message.data!));
54
+ };
55
+
56
+ window.addEventListener('message', handler);
57
+ return () => window.removeEventListener('message', handler);
58
+ }
59
+ };
60
+ };
@@ -0,0 +1,170 @@
1
+ //
2
+ // Copyright 2022 DXOS.org
3
+ //
4
+
5
+ import debug from 'debug';
6
+
7
+ import { sleep } from '@dxos/async';
8
+ import { Config, Defaults, Dynamics } from '@dxos/config';
9
+ import { createBundledRpcServer, RpcPort } from '@dxos/rpc';
10
+
11
+ import { Client } from '../client';
12
+ import { clientServiceBundle } from '../packlets/api';
13
+ import { SingletonMessage } from '../packlets/proto';
14
+ import { ProxyPort } from './proxy-port';
15
+
16
+ const log = debug('dxos:client:singleton');
17
+
18
+ const RECONNECT_BACKOFF = 500;
19
+ const activeProxies = new Map<number, (msg: Uint8Array) => void>();
20
+
21
+ /**
22
+ * Creates RpcPort for communicating with parent window.
23
+ */
24
+ const createWindowPort = (): RpcPort => ({
25
+ send: async message => window.parent.postMessage({
26
+ type: SingletonMessage.Type.WINDOW_MESSAGE,
27
+ data: Array.from(message)
28
+ }, '*'),
29
+ subscribe: callback => {
30
+ const handler = (event: MessageEvent<SingletonMessage>) => {
31
+ const message = event.data;
32
+ if (message?.type !== SingletonMessage.Type.WINDOW_MESSAGE) {
33
+ return;
34
+ }
35
+
36
+ callback(new Uint8Array(message.data!));
37
+ };
38
+
39
+ window.addEventListener('message', handler);
40
+ return () => window.removeEventListener('message', handler);
41
+ }
42
+ });
43
+
44
+ /**
45
+ * Creates RpcPort for communicating with other windows via SharedWorker.
46
+ */
47
+ const createServiceWorkerPort = (sendPort: ProxyPort, sourceId: number): RpcPort => ({
48
+ send: async message => sendPort.postMessage({
49
+ type: SingletonMessage.Type.CLIENT_MESSAGE,
50
+ clientMessage: {
51
+ sourceId,
52
+ data: message
53
+ }
54
+ }),
55
+ subscribe: callback => {
56
+ // Maintain set of proxies and reuse main port message event handler.
57
+ activeProxies.set(sourceId, callback);
58
+ return () => activeProxies.delete(sourceId);
59
+ }
60
+ });
61
+
62
+ if (typeof SharedWorker !== 'undefined') {
63
+ void (async () => {
64
+ let client: Client;
65
+ let windowClientProxyHandler: ((event: MessageEvent<SingletonMessage>) => void) | null = null;
66
+
67
+ const worker = new SharedWorker('./shared-worker.js');
68
+ worker.port.start();
69
+ const port = new ProxyPort(worker.port);
70
+
71
+ window.addEventListener('beforeunload', () => {
72
+ port.postMessage({ type: SingletonMessage.Type.PORT_CLOSING });
73
+ });
74
+
75
+ port.onmessage = async event => {
76
+ const message = event.data;
77
+ log('Recieved message from shared worker', message);
78
+ switch (message?.type) {
79
+ case SingletonMessage.Type.RECONNECT: {
80
+ const { attempt } = message.reconnect!;
81
+ await sleep(attempt * RECONNECT_BACKOFF);
82
+ port.postMessage(message);
83
+ break;
84
+ }
85
+
86
+ case SingletonMessage.Type.SETUP_CLIENT: {
87
+ const config = new Config(await Dynamics(), Defaults());
88
+ client = new Client(config);
89
+ await client.initialize();
90
+
91
+ if (windowClientProxyHandler) {
92
+ window.removeEventListener('message', windowClientProxyHandler);
93
+ windowClientProxyHandler = null;
94
+ }
95
+ const server = createBundledRpcServer({
96
+ services: clientServiceBundle,
97
+ handlers: client.services,
98
+ port: createWindowPort()
99
+ });
100
+
101
+ port.postMessage({ type: SingletonMessage.Type.CLIENT_READY });
102
+ window.parent.postMessage({ type: SingletonMessage.Type.CLIENT_READY }, '*');
103
+ await server.open();
104
+ break;
105
+ }
106
+
107
+ case SingletonMessage.Type.SETUP_PORT: {
108
+ const { sourceId } = message.setupPort!;
109
+ const server = createBundledRpcServer({
110
+ services: clientServiceBundle,
111
+ handlers: client.services,
112
+ port: createServiceWorkerPort(port, sourceId)
113
+ });
114
+ port.postMessage({
115
+ type: SingletonMessage.Type.PORT_READY,
116
+ portReady: {
117
+ sourceId
118
+ }
119
+ });
120
+ await server.open();
121
+ break;
122
+ }
123
+
124
+ case SingletonMessage.Type.PORT_READY: {
125
+ const { sourceId } = message.portReady!;
126
+ windowClientProxyHandler = (event: MessageEvent<SingletonMessage>) => {
127
+ const message = event.data;
128
+ if (message?.type !== SingletonMessage.Type.WINDOW_MESSAGE) {
129
+ return;
130
+ }
131
+
132
+ port.postMessage({
133
+ type: SingletonMessage.Type.PROXY_MESSAGE,
134
+ proxyMessage: {
135
+ sourceId,
136
+ data: message.data!
137
+ }
138
+ });
139
+ };
140
+
141
+ window.addEventListener('message', windowClientProxyHandler);
142
+ window.parent.postMessage({ type: SingletonMessage.Type.CLIENT_READY }, '*');
143
+ break;
144
+ }
145
+
146
+ case SingletonMessage.Type.PROXY_MESSAGE: {
147
+ const { sourceId, data } = message.proxyMessage!;
148
+ activeProxies.get(sourceId)?.(new Uint8Array(data));
149
+ break;
150
+ }
151
+
152
+ case SingletonMessage.Type.CLIENT_MESSAGE: {
153
+ const { data } = message.clientMessage!;
154
+ window.parent.postMessage({
155
+ type: SingletonMessage.Type.WINDOW_MESSAGE,
156
+ data
157
+ }, '*');
158
+ break;
159
+ }
160
+
161
+ case SingletonMessage.Type.RESEND: {
162
+ port.postMessage(message);
163
+ break;
164
+ }
165
+ }
166
+ };
167
+ })();
168
+ } else {
169
+ throw new Error('DXOS Client singleton requires a browser with support for shared workers.');
170
+ }
@@ -0,0 +1,23 @@
1
+ //
2
+ // Copyright 2022 DXOS.org
3
+ //
4
+
5
+ import { MaybePromise } from '@dxos/util';
6
+
7
+ import { SingletonMessage } from '../packlets/proto';
8
+
9
+ export class ProxyPort {
10
+ constructor (private readonly port: MessagePort) {}
11
+
12
+ get onmessage () {
13
+ return this.port.onmessage;
14
+ }
15
+
16
+ set onmessage (handler: ((event: MessageEvent<SingletonMessage>) => MaybePromise<void>) | null) {
17
+ this.port.onmessage = handler;
18
+ }
19
+
20
+ postMessage (message: SingletonMessage) {
21
+ this.port.postMessage(message);
22
+ }
23
+ }
@@ -0,0 +1,147 @@
1
+ //
2
+ // Copyright 2020 DXOS.org
3
+ //
4
+
5
+ import debug from 'debug';
6
+
7
+ import { SingletonMessage } from '../packlets/proto';
8
+ import { ProxyPort } from './proxy-port';
9
+
10
+ const log = debug('dxos:client:shared-worker');
11
+ const error = log.extend('error');
12
+
13
+ let nextId = 1;
14
+ const communicationPorts = new Map<number, ProxyPort>();
15
+ let clientId: number | null = null;
16
+
17
+ const getClientPort = () => {
18
+ const port = communicationPorts.get(clientId!);
19
+ if (!port) {
20
+ throw new Error('clientId defined and port not found');
21
+ }
22
+
23
+ return port;
24
+ };
25
+
26
+ onconnect = event => {
27
+ const sourceId = nextId;
28
+ nextId++;
29
+
30
+ const handlePortMessage = async (event: MessageEvent<SingletonMessage>) => {
31
+ const message = event.data;
32
+ log(`Recieved message from source ${sourceId}`, message);
33
+
34
+ switch (message?.type) {
35
+ case SingletonMessage.Type.RECONNECT: {
36
+ const { attempt } = message.reconnect!;
37
+ if (attempt >= 5) {
38
+ error(`Failed to connect to client for source ${sourceId}`);
39
+ break;
40
+ }
41
+
42
+ if (!clientId) {
43
+ port.postMessage({
44
+ type: SingletonMessage.Type.RECONNECT,
45
+ reconnect: {
46
+ attempt: attempt + 1
47
+ }
48
+ });
49
+ break;
50
+ }
51
+
52
+ getClientPort().postMessage({
53
+ type: SingletonMessage.Type.SETUP_PORT,
54
+ setupPort: {
55
+ sourceId
56
+ }
57
+ });
58
+ break;
59
+ }
60
+
61
+ case SingletonMessage.Type.CLIENT_READY: {
62
+ clientId = sourceId;
63
+ [...communicationPorts.keys()].forEach(id => {
64
+ if (id !== sourceId) {
65
+ getClientPort().postMessage({
66
+ type: SingletonMessage.Type.SETUP_PORT,
67
+ setupPort: {
68
+ sourceId: id
69
+ }
70
+ });
71
+ }
72
+ });
73
+ break;
74
+ }
75
+
76
+ case SingletonMessage.Type.PORT_READY: {
77
+ const { sourceId } = message.portReady!;
78
+ const forwardPort = communicationPorts.get(sourceId);
79
+ forwardPort?.postMessage(message);
80
+ break;
81
+ }
82
+
83
+ case SingletonMessage.Type.PORT_CLOSING: {
84
+ communicationPorts.delete(sourceId);
85
+
86
+ if (sourceId === clientId) {
87
+ clientId = null;
88
+ const [port] = [...communicationPorts.values()];
89
+ port?.postMessage({ type: SingletonMessage.Type.SETUP_CLIENT });
90
+ }
91
+
92
+ break;
93
+ }
94
+
95
+ case SingletonMessage.Type.PROXY_MESSAGE: {
96
+ if (!clientId) {
97
+ port.postMessage({
98
+ type: SingletonMessage.Type.RESEND,
99
+ resend: {
100
+ message
101
+ }
102
+ });
103
+ break;
104
+ }
105
+
106
+ const clientPort = communicationPorts.get(clientId);
107
+ clientPort?.postMessage({
108
+ type: SingletonMessage.Type.PROXY_MESSAGE,
109
+ proxyMessage: {
110
+ sourceId,
111
+ data: message.proxyMessage!.data
112
+ }
113
+ });
114
+ break;
115
+ }
116
+
117
+ case SingletonMessage.Type.CLIENT_MESSAGE: {
118
+ const { sourceId } = message.clientMessage!;
119
+ const forwardPort = communicationPorts.get(sourceId);
120
+ forwardPort?.postMessage(message);
121
+ break;
122
+ }
123
+ }
124
+ };
125
+
126
+ const port = new ProxyPort(event.ports[0]);
127
+ port.onmessage = handlePortMessage;
128
+ communicationPorts.set(sourceId, port);
129
+
130
+ if (communicationPorts.size === 1) {
131
+ port.postMessage({ type: SingletonMessage.Type.SETUP_CLIENT });
132
+ } else if (!clientId) {
133
+ port.postMessage({
134
+ type: SingletonMessage.Type.RECONNECT,
135
+ reconnect: {
136
+ attempt: 1
137
+ }
138
+ });
139
+ } else {
140
+ getClientPort().postMessage({
141
+ type: SingletonMessage.Type.SETUP_PORT,
142
+ setupPort: {
143
+ sourceId
144
+ }
145
+ });
146
+ }
147
+ };
@@ -0,0 +1,36 @@
1
+ //
2
+ // Copyright 2022 DXOS.org
3
+ //
4
+
5
+ import React, { useState } from 'react';
6
+
7
+ import { useAsyncEffect } from '@dxos/react-async';
8
+
9
+ import { Client } from '../packlets/proxy';
10
+
11
+ export default {
12
+ title: 'client/singleton'
13
+ };
14
+
15
+ export const Primary = () => {
16
+ const [client, setClient] = useState<Client>();
17
+
18
+ useAsyncEffect(async () => {
19
+ const client = new Client();
20
+ await client.initialize();
21
+ setClient(client);
22
+ }, []);
23
+
24
+ if (!client) {
25
+ return null;
26
+ }
27
+
28
+ return (
29
+ <pre>
30
+ {JSON.stringify({
31
+ initialized: client.initialized,
32
+ ...(client.initialized ? client.info : {})
33
+ })}
34
+ </pre>
35
+ );
36
+ };
@@ -1,3 +0,0 @@
1
- import { RpcPort } from '@dxos/rpc';
2
- export declare const createWindowMessagePort: () => RpcPort;
3
- //# sourceMappingURL=messages.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../../src/packlets/proxy/messages.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,eAAO,MAAM,uBAAuB,QAAO,OAqB1C,CAAC"}
@@ -1,30 +0,0 @@
1
- "use strict";
2
- //
3
- // Copyright 2021 DXOS.org
4
- //
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.createWindowMessagePort = void 0;
7
- const util_1 = require("@dxos/util");
8
- const createWindowMessagePort = () => {
9
- if ((0, util_1.isNode)()) {
10
- throw new Error('Connecting to wallet extension is not available in Node environment.');
11
- }
12
- return {
13
- send: async (message) => window.postMessage({
14
- payloadFromAppToContentScript: Array.from(message)
15
- }, '*'),
16
- subscribe: (callback) => {
17
- const listener = (event) => {
18
- var _a;
19
- const payload = (_a = event === null || event === void 0 ? void 0 : event.data) === null || _a === void 0 ? void 0 : _a.payloadFromContentScriptToApp;
20
- if (payload) {
21
- callback(new Uint8Array(payload));
22
- }
23
- };
24
- window.addEventListener('message', listener);
25
- return () => window.removeEventListener('message', listener);
26
- }
27
- };
28
- };
29
- exports.createWindowMessagePort = createWindowMessagePort;
30
- //# sourceMappingURL=messages.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"messages.js","sourceRoot":"","sources":["../../../../src/packlets/proxy/messages.ts"],"names":[],"mappings":";AAAA,EAAE;AACF,0BAA0B;AAC1B,EAAE;;;AAGF,qCAAoC;AAE7B,MAAM,uBAAuB,GAAG,GAAY,EAAE;IACnD,IAAI,IAAA,aAAM,GAAE,EAAE;QACZ,MAAM,IAAI,KAAK,CAAC,sEAAsE,CAAC,CAAC;KACzF;IAED,OAAO;QACL,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC;YAC1C,6BAA6B,EAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC;SACnD,EAAE,GAAG,CAAC;QAEP,SAAS,EAAE,CAAC,QAAQ,EAAE,EAAE;YACtB,MAAM,QAAQ,GAAkB,CAAC,KAAK,EAAE,EAAE;;gBACxC,MAAM,OAAO,GAAG,MAAC,KAAa,aAAb,KAAK,uBAAL,KAAK,CAAU,IAAI,0CAAE,6BAA6B,CAAC;gBACpE,IAAI,OAAO,EAAE;oBACX,QAAQ,CAAC,IAAI,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;iBACnC;YACH,CAAC,CAAC;YACF,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;YAC7C,OAAO,GAAG,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAC/D,CAAC;KACF,CAAC;AACJ,CAAC,CAAC;AArBW,QAAA,uBAAuB,2BAqBlC"}
@@ -1,29 +0,0 @@
1
- //
2
- // Copyright 2021 DXOS.org
3
- //
4
-
5
- import { RpcPort } from '@dxos/rpc';
6
- import { isNode } from '@dxos/util';
7
-
8
- export const createWindowMessagePort = (): RpcPort => {
9
- if (isNode()) {
10
- throw new Error('Connecting to wallet extension is not available in Node environment.');
11
- }
12
-
13
- return {
14
- send: async (message) => window.postMessage({
15
- payloadFromAppToContentScript: Array.from(message)
16
- }, '*'),
17
-
18
- subscribe: (callback) => {
19
- const listener: EventListener = (event) => {
20
- const payload = (event as any)?.data?.payloadFromContentScriptToApp;
21
- if (payload) {
22
- callback(new Uint8Array(payload));
23
- }
24
- };
25
- window.addEventListener('message', listener);
26
- return () => window.removeEventListener('message', listener);
27
- }
28
- };
29
- };