jazz-tools 0.19.19 → 0.19.21

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 (127) hide show
  1. package/.svelte-kit/__package__/client.d.ts.map +1 -1
  2. package/.svelte-kit/__package__/client.js +3 -1
  3. package/.svelte-kit/__package__/server.d.ts.map +1 -1
  4. package/.svelte-kit/__package__/server.js +9 -7
  5. package/.svelte-kit/__package__/tests/client.test.js +48 -0
  6. package/.turbo/turbo-build.log +70 -66
  7. package/dist/better-auth/auth/client.d.ts.map +1 -1
  8. package/dist/better-auth/auth/client.js +1 -1
  9. package/dist/better-auth/auth/client.js.map +1 -1
  10. package/dist/better-auth/auth/server.d.ts.map +1 -1
  11. package/dist/better-auth/auth/server.js +4 -4
  12. package/dist/better-auth/auth/server.js.map +1 -1
  13. package/dist/better-auth/database-adapter/index.js.map +1 -1
  14. package/dist/better-auth/database-adapter/repository/generic.d.ts +3 -3
  15. package/dist/better-auth/database-adapter/repository/session.d.ts +2 -2
  16. package/dist/better-auth/database-adapter/schema.d.ts +3 -3
  17. package/dist/better-auth/database-adapter/schema.d.ts.map +1 -1
  18. package/dist/{chunk-PEHQ7TN2.js → chunk-QCTQH5RS.js} +31 -4
  19. package/dist/chunk-QCTQH5RS.js.map +1 -0
  20. package/dist/index.js +1 -1
  21. package/dist/index.js.map +1 -1
  22. package/dist/react/hooks.d.ts +1 -2
  23. package/dist/react/hooks.d.ts.map +1 -1
  24. package/dist/react/index.js +7 -2
  25. package/dist/react/index.js.map +1 -1
  26. package/dist/react-core/hooks.d.ts +94 -3
  27. package/dist/react-core/hooks.d.ts.map +1 -1
  28. package/dist/react-core/index.js +130 -135
  29. package/dist/react-core/index.js.map +1 -1
  30. package/dist/react-core/tests/useCoStates.test.d.ts +2 -0
  31. package/dist/react-core/tests/useCoStates.test.d.ts.map +1 -0
  32. package/dist/react-native/chunk-DGUM43GV.js +11 -0
  33. package/dist/react-native/chunk-DGUM43GV.js.map +1 -0
  34. package/dist/react-native/crypto.js +2 -0
  35. package/dist/react-native/crypto.js.map +1 -1
  36. package/dist/react-native/index.js +544 -29
  37. package/dist/react-native/index.js.map +1 -1
  38. package/dist/react-native-core/auth/PasskeyAuth.d.ts +123 -0
  39. package/dist/react-native-core/auth/PasskeyAuth.d.ts.map +1 -0
  40. package/dist/react-native-core/auth/PasskeyAuthBasicUI.d.ts +34 -0
  41. package/dist/react-native-core/auth/PasskeyAuthBasicUI.d.ts.map +1 -0
  42. package/dist/react-native-core/auth/auth.d.ts +3 -0
  43. package/dist/react-native-core/auth/auth.d.ts.map +1 -1
  44. package/dist/react-native-core/auth/passkey-utils.d.ts +16 -0
  45. package/dist/react-native-core/auth/passkey-utils.d.ts.map +1 -0
  46. package/dist/react-native-core/auth/usePasskeyAuth.d.ts +48 -0
  47. package/dist/react-native-core/auth/usePasskeyAuth.d.ts.map +1 -0
  48. package/dist/react-native-core/chunk-DGUM43GV.js +11 -0
  49. package/dist/react-native-core/chunk-DGUM43GV.js.map +1 -0
  50. package/dist/react-native-core/crypto.js +2 -0
  51. package/dist/react-native-core/crypto.js.map +1 -1
  52. package/dist/react-native-core/hooks.d.ts +1 -1
  53. package/dist/react-native-core/hooks.d.ts.map +1 -1
  54. package/dist/react-native-core/index.js +539 -24
  55. package/dist/react-native-core/index.js.map +1 -1
  56. package/dist/react-native-core/tests/PasskeyAuth.test.d.ts +2 -0
  57. package/dist/react-native-core/tests/PasskeyAuth.test.d.ts.map +1 -0
  58. package/dist/react-native-core/tests/passkey-utils.test.d.ts +2 -0
  59. package/dist/react-native-core/tests/passkey-utils.test.d.ts.map +1 -0
  60. package/dist/svelte/auth/ClerkAuth.svelte.d.ts +38 -0
  61. package/dist/svelte/auth/ClerkAuth.svelte.d.ts.map +1 -0
  62. package/dist/svelte/auth/ClerkAuth.svelte.js +47 -0
  63. package/dist/svelte/auth/JazzSvelteProviderWithClerk.svelte +156 -0
  64. package/dist/svelte/auth/JazzSvelteProviderWithClerk.svelte.d.ts +67 -0
  65. package/dist/svelte/auth/JazzSvelteProviderWithClerk.svelte.d.ts.map +1 -0
  66. package/dist/svelte/auth/RegisterClerkAuth.svelte +27 -0
  67. package/dist/svelte/auth/RegisterClerkAuth.svelte.d.ts +17 -0
  68. package/dist/svelte/auth/RegisterClerkAuth.svelte.d.ts.map +1 -0
  69. package/dist/svelte/auth/index.d.ts +2 -0
  70. package/dist/svelte/auth/index.d.ts.map +1 -1
  71. package/dist/svelte/auth/index.js +2 -0
  72. package/dist/svelte/tests/ClerkAuth.svelte.test.d.ts +2 -0
  73. package/dist/svelte/tests/ClerkAuth.svelte.test.d.ts.map +1 -0
  74. package/dist/svelte/tests/ClerkAuth.svelte.test.js +202 -0
  75. package/dist/svelte/tests/TestClerkAuthWrapper.svelte +16 -0
  76. package/dist/svelte/tests/TestClerkAuthWrapper.svelte.d.ts +8 -0
  77. package/dist/svelte/tests/TestClerkAuthWrapper.svelte.d.ts.map +1 -0
  78. package/dist/svelte/tests/testUtils.d.ts +1 -0
  79. package/dist/svelte/tests/testUtils.d.ts.map +1 -1
  80. package/dist/svelte/tests/testUtils.js +3 -1
  81. package/dist/testing.js +1 -1
  82. package/dist/tools/auth/clerk/index.d.ts +1 -1
  83. package/dist/tools/auth/clerk/types.d.ts +1 -1
  84. package/dist/tools/auth/clerk/types.d.ts.map +1 -1
  85. package/dist/tools/coValues/account.d.ts +5 -1
  86. package/dist/tools/coValues/account.d.ts.map +1 -1
  87. package/dist/tools/implementation/zodSchema/schemaTypes/AccountSchema.d.ts +30 -1
  88. package/dist/tools/implementation/zodSchema/schemaTypes/AccountSchema.d.ts.map +1 -1
  89. package/dist/tools/implementation/zodSchema/zodCo.d.ts.map +1 -1
  90. package/dist/tools/subscribe/types.d.ts +1 -1
  91. package/dist/tools/subscribe/types.d.ts.map +1 -1
  92. package/dist/tools/testing.d.ts.map +1 -1
  93. package/package.json +8 -4
  94. package/src/better-auth/auth/client.ts +3 -1
  95. package/src/better-auth/auth/server.ts +9 -7
  96. package/src/better-auth/auth/tests/client.test.ts +66 -2
  97. package/src/better-auth/database-adapter/repository/generic.ts +3 -3
  98. package/src/better-auth/database-adapter/repository/session.ts +2 -2
  99. package/src/better-auth/database-adapter/schema.ts +5 -5
  100. package/src/react/hooks.tsx +4 -2
  101. package/src/react-core/hooks.ts +332 -178
  102. package/src/react-core/tests/useCoState.selector.test.ts +309 -22
  103. package/src/react-core/tests/useCoStates.test.tsx +414 -0
  104. package/src/react-native-core/auth/PasskeyAuth.ts +316 -0
  105. package/src/react-native-core/auth/PasskeyAuthBasicUI.tsx +284 -0
  106. package/src/react-native-core/auth/auth.ts +3 -0
  107. package/src/react-native-core/auth/passkey-utils.ts +47 -0
  108. package/src/react-native-core/auth/usePasskeyAuth.tsx +85 -0
  109. package/src/react-native-core/hooks.tsx +2 -0
  110. package/src/react-native-core/tests/PasskeyAuth.test.ts +463 -0
  111. package/src/react-native-core/tests/passkey-utils.test.ts +144 -0
  112. package/src/svelte/auth/ClerkAuth.svelte.ts +67 -0
  113. package/src/svelte/auth/JazzSvelteProviderWithClerk.svelte +156 -0
  114. package/src/svelte/auth/RegisterClerkAuth.svelte +27 -0
  115. package/src/svelte/auth/index.ts +2 -0
  116. package/src/svelte/tests/ClerkAuth.svelte.test.ts +305 -0
  117. package/src/svelte/tests/TestClerkAuthWrapper.svelte +16 -0
  118. package/src/svelte/tests/testUtils.ts +4 -1
  119. package/src/tools/auth/clerk/types.ts +1 -1
  120. package/src/tools/coValues/account.ts +11 -3
  121. package/src/tools/implementation/zodSchema/schemaTypes/AccountSchema.ts +27 -1
  122. package/src/tools/subscribe/types.ts +1 -1
  123. package/src/tools/tests/account.test.ts +2 -1
  124. package/src/tools/tests/inbox.test.ts +7 -7
  125. package/testSetup.ts +4 -0
  126. package/vitest.config.ts +1 -0
  127. package/dist/chunk-PEHQ7TN2.js.map +0 -1
@@ -0,0 +1,414 @@
1
+ // @vitest-environment happy-dom
2
+
3
+ import { cojsonInternals } from "cojson";
4
+ import { Loaded, co, z } from "jazz-tools";
5
+ import { assertLoaded } from "jazz-tools/testing";
6
+ import { assert, beforeEach, describe, expect, expectTypeOf, it } from "vitest";
7
+ import React, { Suspense } from "react";
8
+ import { useCoStates, useSuspenseCoStates } from "../hooks.js";
9
+ import { createJazzTestAccount, setupJazzTestSync } from "../testing.js";
10
+ import { act, renderHook, waitFor } from "./testUtils.js";
11
+
12
+ const ProjectSchema = co.map({
13
+ name: z.string(),
14
+ });
15
+
16
+ beforeEach(async () => {
17
+ cojsonInternals.setCoValueLoadingRetryDelay(20);
18
+
19
+ await setupJazzTestSync({
20
+ asyncPeers: true,
21
+ });
22
+
23
+ await createJazzTestAccount({
24
+ isCurrentActiveAccount: true,
25
+ });
26
+ });
27
+
28
+ describe("useSuspenseCoStates", () => {
29
+ it("should return loaded values for all subscriptions", async () => {
30
+ const project1 = ProjectSchema.create({ name: "My Project 1" });
31
+ const project2 = ProjectSchema.create({ name: "My Project 2" });
32
+
33
+ const wrapper = ({ children }: { children: React.ReactNode }) => (
34
+ <Suspense fallback={<div>Loading...</div>}>{children}</Suspense>
35
+ );
36
+
37
+ const { result } = await act(async () => {
38
+ return renderHook(
39
+ () =>
40
+ useSuspenseCoStates(ProjectSchema, [
41
+ project1.$jazz.id,
42
+ project2.$jazz.id,
43
+ ]),
44
+ {
45
+ wrapper,
46
+ },
47
+ );
48
+ });
49
+
50
+ // Wait for any async operations to complete
51
+ await waitFor(() => {
52
+ expect(result.current).toBeDefined();
53
+ expect(result.current.length).toBe(2);
54
+ });
55
+
56
+ const [loadedProject1, loadedProject2] = result.current;
57
+
58
+ assert(loadedProject1);
59
+ expect(loadedProject1.name).toBe("My Project 1");
60
+
61
+ assert(loadedProject2);
62
+ expect(loadedProject2.name).toBe("My Project 2");
63
+ });
64
+
65
+ it("should have correct return types for each entry", async () => {
66
+ const project1 = ProjectSchema.create({ name: "Project 1" });
67
+ const project2 = ProjectSchema.create({ name: "Project 2" });
68
+
69
+ const wrapper = ({ children }: { children: React.ReactNode }) => (
70
+ <Suspense fallback={<div>Loading...</div>}>{children}</Suspense>
71
+ );
72
+
73
+ const ids = [project1.$jazz.id, project2.$jazz.id] as const;
74
+
75
+ const { result } = await act(async () => {
76
+ return renderHook(() => useSuspenseCoStates(ProjectSchema, ids), {
77
+ wrapper,
78
+ });
79
+ });
80
+
81
+ await waitFor(() => {
82
+ expect(result.current).toBeDefined();
83
+ expect(result.current.length).toBe(2);
84
+ });
85
+
86
+ expectTypeOf(result.current).toEqualTypeOf<
87
+ Loaded<typeof ProjectSchema>[]
88
+ >();
89
+ });
90
+
91
+ it("should re-render when any value changes", async () => {
92
+ const project1 = ProjectSchema.create({ name: "Project 1" });
93
+ const project2 = ProjectSchema.create({ name: "Project 2" });
94
+
95
+ const wrapper = ({ children }: { children: React.ReactNode }) => (
96
+ <Suspense fallback={<div>Loading...</div>}>{children}</Suspense>
97
+ );
98
+
99
+ const { result } = await act(async () => {
100
+ return renderHook(
101
+ () =>
102
+ useSuspenseCoStates(ProjectSchema, [
103
+ project1.$jazz.id,
104
+ project2.$jazz.id,
105
+ ]),
106
+ {
107
+ wrapper,
108
+ },
109
+ );
110
+ });
111
+
112
+ await waitFor(() => {
113
+ expect(result.current).toBeDefined();
114
+ expect(result.current.length).toBe(2);
115
+ });
116
+
117
+ assert(result.current[0]);
118
+ assert(result.current[0]);
119
+ expect(result.current[0].name).toBe("Project 1");
120
+
121
+ // Update one of the values
122
+ act(() => {
123
+ project1.$jazz.set("name", "updated1");
124
+ });
125
+
126
+ assert(result.current[0]);
127
+ expect(result.current[0].name).toBe("updated1");
128
+ });
129
+
130
+ it("should handle empty subscription array", async () => {
131
+ const wrapper = ({ children }: { children: React.ReactNode }) => (
132
+ <Suspense fallback={<div>Loading...</div>}>{children}</Suspense>
133
+ );
134
+
135
+ const { result } = await act(async () => {
136
+ return renderHook(() => useSuspenseCoStates(ProjectSchema, []), {
137
+ wrapper,
138
+ });
139
+ });
140
+
141
+ await waitFor(() => {
142
+ expect(result.current).toBeDefined();
143
+ });
144
+
145
+ expect(result.current).toEqual([]);
146
+ });
147
+
148
+ it("supports branching CoValues", async () => {
149
+ const project = ProjectSchema.create({ name: "My Project" });
150
+
151
+ const wrapper = ({ children }: { children: React.ReactNode }) => (
152
+ <Suspense fallback={<div>Loading...</div>}>{children}</Suspense>
153
+ );
154
+
155
+ const branchName = "feature-branch";
156
+ const { result } = await act(async () => {
157
+ return renderHook(
158
+ () =>
159
+ useSuspenseCoStates(ProjectSchema, [project.$jazz.id], {
160
+ unstable_branch: { name: branchName },
161
+ }),
162
+ {
163
+ wrapper,
164
+ },
165
+ );
166
+ });
167
+
168
+ assert(result.current[0]);
169
+ expect(result.current[0].name).toBe("My Project");
170
+
171
+ // Updates on changes to the branched CoValue
172
+ act(() => {
173
+ result.current[0]!.$jazz.set("name", "My Project Updated");
174
+ });
175
+ assert(result.current[0]);
176
+ expect(result.current[0].name).toBe("My Project Updated");
177
+
178
+ // Does not update when changes are made to another branch
179
+ act(() => {
180
+ project.$jazz.set("name", "My Project Updated 2");
181
+ });
182
+ assert(result.current[0]);
183
+ expect(result.current[0].name).toBe("My Project Updated");
184
+ });
185
+ });
186
+
187
+ describe("useCoStates", () => {
188
+ it("should return MaybeLoaded values", async () => {
189
+ const project1 = ProjectSchema.create({ name: "My Project 1" });
190
+ const project2 = ProjectSchema.create({ name: "My Project 2" });
191
+
192
+ const { result } = renderHook(() =>
193
+ useCoStates(ProjectSchema, [project1.$jazz.id, project2.$jazz.id]),
194
+ );
195
+
196
+ await waitFor(() => {
197
+ expect(result.current[0]?.$isLoaded).toBe(true);
198
+ expect(result.current[1]?.$isLoaded).toBe(true);
199
+ });
200
+
201
+ const [loadedProject1, loadedProject2] = result.current;
202
+
203
+ assert(loadedProject1);
204
+ assert(loadedProject2);
205
+ assertLoaded(loadedProject1);
206
+ assertLoaded(loadedProject2);
207
+ expect(loadedProject1.name).toBe("My Project 1");
208
+ expect(loadedProject2.name).toBe("My Project 2");
209
+ });
210
+
211
+ it("should re-render when any value changes", async () => {
212
+ const project1 = ProjectSchema.create({ name: "Project 1" });
213
+ const project2 = ProjectSchema.create({ name: "Project 2" });
214
+
215
+ const { result } = renderHook(() =>
216
+ useCoStates(ProjectSchema, [project1.$jazz.id, project2.$jazz.id]),
217
+ );
218
+
219
+ await waitFor(() => {
220
+ expect(result.current[0]?.$isLoaded).toBe(true);
221
+ });
222
+
223
+ expect(result.current[0]).not.toBeNull();
224
+ if (result.current[0]) {
225
+ assertLoaded(result.current[0]);
226
+ expect(result.current[0].name).toBe("Project 1");
227
+ }
228
+
229
+ // Update one of the values
230
+ act(() => {
231
+ project1.$jazz.set("name", "updated1");
232
+ });
233
+
234
+ await waitFor(() => {
235
+ const val = result.current[0];
236
+ return val?.$isLoaded && val.name === "updated1";
237
+ });
238
+
239
+ assert(result.current[0]);
240
+ expect(result.current[0].name).toBe("updated1");
241
+ });
242
+
243
+ it("should handle empty subscription array", async () => {
244
+ const { result } = renderHook(() => useCoStates(ProjectSchema, []));
245
+
246
+ await waitFor(() => {
247
+ expect(result.current).not.toBeNull();
248
+ });
249
+
250
+ expect(result.current).toEqual([]);
251
+ });
252
+
253
+ it("should update when ids change", async () => {
254
+ const project1 = ProjectSchema.create({ name: "My Project 1" });
255
+ const project2 = ProjectSchema.create({ name: "My Project 2" });
256
+
257
+ let ids: string[] = [project1.$jazz.id, project2.$jazz.id];
258
+ const { result, rerender } = renderHook(
259
+ ({ ids }: { ids: string[] }) => useCoStates(ProjectSchema, ids),
260
+ {
261
+ initialProps: { ids },
262
+ },
263
+ );
264
+
265
+ await waitFor(() => {
266
+ expect(result.current[0]?.$isLoaded).toBe(true);
267
+ expect(result.current[1]?.$isLoaded).toBe(true);
268
+ });
269
+
270
+ const project3 = ProjectSchema.create({ name: "My Project 3" });
271
+ act(() => {
272
+ // Create a new array with updated IDs
273
+ ids = [project2.$jazz.id, project3.$jazz.id];
274
+ rerender({ ids });
275
+ });
276
+
277
+ await waitFor(() => {
278
+ expect(result.current[0]?.$isLoaded).toBe(true);
279
+ expect(result.current[1]?.$isLoaded).toBe(true);
280
+ });
281
+
282
+ assert(result.current[0]);
283
+ assert(result.current[1]);
284
+ assertLoaded(result.current[0]);
285
+ assertLoaded(result.current[1]);
286
+ expect(result.current[0].name).toBe("My Project 2");
287
+ expect(result.current[1].name).toBe("My Project 3");
288
+ });
289
+
290
+ it("should not update when ids are the same", async () => {
291
+ const project1 = ProjectSchema.create({ name: "My Project 1" });
292
+ const project2 = ProjectSchema.create({ name: "My Project 2" });
293
+
294
+ let ids: string[] = [project1.$jazz.id, project2.$jazz.id];
295
+ const { result, rerender } = renderHook(
296
+ ({ ids }: { ids: string[] }) => useCoStates(ProjectSchema, ids),
297
+ {
298
+ initialProps: { ids },
299
+ },
300
+ );
301
+
302
+ await waitFor(() => {
303
+ expect(result.current[0]?.$isLoaded).toBe(true);
304
+ expect(result.current[1]?.$isLoaded).toBe(true);
305
+ });
306
+
307
+ const firstResult = result.current;
308
+
309
+ act(() => {
310
+ // Create a new array with the same IDs
311
+ ids = [...ids];
312
+ rerender({ ids });
313
+ });
314
+
315
+ // The result should be the same reference when IDs haven't changed
316
+ expect(result.current).toBe(firstResult);
317
+ expect(result.current[0]).toBe(firstResult[0]);
318
+ expect(result.current[1]).toBe(firstResult[1]);
319
+ });
320
+
321
+ it("supports branching CoValues", async () => {
322
+ const project = ProjectSchema.create({ name: "My Project" });
323
+
324
+ const { result } = renderHook(() =>
325
+ useCoStates(ProjectSchema, [project.$jazz.id], {
326
+ unstable_branch: { name: "feature-branch" },
327
+ }),
328
+ );
329
+
330
+ const loadedProject = result.current[0];
331
+ assert(loadedProject);
332
+ assertLoaded(loadedProject);
333
+ expect(loadedProject.name).toBe("My Project");
334
+
335
+ // Updates on changes to the branched CoValue
336
+ act(() => {
337
+ loadedProject.$jazz.set("name", "My Project Updated");
338
+ });
339
+ const loadedProject2 = result.current[0];
340
+ assert(loadedProject2);
341
+ assertLoaded(loadedProject2);
342
+ expect(loadedProject2.name).toBe("My Project Updated");
343
+
344
+ // Does not update when changes are made to another branch
345
+ act(() => {
346
+ project.$jazz.set("name", "My Project Updated 2");
347
+ });
348
+ const loadedProject3 = result.current[0];
349
+ assert(loadedProject3);
350
+ assertLoaded(loadedProject3);
351
+ expect(loadedProject3.name).toBe("My Project Updated");
352
+ });
353
+
354
+ it("should remove subscriptions for removed ids", async () => {
355
+ const project1 = ProjectSchema.create({ name: "My Project 1" });
356
+ const project2 = ProjectSchema.create({ name: "My Project 2" });
357
+
358
+ let ids = [project1.$jazz.id, project2.$jazz.id];
359
+ let renderCount = 0;
360
+ const { result, rerender } = renderHook(
361
+ ({ ids }: { ids: string[] }) => {
362
+ renderCount++;
363
+ return useCoStates(ProjectSchema, ids);
364
+ },
365
+ {
366
+ initialProps: { ids },
367
+ },
368
+ );
369
+
370
+ await waitFor(() => {
371
+ expect(result.current[0]?.$isLoaded).toBe(true);
372
+ expect(result.current[1]?.$isLoaded).toBe(true);
373
+ });
374
+
375
+ assert(result.current[0]);
376
+ assertLoaded(result.current[0]);
377
+ const loadedProject1 = result.current[0];
378
+
379
+ act(() => {
380
+ ids.shift(); // Remove project1, keeping only project2
381
+ rerender({ ids });
382
+ });
383
+
384
+ await waitFor(() => {
385
+ expect(result.current.length).toBe(1);
386
+ expect(result.current[0]?.$isLoaded).toBe(true);
387
+ });
388
+ assert(result.current[0]);
389
+ assertLoaded(result.current[0]);
390
+ expect(result.current[0].name).toBe("My Project 2");
391
+
392
+ expect(renderCount).toBe(2);
393
+
394
+ // Modify project1. The hook should NOT re-render because project1 is no longer subscribed
395
+ act(() => {
396
+ project1.$jazz.set("name", "Modified Project 1");
397
+ });
398
+
399
+ // Wait a bit to ensure any potential updates would have occurred
400
+ await new Promise((resolve) => setTimeout(resolve, 100));
401
+
402
+ // The hook didn't re-render
403
+ expect(renderCount).toBe(2);
404
+
405
+ // project2's name is still the same
406
+ assert(result.current[0]);
407
+ assertLoaded(result.current[0]);
408
+ expect(result.current[0].name).toBe("My Project 2");
409
+
410
+ // project1's subscription scope is no longer subscribed to
411
+ const project1SubscriptionScope = loadedProject1.$jazz._subscriptionScope;
412
+ expect(project1SubscriptionScope?.subscribers.size).toBe(0);
413
+ });
414
+ });