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
@@ -8,12 +8,15 @@ import {
8
8
  KvStoreContext,
9
9
  } from "jazz-tools";
10
10
  import { LocalStorageKVStore } from "jazz-tools/browser";
11
- import { useAuthSecretStorage, useJazzContext } from "jazz-tools/react-core";
11
+ import {
12
+ useAuthSecretStorage,
13
+ useJazzContextValue,
14
+ } from "jazz-tools/react-core";
12
15
  import { ReactNode, useEffect, useMemo, useState } from "react";
13
16
  import { JazzProviderProps, JazzReactProvider } from "../provider.js";
14
17
 
15
18
  function useJazzClerkAuth(clerk: MinimalClerkClient) {
16
- const context = useJazzContext();
19
+ const context = useJazzContextValue();
17
20
  const authSecretStorage = useAuthSecretStorage();
18
21
 
19
22
  if ("guest" in context) {
@@ -2,7 +2,7 @@ import { BrowserPasskeyAuth } from "jazz-tools/browser";
2
2
  import {
3
3
  useAuthSecretStorage,
4
4
  useIsAuthenticated,
5
- useJazzContext,
5
+ useJazzContextValue,
6
6
  } from "jazz-tools/react-core";
7
7
  import { useMemo, useState } from "react";
8
8
 
@@ -23,7 +23,7 @@ export function usePasskeyAuth({
23
23
  appName: string;
24
24
  appHostname?: string;
25
25
  }) {
26
- const context = useJazzContext();
26
+ const context = useJazzContextValue();
27
27
  const authSecretStorage = useAuthSecretStorage();
28
28
 
29
29
  if ("guest" in context) {
@@ -2,7 +2,7 @@ import { consumeInviteLinkFromWindowLocation } from "jazz-tools/browser";
2
2
  import { useEffect } from "react";
3
3
 
4
4
  import { CoValueClassOrSchema } from "jazz-tools";
5
- import { useJazzContext } from "jazz-tools/react-core";
5
+ import { useJazzContextValue } from "jazz-tools/react-core";
6
6
 
7
7
  export function useAcceptInvite<S extends CoValueClassOrSchema>({
8
8
  invitedObjectSchema,
@@ -13,7 +13,7 @@ export function useAcceptInvite<S extends CoValueClassOrSchema>({
13
13
  onAccept: (valueID: string) => void;
14
14
  forValueHint?: string;
15
15
  }): void {
16
- const context = useJazzContext();
16
+ const context = useJazzContextValue();
17
17
 
18
18
  if (!("me" in context)) {
19
19
  throw new Error(
@@ -46,6 +46,7 @@ export function useAcceptInvite<S extends CoValueClassOrSchema>({
46
46
 
47
47
  export {
48
48
  experimental_useInboxSender,
49
+ useJazzContextValue,
49
50
  useJazzContext,
50
51
  useAuthSecretStorage,
51
52
  useAccount,
@@ -3,15 +3,20 @@ import {
3
3
  AccountClass,
4
4
  AnyAccountSchema,
5
5
  CoValueFromRaw,
6
- InstanceOfSchema,
7
- JazzContextType,
8
6
  } from "jazz-tools";
9
7
  import {
10
8
  JazzBrowserContextManager,
11
9
  JazzContextManagerProps,
12
10
  } from "jazz-tools/browser";
13
- import { JazzContext, JazzContextManagerContext } from "jazz-tools/react-core";
14
- import React, { useEffect, useRef } from "react";
11
+ import { JazzContext } from "jazz-tools/react-core";
12
+ import React, {
13
+ useCallback,
14
+ useContext,
15
+ useEffect,
16
+ useMemo,
17
+ useRef,
18
+ useSyncExternalStore,
19
+ } from "react";
15
20
 
16
21
  export type JazzProviderProps<
17
22
  S extends
@@ -43,6 +48,12 @@ export function JazzReactProvider<
43
48
  fallback = null,
44
49
  authSecretStorageKey,
45
50
  }: JazzProviderProps<S>) {
51
+ if (useContext(JazzContext)) {
52
+ throw new Error(
53
+ "You can't nest a JazzProvider inside another JazzProvider.",
54
+ );
55
+ }
56
+
46
57
  const [contextManager] = React.useState(
47
58
  () =>
48
59
  new JazzBrowserContextManager<S>({
@@ -56,45 +67,40 @@ export function JazzReactProvider<
56
67
  const onAnonymousAccountDiscardedRefCallback = useRefCallback(
57
68
  onAnonymousAccountDiscarded,
58
69
  );
59
- const logoutReplacementActiveRef = useRef(false);
60
- logoutReplacementActiveRef.current = Boolean(logOutReplacement);
61
- const onAnonymousAccountDiscardedEnabled = Boolean(
62
- onAnonymousAccountDiscarded,
63
- );
64
70
 
65
- const value = React.useSyncExternalStore<
66
- JazzContextType<InstanceOfSchema<S>> | undefined
67
- >(
68
- React.useCallback(
69
- (callback) => {
70
- const props = {
71
- AccountSchema,
72
- guestMode,
73
- sync,
74
- storage,
75
- defaultProfileName,
76
- onLogOut: onLogOutRefCallback,
77
- logOutReplacement: logoutReplacementActiveRef.current
78
- ? logOutReplacementRefCallback
79
- : undefined,
80
- onAnonymousAccountDiscarded: onAnonymousAccountDiscardedEnabled
81
- ? onAnonymousAccountDiscardedRefCallback
82
- : undefined,
83
- } satisfies JazzContextManagerProps<S>;
71
+ const props = useMemo(() => {
72
+ return {
73
+ AccountSchema,
74
+ guestMode,
75
+ sync,
76
+ storage,
77
+ defaultProfileName,
78
+ onLogOut: onLogOutRefCallback,
79
+ logOutReplacement: logOutReplacement
80
+ ? logOutReplacementRefCallback
81
+ : undefined,
82
+ onAnonymousAccountDiscarded: onAnonymousAccountDiscarded
83
+ ? onAnonymousAccountDiscardedRefCallback
84
+ : undefined,
85
+ } satisfies JazzContextManagerProps<S>;
86
+ }, [guestMode, sync.peer, sync.when, storage]);
84
87
 
85
- if (contextManager.propsChanged(props)) {
86
- contextManager.createContext(props).catch((error) => {
87
- console.log(error.stack);
88
- console.error("Error creating Jazz browser context:", error);
89
- });
90
- }
88
+ if (contextManager.propsChanged(props) && typeof window !== "undefined") {
89
+ contextManager.createContext(props).catch((error) => {
90
+ console.log(error.stack);
91
+ console.error("Error creating Jazz browser context:", error);
92
+ });
93
+ }
91
94
 
95
+ const isReady = useSyncExternalStore(
96
+ useCallback(
97
+ (callback) => {
92
98
  return contextManager.subscribe(callback);
93
99
  },
94
- [sync, guestMode].concat(storage as any),
100
+ [contextManager],
95
101
  ),
96
- () => contextManager.getCurrentValue(),
97
- () => contextManager.getCurrentValue(),
102
+ () => Boolean(contextManager.getCurrentValue()),
103
+ () => Boolean(contextManager.getCurrentValue()),
98
104
  );
99
105
 
100
106
  useEffect(() => {
@@ -108,10 +114,8 @@ export function JazzReactProvider<
108
114
  }, []);
109
115
 
110
116
  return (
111
- <JazzContext.Provider value={value}>
112
- <JazzContextManagerContext.Provider value={contextManager}>
113
- {value ? children : fallback}
114
- </JazzContextManagerContext.Provider>
117
+ <JazzContext.Provider value={contextManager}>
118
+ {isReady ? children : fallback}
115
119
  </JazzContext.Provider>
116
120
  );
117
121
  }
@@ -1,6 +1,6 @@
1
1
  import { DemoAuth } from "jazz-tools";
2
2
  import { useEffect, useMemo, useState } from "react";
3
- import { useAuthSecretStorage, useJazzContext } from "../hooks.js";
3
+ import { useAuthSecretStorage, useJazzContextValue } from "../hooks.js";
4
4
  import { useIsAuthenticated } from "../hooks.js";
5
5
 
6
6
  /**
@@ -14,7 +14,7 @@ import { useIsAuthenticated } from "../hooks.js";
14
14
  * @category Auth Providers
15
15
  */
16
16
  export function useDemoAuth() {
17
- const context = useJazzContext();
17
+ const context = useJazzContextValue();
18
18
  const authSecretStorage = useAuthSecretStorage();
19
19
 
20
20
  if ("guest" in context) {
@@ -1,6 +1,6 @@
1
1
  import { PassphraseAuth } from "jazz-tools";
2
2
  import { useCallback, useMemo, useSyncExternalStore } from "react";
3
- import { useAuthSecretStorage, useJazzContext } from "../hooks.js";
3
+ import { useAuthSecretStorage, useJazzContextValue } from "../hooks.js";
4
4
  import { useIsAuthenticated } from "../hooks.js";
5
5
 
6
6
  /**
@@ -14,7 +14,7 @@ import { useIsAuthenticated } from "../hooks.js";
14
14
  * @category Auth Providers
15
15
  */
16
16
  export function usePassphraseAuth({ wordlist }: { wordlist: string[] }) {
17
- const context = useJazzContext();
17
+ const context = useJazzContextValue();
18
18
  const authSecretStorage = useAuthSecretStorage();
19
19
 
20
20
  if ("guest" in context) {
@@ -19,7 +19,6 @@ import {
19
19
  InboxSender,
20
20
  InstanceOfSchema,
21
21
  JazzContextManager,
22
- JazzContextType,
23
22
  Loaded,
24
23
  MaybeLoaded,
25
24
  NotLoaded,
@@ -32,13 +31,13 @@ import {
32
31
  getUnloadedCoValueWithoutId,
33
32
  type BranchDefinition,
34
33
  } from "jazz-tools";
35
- import { JazzContext, JazzContextManagerContext } from "./provider.js";
34
+ import { JazzContext } from "./provider.js";
36
35
  import { getCurrentAccountFromContextManager } from "./utils.js";
37
36
  import { CoValueSubscription } from "./types.js";
38
37
  import { use } from "./use.js";
39
38
 
40
39
  export function useJazzContext<Acc extends Account>() {
41
- const value = useContext(JazzContext) as JazzContextType<Acc>;
40
+ const value = useContext(JazzContext) as JazzContextManager<Acc, {}>;
42
41
 
43
42
  if (!value) {
44
43
  throw new Error(
@@ -49,31 +48,31 @@ export function useJazzContext<Acc extends Account>() {
49
48
  return value;
50
49
  }
51
50
 
52
- export function useJazzContextManager<Acc extends Account>() {
53
- const value = useContext(JazzContextManagerContext) as JazzContextManager<
54
- Acc,
55
- {}
56
- >;
51
+ export function useJazzContextValue<Acc extends Account>() {
52
+ const contextManager = useJazzContext<Acc>();
57
53
 
58
- if (!value) {
54
+ const context = useSyncExternalStore(
55
+ useCallback(
56
+ (callback) => {
57
+ return contextManager.subscribe(callback);
58
+ },
59
+ [contextManager],
60
+ ),
61
+ () => contextManager.getCurrentValue(),
62
+ () => contextManager.getCurrentValue(),
63
+ );
64
+
65
+ if (!context) {
59
66
  throw new Error(
60
- "You need to set up a JazzProvider on top of your app to use this hook.",
67
+ "The JazzProvider is not initialized yet. This looks like a bug, please report it.",
61
68
  );
62
69
  }
63
70
 
64
- return value;
71
+ return context;
65
72
  }
66
73
 
67
74
  export function useAuthSecretStorage() {
68
- const value = useContext(JazzContextManagerContext);
69
-
70
- if (!value) {
71
- throw new Error(
72
- "You need to set up a JazzProvider on top of your app to use this useAuthSecretStorage.",
73
- );
74
- }
75
-
76
- return value.getAuthSecretStorage();
75
+ return useJazzContext().getAuthSecretStorage();
77
76
  }
78
77
 
79
78
  export function useIsAuthenticated() {
@@ -122,7 +121,7 @@ interface SubscriptionsState {
122
121
  schema: CoValueClassOrSchema;
123
122
  ids: readonly (string | undefined | null)[];
124
123
  resolve: ResolveQuery<any>;
125
- contextManager: ReturnType<typeof useJazzContextManager>;
124
+ contextManager: ReturnType<typeof useJazzContext>;
126
125
  agent: AnonymousJazzAgent | Loaded<any, true>;
127
126
  branchName?: string;
128
127
  branchOwnerId?: string;
@@ -142,7 +141,7 @@ function useCoValueSubscriptions(
142
141
  resolve: ResolveQuery<any>,
143
142
  branch?: BranchDefinition,
144
143
  ): (SubscriptionScope<CoValue> | null)[] {
145
- const contextManager = useJazzContextManager();
144
+ const contextManager = useJazzContext();
146
145
  const agent = useAgent();
147
146
 
148
147
  const callerStack = useMemo(() => captureStack(), []);
@@ -536,7 +535,7 @@ export function useAccountSubscription<
536
535
  unstable_branch?: BranchDefinition;
537
536
  },
538
537
  ) {
539
- const contextManager = useJazzContextManager();
538
+ const contextManager = useJazzContext();
540
539
 
541
540
  // Capture stack trace at hook call time
542
541
  const callerStack = useMemo(() => captureStack(), []);
@@ -783,7 +782,7 @@ export function useSuspenseAccount<
783
782
  * Returns a function for logging out of the current account.
784
783
  */
785
784
  export function useLogOut(): () => void {
786
- const contextManager = useJazzContextManager();
785
+ const contextManager = useJazzContext();
787
786
  return contextManager.logOut;
788
787
  }
789
788
 
@@ -798,7 +797,7 @@ export function useLogOut(): () => void {
798
797
  export function useAgent<
799
798
  A extends AccountClass<Account> | AnyAccountSchema = typeof Account,
800
799
  >(): AnonymousJazzAgent | Loaded<A, true> {
801
- const contextManager = useJazzContextManager<InstanceOfSchema<A>>();
800
+ const contextManager = useJazzContext<InstanceOfSchema<A>>();
802
801
 
803
802
  const getCurrentValue = () =>
804
803
  getCurrentAccountFromContextManager(contextManager) as
@@ -821,7 +820,7 @@ export function experimental_useInboxSender<
821
820
  I extends CoValue,
822
821
  O extends CoValue | undefined,
823
822
  >(inboxOwnerID: string | undefined) {
824
- const context = useJazzContext();
823
+ const context = useJazzContextValue();
825
824
 
826
825
  if (!("me" in context)) {
827
826
  throw new Error(
@@ -868,7 +867,7 @@ export function experimental_useInboxSender<
868
867
  * after 5 seconds of not receiving a ping from the server.
869
868
  */
870
869
  export function useSyncConnectionStatus() {
871
- const context = useJazzContext();
870
+ const context = useJazzContextValue();
872
871
 
873
872
  const connected = useSyncExternalStore(
874
873
  useCallback(
@@ -1,11 +1,7 @@
1
1
  import React from "react";
2
2
 
3
- import { Account, JazzContextManager, JazzContextType } from "jazz-tools";
3
+ import { Account, JazzContextManager } from "jazz-tools";
4
4
 
5
5
  export const JazzContext = React.createContext<
6
- JazzContextType<Account> | undefined
7
- >(undefined);
8
-
9
- export const JazzContextManagerContext = React.createContext<
10
6
  JazzContextManager<Account, {}> | undefined
11
7
  >(undefined);
@@ -1,7 +1,7 @@
1
1
  import { Account, AnonymousJazzAgent } from "jazz-tools";
2
2
  import { TestJazzContextManager } from "jazz-tools/testing";
3
3
  import { useCallback, useState, useSyncExternalStore } from "react";
4
- import { JazzContext, JazzContextManagerContext } from "./provider.js";
4
+ import { JazzContext } from "./provider.js";
5
5
 
6
6
  export function JazzTestProvider<Acc extends Account>({
7
7
  children,
@@ -18,17 +18,9 @@ export function JazzTestProvider<Acc extends Account>({
18
18
  });
19
19
  });
20
20
 
21
- const value = useSyncExternalStore(
22
- useCallback((callback) => contextManager.subscribe(callback), []),
23
- () => contextManager.getCurrentValue(),
24
- () => contextManager.getCurrentValue(),
25
- );
26
-
27
21
  return (
28
- <JazzContext.Provider value={value}>
29
- <JazzContextManagerContext.Provider value={contextManager}>
30
- {children}
31
- </JazzContextManagerContext.Provider>
22
+ <JazzContext.Provider value={contextManager}>
23
+ {children}
32
24
  </JazzContext.Provider>
33
25
  );
34
26
  }
@@ -1,9 +1,8 @@
1
1
  // @vitest-environment happy-dom
2
2
 
3
- import { Account, RefsToResolve, co, z, Group } from "jazz-tools";
3
+ import { Account, co, z, Group } from "jazz-tools";
4
4
  import { assert, beforeEach, describe, expect, it } from "vitest";
5
- import { useAccount, useJazzContextManager } from "../hooks.js";
6
- import { useIsAuthenticated } from "../index.js";
5
+ import { useAccount } from "../hooks.js";
7
6
  import {
8
7
  createJazzTestAccount,
9
8
  createJazzTestGuest,
@@ -3,12 +3,7 @@
3
3
  import { CoValueLoadingState, Group, RefsToResolve, co, z } from "jazz-tools";
4
4
  import { assertLoaded } from "jazz-tools/testing";
5
5
  import { assert, beforeEach, describe, expect, it } from "vitest";
6
- import {
7
- useAccount,
8
- useAgent,
9
- useJazzContextManager,
10
- useLogOut,
11
- } from "../hooks.js";
6
+ import { useAccount, useAgent, useJazzContext, useLogOut } from "../hooks.js";
12
7
  import { useIsAuthenticated } from "../index.js";
13
8
  import {
14
9
  createJazzTestAccount,
@@ -68,6 +63,61 @@ describe("useAccount", () => {
68
63
  expect(result.current.root.value).toBe("123");
69
64
  });
70
65
 
66
+ it("should return a 'deleted' value when a required resolved child is deleted", async () => {
67
+ const AccountRoot = co.map({
68
+ value: z.string(),
69
+ });
70
+
71
+ const AccountSchema = co
72
+ .account({
73
+ root: AccountRoot,
74
+ profile: co.profile(),
75
+ })
76
+ .withMigration((account) => {
77
+ if (!account.$jazz.refs.root) {
78
+ account.$jazz.set("root", { value: "123" });
79
+ }
80
+ });
81
+
82
+ const account = await createJazzTestAccount({
83
+ AccountSchema,
84
+ isCurrentActiveAccount: true,
85
+ });
86
+
87
+ const { result } = renderHook(
88
+ () =>
89
+ useAccount(AccountSchema, {
90
+ resolve: {
91
+ root: true,
92
+ },
93
+ }),
94
+ {
95
+ account,
96
+ },
97
+ );
98
+
99
+ await waitFor(() => {
100
+ assertLoaded(result.current);
101
+ assertLoaded(result.current.root);
102
+ expect(result.current.root.value).toBe("123");
103
+ });
104
+
105
+ assertLoaded(result.current);
106
+ assertLoaded(result.current.root);
107
+ // Capture the root reference before deletion; after deletion the account may become NotLoaded.
108
+ const root = result.current.root;
109
+
110
+ act(() => {
111
+ root.$jazz.raw.core.deleteCoValue();
112
+ });
113
+
114
+ await waitFor(() => {
115
+ expect(result.current.$jazz.loadingState).toBe(
116
+ CoValueLoadingState.DELETED,
117
+ );
118
+ });
119
+ });
120
+
71
121
  it("should be in sync with useIsAuthenticated when logOut is called", async () => {
72
122
  const account = await createJazzTestAccount({});
73
123
 
@@ -140,7 +190,7 @@ describe("useAccount", () => {
140
190
  () => {
141
191
  const isAuthenticated = useIsAuthenticated();
142
192
  const account = useAccount();
143
- const contextManager = useJazzContextManager();
193
+ const contextManager = useJazzContext();
144
194
 
145
195
  if (account) {
146
196
  if (!accounts.includes(account.$jazz.id)) {
@@ -224,6 +224,43 @@ describe("useCoState", () => {
224
224
  });
225
225
  });
226
226
 
227
+ it("should return a 'deleted' value when the coValue is deleted", async () => {
228
+ const TestMap = co.map({
229
+ value: z.string(),
230
+ });
231
+
232
+ const account = await createJazzTestAccount({
233
+ isCurrentActiveAccount: true,
234
+ });
235
+
236
+ const map = TestMap.create(
237
+ {
238
+ value: "123",
239
+ },
240
+ Group.create(account).makePublic("reader"),
241
+ );
242
+
243
+ const { result } = renderHook(() => useCoState(TestMap, map.$jazz.id), {
244
+ account,
245
+ });
246
+
247
+ await waitFor(() => {
248
+ assertLoaded(result.current);
249
+ expect(result.current.value).toBe("123");
250
+ });
251
+
252
+ console.log("deleting");
253
+ act(() => {
254
+ map.$jazz.raw.core.deleteCoValue();
255
+ });
256
+
257
+ await waitFor(() => {
258
+ expect(result.current.$jazz.loadingState).toBe(
259
+ CoValueLoadingState.DELETED,
260
+ );
261
+ });
262
+ });
263
+
227
264
  it("should return a 'loaded' value if the coValue is shared with everyone", async () => {
228
265
  const TestMap = co.map({
229
266
  value: z.string(),
@@ -3,10 +3,7 @@
3
3
  import { CoMap, Group, Inbox, Loaded, co, z } from "jazz-tools";
4
4
  import { assertLoaded } from "jazz-tools/testing";
5
5
  import { describe, expect, it } from "vitest";
6
- import {
7
- experimental_useInboxSender,
8
- useJazzContextManager,
9
- } from "../index.js";
6
+ import { experimental_useInboxSender, useJazzContext } from "../index.js";
10
7
  import {
11
8
  createJazzTestAccount,
12
9
  linkAccounts,
@@ -75,7 +72,7 @@ describe("useInboxSender", () => {
75
72
 
76
73
  const { result } = renderHook(
77
74
  () => {
78
- const ctx = useJazzContextManager();
75
+ const ctx = useJazzContext();
79
76
  const send = experimental_useInboxSender(inboxReceiver.$jazz.id);
80
77
  return { ctx, send };
81
78
  },
@@ -239,6 +239,74 @@ describe("useSuspenseAccount", () => {
239
239
  });
240
240
  });
241
241
 
242
+ it("should throw error when a required resolved child is deleted", async () => {
243
+ const AccountRoot = co.map({
244
+ value: z.string(),
245
+ });
246
+
247
+ const MyAppAccount = co
248
+ .account({
249
+ profile: co.profile({
250
+ name: z.string(),
251
+ }),
252
+ root: AccountRoot,
253
+ })
254
+ .withMigration((account, creationProps) => {
255
+ if (!account.$jazz.refs.profile) {
256
+ account.$jazz.set("profile", {
257
+ name: creationProps?.name || "John Doe",
258
+ });
259
+ }
260
+ if (!account.$jazz.refs.root) {
261
+ account.$jazz.set("root", {
262
+ value: "123",
263
+ });
264
+ }
265
+ });
266
+
267
+ const account = await createJazzTestAccount({
268
+ AccountSchema: MyAppAccount,
269
+ isCurrentActiveAccount: true,
270
+ creationProps: {
271
+ name: "John Doe",
272
+ },
273
+ });
274
+
275
+ // Ensure root exists, then delete it.
276
+ const loaded = await account.$jazz.ensureLoaded({
277
+ resolve: { root: true },
278
+ });
279
+ loaded.root.$jazz.raw.core.deleteCoValue();
280
+
281
+ const TestComponent = () => {
282
+ const account = useSuspenseAccount(MyAppAccount, {
283
+ resolve: {
284
+ root: true,
285
+ profile: true,
286
+ },
287
+ });
288
+ return <div>{account.profile.name}</div>;
289
+ };
290
+
291
+ const { container } = await act(async () => {
292
+ return render(
293
+ <ErrorBoundary FallbackComponent={ErrorFallback}>
294
+ <Suspense fallback={<div>Loading...</div>}>
295
+ <TestComponent />
296
+ </Suspense>
297
+ </ErrorBoundary>,
298
+ { account },
299
+ );
300
+ });
301
+
302
+ await waitFor(
303
+ () => {
304
+ expect(container.textContent).toContain("Error: deleted");
305
+ },
306
+ { timeout: 10_000 },
307
+ );
308
+ });
309
+
242
310
  it("should throw error for anonymous agent", async () => {
243
311
  const MyAppAccount = co.account({
244
312
  profile: co.profile({