jazz-react-native 0.8.51 → 0.9.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.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +19 -0
- package/README.md +1 -1
- package/dist/auth/DemoAuthMethod.d.ts +1 -0
- package/dist/auth/DemoAuthMethod.js +17 -4
- package/dist/auth/DemoAuthMethod.js.map +1 -1
- package/dist/auth/DemoAuthUI.js +11 -6
- package/dist/auth/DemoAuthUI.js.map +1 -1
- package/dist/hooks.d.ts +10056 -0
- package/dist/hooks.js +36 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +2 -49
- package/dist/index.js +2 -128
- package/dist/index.js.map +1 -1
- package/dist/platform.d.ts +51 -0
- package/dist/platform.js +100 -0
- package/dist/platform.js.map +1 -0
- package/dist/provider.d.ts +13 -45
- package/dist/provider.js +52 -122
- package/dist/provider.js.map +1 -1
- package/dist/storage/kv-store-context.d.ts +1 -0
- package/dist/storage/kv-store-context.js +3 -0
- package/dist/storage/kv-store-context.js.map +1 -1
- package/dist/testing.d.ts +1 -0
- package/dist/testing.js +2 -0
- package/dist/testing.js.map +1 -0
- package/dist/tests/DemoAuthMethod.test.js +28 -7
- package/dist/tests/DemoAuthMethod.test.js.map +1 -1
- package/package.json +10 -5
- package/src/auth/DemoAuthMethod.ts +24 -4
- package/src/auth/DemoAuthUI.tsx +13 -6
- package/src/hooks.tsx +60 -0
- package/src/index.ts +3 -240
- package/src/platform.ts +205 -0
- package/src/provider.tsx +77 -282
- package/src/storage/kv-store-context.ts +4 -0
- package/src/testing.tsx +1 -0
- package/src/tests/DemoAuthMethod.test.ts +34 -7
package/src/platform.ts
ADDED
@@ -0,0 +1,205 @@
|
|
1
|
+
import {
|
2
|
+
Account,
|
3
|
+
AgentID,
|
4
|
+
AnonymousJazzAgent,
|
5
|
+
AuthMethod,
|
6
|
+
CoValue,
|
7
|
+
CoValueClass,
|
8
|
+
CryptoProvider,
|
9
|
+
ID,
|
10
|
+
InviteSecret,
|
11
|
+
SessionID,
|
12
|
+
cojsonInternals,
|
13
|
+
createJazzContext,
|
14
|
+
} from "jazz-tools";
|
15
|
+
|
16
|
+
import { RawAccountID } from "cojson";
|
17
|
+
|
18
|
+
export { RNDemoAuth } from "./auth/DemoAuthMethod.js";
|
19
|
+
|
20
|
+
import { PureJSCrypto } from "cojson/native";
|
21
|
+
import { createWebSocketPeerWithReconnection } from "./createWebSocketPeerWithReconnection.js";
|
22
|
+
import type { RNQuickCrypto } from "./crypto/RNQuickCrypto.js";
|
23
|
+
import { ExpoSecureStoreAdapter } from "./storage/expo-secure-store-adapter.js";
|
24
|
+
import { KvStoreContext } from "./storage/kv-store-context.js";
|
25
|
+
|
26
|
+
/** @category Context Creation */
|
27
|
+
export type ReactNativeContext<Acc extends Account> = {
|
28
|
+
me: Acc;
|
29
|
+
logOut: () => void;
|
30
|
+
// TODO: Symbol.dispose?
|
31
|
+
done: () => void;
|
32
|
+
};
|
33
|
+
|
34
|
+
export type ReactNativeGuestContext = {
|
35
|
+
guest: AnonymousJazzAgent;
|
36
|
+
logOut: () => void;
|
37
|
+
done: () => void;
|
38
|
+
};
|
39
|
+
|
40
|
+
export type ReactNativeContextOptions<Acc extends Account> = {
|
41
|
+
auth: AuthMethod;
|
42
|
+
AccountSchema: CoValueClass<Acc> & {
|
43
|
+
fromNode: (typeof Account)["fromNode"];
|
44
|
+
};
|
45
|
+
} & BaseReactNativeContextOptions;
|
46
|
+
|
47
|
+
export type BaseReactNativeContextOptions = {
|
48
|
+
peer: `wss://${string}` | `ws://${string}`;
|
49
|
+
reconnectionTimeout?: number;
|
50
|
+
storage?: "indexedDB" | "singleTabOPFS";
|
51
|
+
CryptoProvider?: typeof PureJSCrypto | typeof RNQuickCrypto;
|
52
|
+
};
|
53
|
+
|
54
|
+
/** @category Context Creation */
|
55
|
+
export async function createJazzRNContext<Acc extends Account>(
|
56
|
+
options: ReactNativeContextOptions<Acc>,
|
57
|
+
): Promise<ReactNativeContext<Acc>>;
|
58
|
+
export async function createJazzRNContext(
|
59
|
+
options: BaseReactNativeContextOptions,
|
60
|
+
): Promise<ReactNativeGuestContext>;
|
61
|
+
export async function createJazzRNContext<Acc extends Account>(
|
62
|
+
options: ReactNativeContextOptions<Acc> | BaseReactNativeContextOptions,
|
63
|
+
): Promise<ReactNativeContext<Acc> | ReactNativeGuestContext>;
|
64
|
+
export async function createJazzRNContext<Acc extends Account>(
|
65
|
+
options: ReactNativeContextOptions<Acc> | BaseReactNativeContextOptions,
|
66
|
+
): Promise<ReactNativeContext<Acc> | ReactNativeGuestContext> {
|
67
|
+
const websocketPeer = createWebSocketPeerWithReconnection(
|
68
|
+
options.peer,
|
69
|
+
options.reconnectionTimeout,
|
70
|
+
(peer) => {
|
71
|
+
node.syncManager.addPeer(peer);
|
72
|
+
},
|
73
|
+
);
|
74
|
+
|
75
|
+
const CryptoProvider = options.CryptoProvider || PureJSCrypto;
|
76
|
+
|
77
|
+
const context =
|
78
|
+
"auth" in options
|
79
|
+
? await createJazzContext({
|
80
|
+
AccountSchema: options.AccountSchema,
|
81
|
+
auth: options.auth,
|
82
|
+
crypto: await CryptoProvider.create(),
|
83
|
+
peersToLoadFrom: [websocketPeer.peer],
|
84
|
+
sessionProvider: provideLockSession,
|
85
|
+
})
|
86
|
+
: await createJazzContext({
|
87
|
+
crypto: await CryptoProvider.create(),
|
88
|
+
peersToLoadFrom: [websocketPeer.peer],
|
89
|
+
});
|
90
|
+
|
91
|
+
const node =
|
92
|
+
"account" in context ? context.account._raw.core.node : context.agent.node;
|
93
|
+
|
94
|
+
return "account" in context
|
95
|
+
? {
|
96
|
+
me: context.account,
|
97
|
+
done: () => {
|
98
|
+
websocketPeer.done();
|
99
|
+
context.done();
|
100
|
+
},
|
101
|
+
logOut: () => {
|
102
|
+
context.logOut();
|
103
|
+
},
|
104
|
+
}
|
105
|
+
: {
|
106
|
+
guest: context.agent,
|
107
|
+
done: () => {
|
108
|
+
websocketPeer.done();
|
109
|
+
context.done();
|
110
|
+
},
|
111
|
+
logOut: () => {
|
112
|
+
context.logOut();
|
113
|
+
},
|
114
|
+
};
|
115
|
+
}
|
116
|
+
|
117
|
+
/** @category Auth Providers */
|
118
|
+
export type SessionProvider = (
|
119
|
+
accountID: ID<Account> | AgentID,
|
120
|
+
) => Promise<SessionID>;
|
121
|
+
|
122
|
+
export async function provideLockSession(
|
123
|
+
accountID: ID<Account> | AgentID,
|
124
|
+
crypto: CryptoProvider,
|
125
|
+
) {
|
126
|
+
const sessionDone = () => {};
|
127
|
+
|
128
|
+
const kvStore = KvStoreContext.getInstance().getStorage();
|
129
|
+
|
130
|
+
const sessionID =
|
131
|
+
((await kvStore.get(accountID)) as SessionID) ||
|
132
|
+
crypto.newRandomSessionID(accountID as RawAccountID | AgentID);
|
133
|
+
await kvStore.set(accountID, sessionID);
|
134
|
+
|
135
|
+
return Promise.resolve({
|
136
|
+
sessionID,
|
137
|
+
sessionDone,
|
138
|
+
});
|
139
|
+
}
|
140
|
+
|
141
|
+
/** @category Invite Links */
|
142
|
+
export function createInviteLink<C extends CoValue>(
|
143
|
+
value: C,
|
144
|
+
role: "reader" | "writer" | "admin",
|
145
|
+
{ baseURL, valueHint }: { baseURL?: string; valueHint?: string } = {},
|
146
|
+
): string {
|
147
|
+
const coValueCore = value._raw.core;
|
148
|
+
let currentCoValue = coValueCore;
|
149
|
+
|
150
|
+
while (currentCoValue.header.ruleset.type === "ownedByGroup") {
|
151
|
+
currentCoValue = currentCoValue.getGroup().core;
|
152
|
+
}
|
153
|
+
|
154
|
+
if (currentCoValue.header.ruleset.type !== "group") {
|
155
|
+
throw new Error("Can't create invite link for object without group");
|
156
|
+
}
|
157
|
+
|
158
|
+
const group = cojsonInternals.expectGroup(currentCoValue.getCurrentContent());
|
159
|
+
const inviteSecret = group.createInvite(role);
|
160
|
+
|
161
|
+
return `${baseURL}/invite/${valueHint ? valueHint + "/" : ""}${
|
162
|
+
value.id
|
163
|
+
}/${inviteSecret}`;
|
164
|
+
}
|
165
|
+
|
166
|
+
/** @category Invite Links */
|
167
|
+
// TODO: copied from jazz-browser, should be shared
|
168
|
+
export function parseInviteLink<C extends CoValue>(
|
169
|
+
inviteURL: string,
|
170
|
+
):
|
171
|
+
| {
|
172
|
+
valueID: ID<C>;
|
173
|
+
valueHint?: string;
|
174
|
+
inviteSecret: InviteSecret;
|
175
|
+
}
|
176
|
+
| undefined {
|
177
|
+
const url = new URL(inviteURL);
|
178
|
+
const parts = url.hash.split("/");
|
179
|
+
|
180
|
+
let valueHint: string | undefined;
|
181
|
+
let valueID: ID<C> | undefined;
|
182
|
+
let inviteSecret: InviteSecret | undefined;
|
183
|
+
|
184
|
+
if (parts[0] === "#" && parts[1] === "invite") {
|
185
|
+
if (parts.length === 5) {
|
186
|
+
valueHint = parts[2];
|
187
|
+
valueID = parts[3] as ID<C>;
|
188
|
+
inviteSecret = parts[4] as InviteSecret;
|
189
|
+
} else if (parts.length === 4) {
|
190
|
+
valueID = parts[2] as ID<C>;
|
191
|
+
inviteSecret = parts[3] as InviteSecret;
|
192
|
+
}
|
193
|
+
|
194
|
+
if (!valueID || !inviteSecret) {
|
195
|
+
return undefined;
|
196
|
+
}
|
197
|
+
return { valueID, inviteSecret, valueHint };
|
198
|
+
}
|
199
|
+
}
|
200
|
+
|
201
|
+
export function setupKvStore(kvStore = new ExpoSecureStoreAdapter()) {
|
202
|
+
KvStoreContext.getInstance().initialize(kvStore);
|
203
|
+
|
204
|
+
return kvStore;
|
205
|
+
}
|
package/src/provider.tsx
CHANGED
@@ -1,314 +1,109 @@
|
|
1
|
-
import
|
2
|
-
|
3
|
-
import {
|
4
|
-
|
5
|
-
AccountClass,
|
6
|
-
AnonymousJazzAgent,
|
7
|
-
AuthMethod,
|
8
|
-
CoValue,
|
9
|
-
CoValueClass,
|
10
|
-
DeeplyLoaded,
|
11
|
-
DepthsIn,
|
12
|
-
ID,
|
13
|
-
subscribeToCoValue,
|
14
|
-
} from "jazz-tools";
|
15
|
-
import { Linking } from "react-native";
|
1
|
+
import { JazzContext, JazzContextType } from "jazz-react-core";
|
2
|
+
import { Account, AccountClass, AuthMethod } from "jazz-tools";
|
3
|
+
import { useState } from "react";
|
4
|
+
import { useEffect, useRef } from "react";
|
16
5
|
import {
|
17
6
|
BaseReactNativeContextOptions,
|
18
|
-
KvStore,
|
19
|
-
KvStoreContext,
|
20
|
-
ReactNativeContext,
|
21
|
-
ReactNativeGuestContext,
|
22
7
|
createJazzRNContext,
|
23
|
-
|
24
|
-
|
25
|
-
import { ExpoSecureStoreAdapter } from "./storage/expo-secure-store-adapter.js";
|
8
|
+
} from "./platform.js";
|
9
|
+
export interface Register {}
|
26
10
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
11
|
+
export type RegisteredAccount = Register extends { Account: infer Acc }
|
12
|
+
? Acc
|
13
|
+
: Account;
|
14
|
+
|
15
|
+
export type JazzProviderProps<Acc extends Account = RegisteredAccount> = {
|
16
|
+
children: React.ReactNode;
|
17
|
+
auth: AuthMethod | "guest";
|
18
|
+
peer: `wss://${string}` | `ws://${string}`;
|
34
19
|
AccountSchema?: AccountClass<Acc>;
|
35
20
|
CryptoProvider?: BaseReactNativeContextOptions["CryptoProvider"];
|
36
|
-
}
|
37
|
-
const JazzContext = React.createContext<
|
38
|
-
ReactNativeContext<Acc> | ReactNativeGuestContext | undefined
|
39
|
-
>(undefined);
|
40
|
-
|
41
|
-
if (!kvStore) {
|
42
|
-
throw new Error("kvStore is required");
|
43
|
-
}
|
21
|
+
};
|
44
22
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
23
|
+
/** @category Context & Hooks */
|
24
|
+
export function JazzProvider<Acc extends Account = RegisteredAccount>({
|
25
|
+
children,
|
26
|
+
auth,
|
27
|
+
peer,
|
28
|
+
AccountSchema = Account as unknown as AccountClass<Acc>,
|
29
|
+
CryptoProvider,
|
30
|
+
}: JazzProviderProps<Acc>) {
|
31
|
+
const [ctx, setCtx] = useState<JazzContextType<Acc> | undefined>();
|
32
|
+
|
33
|
+
const [sessionCount, setSessionCount] = useState(0);
|
34
|
+
|
35
|
+
const effectExecuted = useRef(false);
|
36
|
+
effectExecuted.current = false;
|
37
|
+
|
38
|
+
useEffect(() => {
|
39
|
+
// Avoid double execution of the effect in development mode for easier debugging.
|
40
|
+
if (process.env.NODE_ENV === "development") {
|
41
|
+
if (effectExecuted.current) {
|
42
|
+
return;
|
43
|
+
}
|
44
|
+
effectExecuted.current = true;
|
45
|
+
|
46
|
+
// In development mode we don't return a cleanup function because otherwise
|
47
|
+
// the double effect execution would mark the context as done immediately.
|
48
|
+
//
|
49
|
+
// So we mark it as done in the subsequent execution.
|
50
|
+
const previousContext = ctx;
|
51
|
+
|
52
|
+
if (previousContext) {
|
53
|
+
previousContext.done();
|
54
|
+
}
|
55
|
+
}
|
63
56
|
|
64
|
-
|
65
|
-
const
|
57
|
+
async function createContext() {
|
58
|
+
const currentContext = await createJazzRNContext<Acc>(
|
66
59
|
auth === "guest"
|
67
60
|
? {
|
68
61
|
peer,
|
69
|
-
storage,
|
70
62
|
CryptoProvider,
|
71
63
|
}
|
72
64
|
: {
|
73
65
|
AccountSchema,
|
74
66
|
auth: auth,
|
75
67
|
peer,
|
76
|
-
storage,
|
77
68
|
CryptoProvider,
|
78
69
|
},
|
79
|
-
).then((context) => {
|
80
|
-
setCtx({
|
81
|
-
...context,
|
82
|
-
logOut: () => {
|
83
|
-
context.logOut();
|
84
|
-
setCtx(undefined);
|
85
|
-
setSessionCount(sessionCount + 1);
|
86
|
-
},
|
87
|
-
});
|
88
|
-
return context.done;
|
89
|
-
});
|
90
|
-
|
91
|
-
return () => {
|
92
|
-
void promiseWithDoneCallback
|
93
|
-
.then((done) => done())
|
94
|
-
.catch((e) => {
|
95
|
-
console.error("Error in createJazzRNContext", e);
|
96
|
-
});
|
97
|
-
};
|
98
|
-
}, [AccountSchema, auth, peer, storage, sessionCount]);
|
99
|
-
|
100
|
-
return (
|
101
|
-
<JazzContext.Provider value={ctx}>{ctx && children}</JazzContext.Provider>
|
102
|
-
);
|
103
|
-
}
|
104
|
-
|
105
|
-
function useAccount(): { me: Acc; logOut: () => void };
|
106
|
-
function useAccount<D extends DepthsIn<Acc>>(
|
107
|
-
depth: D,
|
108
|
-
): { me: DeeplyLoaded<Acc, D> | undefined; logOut: () => void };
|
109
|
-
function useAccount<D extends DepthsIn<Acc>>(
|
110
|
-
depth?: D,
|
111
|
-
): { me: Acc | DeeplyLoaded<Acc, D> | undefined; logOut: () => void } {
|
112
|
-
const context = React.useContext(JazzContext);
|
113
|
-
|
114
|
-
if (!context) {
|
115
|
-
throw new Error("useAccount must be used within a JazzProvider");
|
116
|
-
}
|
117
|
-
|
118
|
-
if (!("me" in context)) {
|
119
|
-
throw new Error(
|
120
|
-
"useAccount can't be used in a JazzProvider with auth === 'guest' - consider using useAccountOrGuest()",
|
121
70
|
);
|
122
|
-
}
|
123
|
-
|
124
|
-
const me = useCoState<Acc, D>(
|
125
|
-
context?.me.constructor as CoValueClass<Acc>,
|
126
|
-
context?.me.id,
|
127
|
-
depth,
|
128
|
-
);
|
129
|
-
|
130
|
-
return {
|
131
|
-
me: depth === undefined ? me || context.me : me,
|
132
|
-
logOut: context.logOut,
|
133
|
-
};
|
134
|
-
}
|
135
|
-
|
136
|
-
function useAccountOrGuest(): { me: Acc | AnonymousJazzAgent };
|
137
|
-
function useAccountOrGuest<D extends DepthsIn<Acc>>(
|
138
|
-
depth: D,
|
139
|
-
): { me: DeeplyLoaded<Acc, D> | undefined | AnonymousJazzAgent };
|
140
|
-
function useAccountOrGuest<D extends DepthsIn<Acc>>(
|
141
|
-
depth?: D,
|
142
|
-
): { me: Acc | DeeplyLoaded<Acc, D> | undefined | AnonymousJazzAgent } {
|
143
|
-
const context = React.useContext(JazzContext);
|
144
|
-
|
145
|
-
if (!context) {
|
146
|
-
throw new Error("useAccountOrGuest must be used within a JazzProvider");
|
147
|
-
}
|
148
71
|
|
149
|
-
|
72
|
+
const logOut = () => {
|
73
|
+
currentContext.logOut();
|
74
|
+
setCtx(undefined);
|
75
|
+
setSessionCount(sessionCount + 1);
|
150
76
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
);
|
156
|
-
|
157
|
-
if ("me" in context) {
|
158
|
-
return {
|
159
|
-
me: depth === undefined ? me || context.me : me,
|
160
|
-
};
|
161
|
-
} else {
|
162
|
-
return { me: context.guest };
|
163
|
-
}
|
164
|
-
}
|
165
|
-
|
166
|
-
function useCoState<V extends CoValue, D>(
|
167
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
168
|
-
Schema: CoValueClass<V>,
|
169
|
-
id: ID<V> | undefined,
|
170
|
-
depth: D & DepthsIn<V> = [] as D & DepthsIn<V>,
|
171
|
-
): DeeplyLoaded<V, D> | undefined {
|
172
|
-
const [state, setState] = useState<{
|
173
|
-
value: DeeplyLoaded<V, D> | undefined;
|
174
|
-
}>({ value: undefined });
|
175
|
-
const context = React.useContext(JazzContext);
|
176
|
-
|
177
|
-
if (!context) {
|
178
|
-
throw new Error("useCoState must be used within a JazzProvider");
|
179
|
-
}
|
180
|
-
|
181
|
-
useEffect(() => {
|
182
|
-
if (!id) return;
|
183
|
-
|
184
|
-
return subscribeToCoValue(
|
185
|
-
Schema,
|
186
|
-
id,
|
187
|
-
"me" in context ? context.me : context.guest,
|
188
|
-
depth,
|
189
|
-
(value) => {
|
190
|
-
setState({ value });
|
191
|
-
},
|
192
|
-
);
|
193
|
-
}, [Schema, id, context]);
|
194
|
-
|
195
|
-
return state.value;
|
196
|
-
}
|
197
|
-
|
198
|
-
function useAcceptInvite<V extends CoValue>({
|
199
|
-
invitedObjectSchema,
|
200
|
-
onAccept,
|
201
|
-
forValueHint,
|
202
|
-
}: {
|
203
|
-
invitedObjectSchema: CoValueClass<V>;
|
204
|
-
onAccept: (projectID: ID<V>) => void;
|
205
|
-
forValueHint?: string;
|
206
|
-
}): void {
|
207
|
-
const context = React.useContext(JazzContext);
|
208
|
-
|
209
|
-
if (!context) {
|
210
|
-
throw new Error("useAcceptInvite must be used within a JazzProvider");
|
211
|
-
}
|
212
|
-
|
213
|
-
if (!("me" in context)) {
|
214
|
-
throw new Error(
|
215
|
-
"useAcceptInvite can't be used in a JazzProvider with auth === 'guest'.",
|
216
|
-
);
|
217
|
-
}
|
218
|
-
|
219
|
-
useEffect(() => {
|
220
|
-
const handleDeepLink = ({ url }: { url: string }) => {
|
221
|
-
const result = parseInviteLink<V>(url);
|
222
|
-
if (result && result.valueHint === forValueHint) {
|
223
|
-
context.me
|
224
|
-
.acceptInvite(
|
225
|
-
result.valueID,
|
226
|
-
result.inviteSecret,
|
227
|
-
invitedObjectSchema,
|
228
|
-
)
|
229
|
-
.then(() => {
|
230
|
-
onAccept(result.valueID);
|
231
|
-
})
|
232
|
-
.catch((e) => {
|
233
|
-
console.error("Failed to accept invite", e);
|
234
|
-
});
|
77
|
+
if (process.env.NODE_ENV === "development") {
|
78
|
+
// In development mode we don't return a cleanup function
|
79
|
+
// so we mark the context as done here.
|
80
|
+
currentContext.done();
|
235
81
|
}
|
236
82
|
};
|
237
83
|
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
84
|
+
setCtx({
|
85
|
+
...currentContext,
|
86
|
+
AccountSchema,
|
87
|
+
logOut,
|
242
88
|
});
|
243
89
|
|
244
|
-
return
|
245
|
-
|
246
|
-
};
|
247
|
-
}, [context, onAccept, invitedObjectSchema, forValueHint]);
|
248
|
-
}
|
249
|
-
|
250
|
-
return {
|
251
|
-
Provider,
|
252
|
-
useAccount,
|
253
|
-
useAccountOrGuest,
|
254
|
-
useCoState,
|
255
|
-
useAcceptInvite,
|
256
|
-
kvStore,
|
257
|
-
};
|
258
|
-
}
|
259
|
-
|
260
|
-
/** @category Context & Hooks */
|
261
|
-
export interface JazzReactApp<Acc extends Account> {
|
262
|
-
/** @category Provider Component */
|
263
|
-
Provider: React.FC<{
|
264
|
-
children: React.ReactNode;
|
265
|
-
auth: AuthMethod | "guest";
|
266
|
-
peer: `wss://${string}` | `ws://${string}`;
|
267
|
-
storage?: "indexedDB" | "singleTabOPFS";
|
268
|
-
}>;
|
90
|
+
return currentContext;
|
91
|
+
}
|
269
92
|
|
270
|
-
|
271
|
-
useAccount(): {
|
272
|
-
me: Acc;
|
273
|
-
logOut: () => void;
|
274
|
-
};
|
275
|
-
/** @category Hooks */
|
276
|
-
useAccount<D extends DepthsIn<Acc>>(
|
277
|
-
depth: D,
|
278
|
-
): {
|
279
|
-
me: DeeplyLoaded<Acc, D> | undefined;
|
280
|
-
logOut: () => void;
|
281
|
-
};
|
93
|
+
const promise = createContext();
|
282
94
|
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
depth: D,
|
289
|
-
): {
|
290
|
-
me: DeeplyLoaded<Acc, D> | undefined | AnonymousJazzAgent;
|
291
|
-
};
|
292
|
-
/** @category Hooks */
|
293
|
-
useCoState<V extends CoValue, D>(
|
294
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
295
|
-
Schema: { new (...args: any[]): V } & CoValueClass,
|
296
|
-
id: ID<V> | undefined,
|
297
|
-
depth?: D & DepthsIn<V>,
|
298
|
-
): DeeplyLoaded<V, D> | undefined;
|
95
|
+
// In development mode we don't return a cleanup function because otherwise
|
96
|
+
// the double effect execution would mark the context as done immediately.
|
97
|
+
if (process.env.NODE_ENV === "development") {
|
98
|
+
return;
|
99
|
+
}
|
299
100
|
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
forValueHint,
|
305
|
-
}: {
|
306
|
-
invitedObjectSchema: CoValueClass<V>;
|
307
|
-
onAccept: (projectID: ID<V>) => void;
|
308
|
-
forValueHint?: string;
|
309
|
-
}): void;
|
101
|
+
return () => {
|
102
|
+
void promise.then((context) => context.done());
|
103
|
+
};
|
104
|
+
}, [AccountSchema, auth, peer, sessionCount]);
|
310
105
|
|
311
|
-
|
106
|
+
return (
|
107
|
+
<JazzContext.Provider value={ctx}>{ctx && children}</JazzContext.Provider>
|
108
|
+
);
|
312
109
|
}
|
313
|
-
|
314
|
-
export * from "./media.js";
|
@@ -18,6 +18,10 @@ export class KvStoreContext {
|
|
18
18
|
return KvStoreContext.instance;
|
19
19
|
}
|
20
20
|
|
21
|
+
public isInitialized(): boolean {
|
22
|
+
return this.storageInstance !== null;
|
23
|
+
}
|
24
|
+
|
21
25
|
public initialize(store: KvStore): void {
|
22
26
|
if (!this.storageInstance) {
|
23
27
|
this.storageInstance = store;
|
package/src/testing.tsx
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
export * from "jazz-react-core/testing";
|