@dxos/react-client 0.8.4-main.ae835ea → 0.8.4-main.bc674ce
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.storybook/main.mts +1 -1
- package/.storybook/preview.mts +2 -2
- package/dist/lib/browser/chunk-5UKA2BMA.mjs +179 -0
- package/dist/lib/browser/chunk-5UKA2BMA.mjs.map +7 -0
- package/dist/lib/browser/chunk-PFF63FPR.mjs +16 -0
- package/dist/lib/browser/chunk-PFF63FPR.mjs.map +7 -0
- package/dist/lib/browser/chunk-TSF6Y5VB.mjs +8 -0
- package/dist/lib/browser/chunk-TSF6Y5VB.mjs.map +7 -0
- package/dist/lib/browser/devtools/index.mjs +2 -1
- package/dist/lib/browser/devtools/index.mjs.map +1 -1
- package/dist/lib/browser/echo/index.mjs +44 -94
- package/dist/lib/browser/echo/index.mjs.map +4 -4
- package/dist/lib/browser/halo/index.mjs +2 -1
- package/dist/lib/browser/halo/index.mjs.map +1 -1
- package/dist/lib/browser/index.mjs +114 -12
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/mesh/index.mjs +2 -1
- package/dist/lib/browser/mesh/index.mjs.map +1 -1
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +78 -73
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/node-esm/chunk-373DPHEQ.mjs +10 -0
- package/dist/lib/node-esm/chunk-373DPHEQ.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-NETTSER2.mjs +17 -0
- package/dist/lib/node-esm/chunk-NETTSER2.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-T3QTQHBD.mjs +180 -0
- package/dist/lib/node-esm/chunk-T3QTQHBD.mjs.map +7 -0
- package/dist/lib/node-esm/devtools/index.mjs +2 -1
- package/dist/lib/node-esm/devtools/index.mjs.map +1 -1
- package/dist/lib/node-esm/echo/index.mjs +44 -94
- package/dist/lib/node-esm/echo/index.mjs.map +4 -4
- package/dist/lib/node-esm/halo/index.mjs +2 -1
- package/dist/lib/node-esm/halo/index.mjs.map +1 -1
- package/dist/lib/node-esm/index.mjs +114 -12
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/mesh/index.mjs +2 -1
- package/dist/lib/node-esm/mesh/index.mjs.map +1 -1
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +78 -73
- package/dist/lib/node-esm/testing/index.mjs.map +3 -3
- package/dist/types/src/client/ClientProvider.d.ts +0 -10
- package/dist/types/src/client/ClientProvider.d.ts.map +1 -1
- package/dist/types/src/echo/index.d.ts +2 -2
- package/dist/types/src/echo/index.d.ts.map +1 -1
- package/dist/types/src/echo/useMembers.d.ts +2 -2
- package/dist/types/src/echo/useMembers.d.ts.map +1 -1
- package/dist/types/src/echo/useQueue.d.ts +2 -2
- package/dist/types/src/echo/useQueue.d.ts.map +1 -1
- package/dist/types/src/echo/useSpaceInvitations.d.ts +3 -2
- package/dist/types/src/echo/useSpaceInvitations.d.ts.map +1 -1
- package/dist/types/src/echo/useSpaceProperties.d.ts +13 -0
- package/dist/types/src/echo/useSpaceProperties.d.ts.map +1 -0
- package/dist/types/src/echo/useSpaces.d.ts +17 -8
- package/dist/types/src/echo/useSpaces.d.ts.map +1 -1
- package/dist/types/src/testing/ClientRepeater.d.ts +5 -4
- package/dist/types/src/testing/ClientRepeater.d.ts.map +1 -1
- package/dist/types/src/testing/ClientRepeater.stories.d.ts.map +1 -1
- package/dist/types/src/testing/context.d.ts +4 -2
- package/dist/types/src/testing/context.d.ts.map +1 -1
- package/dist/types/src/testing/withClientProvider.d.ts +0 -3
- package/dist/types/src/testing/withClientProvider.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +35 -31
- package/src/client/ClientProvider.tsx +12 -26
- package/src/echo/index.ts +2 -2
- package/src/echo/useMembers.ts +5 -3
- package/src/echo/useQueue.ts +2 -2
- package/src/echo/useSpaceInvitations.ts +9 -4
- package/src/echo/useSpaceProperties.ts +28 -0
- package/src/echo/useSpaces.test.tsx +1 -1
- package/src/echo/useSpaces.ts +33 -12
- package/src/echo/useSyncState.ts +2 -2
- package/src/playwright/playwright.config.ts +1 -1
- package/src/testing/ClientRepeater.stories.tsx +8 -3
- package/src/testing/ClientRepeater.tsx +9 -12
- package/src/testing/context.tsx +4 -3
- package/src/testing/withClientProvider.tsx +61 -47
- package/tsconfig.json +3 -3
- package/vitest.config.ts +1 -1
- package/dist/lib/browser/chunk-TA2HGRAF.mjs +0 -309
- package/dist/lib/browser/chunk-TA2HGRAF.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-ZJMNF7GC.mjs +0 -311
- package/dist/lib/node-esm/chunk-ZJMNF7GC.mjs.map +0 -7
- package/dist/types/src/echo/useQuery.d.ts +0 -11
- package/dist/types/src/echo/useQuery.d.ts.map +0 -1
- package/dist/types/src/echo/useQuery.test.d.ts +0 -2
- package/dist/types/src/echo/useQuery.test.d.ts.map +0 -1
- package/dist/types/src/echo/useSchema.d.ts +0 -8
- package/dist/types/src/echo/useSchema.d.ts.map +0 -1
- package/src/echo/useQuery.test.tsx +0 -129
- package/src/echo/useQuery.ts +0 -63
- package/src/echo/useSchema.ts +0 -54
package/package.json
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/react-client",
|
|
3
|
-
"version": "0.8.4-main.
|
|
3
|
+
"version": "0.8.4-main.bc674ce",
|
|
4
4
|
"description": "React client API",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/dxos/dxos"
|
|
10
|
+
},
|
|
7
11
|
"license": "MIT",
|
|
8
12
|
"author": "DXOS.org",
|
|
9
|
-
"sideEffects":
|
|
13
|
+
"sideEffects": false,
|
|
10
14
|
"type": "module",
|
|
11
15
|
"exports": {
|
|
12
16
|
"./devtools": {
|
|
@@ -86,42 +90,42 @@
|
|
|
86
90
|
},
|
|
87
91
|
"dependencies": {
|
|
88
92
|
"react-error-boundary": "^4.0.13",
|
|
89
|
-
"@dxos/async": "0.8.4-main.
|
|
90
|
-
"@dxos/
|
|
91
|
-
"@dxos/
|
|
92
|
-
"@dxos/
|
|
93
|
-
"@dxos/
|
|
94
|
-
"@dxos/
|
|
95
|
-
"@dxos/echo
|
|
96
|
-
"@dxos/
|
|
97
|
-
"@dxos/
|
|
98
|
-
"@dxos/
|
|
99
|
-
"@dxos/
|
|
100
|
-
"@dxos/
|
|
101
|
-
"@dxos/
|
|
102
|
-
"@dxos/util": "0.8.4-main.
|
|
93
|
+
"@dxos/async": "0.8.4-main.bc674ce",
|
|
94
|
+
"@dxos/client": "0.8.4-main.bc674ce",
|
|
95
|
+
"@dxos/codec-protobuf": "0.8.4-main.bc674ce",
|
|
96
|
+
"@dxos/context": "0.8.4-main.bc674ce",
|
|
97
|
+
"@dxos/config": "0.8.4-main.bc674ce",
|
|
98
|
+
"@dxos/debug": "0.8.4-main.bc674ce",
|
|
99
|
+
"@dxos/echo": "0.8.4-main.bc674ce",
|
|
100
|
+
"@dxos/echo-react": "0.8.4-main.bc674ce",
|
|
101
|
+
"@dxos/log": "0.8.4-main.bc674ce",
|
|
102
|
+
"@dxos/protocols": "0.8.4-main.bc674ce",
|
|
103
|
+
"@dxos/invariant": "0.8.4-main.bc674ce",
|
|
104
|
+
"@dxos/react-hooks": "0.8.4-main.bc674ce",
|
|
105
|
+
"@dxos/node-std": "0.8.4-main.bc674ce",
|
|
106
|
+
"@dxos/util": "0.8.4-main.bc674ce"
|
|
103
107
|
},
|
|
104
108
|
"devDependencies": {
|
|
105
|
-
"@types/react": "~19.2.
|
|
106
|
-
"@types/react-dom": "~19.2.
|
|
107
|
-
"react": "~19.2.
|
|
108
|
-
"react-dom": "~19.2.
|
|
109
|
+
"@types/react": "~19.2.7",
|
|
110
|
+
"@types/react-dom": "~19.2.3",
|
|
111
|
+
"react": "~19.2.3",
|
|
112
|
+
"react-dom": "~19.2.3",
|
|
109
113
|
"typedoc": "0.28.1",
|
|
110
|
-
"@dxos/random": "0.8.4-main.
|
|
111
|
-
"@dxos/react-ui
|
|
112
|
-
"@dxos/
|
|
113
|
-
"@dxos/
|
|
114
|
-
"@dxos/
|
|
115
|
-
"@dxos/
|
|
114
|
+
"@dxos/random": "0.8.4-main.bc674ce",
|
|
115
|
+
"@dxos/react-ui": "0.8.4-main.bc674ce",
|
|
116
|
+
"@dxos/storybook-utils": "0.8.4-main.bc674ce",
|
|
117
|
+
"@dxos/test-utils": "0.8.4-main.bc674ce",
|
|
118
|
+
"@dxos/ui-theme": "0.8.4-main.bc674ce",
|
|
119
|
+
"@dxos/react-ui-syntax-highlighter": "0.8.4-main.bc674ce"
|
|
116
120
|
},
|
|
117
121
|
"peerDependencies": {
|
|
118
|
-
"react": "
|
|
119
|
-
"react-dom": "
|
|
122
|
+
"react": "~19.2.3",
|
|
123
|
+
"react-dom": "~19.2.3"
|
|
120
124
|
},
|
|
121
125
|
"optionalDependencies": {
|
|
122
|
-
"@dxos/random": "0.8.4-main.
|
|
123
|
-
"@dxos/
|
|
124
|
-
"@dxos/react-ui
|
|
126
|
+
"@dxos/random": "0.8.4-main.bc674ce",
|
|
127
|
+
"@dxos/ui-theme": "0.8.4-main.bc674ce",
|
|
128
|
+
"@dxos/react-ui": "0.8.4-main.bc674ce"
|
|
125
129
|
},
|
|
126
130
|
"publishConfig": {
|
|
127
131
|
"access": "public"
|
|
@@ -13,7 +13,6 @@ import React, {
|
|
|
13
13
|
|
|
14
14
|
import { Client, type ClientOptions, type ClientServicesProvider, SystemStatus } from '@dxos/client';
|
|
15
15
|
import { type Config } from '@dxos/config';
|
|
16
|
-
import { registerSignalsRuntime } from '@dxos/echo-signals/react';
|
|
17
16
|
import { log } from '@dxos/log';
|
|
18
17
|
import { useAsyncEffect, useControlledState } from '@dxos/react-hooks';
|
|
19
18
|
import { type MaybePromise, type Provider, getAsyncProviderValue } from '@dxos/util';
|
|
@@ -56,12 +55,6 @@ export type ClientProviderProps = Omit<ClientOptions, 'config' | 'services'> &
|
|
|
56
55
|
*/
|
|
57
56
|
fallback?: FunctionComponent<Partial<ClientContextProps>>;
|
|
58
57
|
|
|
59
|
-
/**
|
|
60
|
-
* Enable (by default) registration of Preact signals runtime for reactive ECHO objects.
|
|
61
|
-
* @see https://www.npmjs.com/package/@preact/signals-react
|
|
62
|
-
*/
|
|
63
|
-
signalsRuntime?: boolean;
|
|
64
|
-
|
|
65
58
|
/**
|
|
66
59
|
* Skip the DXOS banner.
|
|
67
60
|
*/
|
|
@@ -81,24 +74,17 @@ export const ClientProvider = forwardRef<Client | undefined, ClientProviderProps
|
|
|
81
74
|
(
|
|
82
75
|
{
|
|
83
76
|
children,
|
|
84
|
-
config:
|
|
85
|
-
client:
|
|
86
|
-
services:
|
|
87
|
-
status:
|
|
77
|
+
config: configProp,
|
|
78
|
+
client: clientProp,
|
|
79
|
+
services: servicesProp,
|
|
80
|
+
status: statusProp,
|
|
88
81
|
fallback: Fallback = () => null,
|
|
89
|
-
signalsRuntime = true,
|
|
90
82
|
noBanner,
|
|
91
83
|
onInitialized,
|
|
92
84
|
...options
|
|
93
85
|
},
|
|
94
86
|
forwardedRef,
|
|
95
87
|
) => {
|
|
96
|
-
useEffect(() => {
|
|
97
|
-
// TODO(wittjosiah): Ideally this should be imported asynchronously because it is optional.
|
|
98
|
-
// Unfortunately, async import seemed to break signals React instrumentation.
|
|
99
|
-
signalsRuntime && registerSignalsRuntime();
|
|
100
|
-
}, []);
|
|
101
|
-
|
|
102
88
|
// The client is initialized asynchronously.
|
|
103
89
|
// If an error occurs during initialization, it is caught and the state is set.
|
|
104
90
|
// This allows the error to be thrown in the render method.
|
|
@@ -109,13 +95,13 @@ export const ClientProvider = forwardRef<Client | undefined, ClientProviderProps
|
|
|
109
95
|
throw error;
|
|
110
96
|
}
|
|
111
97
|
|
|
112
|
-
const [client, setClient] = useState(
|
|
98
|
+
const [client, setClient] = useState(clientProp instanceof Client ? clientProp : undefined);
|
|
113
99
|
|
|
114
100
|
// Provide external access.
|
|
115
101
|
useImperativeHandle(forwardedRef, () => client, [client]);
|
|
116
102
|
|
|
117
103
|
// Client status subscription.
|
|
118
|
-
const [status, setStatus] = useControlledState(
|
|
104
|
+
const [status, setStatus] = useControlledState(statusProp);
|
|
119
105
|
useEffect(() => {
|
|
120
106
|
if (!client) {
|
|
121
107
|
return;
|
|
@@ -148,15 +134,15 @@ export const ClientProvider = forwardRef<Client | undefined, ClientProviderProps
|
|
|
148
134
|
|
|
149
135
|
let client: Client;
|
|
150
136
|
try {
|
|
151
|
-
if (
|
|
137
|
+
if (clientProp) {
|
|
152
138
|
// Asynchronously request client.
|
|
153
|
-
client = await getAsyncProviderValue(
|
|
139
|
+
client = await getAsyncProviderValue(clientProp);
|
|
154
140
|
await initialize(client);
|
|
155
141
|
} else {
|
|
156
142
|
// Asynchronously construct client (config may be undefined).
|
|
157
|
-
const config = await getAsyncProviderValue(
|
|
143
|
+
const config = await getAsyncProviderValue(configProp);
|
|
158
144
|
log('resolved config', { config });
|
|
159
|
-
const services = await getAsyncProviderValue(
|
|
145
|
+
const services = await getAsyncProviderValue(servicesProp, config);
|
|
160
146
|
log('created services', { services });
|
|
161
147
|
client = new Client({ config, services, ...options });
|
|
162
148
|
log('created client');
|
|
@@ -172,7 +158,7 @@ export const ClientProvider = forwardRef<Client | undefined, ClientProviderProps
|
|
|
172
158
|
log('clean up');
|
|
173
159
|
disposed = true;
|
|
174
160
|
// Only destroy if the client is not provided by the parent.
|
|
175
|
-
if (!
|
|
161
|
+
if (!clientProp) {
|
|
176
162
|
void client
|
|
177
163
|
?.destroy()
|
|
178
164
|
.then(() => {
|
|
@@ -181,7 +167,7 @@ export const ClientProvider = forwardRef<Client | undefined, ClientProviderProps
|
|
|
181
167
|
.catch((err) => log.catch(err));
|
|
182
168
|
}
|
|
183
169
|
};
|
|
184
|
-
}, [
|
|
170
|
+
}, [configProp, clientProp, servicesProp, noBanner]);
|
|
185
171
|
|
|
186
172
|
if (!client?.initialized || status !== SystemStatus.ACTIVE) {
|
|
187
173
|
return <Fallback client={client} status={status} />;
|
package/src/echo/index.ts
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
export * from '@dxos/client/echo';
|
|
6
|
+
export * from '@dxos/echo-react';
|
|
6
7
|
|
|
7
8
|
export * from './useMembers';
|
|
8
|
-
export * from './useQuery';
|
|
9
9
|
export * from './useQueue';
|
|
10
|
-
export * from './useSchema';
|
|
11
10
|
export * from './useSpaces';
|
|
12
11
|
export * from './useSpaceInvitations';
|
|
12
|
+
export * from './useSpaceProperties';
|
|
13
13
|
export * from './useSubscription';
|
|
14
14
|
export * from './useSyncState';
|
package/src/echo/useMembers.ts
CHANGED
|
@@ -3,16 +3,18 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { MulticastObservable } from '@dxos/async';
|
|
6
|
-
import { type
|
|
6
|
+
import { PublicKey, type PublicKeyLike } from '@dxos/client';
|
|
7
7
|
import { HaloSpaceMember, type SpaceMember } from '@dxos/client/echo';
|
|
8
8
|
import { useMulticastObservable } from '@dxos/react-hooks';
|
|
9
9
|
|
|
10
10
|
import { useSpaces } from './useSpaces';
|
|
11
11
|
|
|
12
|
-
export const useMembers = (spaceKey:
|
|
12
|
+
export const useMembers = (spaceKey: PublicKeyLike | undefined): SpaceMember[] => {
|
|
13
13
|
// TODO(dmaretskyi): useSpace hook for spaces that are not ready.
|
|
14
14
|
const spaces = useSpaces({ all: true });
|
|
15
|
-
const space = spaceKey
|
|
15
|
+
const space = spaceKey
|
|
16
|
+
? spaces.find((space) => (spaceKey instanceof PublicKey ? space.key.equals(spaceKey) : space.id === spaceKey))
|
|
17
|
+
: undefined;
|
|
16
18
|
|
|
17
19
|
// EMPTY_OBSERVABLE needs to be a stable reference to avoid re-subscribing on every render.
|
|
18
20
|
const members = useMulticastObservable(space?.members ?? MulticastObservable.empty()) ?? [];
|
package/src/echo/useQueue.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { useEffect, useMemo, useRef } from 'react';
|
|
|
6
6
|
|
|
7
7
|
import { type Queue } from '@dxos/client/echo';
|
|
8
8
|
import { raise } from '@dxos/debug';
|
|
9
|
-
import { type
|
|
9
|
+
import { type Entity } from '@dxos/echo';
|
|
10
10
|
import { type DXN } from '@dxos/keys';
|
|
11
11
|
|
|
12
12
|
import { useClient } from '../client';
|
|
@@ -24,7 +24,7 @@ export type UseQueueOptions = {
|
|
|
24
24
|
// TODO(dmaretskyi): Move into client package.
|
|
25
25
|
// TODO(dmaretskyi): Consider passing the space into the hook to support queue DXNs without space id.
|
|
26
26
|
// TODO(ZaymonFC): If queue is unchanged returned object should be refferentially stable on poll.
|
|
27
|
-
export const useQueue = <T extends
|
|
27
|
+
export const useQueue = <T extends Entity.Unknown>(
|
|
28
28
|
queueDxn?: DXN,
|
|
29
29
|
options: UseQueueOptions = {},
|
|
30
30
|
): Queue<T> | undefined => {
|
|
@@ -6,19 +6,24 @@ import { useMemo } from 'react';
|
|
|
6
6
|
|
|
7
7
|
import { MulticastObservable } from '@dxos/async';
|
|
8
8
|
import { type PublicKey } from '@dxos/client';
|
|
9
|
+
import { type SpaceId } from '@dxos/client/echo';
|
|
9
10
|
import { useMulticastObservable } from '@dxos/react-hooks';
|
|
10
11
|
|
|
11
12
|
import { type CancellableInvitationObservable, useInvitationStatus } from '../invitations';
|
|
12
13
|
|
|
13
14
|
import { useSpace } from './useSpaces';
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
// TODO(wittjosiah): Currently unable to remove `PublicKey` from this api.
|
|
17
|
+
// When initially joining a space that is all that is returned.
|
|
18
|
+
export const useSpaceInvitations = (spaceId?: SpaceId | PublicKey): CancellableInvitationObservable[] => {
|
|
19
|
+
const space = useSpace(spaceId);
|
|
17
20
|
return useMulticastObservable(space?.invitations ?? MulticastObservable.empty()) ?? [];
|
|
18
21
|
};
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
|
|
23
|
+
// TODO(wittjosiah): Currently unable to remove `PublicKey` from this api.
|
|
24
|
+
// When initially joining a space that is all that is returned.
|
|
25
|
+
export const useSpaceInvitation = (spaceId?: SpaceId | PublicKey, invitationId?: string) => {
|
|
26
|
+
const invitations = useSpaceInvitations(spaceId);
|
|
22
27
|
const invitation = useMemo(
|
|
23
28
|
() => invitations.find((invitation) => invitation.get().invitationId === invitationId),
|
|
24
29
|
[invitations],
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { MulticastObservable } from '@dxos/async';
|
|
6
|
+
import { type SpaceProperties, SpaceState } from '@dxos/client/echo';
|
|
7
|
+
import { type Key, type Obj } from '@dxos/echo';
|
|
8
|
+
import { type ObjectUpdateCallback, useObject } from '@dxos/echo-react';
|
|
9
|
+
import { useMulticastObservable } from '@dxos/react-hooks';
|
|
10
|
+
|
|
11
|
+
import { useSpace } from './useSpaces';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Subscribe to a space's properties with reactive updates.
|
|
15
|
+
* Returns undefined if the space is undefined or not ready yet.
|
|
16
|
+
* Automatically waits for the space to be ready before returning properties.
|
|
17
|
+
*
|
|
18
|
+
* @param spaceId - The space ID to get properties from (can be undefined).
|
|
19
|
+
* @returns A tuple of [snapshot, updateCallback] or [undefined, no-op] if not ready.
|
|
20
|
+
*/
|
|
21
|
+
export const useSpaceProperties = (
|
|
22
|
+
spaceId: Key.SpaceId | undefined,
|
|
23
|
+
): [Obj.Snapshot<SpaceProperties> | undefined, ObjectUpdateCallback<SpaceProperties>] => {
|
|
24
|
+
const space = useSpace(spaceId);
|
|
25
|
+
const spaceState = useMulticastObservable(space?.state ?? MulticastObservable.empty());
|
|
26
|
+
const properties = spaceState === SpaceState.SPACE_READY ? space?.properties : undefined;
|
|
27
|
+
return useObject(properties);
|
|
28
|
+
};
|
|
@@ -47,7 +47,7 @@ describe('useSpace', () => {
|
|
|
47
47
|
test('gets space by key', async () => {
|
|
48
48
|
const { client, space } = await createClient({ createIdentity: true, createSpace: true });
|
|
49
49
|
const wrapper = await createClientContextProvider(client);
|
|
50
|
-
const { result } = renderHook(() => useSpace(space!.
|
|
50
|
+
const { result } = renderHook(() => useSpace(space!.id), { wrapper });
|
|
51
51
|
expect(result.current).to.not.be.undefined;
|
|
52
52
|
});
|
|
53
53
|
});
|
package/src/echo/useSpaces.ts
CHANGED
|
@@ -4,37 +4,45 @@
|
|
|
4
4
|
|
|
5
5
|
import { useState } from 'react';
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
import { type Space, SpaceState } from '@dxos/client/echo';
|
|
7
|
+
import { PublicKey } from '@dxos/client';
|
|
8
|
+
import { type Space, type SpaceId, SpaceState } from '@dxos/client/echo';
|
|
9
9
|
import { useAsyncEffect, useMulticastObservable } from '@dxos/react-hooks';
|
|
10
10
|
|
|
11
11
|
import { useClient } from '../client';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* Get a specific Space using its
|
|
14
|
+
* Get a specific Space using its id.
|
|
15
15
|
* The space is not guaranteed to be in the ready state.
|
|
16
|
-
* Returns the default space if no
|
|
16
|
+
* Returns the default space if no id is provided.
|
|
17
17
|
* Requires a ClientProvider somewhere in the parent tree.
|
|
18
18
|
*
|
|
19
|
-
* @param
|
|
19
|
+
* @param spaceId the id of the space to look for
|
|
20
20
|
*/
|
|
21
|
-
|
|
21
|
+
// TODO(wittjosiah): Currently unable to remove `PublicKey` from this api.
|
|
22
|
+
// When initially joining a space that is all that is returned.
|
|
23
|
+
export const useSpace = (spaceId?: SpaceId | PublicKey): Space | undefined => {
|
|
22
24
|
const client = useClient();
|
|
23
25
|
const spaces = useMulticastObservable<Space[]>(client.spaces);
|
|
24
26
|
const [ready, setReady] = useState(false);
|
|
25
27
|
|
|
26
28
|
useAsyncEffect(async () => {
|
|
27
29
|
// Only wait for ready if looking for the default space.
|
|
28
|
-
if (
|
|
30
|
+
if (spaceId) {
|
|
29
31
|
return;
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
await client.spaces.waitUntilReady();
|
|
33
35
|
setReady(true);
|
|
34
|
-
}, [client,
|
|
36
|
+
}, [client, spaceId]);
|
|
35
37
|
|
|
36
|
-
if (
|
|
37
|
-
return spaces.find((space) =>
|
|
38
|
+
if (spaceId) {
|
|
39
|
+
return spaces.find((space) => {
|
|
40
|
+
if (spaceId instanceof PublicKey) {
|
|
41
|
+
return space.key.equals(spaceId);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return space.id === spaceId;
|
|
45
|
+
});
|
|
38
46
|
}
|
|
39
47
|
|
|
40
48
|
if (ready && client.halo.identity.get()) {
|
|
@@ -42,7 +50,20 @@ export const useSpace = (spaceKeyLike?: PublicKeyLike): Space | undefined => {
|
|
|
42
50
|
}
|
|
43
51
|
};
|
|
44
52
|
|
|
45
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Get a Space database by the id of the space.
|
|
55
|
+
* The space is not guaranteed to be in the ready state.
|
|
56
|
+
* Returns the default space if no id is provided.
|
|
57
|
+
* Requires a ClientProvider somewhere in the parent tree.
|
|
58
|
+
*
|
|
59
|
+
* @param spaceId the id of the space to look for
|
|
60
|
+
*/
|
|
61
|
+
export const useDatabase = (spaceId?: SpaceId): Space['db'] | undefined => {
|
|
62
|
+
const space = useSpace(spaceId);
|
|
63
|
+
return space?.db;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export type UseSpacesProps = {
|
|
46
67
|
/**
|
|
47
68
|
* Return uninitialized spaces as well.
|
|
48
69
|
*/
|
|
@@ -55,7 +76,7 @@ export type UseSpacesParams = {
|
|
|
55
76
|
* By default, only ready spaces are returned.
|
|
56
77
|
* @returns an array of Spaces
|
|
57
78
|
*/
|
|
58
|
-
export const useSpaces = ({ all = false }:
|
|
79
|
+
export const useSpaces = ({ all = false }: UseSpacesProps = {}): Space[] => {
|
|
59
80
|
const client = useClient();
|
|
60
81
|
const spaces = useMulticastObservable<Space[]>(client.spaces);
|
|
61
82
|
|
package/src/echo/useSyncState.ts
CHANGED
|
@@ -30,7 +30,7 @@ export const useSyncState = (): SpaceSyncStateMap => {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
ctx.onDispose(
|
|
33
|
-
space.db.subscribeToSyncState(ctx, ({ peers = [] }) => {
|
|
33
|
+
space.internal.db.subscribeToSyncState(ctx, ({ peers = [] }) => {
|
|
34
34
|
const syncState = peers.find((state) => isEdgePeerId(state.peerId, space.id));
|
|
35
35
|
if (syncState) {
|
|
36
36
|
setSpaceState((spaceState) => ({ ...spaceState, [space.id]: syncState }));
|
|
@@ -62,7 +62,7 @@ export const useSpaceSyncState = (space: Space): PeerSyncState | undefined => {
|
|
|
62
62
|
|
|
63
63
|
useEffect(() => {
|
|
64
64
|
const ctx = new Context();
|
|
65
|
-
space.db.subscribeToSyncState(ctx, ({ peers = [] }) => {
|
|
65
|
+
space.internal.db.subscribeToSyncState(ctx, ({ peers = [] }) => {
|
|
66
66
|
const syncState = peers.find((state) => isEdgePeerId(state.peerId, space.id));
|
|
67
67
|
if (syncState) {
|
|
68
68
|
setSpaceState(syncState);
|
|
@@ -10,7 +10,7 @@ export default defineConfig({
|
|
|
10
10
|
...e2ePreset(import.meta.dirname),
|
|
11
11
|
// TODO(wittjosiah): Avoid hard-coding ports.
|
|
12
12
|
webServer: {
|
|
13
|
-
command: 'moon run storybook:serve-e2e -- --port=9000',
|
|
13
|
+
command: 'moon run storybook-react:serve-e2e -- --port=9000',
|
|
14
14
|
port: 9000,
|
|
15
15
|
reuseExistingServer: false,
|
|
16
16
|
},
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
6
6
|
import React from 'react';
|
|
7
7
|
|
|
8
|
+
import { Obj } from '@dxos/echo';
|
|
8
9
|
import { Input } from '@dxos/react-ui';
|
|
9
10
|
import { withTheme } from '@dxos/react-ui/testing';
|
|
10
11
|
import { SyntaxHighlighter } from '@dxos/react-ui-syntax-highlighter';
|
|
@@ -32,9 +33,9 @@ const ClientStory = () => {
|
|
|
32
33
|
return <JsonPanel value={client.toJSON()} />;
|
|
33
34
|
};
|
|
34
35
|
|
|
35
|
-
const ClientSpace = ({
|
|
36
|
+
const ClientSpace = ({ spaceId }: ClientRepeatedComponentProps) => {
|
|
36
37
|
const client = useClient();
|
|
37
|
-
const space = useSpace(
|
|
38
|
+
const space = useSpace(spaceId);
|
|
38
39
|
if (!space?.isOpen) {
|
|
39
40
|
return null;
|
|
40
41
|
}
|
|
@@ -45,7 +46,11 @@ const ClientSpace = ({ spaceKey }: ClientRepeatedComponentProps) => {
|
|
|
45
46
|
<Input.TextInput
|
|
46
47
|
placeholder='Name'
|
|
47
48
|
value={space.properties.name}
|
|
48
|
-
onChange={(event) =>
|
|
49
|
+
onChange={(event) =>
|
|
50
|
+
Obj.change(space.properties, (p) => {
|
|
51
|
+
p.name = event.target.value;
|
|
52
|
+
})
|
|
53
|
+
}
|
|
49
54
|
/>
|
|
50
55
|
</Input.Root>
|
|
51
56
|
<JsonPanel value={client.toJSON()} />
|
|
@@ -2,20 +2,20 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import React, { type FC,
|
|
5
|
+
import React, { type FC, useRef, useState } from 'react';
|
|
6
6
|
|
|
7
|
-
import { Client
|
|
7
|
+
import { Client } from '@dxos/client';
|
|
8
8
|
import { TestBuilder, performInvitation } from '@dxos/client/testing';
|
|
9
|
-
import { type
|
|
10
|
-
import { registerSignalsRuntime } from '@dxos/echo-signals/react';
|
|
9
|
+
import { type Type } from '@dxos/echo';
|
|
11
10
|
import { faker } from '@dxos/random';
|
|
12
11
|
import { useAsyncEffect } from '@dxos/react-hooks';
|
|
13
12
|
|
|
14
13
|
import { ClientProvider } from '../client';
|
|
14
|
+
import { type SpaceId } from '../echo';
|
|
15
15
|
|
|
16
16
|
import { type WithClientProviderProps } from './withClientProvider';
|
|
17
17
|
|
|
18
|
-
export type ClientRepeatedComponentProps = { id: number; count: number;
|
|
18
|
+
export type ClientRepeatedComponentProps = { id: number; count: number; spaceId?: SpaceId };
|
|
19
19
|
|
|
20
20
|
export type ClientRepeaterControlsProps = { clients: Client[] };
|
|
21
21
|
|
|
@@ -26,7 +26,7 @@ export type ClientRepeaterProps<P extends ClientRepeatedComponentProps> = {
|
|
|
26
26
|
controls?: FC<ClientRepeaterControlsProps>;
|
|
27
27
|
count?: number;
|
|
28
28
|
clients?: Client[];
|
|
29
|
-
types?:
|
|
29
|
+
types?: Type.Obj.Any[];
|
|
30
30
|
args?: Omit<P, 'id' | 'count'>;
|
|
31
31
|
} & Pick<WithClientProviderProps, 'createIdentity' | 'createSpace' | 'onCreateSpace'>;
|
|
32
32
|
|
|
@@ -50,12 +50,9 @@ export const ClientRepeater = <P extends ClientRepeatedComponentProps>(props: Cl
|
|
|
50
50
|
createSpace,
|
|
51
51
|
onCreateSpace,
|
|
52
52
|
} = props;
|
|
53
|
-
useEffect(() => {
|
|
54
|
-
registerSignalsRuntime();
|
|
55
|
-
}, []);
|
|
56
53
|
|
|
57
54
|
const [clients, setClients] = useState(props.clients ?? []);
|
|
58
|
-
const [
|
|
55
|
+
const [spaceId, setSpaceId] = useState<SpaceId>();
|
|
59
56
|
|
|
60
57
|
const testBuilder = useRef(new TestBuilder());
|
|
61
58
|
useAsyncEffect(async () => {
|
|
@@ -71,7 +68,7 @@ export const ClientRepeater = <P extends ClientRepeatedComponentProps>(props: Cl
|
|
|
71
68
|
if (createSpace) {
|
|
72
69
|
const client = clients[0];
|
|
73
70
|
const space = await client.spaces.create({ name: faker.commerce.productName() });
|
|
74
|
-
|
|
71
|
+
setSpaceId(space.id);
|
|
75
72
|
await onCreateSpace?.({ client, space }, {});
|
|
76
73
|
await Promise.all(clients.slice(1).flatMap((client) => performInvitation({ host: space, guest: client.spaces })));
|
|
77
74
|
}
|
|
@@ -88,7 +85,7 @@ export const ClientRepeater = <P extends ClientRepeatedComponentProps>(props: Cl
|
|
|
88
85
|
{Controls && <Controls clients={clients} />}
|
|
89
86
|
{clients.map((client, index) => (
|
|
90
87
|
<ClientProvider key={index} client={client}>
|
|
91
|
-
<Component id={index} count={clients.length}
|
|
88
|
+
<Component id={index} count={clients.length} spaceId={spaceId} {...{ ...props.args }} />
|
|
92
89
|
</ClientProvider>
|
|
93
90
|
))}
|
|
94
91
|
</>
|
package/src/testing/context.tsx
CHANGED
|
@@ -4,16 +4,17 @@
|
|
|
4
4
|
|
|
5
5
|
import { createContext, useContext } from 'react';
|
|
6
6
|
|
|
7
|
-
import { type Space } from '@dxos/client/echo';
|
|
7
|
+
import { type Space, type SpaceId } from '@dxos/client/echo';
|
|
8
8
|
import { raise } from '@dxos/debug';
|
|
9
9
|
|
|
10
10
|
export type ClientStory = {
|
|
11
|
+
index?: number;
|
|
12
|
+
spaceId?: SpaceId;
|
|
11
13
|
space?: Space;
|
|
12
14
|
};
|
|
13
15
|
|
|
14
|
-
// TODO(wittjosiah): Add to multi-client as well.
|
|
15
16
|
export const ClientStory = createContext<ClientStory | undefined>(undefined);
|
|
16
17
|
|
|
17
|
-
export const
|
|
18
|
+
export const useClientStory = (): ClientStory => {
|
|
18
19
|
return useContext(ClientStory) ?? raise(new Error('Missing ClientStory'));
|
|
19
20
|
};
|