jazz-tools 0.19.20 → 0.19.22

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 (105) hide show
  1. package/.svelte-kit/__package__/server.d.ts.map +1 -1
  2. package/.svelte-kit/__package__/server.js +9 -7
  3. package/.turbo/turbo-build.log +56 -56
  4. package/CHANGELOG.md +15 -0
  5. package/dist/better-auth/auth/server.d.ts.map +1 -1
  6. package/dist/better-auth/auth/server.js +4 -4
  7. package/dist/better-auth/auth/server.js.map +1 -1
  8. package/dist/better-auth/database-adapter/index.js.map +1 -1
  9. package/dist/better-auth/database-adapter/repository/generic.d.ts +3 -3
  10. package/dist/better-auth/database-adapter/repository/session.d.ts +2 -2
  11. package/dist/better-auth/database-adapter/schema.d.ts +3 -3
  12. package/dist/better-auth/database-adapter/schema.d.ts.map +1 -1
  13. package/dist/{chunk-MI24YFCY.js → chunk-QCTQH5RS.js} +1 -1
  14. package/dist/chunk-QCTQH5RS.js.map +1 -0
  15. package/dist/index.js +36 -1
  16. package/dist/index.js.map +1 -1
  17. package/dist/media/{chunk-3LKBM3G3.js → chunk-IRL3KNPO.js} +2 -2
  18. package/dist/media/{chunk-3LKBM3G3.js.map → chunk-IRL3KNPO.js.map} +1 -1
  19. package/dist/media/create-image/react-native.d.ts +1 -1
  20. package/dist/media/create-image/react-native.d.ts.map +1 -1
  21. package/dist/media/index.browser.js +1 -1
  22. package/dist/media/index.js +1 -1
  23. package/dist/media/index.native.js +5 -5
  24. package/dist/media/index.native.js.map +1 -1
  25. package/dist/media/index.server.js +1 -1
  26. package/dist/react/hooks.d.ts +1 -2
  27. package/dist/react/hooks.d.ts.map +1 -1
  28. package/dist/react/index.js +7 -2
  29. package/dist/react/index.js.map +1 -1
  30. package/dist/react-core/hooks.d.ts +92 -1
  31. package/dist/react-core/hooks.d.ts.map +1 -1
  32. package/dist/react-core/index.js +126 -57
  33. package/dist/react-core/index.js.map +1 -1
  34. package/dist/react-core/tests/useCoStates.test.d.ts +2 -0
  35. package/dist/react-core/tests/useCoStates.test.d.ts.map +1 -0
  36. package/dist/react-native/index.js +4 -0
  37. package/dist/react-native/index.js.map +1 -1
  38. package/dist/react-native-core/hooks.d.ts +1 -1
  39. package/dist/react-native-core/hooks.d.ts.map +1 -1
  40. package/dist/react-native-core/index.js +4 -0
  41. package/dist/react-native-core/index.js.map +1 -1
  42. package/dist/svelte/auth/ClerkAuth.svelte.d.ts +38 -0
  43. package/dist/svelte/auth/ClerkAuth.svelte.d.ts.map +1 -0
  44. package/dist/svelte/auth/ClerkAuth.svelte.js +47 -0
  45. package/dist/svelte/auth/JazzSvelteProviderWithClerk.svelte +156 -0
  46. package/dist/svelte/auth/JazzSvelteProviderWithClerk.svelte.d.ts +67 -0
  47. package/dist/svelte/auth/JazzSvelteProviderWithClerk.svelte.d.ts.map +1 -0
  48. package/dist/svelte/auth/RegisterClerkAuth.svelte +27 -0
  49. package/dist/svelte/auth/RegisterClerkAuth.svelte.d.ts +17 -0
  50. package/dist/svelte/auth/RegisterClerkAuth.svelte.d.ts.map +1 -0
  51. package/dist/svelte/auth/index.d.ts +2 -0
  52. package/dist/svelte/auth/index.d.ts.map +1 -1
  53. package/dist/svelte/auth/index.js +2 -0
  54. package/dist/svelte/tests/ClerkAuth.svelte.test.d.ts +2 -0
  55. package/dist/svelte/tests/ClerkAuth.svelte.test.d.ts.map +1 -0
  56. package/dist/svelte/tests/ClerkAuth.svelte.test.js +202 -0
  57. package/dist/svelte/tests/TestClerkAuthWrapper.svelte +16 -0
  58. package/dist/svelte/tests/TestClerkAuthWrapper.svelte.d.ts +8 -0
  59. package/dist/svelte/tests/TestClerkAuthWrapper.svelte.d.ts.map +1 -0
  60. package/dist/svelte/tests/testUtils.d.ts +1 -0
  61. package/dist/svelte/tests/testUtils.d.ts.map +1 -1
  62. package/dist/svelte/tests/testUtils.js +3 -1
  63. package/dist/testing.js +1 -1
  64. package/dist/tools/auth/clerk/index.d.ts +1 -1
  65. package/dist/tools/auth/clerk/types.d.ts +1 -1
  66. package/dist/tools/auth/clerk/types.d.ts.map +1 -1
  67. package/dist/tools/exports.d.ts +1 -0
  68. package/dist/tools/exports.d.ts.map +1 -1
  69. package/dist/tools/subscribe/types.d.ts +1 -1
  70. package/dist/tools/subscribe/types.d.ts.map +1 -1
  71. package/dist/worker/JazzMessageChannel.d.ts +36 -0
  72. package/dist/worker/JazzMessageChannel.d.ts.map +1 -0
  73. package/dist/worker/index.d.ts +7 -1
  74. package/dist/worker/index.d.ts.map +1 -1
  75. package/dist/worker/index.js +28 -17
  76. package/dist/worker/index.js.map +1 -1
  77. package/package.json +4 -4
  78. package/src/better-auth/auth/server.ts +9 -7
  79. package/src/better-auth/database-adapter/repository/generic.ts +3 -3
  80. package/src/better-auth/database-adapter/repository/session.ts +2 -2
  81. package/src/better-auth/database-adapter/schema.ts +5 -5
  82. package/src/media/create-image/react-native.ts +9 -7
  83. package/src/media/create-image-factory.test.ts +1 -1
  84. package/src/media/create-image-factory.ts +1 -1
  85. package/src/react/hooks.tsx +4 -2
  86. package/src/react-core/hooks.ts +321 -76
  87. package/src/react-core/tests/testUtils.tsx +2 -2
  88. package/src/react-core/tests/useCoState.selector.test.ts +309 -22
  89. package/src/react-core/tests/useCoStates.test.tsx +414 -0
  90. package/src/react-native-core/hooks.tsx +2 -0
  91. package/src/svelte/auth/ClerkAuth.svelte.ts +67 -0
  92. package/src/svelte/auth/JazzSvelteProviderWithClerk.svelte +156 -0
  93. package/src/svelte/auth/RegisterClerkAuth.svelte +27 -0
  94. package/src/svelte/auth/index.ts +2 -0
  95. package/src/svelte/tests/ClerkAuth.svelte.test.ts +305 -0
  96. package/src/svelte/tests/TestClerkAuthWrapper.svelte +16 -0
  97. package/src/svelte/tests/testUtils.ts +4 -1
  98. package/src/tools/auth/clerk/types.ts +1 -1
  99. package/src/tools/exports.ts +5 -0
  100. package/src/tools/subscribe/types.ts +1 -1
  101. package/src/tools/tests/inbox.test.ts +7 -7
  102. package/src/tools/tests/testStorage.ts +2 -2
  103. package/src/worker/JazzMessageChannel.ts +73 -0
  104. package/src/worker/index.ts +36 -17
  105. package/dist/chunk-MI24YFCY.js.map +0 -1
@@ -23,7 +23,6 @@ import {
23
23
  Loaded,
24
24
  MaybeLoaded,
25
25
  NotLoaded,
26
- RefsToResolve,
27
26
  ResolveQuery,
28
27
  ResolveQueryStrict,
29
28
  SchemaResolveQuery,
@@ -103,94 +102,107 @@ export function useCoValueSubscription<
103
102
  resolve?: ResolveQueryStrict<S, R>;
104
103
  unstable_branch?: BranchDefinition;
105
104
  },
106
- ) {
105
+ ): CoValueSubscription<S, R> | null {
106
+ const resolve = getResolveQuery(Schema, options?.resolve);
107
+ const subscriptions = useCoValueSubscriptions(
108
+ Schema,
109
+ [id],
110
+ resolve,
111
+ options?.unstable_branch,
112
+ );
113
+ return (subscriptions[0] ?? null) as CoValueSubscription<S, R> | null;
114
+ }
115
+
116
+ /**
117
+ * Tracked state for the entire subscriptions array.
118
+ * If any of the dependencies change, the subscriptions are recreated.
119
+ */
120
+ interface SubscriptionsState {
121
+ subscriptions: (SubscriptionScope<CoValue> | null)[];
122
+ schema: CoValueClassOrSchema;
123
+ ids: readonly (string | undefined | null)[];
124
+ resolve: ResolveQuery<any>;
125
+ contextManager: ReturnType<typeof useJazzContextManager>;
126
+ agent: AnonymousJazzAgent | Loaded<any, true>;
127
+ branchName?: string;
128
+ branchOwnerId?: string;
129
+ }
130
+
131
+ /**
132
+ * Internal hook that manages an array of SubscriptionScope instances.
133
+ *
134
+ * - Uses a ref to track subscriptions by index
135
+ * - Detects changes by comparing schema/ids/resolve/branch
136
+ * - Creates new subscriptions via SubscriptionScopeCache.getOrCreate()
137
+ * - Returns null for entries with undefined/null IDs or invalid branches
138
+ */
139
+ function useCoValueSubscriptions(
140
+ schema: CoValueClassOrSchema,
141
+ ids: readonly (string | undefined | null)[],
142
+ resolve: ResolveQuery<any>,
143
+ branch?: BranchDefinition,
144
+ ): (SubscriptionScope<CoValue> | null)[] {
107
145
  const contextManager = useJazzContextManager();
108
146
  const agent = useAgent();
109
147
 
110
- const callerStack = React.useRef<Error | undefined>(undefined);
148
+ const callerStack = useMemo(() => captureStack(), []);
111
149
 
112
- if (!callerStack.current) {
113
- callerStack.current = captureStack();
114
- }
150
+ const createAllSubscriptions = (): SubscriptionsState => {
151
+ const node = contextManager.getCurrentValue()!.node;
152
+ const cache = contextManager.getSubscriptionScopeCache();
115
153
 
116
- const createSubscription = () => {
117
- if (!id) {
118
- return {
119
- subscription: null,
120
- contextManager,
121
- id,
122
- Schema,
123
- };
124
- }
154
+ const subscriptions = ids.map((id) => {
155
+ if (id === undefined || id === null) {
156
+ return null;
157
+ }
125
158
 
126
- if (options?.unstable_branch?.owner === null) {
127
- return {
128
- subscription: null,
129
- contextManager,
159
+ const subscription = cache.getOrCreate(
160
+ node,
161
+ schema,
130
162
  id,
131
- Schema,
132
- };
133
- }
134
-
135
- const resolve = getResolveQuery(Schema, options?.resolve);
136
-
137
- const node = contextManager.getCurrentValue()!.node;
138
- const cache = contextManager.getSubscriptionScopeCache();
139
- const subscription = cache.getOrCreate(
140
- node,
141
- Schema,
142
- id,
143
- resolve,
144
- false,
145
- false,
146
- options?.unstable_branch,
147
- );
163
+ resolve,
164
+ false,
165
+ false,
166
+ branch,
167
+ );
168
+
169
+ if (callerStack) {
170
+ subscription.callerStack = callerStack;
171
+ }
148
172
 
149
- // Set callerStack on returned subscription after retrieval
150
- if (callerStack.current) {
151
- subscription.callerStack = callerStack.current;
152
- }
173
+ return subscription;
174
+ });
153
175
 
154
176
  return {
155
- value: subscription,
177
+ subscriptions,
178
+ schema,
179
+ ids,
180
+ resolve,
156
181
  contextManager,
157
- id,
158
- Schema,
159
- branchName: options?.unstable_branch?.name,
160
- branchOwnerId: options?.unstable_branch?.owner?.$jazz.id,
161
182
  agent,
183
+ branchName: branch?.name,
184
+ branchOwnerId: branch?.owner?.$jazz.id,
162
185
  };
163
186
  };
164
187
 
165
- const subscriptionRef = React.useRef<null | ReturnType<
166
- typeof createSubscription
167
- >>(null);
188
+ const stateRef = React.useRef<SubscriptionsState | null>(null);
189
+ const newSubscriptions = createAllSubscriptions();
168
190
 
169
- if (!subscriptionRef.current) {
170
- subscriptionRef.current = createSubscription();
171
- }
191
+ const state = stateRef.current;
172
192
 
173
- const branchName = options?.unstable_branch?.name;
174
- const branchOwnerId = options?.unstable_branch?.owner?.$jazz.id;
193
+ // Avoid recreating the subscriptions array if all subscriptions are already cached
194
+ const anySubscriptionChanged =
195
+ newSubscriptions.subscriptions.length !== state?.subscriptions.length ||
196
+ newSubscriptions.subscriptions.some(
197
+ (newSubscriptions, index) =>
198
+ newSubscriptions !== state.subscriptions[index],
199
+ );
175
200
 
176
- let subscription = subscriptionRef.current;
177
-
178
- // Check if the subscription needs to be updated
179
- // because one of the dependencies has changed
180
- if (
181
- subscription.contextManager !== contextManager ||
182
- subscription.id !== id ||
183
- subscription.Schema !== Schema ||
184
- subscription.branchName !== branchName ||
185
- subscription.branchOwnerId !== branchOwnerId ||
186
- subscription.agent !== agent
187
- ) {
188
- subscriptionRef.current = createSubscription();
189
- subscription = subscriptionRef.current;
201
+ if (anySubscriptionChanged) {
202
+ stateRef.current = newSubscriptions;
190
203
  }
191
204
 
192
- // Subscribe to the context manager to react to auth changes
193
- return subscription.value as CoValueSubscription<S, R>;
205
+ return stateRef.current!.subscriptions;
194
206
  }
195
207
 
196
208
  function useImportCoValueContent<V>(
@@ -471,6 +483,13 @@ export function useSuspenseCoState<
471
483
  return useSubscriptionSelector(subscription, options);
472
484
  }
473
485
 
486
+ /**
487
+ * Returns a subscription's current value.
488
+ * Allows to optionally select a subset of the subscription's value.
489
+ *
490
+ * This is the single-value counterpart to {@link useSubscriptionsSelector}.
491
+ * Keeping it separate for performance reasons.
492
+ */
474
493
  export function useSubscriptionSelector<
475
494
  S extends CoValueClassOrSchema,
476
495
  // @ts-expect-error we can't statically enforce the schema's resolve query is a valid resolve query, but in practice it is
@@ -488,7 +507,7 @@ export function useSubscriptionSelector<
488
507
  ): TSelectorReturn {
489
508
  const getCurrentValue = useGetCurrentValue(subscription);
490
509
 
491
- return useSyncExternalStoreWithSelector<TSelectorInput, TSelectorReturn>(
510
+ return useSyncExternalStoreWithSelector(
492
511
  React.useCallback(
493
512
  (callback) => {
494
513
  if (!subscription) {
@@ -520,10 +539,7 @@ export function useAccountSubscription<
520
539
  const contextManager = useJazzContextManager();
521
540
 
522
541
  // Capture stack trace at hook call time
523
- const callerStack = React.useRef<Error | undefined>(undefined);
524
- if (!callerStack.current) {
525
- callerStack.current = captureStack();
526
- }
542
+ const callerStack = useMemo(() => captureStack(), []);
527
543
 
528
544
  const createSubscription = () => {
529
545
  const agent = getCurrentAccountFromContextManager(contextManager);
@@ -551,8 +567,8 @@ export function useAccountSubscription<
551
567
  );
552
568
 
553
569
  // Set callerStack on returned subscription after retrieval
554
- if (callerStack.current) {
555
- subscription.callerStack = callerStack.current;
570
+ if (callerStack) {
571
+ subscription.callerStack = callerStack;
556
572
  }
557
573
 
558
574
  return {
@@ -882,3 +898,232 @@ function getResolveQuery(
882
898
  }
883
899
  return true;
884
900
  }
901
+
902
+ /**
903
+ * Internal hook that suspends until all values are loaded.
904
+ *
905
+ * - Creates a Promise.all from individual getCachedPromise() calls
906
+ * - Returns Promise.resolve(null) for null subscriptions (undefined/null IDs)
907
+ * - Suspends via the use() hook until all values are loaded
908
+ */
909
+ function useSuspendUntilLoaded(
910
+ subscriptions: (SubscriptionScope<CoValue> | null)[],
911
+ ): void {
912
+ const combinedPromise = useMemo(() => {
913
+ const promises = subscriptions.map((sub) => {
914
+ if (!sub) {
915
+ // For null subscriptions (undefined/null IDs), resolve immediately with null
916
+ return Promise.resolve(null);
917
+ }
918
+ return sub.getCachedPromise();
919
+ });
920
+
921
+ return Promise.all(promises);
922
+ }, [subscriptions]);
923
+
924
+ use(combinedPromise);
925
+ }
926
+
927
+ /**
928
+ * Internal hook that uses useSyncExternalStore to subscribe to multiple SubscriptionScopes.
929
+ *
930
+ * - Creates a combined subscribe function that subscribes to all scopes
931
+ * - Returns an array of current values from each scope
932
+ * - Maintains stable references for unchanged values
933
+ *
934
+ * @param subscriptions - Array of SubscriptionScope instances (or null for skipped entries)
935
+ * @returns Array of loaded CoValues (or null for skipped entries)
936
+ */
937
+ function useSubscriptionsSelector<
938
+ T extends CoValue[] | MaybeLoaded<CoValue>[],
939
+ // Selector input can be an already loaded or a maybe-loaded value,
940
+ // depending on whether a suspense hook is used or not, respectively.
941
+ TSelectorInput = T[number],
942
+ TSelectorReturn = TSelectorInput,
943
+ >(
944
+ subscriptions: SubscriptionScope<CoValue>[],
945
+ options?: {
946
+ select?: (value: TSelectorInput) => TSelectorReturn;
947
+ equalityFn?: (a: TSelectorReturn, b: TSelectorReturn) => boolean;
948
+ },
949
+ ): TSelectorReturn[] {
950
+ // Combined subscribe function that subscribes to all scopes
951
+ const subscribe = useCallback(
952
+ (callback: () => void) => {
953
+ const unsubscribes = subscriptions.map((sub) => sub.subscribe(callback));
954
+
955
+ return () => {
956
+ unsubscribes.forEach((unsub) => unsub());
957
+ };
958
+ },
959
+ [subscriptions],
960
+ );
961
+
962
+ // Cache current values to avoid infinite loops
963
+ const cachedCurrentValuesRef = useRef<T>([] as unknown as T);
964
+ const getCurrentValues = useCallback(() => {
965
+ const newValues = subscriptions.map((sub) => sub.getCurrentValue());
966
+
967
+ // Check if values have changed by comparing each element
968
+ const cached = cachedCurrentValuesRef.current;
969
+ const hasChanged =
970
+ cached.length !== newValues.length ||
971
+ newValues.some((value, index) => value !== cached[index]);
972
+
973
+ if (hasChanged) {
974
+ cachedCurrentValuesRef.current = newValues as T;
975
+ }
976
+
977
+ return cachedCurrentValuesRef.current as unknown as TSelectorInput[];
978
+ }, [subscriptions]);
979
+
980
+ const selectFn = useMemo(() => {
981
+ if (!options?.select) {
982
+ return (values: TSelectorInput[]) =>
983
+ values as unknown as TSelectorReturn[];
984
+ }
985
+ return (values: TSelectorInput[]) =>
986
+ values.map((value) => options.select!(value));
987
+ }, [options?.select]);
988
+
989
+ const elementEqualityFn = useMemo(
990
+ () => options?.equalityFn ?? Object.is,
991
+ [options?.equalityFn],
992
+ );
993
+ const equalityFn = useMemo(() => {
994
+ return (a: TSelectorReturn[], b: TSelectorReturn[]) =>
995
+ a.length === b.length &&
996
+ a.every((value, index) => elementEqualityFn(value, b[index]));
997
+ }, [elementEqualityFn]);
998
+
999
+ return useSyncExternalStoreWithSelector(
1000
+ subscribe,
1001
+ getCurrentValues,
1002
+ getCurrentValues,
1003
+ selectFn,
1004
+ equalityFn,
1005
+ );
1006
+ }
1007
+
1008
+ /**
1009
+ * Subscribe to multiple CoValues with unified Suspense handling.
1010
+ *
1011
+ * This hook accepts a list of CoValue IDs and returns an array of loaded values,
1012
+ * suspending until all values are available.
1013
+ *
1014
+ * @param Schema - The CoValue schema or class constructor
1015
+ * @param ids - Array of CoValue IDs to subscribe to
1016
+ * @param options - Optional configuration, including resolve query
1017
+ * @returns An array of loaded CoValues in the same order as the input IDs
1018
+ */
1019
+ export function useSuspenseCoStates<
1020
+ S extends CoValueClassOrSchema,
1021
+ // @ts-expect-error we can't statically enforce the schema's resolve query is a valid resolve query, but in practice it is
1022
+ const R extends ResolveQuery<S> = SchemaResolveQuery<S>,
1023
+ TSelectorReturn = Loaded<S, R>,
1024
+ >(
1025
+ Schema: S,
1026
+ ids: readonly string[],
1027
+ options?: {
1028
+ /** Resolve query to specify which nested CoValues to load */
1029
+ resolve?: ResolveQueryStrict<S, R>;
1030
+ /** Select which value to return. Applies to each element individually. */
1031
+ select?: (value: Loaded<S, R>) => TSelectorReturn;
1032
+ /** Equality function to determine if a selected value has changed, defaults to `Object.is` */
1033
+ equalityFn?: (a: TSelectorReturn, b: TSelectorReturn) => boolean;
1034
+ /**
1035
+ * Create or load a branch for isolated editing.
1036
+ *
1037
+ * Branching lets you take a snapshot of the current state and start modifying it without affecting the canonical/shared version.
1038
+ * It's a fork of your data graph: the same schema, but with diverging values.
1039
+ *
1040
+ * The checkout of the branch is applied on all the resolved values.
1041
+ *
1042
+ * @param name - A unique name for the branch. This identifies the branch
1043
+ * and can be used to switch between different branches of the same CoValue.
1044
+ * @param owner - The owner of the branch. Determines who can access and modify
1045
+ * the branch. If not provided, the branch is owned by the current user.
1046
+ *
1047
+ * For more info see the [branching](https://jazz.tools/docs/react/using-covalues/version-control) documentation.
1048
+ */
1049
+ unstable_branch?: BranchDefinition;
1050
+ },
1051
+ ): TSelectorReturn[] {
1052
+ const resolve = getResolveQuery(Schema, options?.resolve);
1053
+ const subscriptionScopes = useCoValueSubscriptions(
1054
+ Schema,
1055
+ ids,
1056
+ resolve,
1057
+ options?.unstable_branch,
1058
+ ) as SubscriptionScope<CoValue>[];
1059
+ useSuspendUntilLoaded(subscriptionScopes);
1060
+ return useSubscriptionsSelector(subscriptionScopes, options);
1061
+ }
1062
+
1063
+ /**
1064
+ * Subscribe to multiple CoValues without Suspense.
1065
+ *
1066
+ * This hook accepts a list of CoValue IDs and returns an array of maybe-loaded values.
1067
+ * Unlike `useSuspenseCoStates`, this hook does not suspend and returns loading/unavailable
1068
+ * states that can be checked via the `$isLoaded` property.
1069
+ *
1070
+ * @param Schema - The CoValue schema or class constructor
1071
+ * @param ids - Array of CoValue IDs to subscribe to
1072
+ * @param options - Optional configuration, including resolve query
1073
+ * @returns An array of MaybeLoaded CoValues in the same order as the input IDs
1074
+ *
1075
+ * @example
1076
+ * ```typescript
1077
+ * const [project1, project2] = useCoStates(
1078
+ * ProjectSchema,
1079
+ * [projectId1, projectId2],
1080
+ * { resolve: { assignee: true } }
1081
+ * );
1082
+ *
1083
+ * if (!project1.$isLoaded || !project2.$isLoaded) {
1084
+ * return <Loading />;
1085
+ * }
1086
+ * ```
1087
+ */
1088
+ export function useCoStates<
1089
+ S extends CoValueClassOrSchema,
1090
+ // @ts-expect-error we can't statically enforce the schema's resolve query is a valid resolve query, but in practice it is
1091
+ const R extends ResolveQuery<S> = SchemaResolveQuery<S>,
1092
+ TSelectorReturn = MaybeLoaded<Loaded<S, R>>,
1093
+ >(
1094
+ Schema: S,
1095
+ ids: readonly string[],
1096
+ options?: {
1097
+ /** Resolve query to specify which nested CoValues to load */
1098
+ resolve?: ResolveQueryStrict<S, R>;
1099
+ /** Select which value to return. Applies to each element individually. */
1100
+ select?: (value: MaybeLoaded<Loaded<S, R>>) => TSelectorReturn;
1101
+ /** Equality function to determine if a selected value has changed, defaults to `Object.is` */
1102
+ equalityFn?: (a: TSelectorReturn, b: TSelectorReturn) => boolean;
1103
+ /**
1104
+ * Create or load a branch for isolated editing.
1105
+ *
1106
+ * Branching lets you take a snapshot of the current state and start modifying it without affecting the canonical/shared version.
1107
+ * It's a fork of your data graph: the same schema, but with diverging values.
1108
+ *
1109
+ * The checkout of the branch is applied on all the resolved values.
1110
+ *
1111
+ * @param name - A unique name for the branch. This identifies the branch
1112
+ * and can be used to switch between different branches of the same CoValue.
1113
+ * @param owner - The owner of the branch. Determines who can access and modify
1114
+ * the branch. If not provided, the branch is owned by the current user.
1115
+ *
1116
+ * For more info see the [branching](https://jazz.tools/docs/react/using-covalues/version-control) documentation.
1117
+ */
1118
+ unstable_branch?: BranchDefinition;
1119
+ },
1120
+ ): TSelectorReturn[] {
1121
+ const resolve = getResolveQuery(Schema, options?.resolve);
1122
+ const subscriptionScopes = useCoValueSubscriptions(
1123
+ Schema,
1124
+ ids,
1125
+ resolve,
1126
+ options?.unstable_branch,
1127
+ ) as SubscriptionScope<CoValue>[];
1128
+ return useSubscriptionsSelector(subscriptionScopes, options);
1129
+ }
@@ -111,8 +111,8 @@ export async function createAsyncStorage() {
111
111
  new LibSQLSqliteAsyncDriver(":memory:"),
112
112
  );
113
113
 
114
- onTestFinished(() => {
115
- storage.close();
114
+ onTestFinished(async () => {
115
+ await storage.close();
116
116
  });
117
117
 
118
118
  return storage;