jazz-tools 0.19.21 → 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.
- package/.svelte-kit/__package__/react.d.ts.map +1 -1
- package/.svelte-kit/__package__/react.tsx +5 -2
- package/.turbo/turbo-build.log +77 -89
- package/CHANGELOG.md +84 -0
- package/dist/better-auth/auth/react.d.ts.map +1 -1
- package/dist/better-auth/auth/react.js +5 -2
- package/dist/better-auth/auth/react.js.map +1 -1
- package/dist/browser/createBrowserContext.d.ts +1 -2
- package/dist/browser/createBrowserContext.d.ts.map +1 -1
- package/dist/browser/index.js +1 -8
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/provideBrowserLockSession/SessionIDStorage.d.ts +1 -1
- package/dist/{chunk-QCTQH5RS.js → chunk-3CAPPS2F.js} +234 -101
- package/dist/chunk-3CAPPS2F.js.map +1 -0
- package/dist/{chunk-M2HGBOXS.js → chunk-K4D7IMFM.js} +3 -3
- package/dist/chunk-K4D7IMFM.js.map +1 -0
- package/dist/expo/auth/clerk/index.d.ts.map +1 -1
- package/dist/expo/index.js +5 -2
- package/dist/expo/index.js.map +1 -1
- package/dist/index.js +39 -2
- package/dist/index.js.map +1 -1
- package/dist/inspector/{chunk-YQNK5Y7B.js → chunk-MCTB5ZJC.js} +1 -1
- package/dist/inspector/chunk-MCTB5ZJC.js.map +1 -0
- package/dist/inspector/contexts/node.d.ts.map +1 -1
- package/dist/inspector/{custom-element-KYV64IOC.js → custom-element-5YWVZBWA.js} +1 -1
- package/dist/inspector/{custom-element-KYV64IOC.js.map → custom-element-5YWVZBWA.js.map} +1 -1
- package/dist/inspector/index.js +3 -3
- package/dist/inspector/index.js.map +1 -1
- package/dist/inspector/register-custom-element.js +1 -1
- package/dist/inspector/standalone.js +1 -1
- package/dist/media/{chunk-3LKBM3G3.js → chunk-IRL3KNPO.js} +2 -2
- package/dist/media/{chunk-3LKBM3G3.js.map → chunk-IRL3KNPO.js.map} +1 -1
- package/dist/media/create-image/react-native.d.ts +1 -1
- package/dist/media/create-image/react-native.d.ts.map +1 -1
- package/dist/media/index.browser.js +1 -1
- package/dist/media/index.js +1 -1
- package/dist/media/index.native.js +5 -5
- package/dist/media/index.native.js.map +1 -1
- package/dist/media/index.server.js +1 -1
- package/dist/react/auth/Clerk.d.ts.map +1 -1
- package/dist/react/hooks.d.ts +1 -1
- package/dist/react/hooks.d.ts.map +1 -1
- package/dist/react/index.js +61 -47
- package/dist/react/index.js.map +1 -1
- package/dist/react/provider.d.ts.map +1 -1
- package/dist/react/ssr.js +2 -2
- package/dist/react/ssr.js.map +1 -1
- package/dist/react-core/chunk-UOYH6JFJ.js +10 -0
- package/dist/react-core/chunk-UOYH6JFJ.js.map +1 -0
- package/dist/react-core/hooks.d.ts +3 -3
- package/dist/react-core/hooks.d.ts.map +1 -1
- package/dist/react-core/index.js +27 -25
- package/dist/react-core/index.js.map +1 -1
- package/dist/react-core/provider.d.ts +2 -3
- package/dist/react-core/provider.d.ts.map +1 -1
- package/dist/react-core/testing.d.ts.map +1 -1
- package/dist/react-core/testing.js +4 -10
- package/dist/react-core/testing.js.map +1 -1
- package/dist/react-native/index.js +61 -53
- package/dist/react-native/index.js.map +1 -1
- package/dist/react-native-core/ReactNativeContextManager.d.ts +0 -1
- package/dist/react-native-core/ReactNativeContextManager.d.ts.map +1 -1
- package/dist/react-native-core/hooks.d.ts +1 -1
- package/dist/react-native-core/hooks.d.ts.map +1 -1
- package/dist/react-native-core/index.js +58 -50
- package/dist/react-native-core/index.js.map +1 -1
- package/dist/react-native-core/platform.d.ts +0 -4
- package/dist/react-native-core/platform.d.ts.map +1 -1
- package/dist/react-native-core/provider.d.ts +2 -1
- package/dist/react-native-core/provider.d.ts.map +1 -1
- package/dist/svelte/jazz.class.svelte.d.ts.map +1 -1
- package/dist/svelte/jazz.class.svelte.js +2 -8
- package/dist/svelte/tests/AccountCoState.svelte.test.d.ts +2 -0
- package/dist/svelte/tests/AccountCoState.svelte.test.d.ts.map +1 -0
- package/dist/svelte/tests/AccountCoState.svelte.test.js +59 -0
- package/dist/svelte/tests/CoState.svelte.test.js +23 -0
- package/dist/svelte/tests/TestAccountCoStateWrapper.svelte +24 -0
- package/dist/svelte/tests/TestAccountCoStateWrapper.svelte.d.ts +11 -0
- package/dist/svelte/tests/TestAccountCoStateWrapper.svelte.d.ts.map +1 -0
- package/dist/testing.js +6 -6
- package/dist/testing.js.map +1 -1
- package/dist/tools/coValues/coList.d.ts +2 -2
- package/dist/tools/coValues/coList.d.ts.map +1 -1
- package/dist/tools/coValues/coMap.d.ts +2 -2
- package/dist/tools/coValues/deepLoading.d.ts +2 -2
- package/dist/tools/coValues/deepLoading.d.ts.map +1 -1
- package/dist/tools/coValues/interfaces.d.ts +32 -0
- package/dist/tools/coValues/interfaces.d.ts.map +1 -1
- package/dist/tools/exports.d.ts +2 -1
- package/dist/tools/exports.d.ts.map +1 -1
- package/dist/tools/implementation/ContextManager.d.ts.map +1 -1
- package/dist/tools/implementation/createContext.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/schemaTypes/AccountSchema.d.ts +3 -2
- package/dist/tools/implementation/zodSchema/schemaTypes/AccountSchema.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/schemaTypes/CoDiscriminatedUnionSchema.d.ts +3 -2
- package/dist/tools/implementation/zodSchema/schemaTypes/CoDiscriminatedUnionSchema.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts +3 -3
- package/dist/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/schemaTypes/CoListSchema.d.ts +3 -2
- package/dist/tools/implementation/zodSchema/schemaTypes/CoListSchema.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts +5 -2
- package/dist/tools/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/zodCo.d.ts.map +1 -1
- package/dist/tools/ssr.js +1 -1
- package/dist/tools/subscribe/JazzError.d.ts +3 -3
- package/dist/tools/subscribe/JazzError.d.ts.map +1 -1
- package/dist/tools/subscribe/SubscriptionScope.d.ts.map +1 -1
- package/dist/tools/subscribe/types.d.ts +5 -1
- package/dist/tools/subscribe/types.d.ts.map +1 -1
- package/dist/tools/testing.d.ts +3 -3
- package/dist/tools/testing.d.ts.map +1 -1
- package/dist/tools/tests/deleteCoValues.test.d.ts +2 -0
- package/dist/tools/tests/deleteCoValues.test.d.ts.map +1 -0
- package/dist/tools/tests/deletedState.test.d.ts +2 -0
- package/dist/tools/tests/deletedState.test.d.ts.map +1 -0
- package/dist/worker/JazzMessageChannel.d.ts +36 -0
- package/dist/worker/JazzMessageChannel.d.ts.map +1 -0
- package/dist/worker/edge-wasm.js +2 -1
- package/dist/worker/edge-wasm.js.map +1 -1
- package/dist/worker/index.d.ts +7 -1
- package/dist/worker/index.d.ts.map +1 -1
- package/dist/worker/index.js +28 -17
- package/dist/worker/index.js.map +1 -1
- package/dist/worker/wasm.d.ts +2 -0
- package/dist/worker/wasm.d.ts.map +1 -0
- package/package.json +9 -28
- package/src/better-auth/auth/react.tsx +5 -2
- package/src/browser/createBrowserContext.ts +2 -5
- package/src/expo/auth/clerk/index.tsx +5 -2
- package/src/inspector/contexts/node.tsx +1 -2
- package/src/inspector/index.tsx +2 -2
- package/src/media/create-image/react-native.ts +9 -7
- package/src/media/create-image-factory.test.ts +1 -1
- package/src/media/create-image-factory.ts +1 -1
- package/src/react/auth/Clerk.tsx +5 -2
- package/src/react/auth/PasskeyAuth.tsx +2 -2
- package/src/react/hooks.tsx +3 -2
- package/src/react/provider.tsx +45 -41
- package/src/react-core/auth/DemoAuth.tsx +2 -2
- package/src/react-core/auth/PassphraseAuth.tsx +2 -2
- package/src/react-core/hooks.ts +26 -27
- package/src/react-core/provider.tsx +1 -5
- package/src/react-core/testing.tsx +3 -11
- package/src/react-core/tests/testUtils.tsx +2 -2
- package/src/react-core/tests/useAccount.selector.test.ts +2 -3
- package/src/react-core/tests/useAccount.test.ts +57 -7
- package/src/react-core/tests/useCoState.test.ts +37 -0
- package/src/react-core/tests/useInboxSender.test.ts +2 -5
- package/src/react-core/tests/useSuspenseAccount.test.tsx +68 -0
- package/src/react-core/tests/useSuspenseCoState.test.tsx +44 -0
- package/src/react-native-core/ReactNativeContextManager.ts +0 -3
- package/src/react-native-core/auth/usePasskeyAuth.tsx +2 -2
- package/src/react-native-core/hooks.tsx +3 -3
- package/src/react-native-core/platform.ts +2 -6
- package/src/react-native-core/provider.tsx +47 -43
- package/src/svelte/jazz.class.svelte.ts +2 -8
- package/src/svelte/tests/AccountCoState.svelte.test.ts +79 -0
- package/src/svelte/tests/CoState.svelte.test.ts +36 -0
- package/src/svelte/tests/TestAccountCoStateWrapper.svelte +24 -0
- package/src/tools/coValues/deepLoading.ts +2 -0
- package/src/tools/coValues/interfaces.ts +170 -32
- package/src/tools/exports.ts +6 -0
- package/src/tools/implementation/ContextManager.ts +2 -2
- package/src/tools/implementation/createContext.ts +4 -0
- package/src/tools/implementation/zodSchema/schemaTypes/AccountSchema.ts +30 -6
- package/src/tools/implementation/zodSchema/schemaTypes/CoDiscriminatedUnionSchema.ts +55 -7
- package/src/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.ts +33 -14
- package/src/tools/implementation/zodSchema/schemaTypes/CoListSchema.ts +35 -6
- package/src/tools/implementation/zodSchema/schemaTypes/CoMapSchema.ts +35 -14
- package/src/tools/ssr/ssr.ts +2 -2
- package/src/tools/subscribe/CoValueCoreSubscription.ts +1 -0
- package/src/tools/subscribe/JazzError.ts +4 -1
- package/src/tools/subscribe/SubscriptionScope.ts +23 -0
- package/src/tools/subscribe/types.ts +5 -0
- package/src/tools/testing.ts +5 -5
- package/src/tools/tests/PassphraseAuth.test.ts +5 -5
- package/src/tools/tests/deleteCoValues.test.ts +231 -0
- package/src/tools/tests/deletedState.test.ts +110 -0
- package/src/tools/tests/request.test.ts +15 -2
- package/src/tools/tests/testStorage.ts +2 -2
- package/src/worker/JazzMessageChannel.ts +73 -0
- package/src/worker/edge-wasm.ts +2 -1
- package/src/worker/index.ts +36 -17
- package/src/worker/wasm.ts +1 -0
- package/tsup.config.ts +0 -4
- package/dist/browser/storageOptions.d.ts +0 -8
- package/dist/browser/storageOptions.d.ts.map +0 -1
- package/dist/browser/tests/storageOptions.test.d.ts +0 -2
- package/dist/browser/tests/storageOptions.test.d.ts.map +0 -1
- package/dist/chunk-M2HGBOXS.js.map +0 -1
- package/dist/chunk-QCTQH5RS.js.map +0 -1
- package/dist/expo/crypto.d.ts +0 -2
- package/dist/expo/crypto.d.ts.map +0 -1
- package/dist/expo/crypto.js +0 -6
- package/dist/expo/crypto.js.map +0 -1
- package/dist/inspector/chunk-YQNK5Y7B.js.map +0 -1
- package/dist/react-core/chunk-7DYMJ74I.js +0 -12
- package/dist/react-core/chunk-7DYMJ74I.js.map +0 -1
- package/dist/react-native/chunk-DGUM43GV.js +0 -11
- package/dist/react-native/chunk-DGUM43GV.js.map +0 -1
- package/dist/react-native/crypto.d.ts +0 -2
- package/dist/react-native/crypto.d.ts.map +0 -1
- package/dist/react-native/crypto.js +0 -8
- package/dist/react-native/crypto.js.map +0 -1
- package/dist/react-native-core/chunk-DGUM43GV.js +0 -11
- package/dist/react-native-core/chunk-DGUM43GV.js.map +0 -1
- package/dist/react-native-core/crypto/RNCrypto.d.ts +0 -2
- package/dist/react-native-core/crypto/RNCrypto.d.ts.map +0 -1
- package/dist/react-native-core/crypto/RNCrypto.js +0 -3
- package/dist/react-native-core/crypto/RNCrypto.js.map +0 -1
- package/dist/react-native-core/crypto/RNQuickCrypto.d.ts +0 -17
- package/dist/react-native-core/crypto/RNQuickCrypto.d.ts.map +0 -1
- package/dist/react-native-core/crypto/index.d.ts +0 -2
- package/dist/react-native-core/crypto/index.d.ts.map +0 -1
- package/dist/react-native-core/crypto.js +0 -89
- package/dist/react-native-core/crypto.js.map +0 -1
- package/src/browser/storageOptions.ts +0 -17
- package/src/browser/tests/storageOptions.test.ts +0 -33
- package/src/expo/crypto.ts +0 -1
- package/src/react-native/crypto.ts +0 -1
- package/src/react-native-core/crypto/RNCrypto.ts +0 -1
- package/src/react-native-core/crypto/RNQuickCrypto.ts +0 -122
- package/src/react-native-core/crypto/index.ts +0 -1
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
// @vitest-environment happy-dom
|
|
2
2
|
|
|
3
|
-
import { Account,
|
|
3
|
+
import { Account, co, z, Group } from "jazz-tools";
|
|
4
4
|
import { assert, beforeEach, describe, expect, it } from "vitest";
|
|
5
|
-
import { useAccount
|
|
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 =
|
|
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 =
|
|
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({
|
|
@@ -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
|
-
|
|
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 =
|
|
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 {
|
|
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
|
-
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
11
|
-
import 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
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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
|
-
[
|
|
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={
|
|
110
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
});
|