jazz-tools 0.19.22 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. package/.svelte-kit/__package__/react.d.ts.map +1 -1
  2. package/.svelte-kit/__package__/react.tsx +5 -2
  3. package/.turbo/turbo-build.log +71 -83
  4. package/CHANGELOG.md +69 -0
  5. package/dist/better-auth/auth/react.d.ts.map +1 -1
  6. package/dist/better-auth/auth/react.js +5 -2
  7. package/dist/better-auth/auth/react.js.map +1 -1
  8. package/dist/browser/createBrowserContext.d.ts +1 -2
  9. package/dist/browser/createBrowserContext.d.ts.map +1 -1
  10. package/dist/browser/index.js +1 -8
  11. package/dist/browser/index.js.map +1 -1
  12. package/dist/browser/provideBrowserLockSession/SessionIDStorage.d.ts +1 -1
  13. package/dist/{chunk-QCTQH5RS.js → chunk-3CAPPS2F.js} +234 -101
  14. package/dist/chunk-3CAPPS2F.js.map +1 -0
  15. package/dist/{chunk-M2HGBOXS.js → chunk-K4D7IMFM.js} +3 -3
  16. package/dist/chunk-K4D7IMFM.js.map +1 -0
  17. package/dist/expo/auth/clerk/index.d.ts.map +1 -1
  18. package/dist/expo/index.js +5 -2
  19. package/dist/expo/index.js.map +1 -1
  20. package/dist/index.js +4 -2
  21. package/dist/index.js.map +1 -1
  22. package/dist/inspector/{chunk-YQNK5Y7B.js → chunk-MCTB5ZJC.js} +1 -1
  23. package/dist/inspector/chunk-MCTB5ZJC.js.map +1 -0
  24. package/dist/inspector/contexts/node.d.ts.map +1 -1
  25. package/dist/inspector/{custom-element-KYV64IOC.js → custom-element-5YWVZBWA.js} +1 -1
  26. package/dist/inspector/{custom-element-KYV64IOC.js.map → custom-element-5YWVZBWA.js.map} +1 -1
  27. package/dist/inspector/index.js +3 -3
  28. package/dist/inspector/index.js.map +1 -1
  29. package/dist/inspector/register-custom-element.js +1 -1
  30. package/dist/inspector/standalone.js +1 -1
  31. package/dist/react/auth/Clerk.d.ts.map +1 -1
  32. package/dist/react/hooks.d.ts +1 -1
  33. package/dist/react/hooks.d.ts.map +1 -1
  34. package/dist/react/index.js +61 -47
  35. package/dist/react/index.js.map +1 -1
  36. package/dist/react/provider.d.ts.map +1 -1
  37. package/dist/react/ssr.js +2 -2
  38. package/dist/react/ssr.js.map +1 -1
  39. package/dist/react-core/chunk-UOYH6JFJ.js +10 -0
  40. package/dist/react-core/chunk-UOYH6JFJ.js.map +1 -0
  41. package/dist/react-core/hooks.d.ts +3 -3
  42. package/dist/react-core/hooks.d.ts.map +1 -1
  43. package/dist/react-core/index.js +27 -25
  44. package/dist/react-core/index.js.map +1 -1
  45. package/dist/react-core/provider.d.ts +2 -3
  46. package/dist/react-core/provider.d.ts.map +1 -1
  47. package/dist/react-core/testing.d.ts.map +1 -1
  48. package/dist/react-core/testing.js +4 -10
  49. package/dist/react-core/testing.js.map +1 -1
  50. package/dist/react-native/index.js +61 -53
  51. package/dist/react-native/index.js.map +1 -1
  52. package/dist/react-native-core/ReactNativeContextManager.d.ts +0 -1
  53. package/dist/react-native-core/ReactNativeContextManager.d.ts.map +1 -1
  54. package/dist/react-native-core/hooks.d.ts +1 -1
  55. package/dist/react-native-core/hooks.d.ts.map +1 -1
  56. package/dist/react-native-core/index.js +58 -50
  57. package/dist/react-native-core/index.js.map +1 -1
  58. package/dist/react-native-core/platform.d.ts +0 -4
  59. package/dist/react-native-core/platform.d.ts.map +1 -1
  60. package/dist/react-native-core/provider.d.ts +2 -1
  61. package/dist/react-native-core/provider.d.ts.map +1 -1
  62. package/dist/svelte/jazz.class.svelte.d.ts.map +1 -1
  63. package/dist/svelte/jazz.class.svelte.js +2 -8
  64. package/dist/svelte/tests/AccountCoState.svelte.test.d.ts +2 -0
  65. package/dist/svelte/tests/AccountCoState.svelte.test.d.ts.map +1 -0
  66. package/dist/svelte/tests/AccountCoState.svelte.test.js +59 -0
  67. package/dist/svelte/tests/CoState.svelte.test.js +23 -0
  68. package/dist/svelte/tests/TestAccountCoStateWrapper.svelte +24 -0
  69. package/dist/svelte/tests/TestAccountCoStateWrapper.svelte.d.ts +11 -0
  70. package/dist/svelte/tests/TestAccountCoStateWrapper.svelte.d.ts.map +1 -0
  71. package/dist/testing.js +6 -6
  72. package/dist/testing.js.map +1 -1
  73. package/dist/tools/coValues/coList.d.ts +2 -2
  74. package/dist/tools/coValues/coList.d.ts.map +1 -1
  75. package/dist/tools/coValues/coMap.d.ts +2 -2
  76. package/dist/tools/coValues/deepLoading.d.ts +2 -2
  77. package/dist/tools/coValues/deepLoading.d.ts.map +1 -1
  78. package/dist/tools/coValues/interfaces.d.ts +32 -0
  79. package/dist/tools/coValues/interfaces.d.ts.map +1 -1
  80. package/dist/tools/exports.d.ts +1 -1
  81. package/dist/tools/exports.d.ts.map +1 -1
  82. package/dist/tools/implementation/ContextManager.d.ts.map +1 -1
  83. package/dist/tools/implementation/createContext.d.ts.map +1 -1
  84. package/dist/tools/implementation/zodSchema/schemaTypes/AccountSchema.d.ts +3 -2
  85. package/dist/tools/implementation/zodSchema/schemaTypes/AccountSchema.d.ts.map +1 -1
  86. package/dist/tools/implementation/zodSchema/schemaTypes/CoDiscriminatedUnionSchema.d.ts +3 -2
  87. package/dist/tools/implementation/zodSchema/schemaTypes/CoDiscriminatedUnionSchema.d.ts.map +1 -1
  88. package/dist/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts +3 -3
  89. package/dist/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts.map +1 -1
  90. package/dist/tools/implementation/zodSchema/schemaTypes/CoListSchema.d.ts +3 -2
  91. package/dist/tools/implementation/zodSchema/schemaTypes/CoListSchema.d.ts.map +1 -1
  92. package/dist/tools/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts +5 -2
  93. package/dist/tools/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts.map +1 -1
  94. package/dist/tools/implementation/zodSchema/zodCo.d.ts.map +1 -1
  95. package/dist/tools/ssr.js +1 -1
  96. package/dist/tools/subscribe/JazzError.d.ts +3 -3
  97. package/dist/tools/subscribe/JazzError.d.ts.map +1 -1
  98. package/dist/tools/subscribe/SubscriptionScope.d.ts.map +1 -1
  99. package/dist/tools/subscribe/types.d.ts +5 -1
  100. package/dist/tools/subscribe/types.d.ts.map +1 -1
  101. package/dist/tools/testing.d.ts +3 -3
  102. package/dist/tools/testing.d.ts.map +1 -1
  103. package/dist/tools/tests/deleteCoValues.test.d.ts +2 -0
  104. package/dist/tools/tests/deleteCoValues.test.d.ts.map +1 -0
  105. package/dist/tools/tests/deletedState.test.d.ts +2 -0
  106. package/dist/tools/tests/deletedState.test.d.ts.map +1 -0
  107. package/dist/worker/edge-wasm.js +2 -1
  108. package/dist/worker/edge-wasm.js.map +1 -1
  109. package/dist/worker/wasm.d.ts +2 -0
  110. package/dist/worker/wasm.d.ts.map +1 -0
  111. package/package.json +9 -28
  112. package/src/better-auth/auth/react.tsx +5 -2
  113. package/src/browser/createBrowserContext.ts +2 -5
  114. package/src/expo/auth/clerk/index.tsx +5 -2
  115. package/src/inspector/contexts/node.tsx +1 -2
  116. package/src/inspector/index.tsx +2 -2
  117. package/src/react/auth/Clerk.tsx +5 -2
  118. package/src/react/auth/PasskeyAuth.tsx +2 -2
  119. package/src/react/hooks.tsx +3 -2
  120. package/src/react/provider.tsx +45 -41
  121. package/src/react-core/auth/DemoAuth.tsx +2 -2
  122. package/src/react-core/auth/PassphraseAuth.tsx +2 -2
  123. package/src/react-core/hooks.ts +26 -27
  124. package/src/react-core/provider.tsx +1 -5
  125. package/src/react-core/testing.tsx +3 -11
  126. package/src/react-core/tests/useAccount.selector.test.ts +2 -3
  127. package/src/react-core/tests/useAccount.test.ts +57 -7
  128. package/src/react-core/tests/useCoState.test.ts +37 -0
  129. package/src/react-core/tests/useInboxSender.test.ts +2 -5
  130. package/src/react-core/tests/useSuspenseAccount.test.tsx +68 -0
  131. package/src/react-core/tests/useSuspenseCoState.test.tsx +44 -0
  132. package/src/react-native-core/ReactNativeContextManager.ts +0 -3
  133. package/src/react-native-core/auth/usePasskeyAuth.tsx +2 -2
  134. package/src/react-native-core/hooks.tsx +3 -3
  135. package/src/react-native-core/platform.ts +2 -6
  136. package/src/react-native-core/provider.tsx +47 -43
  137. package/src/svelte/jazz.class.svelte.ts +2 -8
  138. package/src/svelte/tests/AccountCoState.svelte.test.ts +79 -0
  139. package/src/svelte/tests/CoState.svelte.test.ts +36 -0
  140. package/src/svelte/tests/TestAccountCoStateWrapper.svelte +24 -0
  141. package/src/tools/coValues/deepLoading.ts +2 -0
  142. package/src/tools/coValues/interfaces.ts +170 -32
  143. package/src/tools/exports.ts +1 -0
  144. package/src/tools/implementation/ContextManager.ts +2 -2
  145. package/src/tools/implementation/createContext.ts +4 -0
  146. package/src/tools/implementation/zodSchema/schemaTypes/AccountSchema.ts +30 -6
  147. package/src/tools/implementation/zodSchema/schemaTypes/CoDiscriminatedUnionSchema.ts +55 -7
  148. package/src/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.ts +33 -14
  149. package/src/tools/implementation/zodSchema/schemaTypes/CoListSchema.ts +35 -6
  150. package/src/tools/implementation/zodSchema/schemaTypes/CoMapSchema.ts +35 -14
  151. package/src/tools/ssr/ssr.ts +2 -2
  152. package/src/tools/subscribe/CoValueCoreSubscription.ts +1 -0
  153. package/src/tools/subscribe/JazzError.ts +4 -1
  154. package/src/tools/subscribe/SubscriptionScope.ts +23 -0
  155. package/src/tools/subscribe/types.ts +5 -0
  156. package/src/tools/testing.ts +5 -5
  157. package/src/tools/tests/PassphraseAuth.test.ts +5 -5
  158. package/src/tools/tests/deleteCoValues.test.ts +231 -0
  159. package/src/tools/tests/deletedState.test.ts +110 -0
  160. package/src/tools/tests/request.test.ts +15 -2
  161. package/src/worker/edge-wasm.ts +2 -1
  162. package/src/worker/wasm.ts +1 -0
  163. package/tsup.config.ts +0 -4
  164. package/dist/browser/storageOptions.d.ts +0 -8
  165. package/dist/browser/storageOptions.d.ts.map +0 -1
  166. package/dist/browser/tests/storageOptions.test.d.ts +0 -2
  167. package/dist/browser/tests/storageOptions.test.d.ts.map +0 -1
  168. package/dist/chunk-M2HGBOXS.js.map +0 -1
  169. package/dist/chunk-QCTQH5RS.js.map +0 -1
  170. package/dist/expo/crypto.d.ts +0 -2
  171. package/dist/expo/crypto.d.ts.map +0 -1
  172. package/dist/expo/crypto.js +0 -6
  173. package/dist/expo/crypto.js.map +0 -1
  174. package/dist/inspector/chunk-YQNK5Y7B.js.map +0 -1
  175. package/dist/react-core/chunk-7DYMJ74I.js +0 -12
  176. package/dist/react-core/chunk-7DYMJ74I.js.map +0 -1
  177. package/dist/react-native/chunk-DGUM43GV.js +0 -11
  178. package/dist/react-native/chunk-DGUM43GV.js.map +0 -1
  179. package/dist/react-native/crypto.d.ts +0 -2
  180. package/dist/react-native/crypto.d.ts.map +0 -1
  181. package/dist/react-native/crypto.js +0 -8
  182. package/dist/react-native/crypto.js.map +0 -1
  183. package/dist/react-native-core/chunk-DGUM43GV.js +0 -11
  184. package/dist/react-native-core/chunk-DGUM43GV.js.map +0 -1
  185. package/dist/react-native-core/crypto/RNCrypto.d.ts +0 -2
  186. package/dist/react-native-core/crypto/RNCrypto.d.ts.map +0 -1
  187. package/dist/react-native-core/crypto/RNCrypto.js +0 -3
  188. package/dist/react-native-core/crypto/RNCrypto.js.map +0 -1
  189. package/dist/react-native-core/crypto/RNQuickCrypto.d.ts +0 -17
  190. package/dist/react-native-core/crypto/RNQuickCrypto.d.ts.map +0 -1
  191. package/dist/react-native-core/crypto/index.d.ts +0 -2
  192. package/dist/react-native-core/crypto/index.d.ts.map +0 -1
  193. package/dist/react-native-core/crypto.js +0 -89
  194. package/dist/react-native-core/crypto.js.map +0 -1
  195. package/src/browser/storageOptions.ts +0 -17
  196. package/src/browser/tests/storageOptions.test.ts +0 -33
  197. package/src/expo/crypto.ts +0 -1
  198. package/src/react-native/crypto.ts +0 -1
  199. package/src/react-native-core/crypto/RNCrypto.ts +0 -1
  200. package/src/react-native-core/crypto/RNQuickCrypto.ts +0 -122
  201. package/src/react-native-core/crypto/index.ts +0 -1
@@ -218,6 +218,50 @@ describe("useSuspenseCoState", () => {
218
218
  );
219
219
  });
220
220
 
221
+ it("should throw error when CoValue is deleted", async () => {
222
+ const TestMap = co.map({
223
+ value: z.string(),
224
+ });
225
+
226
+ const owner = await createJazzTestAccount({
227
+ isCurrentActiveAccount: true,
228
+ });
229
+
230
+ const map = TestMap.create(
231
+ {
232
+ value: "123",
233
+ },
234
+ Group.create(owner).makePublic("reader"),
235
+ );
236
+
237
+ map.$jazz.raw.core.deleteCoValue();
238
+
239
+ const TestComponent = () => {
240
+ const value = useSuspenseCoState(TestMap, map.$jazz.id);
241
+ return <div>{value.value}</div>;
242
+ };
243
+
244
+ const { container } = await act(async () => {
245
+ return render(
246
+ <ErrorBoundary FallbackComponent={ErrorFallback}>
247
+ <Suspense fallback={<div>Loading...</div>}>
248
+ <TestComponent />
249
+ </Suspense>
250
+ </ErrorBoundary>,
251
+ {
252
+ account: owner,
253
+ },
254
+ );
255
+ });
256
+
257
+ await waitFor(
258
+ () => {
259
+ expect(container.textContent).toContain("Error: deleted");
260
+ },
261
+ { timeout: 10_000 },
262
+ );
263
+ });
264
+
221
265
  it("should throw error when CoValue is unavailable due disabled network", async () => {
222
266
  disableJazzTestSync();
223
267
 
@@ -33,7 +33,6 @@ export type JazzContextManagerProps<
33
33
  onAnonymousAccountDiscarded?: (
34
34
  anonymousAccount: InstanceOfSchema<S>,
35
35
  ) => Promise<void>;
36
- CryptoProvider?: BaseReactNativeContextOptions["CryptoProvider"];
37
36
  };
38
37
 
39
38
  export class ReactNativeContextManager<
@@ -50,7 +49,6 @@ export class ReactNativeContextManager<
50
49
  sync: props.sync,
51
50
  storage: props.storage,
52
51
  authSecretStorage: this.authSecretStorage,
53
- CryptoProvider: props.CryptoProvider,
54
52
  });
55
53
  } else {
56
54
  return createJazzReactNativeContext<S>({
@@ -61,7 +59,6 @@ export class ReactNativeContextManager<
61
59
  newAccountProps: authProps?.newAccountProps,
62
60
  defaultProfileName: props.defaultProfileName,
63
61
  authSecretStorage: this.authSecretStorage,
64
- CryptoProvider: props.CryptoProvider,
65
62
  });
66
63
  }
67
64
  }
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  useAuthSecretStorage,
3
3
  useIsAuthenticated,
4
- useJazzContext,
4
+ useJazzContextValue,
5
5
  } from "jazz-tools/react-core";
6
6
  import { useMemo } from "react";
7
7
  import { ReactNativePasskeyAuth } from "./PasskeyAuth.js";
@@ -52,7 +52,7 @@ export function usePasskeyAuth({
52
52
  appName: string;
53
53
  rpId: string;
54
54
  }) {
55
- const context = useJazzContext();
55
+ const context = useJazzContextValue();
56
56
  const authSecretStorage = useAuthSecretStorage();
57
57
 
58
58
  if ("guest" in context) {
@@ -1,7 +1,7 @@
1
1
  import { useEffect } from "react";
2
2
 
3
3
  import { CoValueClassOrSchema, parseInviteLink } from "jazz-tools";
4
- import { useJazzContext } from "jazz-tools/react-core";
4
+ import { useJazzContextValue } from "jazz-tools/react-core";
5
5
  import { Linking } from "react-native";
6
6
 
7
7
  export {
@@ -10,7 +10,7 @@ export {
10
10
  experimental_useInboxSender,
11
11
  useDemoAuth,
12
12
  usePassphraseAuth,
13
- useJazzContext,
13
+ useJazzContextValue,
14
14
  useAuthSecretStorage,
15
15
  useIsAuthenticated,
16
16
  useAccount,
@@ -34,7 +34,7 @@ export function useAcceptInviteNative<S extends CoValueClassOrSchema>({
34
34
  onAccept: (projectID: string) => void;
35
35
  forValueHint?: string;
36
36
  }): void {
37
- const context = useJazzContext();
37
+ const context = useJazzContextValue();
38
38
 
39
39
  if (!("me" in context)) {
40
40
  throw new Error(
@@ -1,6 +1,5 @@
1
1
  import NetInfo from "@react-native-community/netinfo";
2
2
  import { LocalNode, Peer, getSqliteStorageAsync } from "cojson";
3
- import { PureJSCrypto } from "cojson/dist/crypto/PureJSCrypto"; // Importing from dist to not rely on the exports field
4
3
  import {
5
4
  Account,
6
5
  AccountClass,
@@ -20,14 +19,12 @@ import { ReactNativeSessionProvider } from "./ReactNativeSessionProvider.js";
20
19
 
21
20
  import { SQLiteDatabaseDriverAsync } from "cojson";
22
21
  import { WebSocketPeerWithReconnection } from "cojson-transport-ws";
23
- import type { RNQuickCrypto } from "jazz-tools/react-native-core/crypto";
24
- import type { RNCrypto } from "cojson/crypto/RNCrypto";
22
+ import { RNCrypto } from "cojson/crypto/RNCrypto";
25
23
 
26
24
  export type BaseReactNativeContextOptions = {
27
25
  sync: SyncConfig;
28
26
  reconnectionTimeout?: number;
29
27
  storage?: SQLiteDatabaseDriverAsync | "disabled";
30
- CryptoProvider?: typeof PureJSCrypto | typeof RNQuickCrypto | typeof RNCrypto;
31
28
  authSecretStorage: AuthSecretStorage;
32
29
  };
33
30
 
@@ -40,8 +37,7 @@ class ReactNativeWebSocketPeerWithReconnection extends WebSocketPeerWithReconnec
40
37
  }
41
38
 
42
39
  async function setupPeers(options: BaseReactNativeContextOptions) {
43
- const CryptoProvider = options.CryptoProvider || PureJSCrypto;
44
- const crypto = await CryptoProvider.create();
40
+ const crypto = await RNCrypto.create();
45
41
  let node: LocalNode | undefined = undefined;
46
42
 
47
43
  const peers: Peer[] = [];
@@ -3,12 +3,17 @@ import {
3
3
  AccountClass,
4
4
  AnyAccountSchema,
5
5
  CoValueFromRaw,
6
- InstanceOfSchema,
7
- JazzContextType,
8
6
  KvStore,
9
7
  } from "jazz-tools";
10
- import { JazzContext, JazzContextManagerContext } from "jazz-tools/react-core";
11
- import React, { useEffect, useRef } from "react";
8
+ import { JazzContext } from "jazz-tools/react-core";
9
+ import React, {
10
+ useCallback,
11
+ useContext,
12
+ useEffect,
13
+ useMemo,
14
+ useRef,
15
+ useSyncExternalStore,
16
+ } from "react";
12
17
  import type { JazzContextManagerProps } from "./ReactNativeContextManager.js";
13
18
  import { ReactNativeContextManager } from "./ReactNativeContextManager.js";
14
19
  import { setupKvStore } from "./platform.js";
@@ -20,6 +25,7 @@ export type JazzProviderProps<
20
25
  > = {
21
26
  children: React.ReactNode;
22
27
  kvStore?: KvStore;
28
+ fallback?: React.ReactNode | null;
23
29
  authSecretStorageKey?: string;
24
30
  } & JazzContextManagerProps<S>;
25
31
 
@@ -39,9 +45,15 @@ export function JazzProviderCore<
39
45
  logOutReplacement,
40
46
  onAnonymousAccountDiscarded,
41
47
  kvStore,
42
- CryptoProvider,
43
48
  authSecretStorageKey,
49
+ fallback = null,
44
50
  }: JazzProviderProps<S>) {
51
+ if (useContext(JazzContext)) {
52
+ throw new Error(
53
+ "You can't nest a JazzProvider inside another JazzProvider.",
54
+ );
55
+ }
56
+
45
57
  setupKvStore(kvStore);
46
58
 
47
59
  const [contextManager] = React.useState(
@@ -53,46 +65,40 @@ export function JazzProviderCore<
53
65
  const onAnonymousAccountDiscardedRefCallback = useRefCallback(
54
66
  onAnonymousAccountDiscarded,
55
67
  );
56
- const logoutReplacementActiveRef = useRef(false);
57
- logoutReplacementActiveRef.current = Boolean(logOutReplacement);
58
- const onAnonymousAccountDiscardedEnabled = Boolean(
59
- onAnonymousAccountDiscarded,
60
- );
61
68
 
62
- const value = React.useSyncExternalStore<
63
- JazzContextType<InstanceOfSchema<S>> | undefined
64
- >(
65
- React.useCallback(
66
- (callback) => {
67
- const props = {
68
- AccountSchema,
69
- guestMode,
70
- sync,
71
- storage,
72
- defaultProfileName,
73
- onLogOut: onLogOutRefCallback,
74
- logOutReplacement: logoutReplacementActiveRef.current
75
- ? logOutReplacementRefCallback
76
- : undefined,
77
- onAnonymousAccountDiscarded: onAnonymousAccountDiscardedEnabled
78
- ? onAnonymousAccountDiscardedRefCallback
79
- : undefined,
80
- CryptoProvider,
81
- } satisfies JazzContextManagerProps<S>;
69
+ const props = useMemo(() => {
70
+ return {
71
+ AccountSchema,
72
+ guestMode,
73
+ sync,
74
+ storage,
75
+ defaultProfileName,
76
+ onLogOut: onLogOutRefCallback,
77
+ logOutReplacement: logOutReplacement
78
+ ? logOutReplacementRefCallback
79
+ : undefined,
80
+ onAnonymousAccountDiscarded: onAnonymousAccountDiscarded
81
+ ? onAnonymousAccountDiscardedRefCallback
82
+ : undefined,
83
+ } satisfies JazzContextManagerProps<S>;
84
+ }, [guestMode, sync.peer, sync.when, storage]);
82
85
 
83
- if (contextManager.propsChanged(props)) {
84
- contextManager.createContext(props).catch((error) => {
85
- console.log(error.stack);
86
- console.error("Error creating Jazz React Native context:", error);
87
- });
88
- }
86
+ if (contextManager.propsChanged(props)) {
87
+ contextManager.createContext(props).catch((error) => {
88
+ console.log(error.stack);
89
+ console.error("Error creating Jazz React Native context:", error);
90
+ });
91
+ }
89
92
 
93
+ const isReady = useSyncExternalStore(
94
+ useCallback(
95
+ (callback) => {
90
96
  return contextManager.subscribe(callback);
91
97
  },
92
- [sync, guestMode].concat(storage as any),
98
+ [contextManager],
93
99
  ),
94
- () => contextManager.getCurrentValue(),
95
- () => contextManager.getCurrentValue(),
100
+ () => Boolean(contextManager.getCurrentValue()),
101
+ () => Boolean(contextManager.getCurrentValue()),
96
102
  );
97
103
 
98
104
  useEffect(() => {
@@ -106,10 +112,8 @@ export function JazzProviderCore<
106
112
  }, []);
107
113
 
108
114
  return (
109
- <JazzContext.Provider value={value}>
110
- <JazzContextManagerContext.Provider value={contextManager}>
111
- {value && children}
112
- </JazzContextManagerContext.Provider>
115
+ <JazzContext.Provider value={contextManager}>
116
+ {isReady ? children : fallback}
113
117
  </JazzContext.Provider>
114
118
  );
115
119
  }
@@ -99,10 +99,7 @@ export class CoState<
99
99
  // @ts-expect-error The resolve query type isn't compatible with the coValueClassFromCoValueClassOrSchema conversion
100
100
  resolve,
101
101
  loadAs: agent,
102
- onUnavailable: (value) => {
103
- this.update(value);
104
- },
105
- onUnauthorized: (value) => {
102
+ onError: (value) => {
106
103
  this.update(value);
107
104
  },
108
105
  syncResolution: true,
@@ -181,10 +178,7 @@ export class AccountCoState<
181
178
  {
182
179
  resolve,
183
180
  loadAs: me,
184
- onUnavailable: (value) => {
185
- this.update(value);
186
- },
187
- onUnauthorized: (value) => {
181
+ onError: (value) => {
188
182
  this.update(value);
189
183
  },
190
184
  syncResolution: true,
@@ -0,0 +1,79 @@
1
+ // @vitest-environment happy-dom
2
+
3
+ import { CoValueLoadingState, co, z } from "jazz-tools";
4
+ import { assertLoaded } from "jazz-tools/testing";
5
+ import { beforeEach, describe, expect, it } from "vitest";
6
+ import { createJazzTestAccount, setupJazzTestSync } from "../testing";
7
+ import { render, screen, waitFor } from "./testUtils";
8
+ import TestAccountCoStateWrapper from "./TestAccountCoStateWrapper.svelte";
9
+
10
+ describe("AccountCoState", () => {
11
+ beforeEach(async () => {
12
+ await setupJazzTestSync();
13
+ });
14
+
15
+ it("should return a 'deleted' value when a required resolved child is deleted", async () => {
16
+ const AccountRoot = co.map({
17
+ value: z.string(),
18
+ });
19
+
20
+ const AccountSchema = co
21
+ .account({
22
+ profile: co.profile(),
23
+ root: AccountRoot,
24
+ })
25
+ .withMigration((account) => {
26
+ if (!account.$jazz.refs.root) {
27
+ account.$jazz.set("root", { value: "123" });
28
+ }
29
+ });
30
+
31
+ const account = await createJazzTestAccount({
32
+ AccountSchema,
33
+ isCurrentActiveAccount: true,
34
+ });
35
+
36
+ render(
37
+ TestAccountCoStateWrapper,
38
+ {
39
+ Schema: AccountSchema,
40
+ options: {
41
+ resolve: {
42
+ root: true,
43
+ },
44
+ },
45
+ },
46
+ {
47
+ account,
48
+ },
49
+ );
50
+
51
+ // Ensure the account (and root) is loaded first.
52
+ const loaded = await account.$jazz.ensureLoaded({
53
+ resolve: {
54
+ root: true,
55
+ },
56
+ });
57
+ assertLoaded(loaded.root);
58
+
59
+ await waitFor(() => {
60
+ expect(screen.getByTestId("loading-state").textContent).toBe(
61
+ CoValueLoadingState.LOADED,
62
+ );
63
+ expect(screen.getByTestId("is-loaded").textContent).toBe("true");
64
+ });
65
+
66
+ // Delete the required child (root) -> AccountCoState should bubble the error.
67
+ loaded.root.$jazz.raw.core.deleteCoValue();
68
+ await loaded.root.$jazz.raw.core.waitForSync();
69
+
70
+ await waitFor(() => {
71
+ expect(screen.getByTestId("loading-state").textContent).toBe(
72
+ CoValueLoadingState.DELETED,
73
+ );
74
+ expect(screen.getByTestId("is-loaded").textContent).toBe("false");
75
+ });
76
+ });
77
+ });
78
+
79
+
@@ -54,4 +54,40 @@ describe("CoState", () => {
54
54
  );
55
55
  expect(stateValue.name).toBe("John Doe");
56
56
  });
57
+
58
+ it("should return a 'deleted' value when the coValue is deleted", async () => {
59
+ const Person = co.map({
60
+ name: co.plainText(),
61
+ });
62
+ const PersonWithName = Person.resolved({ name: true });
63
+ const person = Person.create({ name: "John Doe" }, publicGroup);
64
+
65
+ render(
66
+ TestCoStateWrapper,
67
+ {
68
+ Schema: PersonWithName,
69
+ id: person.$jazz.id,
70
+ },
71
+ {
72
+ account: clientAccount,
73
+ },
74
+ );
75
+
76
+ await waitFor(() => {
77
+ expect(screen.getByTestId("loading-state").textContent).toBe(
78
+ CoValueLoadingState.LOADED,
79
+ );
80
+ });
81
+
82
+ // Delete on the server (owner/admin) and ensure it propagates.
83
+ person.$jazz.raw.core.deleteCoValue();
84
+ await person.$jazz.raw.core.waitForSync();
85
+
86
+ await waitFor(() => {
87
+ expect(screen.getByTestId("loading-state").textContent).toBe(
88
+ CoValueLoadingState.DELETED,
89
+ );
90
+ expect(screen.getByTestId("is-loaded").textContent).toBe("false");
91
+ });
92
+ });
57
93
  });
@@ -0,0 +1,24 @@
1
+ <script lang="ts">
2
+ import type { AnyAccountSchema, ResolveQuery } from "jazz-tools";
3
+ import { AccountCoState } from "../jazz.class.svelte";
4
+
5
+ type Props<A extends AnyAccountSchema, R extends ResolveQuery<A>> = {
6
+ Schema: A;
7
+ options?: { resolve?: R };
8
+ };
9
+
10
+ let { Schema, options }: Props<any, any> = $props();
11
+
12
+ const state = new AccountCoState(Schema, options);
13
+ </script>
14
+
15
+ <div data-testid="account-costate-wrapper">
16
+ <div data-testid="loading-state">{state.current.$jazz.loadingState}</div>
17
+ <div data-testid="is-loaded">{state.current.$isLoaded ? "true" : "false"}</div>
18
+ {#if state.current.$isLoaded}
19
+ <div data-testid="account-id">{state.current.$jazz.id}</div>
20
+ <div data-testid="state-json">{JSON.stringify(state.current.toJSON())}</div>
21
+ {/if}
22
+ </div>
23
+
24
+
@@ -46,6 +46,7 @@ export type NotLoaded<T> = {
46
46
  id: ID<T>;
47
47
  loadingState:
48
48
  | typeof CoValueLoadingState.LOADING
49
+ | typeof CoValueLoadingState.DELETED
49
50
  | typeof CoValueLoadingState.UNAVAILABLE
50
51
  | typeof CoValueLoadingState.UNAUTHORIZED;
51
52
  };
@@ -70,6 +71,7 @@ export type Inaccessible<T> = {
70
71
  $jazz: {
71
72
  id: ID<T>;
72
73
  loadingState:
74
+ | typeof CoValueLoadingState.DELETED
73
75
  | typeof CoValueLoadingState.UNAVAILABLE
74
76
  | typeof CoValueLoadingState.UNAUTHORIZED;
75
77
  };