@vaiftech/sdk-expo 1.0.0 → 1.0.2
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/README.md +17 -17
- package/dist/index.d.mts +528 -3
- package/dist/index.d.ts +528 -3
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +4 -3
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { VaifClientConfig, User, VaifClient, AuthResponse, QueryOptions, WhereFilter, OrderByClause, DbOperation, SubscriptionFilter, DbChangeEvent, ConnectionState, PresenceState, PresenceEntry, UploadResult, FileMetadata, RetryConfig, VaifFunction } from '@
|
|
4
|
-
export { AuthResponse, ConnectionState, DbChangeEvent, DbOperation, FileMetadata, InvokeResult, OrderByClause, PresenceState, QueryOptions, UploadResult, User, VaifClient, VaifClientConfig, VaifFunction, WhereFilter } from '@
|
|
3
|
+
import { VaifClientConfig, User, VaifClient, AuthResponse, OAuthProviderType, MFAMethod, MFASetupResponse, QueryOptions, WhereFilter, OrderByClause, DbOperation, SubscriptionFilter, DbChangeEvent, ConnectionState, PresenceState, PresenceEntry, UploadResult, FileMetadata, RetryConfig, VaifFunction } from '@vaiftech/client';
|
|
4
|
+
export { AuthResponse, ConnectionState, DbChangeEvent, DbOperation, FileMetadata, InvokeResult, OrderByClause, PresenceState, QueryOptions, UploadResult, User, VaifClient, VaifClientConfig, VaifFunction, WhereFilter } from '@vaiftech/client';
|
|
5
|
+
export { AuthChangeEvent, AuthClientConfig, AuthEventType, AuthProvider, AuthProviderProps, Session as AuthSession, AuthSubscription, MFAFactor, VaifAuthClient, createAuthClient, useAuthClient, useIdentities, useIsAuthenticated, usePassword, useSession, useSessions, useAuth as useStandaloneAuth, useMFA as useStandaloneMFA } from '@vaiftech/auth/react';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Storage interface for React Native (AsyncStorage compatible)
|
|
@@ -71,6 +72,43 @@ interface UseAuthReturn {
|
|
|
71
72
|
updateProfile: (updates: Record<string, unknown>) => Promise<User>;
|
|
72
73
|
changePassword: (currentPassword: string, newPassword: string) => Promise<void>;
|
|
73
74
|
}
|
|
75
|
+
interface UsePasswordResetReturn {
|
|
76
|
+
requestReset: (email: string) => Promise<void>;
|
|
77
|
+
confirmReset: (token: string, newPassword: string) => Promise<void>;
|
|
78
|
+
isLoading: boolean;
|
|
79
|
+
error: Error | null;
|
|
80
|
+
isRequested: boolean;
|
|
81
|
+
isConfirmed: boolean;
|
|
82
|
+
}
|
|
83
|
+
interface UseEmailVerificationReturn {
|
|
84
|
+
requestVerification: (email: string) => Promise<void>;
|
|
85
|
+
confirmVerification: (token: string) => Promise<void>;
|
|
86
|
+
isLoading: boolean;
|
|
87
|
+
error: Error | null;
|
|
88
|
+
isSent: boolean;
|
|
89
|
+
isVerified: boolean;
|
|
90
|
+
}
|
|
91
|
+
interface UseMagicLinkReturn {
|
|
92
|
+
sendMagicLink: (email: string) => Promise<void>;
|
|
93
|
+
verifyMagicLink: (token: string) => Promise<AuthResponse>;
|
|
94
|
+
isLoading: boolean;
|
|
95
|
+
error: Error | null;
|
|
96
|
+
isSent: boolean;
|
|
97
|
+
}
|
|
98
|
+
interface UseOAuthReturn {
|
|
99
|
+
signInWithOAuth: (provider: OAuthProviderType, redirectTo?: string) => Promise<{
|
|
100
|
+
url: string;
|
|
101
|
+
}>;
|
|
102
|
+
isLoading: boolean;
|
|
103
|
+
error: Error | null;
|
|
104
|
+
}
|
|
105
|
+
interface UseMFAReturn {
|
|
106
|
+
setup: (method: MFAMethod) => Promise<MFASetupResponse>;
|
|
107
|
+
verify: (mfaToken: string, code: string) => Promise<AuthResponse>;
|
|
108
|
+
disable: (code: string) => Promise<void>;
|
|
109
|
+
isLoading: boolean;
|
|
110
|
+
error: Error | null;
|
|
111
|
+
}
|
|
74
112
|
/**
|
|
75
113
|
* Hook for authentication
|
|
76
114
|
*
|
|
@@ -100,6 +138,150 @@ declare function useAuth(): UseAuthReturn;
|
|
|
100
138
|
* Hook to get just the current user
|
|
101
139
|
*/
|
|
102
140
|
declare function useUser(): User | null;
|
|
141
|
+
/**
|
|
142
|
+
* Hook to get the current access token
|
|
143
|
+
*/
|
|
144
|
+
declare function useToken(): string | null;
|
|
145
|
+
/**
|
|
146
|
+
* Password reset hook for Expo/React Native
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```tsx
|
|
150
|
+
* function ForgotPasswordScreen() {
|
|
151
|
+
* const { requestReset, confirmReset, isLoading, isRequested } = usePasswordReset();
|
|
152
|
+
*
|
|
153
|
+
* if (!isRequested) {
|
|
154
|
+
* return <Button onPress={() => requestReset(email)} title="Send Reset Link" />;
|
|
155
|
+
* }
|
|
156
|
+
*
|
|
157
|
+
* return (
|
|
158
|
+
* <View>
|
|
159
|
+
* <TextInput placeholder="Enter code" />
|
|
160
|
+
* <TextInput placeholder="New password" secureTextEntry />
|
|
161
|
+
* <Button onPress={() => confirmReset(token, newPassword)} title="Reset Password" />
|
|
162
|
+
* </View>
|
|
163
|
+
* );
|
|
164
|
+
* }
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
declare function usePasswordReset(): UsePasswordResetReturn;
|
|
168
|
+
/**
|
|
169
|
+
* Email verification hook for Expo/React Native
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* ```tsx
|
|
173
|
+
* function VerifyEmailScreen() {
|
|
174
|
+
* const { requestVerification, confirmVerification, isSent, isVerified } = useEmailVerification();
|
|
175
|
+
*
|
|
176
|
+
* if (isVerified) {
|
|
177
|
+
* return <Text>Email verified successfully!</Text>;
|
|
178
|
+
* }
|
|
179
|
+
*
|
|
180
|
+
* if (isSent) {
|
|
181
|
+
* return (
|
|
182
|
+
* <View>
|
|
183
|
+
* <TextInput placeholder="Enter verification code" />
|
|
184
|
+
* <Button onPress={() => confirmVerification(token)} title="Verify" />
|
|
185
|
+
* </View>
|
|
186
|
+
* );
|
|
187
|
+
* }
|
|
188
|
+
*
|
|
189
|
+
* return <Button onPress={() => requestVerification(email)} title="Send Verification" />;
|
|
190
|
+
* }
|
|
191
|
+
* ```
|
|
192
|
+
*/
|
|
193
|
+
declare function useEmailVerification(): UseEmailVerificationReturn;
|
|
194
|
+
/**
|
|
195
|
+
* Magic link authentication hook for Expo/React Native
|
|
196
|
+
*
|
|
197
|
+
* @example
|
|
198
|
+
* ```tsx
|
|
199
|
+
* function MagicLinkScreen() {
|
|
200
|
+
* const { sendMagicLink, isSent, isLoading } = useMagicLink();
|
|
201
|
+
*
|
|
202
|
+
* if (isSent) {
|
|
203
|
+
* return <Text>Check your email for the login link!</Text>;
|
|
204
|
+
* }
|
|
205
|
+
*
|
|
206
|
+
* return (
|
|
207
|
+
* <Button
|
|
208
|
+
* onPress={() => sendMagicLink(email)}
|
|
209
|
+
* disabled={isLoading}
|
|
210
|
+
* title={isLoading ? 'Sending...' : 'Send Magic Link'}
|
|
211
|
+
* />
|
|
212
|
+
* );
|
|
213
|
+
* }
|
|
214
|
+
* ```
|
|
215
|
+
*/
|
|
216
|
+
declare function useMagicLink(): UseMagicLinkReturn;
|
|
217
|
+
/**
|
|
218
|
+
* OAuth authentication hook for Expo/React Native
|
|
219
|
+
*
|
|
220
|
+
* Note: For React Native, you'll need to handle the OAuth flow using
|
|
221
|
+
* expo-auth-session or react-native-app-auth to open the URL in a browser.
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* ```tsx
|
|
225
|
+
* import * as WebBrowser from 'expo-web-browser';
|
|
226
|
+
*
|
|
227
|
+
* function OAuthScreen() {
|
|
228
|
+
* const { signInWithOAuth, isLoading, error } = useOAuth();
|
|
229
|
+
*
|
|
230
|
+
* const handleGoogleSignIn = async () => {
|
|
231
|
+
* const { url } = await signInWithOAuth('google', 'myapp://auth/callback');
|
|
232
|
+
* await WebBrowser.openAuthSessionAsync(url, 'myapp://auth/callback');
|
|
233
|
+
* };
|
|
234
|
+
*
|
|
235
|
+
* return (
|
|
236
|
+
* <Button
|
|
237
|
+
* onPress={handleGoogleSignIn}
|
|
238
|
+
* disabled={isLoading}
|
|
239
|
+
* title="Sign in with Google"
|
|
240
|
+
* />
|
|
241
|
+
* );
|
|
242
|
+
* }
|
|
243
|
+
* ```
|
|
244
|
+
*/
|
|
245
|
+
declare function useOAuth(): UseOAuthReturn;
|
|
246
|
+
/**
|
|
247
|
+
* Multi-factor authentication hook for Expo/React Native
|
|
248
|
+
*
|
|
249
|
+
* @example
|
|
250
|
+
* ```tsx
|
|
251
|
+
* function MFASetupScreen() {
|
|
252
|
+
* const { setup, verify, isLoading } = useMFA();
|
|
253
|
+
* const [qrCode, setQrCode] = useState<string | null>(null);
|
|
254
|
+
* const [mfaToken, setMfaToken] = useState<string | null>(null);
|
|
255
|
+
*
|
|
256
|
+
* const handleSetup = async () => {
|
|
257
|
+
* const result = await setup('totp');
|
|
258
|
+
* setQrCode(result.qrCode);
|
|
259
|
+
* };
|
|
260
|
+
*
|
|
261
|
+
* const handleVerify = async (code: string) => {
|
|
262
|
+
* if (mfaToken) {
|
|
263
|
+
* await verify(mfaToken, code);
|
|
264
|
+
* Alert.alert('Success', 'MFA verified!');
|
|
265
|
+
* }
|
|
266
|
+
* };
|
|
267
|
+
*
|
|
268
|
+
* return (
|
|
269
|
+
* <View>
|
|
270
|
+
* {qrCode ? (
|
|
271
|
+
* <>
|
|
272
|
+
* <Image source={{ uri: qrCode }} style={{ width: 200, height: 200 }} />
|
|
273
|
+
* <TextInput placeholder="Enter code" />
|
|
274
|
+
* <Button onPress={() => handleVerify(code)} title="Verify" />
|
|
275
|
+
* </>
|
|
276
|
+
* ) : (
|
|
277
|
+
* <Button onPress={handleSetup} title="Enable 2FA" />
|
|
278
|
+
* )}
|
|
279
|
+
* </View>
|
|
280
|
+
* );
|
|
281
|
+
* }
|
|
282
|
+
* ```
|
|
283
|
+
*/
|
|
284
|
+
declare function useMFA(): UseMFAReturn;
|
|
103
285
|
|
|
104
286
|
type QueryStatus = "idle" | "loading" | "success" | "error";
|
|
105
287
|
interface UseQueryOptions extends Omit<QueryOptions, "where" | "orderBy"> {
|
|
@@ -121,6 +303,18 @@ interface UseQueryReturn<T> {
|
|
|
121
303
|
error: Error | null;
|
|
122
304
|
refetch: () => Promise<void>;
|
|
123
305
|
}
|
|
306
|
+
interface UseQueryFirstReturn<T> {
|
|
307
|
+
/** Query result (single item) */
|
|
308
|
+
data: T | null;
|
|
309
|
+
/** Loading state */
|
|
310
|
+
isLoading: boolean;
|
|
311
|
+
/** Error state */
|
|
312
|
+
error: Error | null;
|
|
313
|
+
/** Not found state */
|
|
314
|
+
isNotFound: boolean;
|
|
315
|
+
/** Refetch function */
|
|
316
|
+
refetch: () => Promise<void>;
|
|
317
|
+
}
|
|
124
318
|
interface UsePaginatedQueryOptions extends UseQueryOptions {
|
|
125
319
|
pageSize?: number;
|
|
126
320
|
initialPage?: number;
|
|
@@ -136,6 +330,50 @@ interface UsePaginatedQueryReturn<T> extends UseQueryReturn<T> {
|
|
|
136
330
|
previousPage: () => void;
|
|
137
331
|
goToPage: (page: number) => void;
|
|
138
332
|
}
|
|
333
|
+
interface UseInfiniteQueryOptions extends UseQueryOptions {
|
|
334
|
+
/** Page size for each page */
|
|
335
|
+
pageSize?: number;
|
|
336
|
+
/** Callback on success */
|
|
337
|
+
onSuccess?: (data: unknown[], hasMore: boolean) => void;
|
|
338
|
+
/** Callback on error */
|
|
339
|
+
onError?: (error: Error) => void;
|
|
340
|
+
}
|
|
341
|
+
interface UseInfiniteQueryReturn<T> {
|
|
342
|
+
/** All loaded data (flattened) */
|
|
343
|
+
data: T[];
|
|
344
|
+
/** Pages loaded */
|
|
345
|
+
pages: T[][];
|
|
346
|
+
/** Whether there's a next page */
|
|
347
|
+
hasNextPage: boolean;
|
|
348
|
+
/** Loading state */
|
|
349
|
+
isLoading: boolean;
|
|
350
|
+
/** Fetching next page state */
|
|
351
|
+
isFetchingNextPage: boolean;
|
|
352
|
+
/** Error state */
|
|
353
|
+
error: Error | null;
|
|
354
|
+
/** Fetch next page */
|
|
355
|
+
fetchNextPage: () => Promise<void>;
|
|
356
|
+
/** Refetch all pages */
|
|
357
|
+
refetch: () => Promise<void>;
|
|
358
|
+
/** Reset to first page */
|
|
359
|
+
reset: () => void;
|
|
360
|
+
}
|
|
361
|
+
interface UseCountOptions {
|
|
362
|
+
/** Where conditions */
|
|
363
|
+
where?: WhereFilter;
|
|
364
|
+
/** Skip fetching */
|
|
365
|
+
enabled?: boolean;
|
|
366
|
+
}
|
|
367
|
+
interface UseCountReturn {
|
|
368
|
+
/** Count result */
|
|
369
|
+
count: number;
|
|
370
|
+
/** Loading state */
|
|
371
|
+
isLoading: boolean;
|
|
372
|
+
/** Error state */
|
|
373
|
+
error: Error | null;
|
|
374
|
+
/** Refetch function */
|
|
375
|
+
refetch: () => Promise<void>;
|
|
376
|
+
}
|
|
139
377
|
/**
|
|
140
378
|
* Hook for querying data from a table
|
|
141
379
|
*
|
|
@@ -179,6 +417,76 @@ declare function useQueryById<T extends Record<string, unknown> = Record<string,
|
|
|
179
417
|
* Hook for paginated queries
|
|
180
418
|
*/
|
|
181
419
|
declare function usePaginatedQuery<T extends Record<string, unknown> = Record<string, unknown>>(table: string, options?: UsePaginatedQueryOptions): UsePaginatedQueryReturn<T>;
|
|
420
|
+
/**
|
|
421
|
+
* Hook for fetching the first matching record
|
|
422
|
+
*
|
|
423
|
+
* @example
|
|
424
|
+
* ```tsx
|
|
425
|
+
* function LatestPost() {
|
|
426
|
+
* const { data: post, isLoading, isNotFound } = useQueryFirst<Post>('posts', {
|
|
427
|
+
* where: { published: true },
|
|
428
|
+
* orderBy: { column: 'created_at', direction: 'desc' },
|
|
429
|
+
* });
|
|
430
|
+
*
|
|
431
|
+
* if (isLoading) return <ActivityIndicator />;
|
|
432
|
+
* if (isNotFound) return <Text>No posts yet</Text>;
|
|
433
|
+
*
|
|
434
|
+
* return <PostCard post={post} />;
|
|
435
|
+
* }
|
|
436
|
+
* ```
|
|
437
|
+
*/
|
|
438
|
+
declare function useQueryFirst<T extends Record<string, unknown> = Record<string, unknown>>(table: string, options?: UseQueryOptions): UseQueryFirstReturn<T>;
|
|
439
|
+
/**
|
|
440
|
+
* Hook for infinite scroll / load more pagination
|
|
441
|
+
*
|
|
442
|
+
* @example
|
|
443
|
+
* ```tsx
|
|
444
|
+
* function InfiniteTaskList() {
|
|
445
|
+
* const {
|
|
446
|
+
* data: tasks,
|
|
447
|
+
* isLoading,
|
|
448
|
+
* isFetchingNextPage,
|
|
449
|
+
* hasNextPage,
|
|
450
|
+
* fetchNextPage,
|
|
451
|
+
* } = useInfiniteQuery<Task>('tasks', {
|
|
452
|
+
* where: { status: 'active' },
|
|
453
|
+
* orderBy: { column: 'created_at', direction: 'desc' },
|
|
454
|
+
* pageSize: 20,
|
|
455
|
+
* });
|
|
456
|
+
*
|
|
457
|
+
* if (isLoading) return <ActivityIndicator />;
|
|
458
|
+
*
|
|
459
|
+
* return (
|
|
460
|
+
* <FlatList
|
|
461
|
+
* data={tasks}
|
|
462
|
+
* keyExtractor={(item) => item.id}
|
|
463
|
+
* renderItem={({ item }) => <TaskItem task={item} />}
|
|
464
|
+
* onEndReached={() => hasNextPage && fetchNextPage()}
|
|
465
|
+
* onEndReachedThreshold={0.5}
|
|
466
|
+
* ListFooterComponent={isFetchingNextPage ? <ActivityIndicator /> : null}
|
|
467
|
+
* />
|
|
468
|
+
* );
|
|
469
|
+
* }
|
|
470
|
+
* ```
|
|
471
|
+
*/
|
|
472
|
+
declare function useInfiniteQuery<T extends Record<string, unknown> = Record<string, unknown>>(table: string, options?: UseInfiniteQueryOptions): UseInfiniteQueryReturn<T>;
|
|
473
|
+
/**
|
|
474
|
+
* Hook for counting records
|
|
475
|
+
*
|
|
476
|
+
* @example
|
|
477
|
+
* ```tsx
|
|
478
|
+
* function TaskStats() {
|
|
479
|
+
* const { count: activeCount, isLoading } = useCount('tasks', {
|
|
480
|
+
* where: { status: 'active' },
|
|
481
|
+
* });
|
|
482
|
+
*
|
|
483
|
+
* if (isLoading) return <ActivityIndicator />;
|
|
484
|
+
*
|
|
485
|
+
* return <Text>Active tasks: {activeCount}</Text>;
|
|
486
|
+
* }
|
|
487
|
+
* ```
|
|
488
|
+
*/
|
|
489
|
+
declare function useCount(table: string, options?: UseCountOptions): UseCountReturn;
|
|
182
490
|
|
|
183
491
|
type MutationStatus = "idle" | "loading" | "success" | "error";
|
|
184
492
|
interface UseMutationReturn<T, TInput = Partial<T>> {
|
|
@@ -323,6 +631,121 @@ declare function useBatchCreate<T extends Record<string, unknown> = Record<strin
|
|
|
323
631
|
isError: boolean;
|
|
324
632
|
error: Error | null;
|
|
325
633
|
};
|
|
634
|
+
interface UseBatchUpdateReturn<T> {
|
|
635
|
+
batchUpdate: (where: WhereFilter, data: Partial<T>) => Promise<{
|
|
636
|
+
count: number;
|
|
637
|
+
records?: T[];
|
|
638
|
+
}>;
|
|
639
|
+
data: {
|
|
640
|
+
count: number;
|
|
641
|
+
records?: T[];
|
|
642
|
+
} | null;
|
|
643
|
+
isLoading: boolean;
|
|
644
|
+
isError: boolean;
|
|
645
|
+
error: Error | null;
|
|
646
|
+
reset: () => void;
|
|
647
|
+
}
|
|
648
|
+
interface UseBatchDeleteReturn {
|
|
649
|
+
batchDelete: (where: WhereFilter) => Promise<{
|
|
650
|
+
count: number;
|
|
651
|
+
}>;
|
|
652
|
+
data: {
|
|
653
|
+
count: number;
|
|
654
|
+
} | null;
|
|
655
|
+
isLoading: boolean;
|
|
656
|
+
isError: boolean;
|
|
657
|
+
error: Error | null;
|
|
658
|
+
reset: () => void;
|
|
659
|
+
}
|
|
660
|
+
interface UseOptimisticMutationReturn<TData, TVariables> {
|
|
661
|
+
mutate: (variables: TVariables) => void;
|
|
662
|
+
mutateAsync: (variables: TVariables) => Promise<TData>;
|
|
663
|
+
optimisticData: TData;
|
|
664
|
+
rollback: () => void;
|
|
665
|
+
isLoading: boolean;
|
|
666
|
+
error: Error | null;
|
|
667
|
+
}
|
|
668
|
+
/**
|
|
669
|
+
* Hook for batch updating records
|
|
670
|
+
*
|
|
671
|
+
* @example
|
|
672
|
+
* ```tsx
|
|
673
|
+
* function BulkUpdateStatus() {
|
|
674
|
+
* const { batchUpdate, isLoading, data } = useBatchUpdate<Task>('tasks');
|
|
675
|
+
*
|
|
676
|
+
* const markAllComplete = async () => {
|
|
677
|
+
* await batchUpdate(
|
|
678
|
+
* { assigneeId: currentUserId },
|
|
679
|
+
* { status: 'completed' }
|
|
680
|
+
* );
|
|
681
|
+
* };
|
|
682
|
+
*
|
|
683
|
+
* return (
|
|
684
|
+
* <Button onPress={markAllComplete} disabled={isLoading}>
|
|
685
|
+
* {isLoading ? `Updating... ${data?.count || 0}` : 'Mark All Complete'}
|
|
686
|
+
* </Button>
|
|
687
|
+
* );
|
|
688
|
+
* }
|
|
689
|
+
* ```
|
|
690
|
+
*/
|
|
691
|
+
declare function useBatchUpdate<T extends Record<string, unknown> = Record<string, unknown>>(table: string): UseBatchUpdateReturn<T>;
|
|
692
|
+
/**
|
|
693
|
+
* Hook for batch deleting records
|
|
694
|
+
*
|
|
695
|
+
* @example
|
|
696
|
+
* ```tsx
|
|
697
|
+
* function BulkDelete() {
|
|
698
|
+
* const { batchDelete, isLoading, data } = useBatchDelete('items');
|
|
699
|
+
*
|
|
700
|
+
* const deleteOldItems = async () => {
|
|
701
|
+
* await batchDelete({ createdAt: { lt: thirtyDaysAgo } });
|
|
702
|
+
* };
|
|
703
|
+
*
|
|
704
|
+
* return (
|
|
705
|
+
* <Button onPress={deleteOldItems} disabled={isLoading}>
|
|
706
|
+
* {isLoading ? 'Deleting...' : `Delete old items (${data?.count || 0} deleted)`}
|
|
707
|
+
* </Button>
|
|
708
|
+
* );
|
|
709
|
+
* }
|
|
710
|
+
* ```
|
|
711
|
+
*/
|
|
712
|
+
declare function useBatchDelete(table: string): UseBatchDeleteReturn;
|
|
713
|
+
/**
|
|
714
|
+
* Hook for optimistic mutations
|
|
715
|
+
*
|
|
716
|
+
* @example
|
|
717
|
+
* ```tsx
|
|
718
|
+
* function LikeButton({ postId, likes }: { postId: string; likes: number }) {
|
|
719
|
+
* const client = useVaifClient();
|
|
720
|
+
*
|
|
721
|
+
* const { mutate, optimisticData, isLoading } = useOptimisticMutation(
|
|
722
|
+
* likes,
|
|
723
|
+
* async () => {
|
|
724
|
+
* const result = await client.from('posts').update(postId, { likes: likes + 1 });
|
|
725
|
+
* return result.data.likes;
|
|
726
|
+
* },
|
|
727
|
+
* {
|
|
728
|
+
* optimisticUpdate: (current) => current + 1,
|
|
729
|
+
* onError: () => {
|
|
730
|
+
* Alert.alert('Error', 'Failed to like post');
|
|
731
|
+
* },
|
|
732
|
+
* }
|
|
733
|
+
* );
|
|
734
|
+
*
|
|
735
|
+
* return (
|
|
736
|
+
* <TouchableOpacity onPress={() => mutate()}>
|
|
737
|
+
* <Text>{optimisticData} likes</Text>
|
|
738
|
+
* </TouchableOpacity>
|
|
739
|
+
* );
|
|
740
|
+
* }
|
|
741
|
+
* ```
|
|
742
|
+
*/
|
|
743
|
+
declare function useOptimisticMutation<TData, TVariables = void>(currentData: TData, mutationFn: (variables: TVariables) => Promise<TData>, options: {
|
|
744
|
+
optimisticUpdate: (current: TData, variables: TVariables) => TData;
|
|
745
|
+
onSuccess?: (data: TData, variables: TVariables) => void;
|
|
746
|
+
onError?: (error: Error, variables: TVariables) => void;
|
|
747
|
+
onSettled?: (data: TData | undefined, error: Error | null, variables: TVariables) => void;
|
|
748
|
+
}): UseOptimisticMutationReturn<TData, TVariables>;
|
|
326
749
|
|
|
327
750
|
interface UseSubscriptionOptions<T> {
|
|
328
751
|
/** Filter by operation type */
|
|
@@ -374,6 +797,29 @@ interface UseBroadcastReturn<T> {
|
|
|
374
797
|
/** Connection state */
|
|
375
798
|
isConnected: boolean;
|
|
376
799
|
}
|
|
800
|
+
interface UseChannelOptions {
|
|
801
|
+
/** Channel type */
|
|
802
|
+
type?: "public" | "private" | "presence";
|
|
803
|
+
/** Skip subscription */
|
|
804
|
+
enabled?: boolean;
|
|
805
|
+
}
|
|
806
|
+
interface BroadcastMessage<T = unknown> {
|
|
807
|
+
event: string;
|
|
808
|
+
payload: T;
|
|
809
|
+
senderId?: string;
|
|
810
|
+
}
|
|
811
|
+
interface UseChannelReturn<T> {
|
|
812
|
+
/** Send a broadcast message */
|
|
813
|
+
broadcast: (event: string, payload: T) => void;
|
|
814
|
+
/** Last received broadcast */
|
|
815
|
+
lastMessage: BroadcastMessage<T> | null;
|
|
816
|
+
/** All broadcast messages received */
|
|
817
|
+
messages: BroadcastMessage<T>[];
|
|
818
|
+
/** Whether channel is joined */
|
|
819
|
+
isJoined: boolean;
|
|
820
|
+
/** Leave channel */
|
|
821
|
+
leave: () => void;
|
|
822
|
+
}
|
|
377
823
|
/**
|
|
378
824
|
* Hook for realtime database subscriptions
|
|
379
825
|
*
|
|
@@ -445,6 +891,35 @@ declare function usePresence<T extends PresenceState = PresenceState>(channelNam
|
|
|
445
891
|
* ```
|
|
446
892
|
*/
|
|
447
893
|
declare function useBroadcast<T = unknown>(channelName: string): UseBroadcastReturn<T>;
|
|
894
|
+
/**
|
|
895
|
+
* Hook for joining a realtime channel
|
|
896
|
+
*
|
|
897
|
+
* @example
|
|
898
|
+
* ```tsx
|
|
899
|
+
* function ChatRoom({ roomId }: { roomId: string }) {
|
|
900
|
+
* const { broadcast, messages, isJoined } = useChannel<{ text: string; userId: string }>(
|
|
901
|
+
* `room:${roomId}`
|
|
902
|
+
* );
|
|
903
|
+
*
|
|
904
|
+
* const sendMessage = (text: string) => {
|
|
905
|
+
* broadcast('message', { text, userId: currentUser.id });
|
|
906
|
+
* };
|
|
907
|
+
*
|
|
908
|
+
* return (
|
|
909
|
+
* <View>
|
|
910
|
+
* {!isJoined && <ActivityIndicator />}
|
|
911
|
+
* <FlatList
|
|
912
|
+
* data={messages}
|
|
913
|
+
* keyExtractor={(_, index) => index.toString()}
|
|
914
|
+
* renderItem={({ item }) => <Text>{item.payload.text}</Text>}
|
|
915
|
+
* />
|
|
916
|
+
* <MessageInput onSend={sendMessage} />
|
|
917
|
+
* </View>
|
|
918
|
+
* );
|
|
919
|
+
* }
|
|
920
|
+
* ```
|
|
921
|
+
*/
|
|
922
|
+
declare function useChannel<T = unknown>(channelName: string, options?: UseChannelOptions): UseChannelReturn<T>;
|
|
448
923
|
/**
|
|
449
924
|
* Hook for realtime connection state
|
|
450
925
|
*/
|
|
@@ -601,6 +1076,22 @@ interface UseFunctionListReturn {
|
|
|
601
1076
|
error: Error | null;
|
|
602
1077
|
refetch: () => Promise<void>;
|
|
603
1078
|
}
|
|
1079
|
+
interface UseScheduledFunctionReturn<TInput> {
|
|
1080
|
+
/** Schedule function execution with delay */
|
|
1081
|
+
schedule: (input: TInput, options: {
|
|
1082
|
+
delayMs: number;
|
|
1083
|
+
}) => Promise<string>;
|
|
1084
|
+
/** Cancel scheduled execution */
|
|
1085
|
+
cancel: () => Promise<void>;
|
|
1086
|
+
/** Whether function is currently scheduled */
|
|
1087
|
+
isScheduled: boolean;
|
|
1088
|
+
/** Scheduled execution time */
|
|
1089
|
+
scheduledAt: Date | null;
|
|
1090
|
+
/** Request ID for tracking */
|
|
1091
|
+
requestId: string | null;
|
|
1092
|
+
/** Error state */
|
|
1093
|
+
error: Error | null;
|
|
1094
|
+
}
|
|
604
1095
|
/**
|
|
605
1096
|
* Hook for invoking serverless functions
|
|
606
1097
|
*
|
|
@@ -692,5 +1183,39 @@ declare function useBatchInvoke<TOutput = unknown>(): {
|
|
|
692
1183
|
isLoading: boolean;
|
|
693
1184
|
errors: (Error | null)[];
|
|
694
1185
|
};
|
|
1186
|
+
/**
|
|
1187
|
+
* Hook for scheduling deferred function invocations
|
|
1188
|
+
*
|
|
1189
|
+
* @example
|
|
1190
|
+
* ```tsx
|
|
1191
|
+
* function ScheduleReminder() {
|
|
1192
|
+
* const { schedule, cancel, isScheduled, scheduledAt } = useScheduledFunction<{ userId: string; message: string }>(
|
|
1193
|
+
* 'send-reminder'
|
|
1194
|
+
* );
|
|
1195
|
+
*
|
|
1196
|
+
* const handleSchedule = async () => {
|
|
1197
|
+
* await schedule(
|
|
1198
|
+
* { userId: currentUser.id, message: 'Follow up on task' },
|
|
1199
|
+
* { delayMs: 24 * 60 * 60 * 1000 } // 24 hours
|
|
1200
|
+
* );
|
|
1201
|
+
* Alert.alert('Reminder scheduled!');
|
|
1202
|
+
* };
|
|
1203
|
+
*
|
|
1204
|
+
* return (
|
|
1205
|
+
* <View>
|
|
1206
|
+
* {isScheduled ? (
|
|
1207
|
+
* <>
|
|
1208
|
+
* <Text>Scheduled for {scheduledAt?.toLocaleString()}</Text>
|
|
1209
|
+
* <Button onPress={cancel} title="Cancel" />
|
|
1210
|
+
* </>
|
|
1211
|
+
* ) : (
|
|
1212
|
+
* <Button onPress={handleSchedule} title="Schedule Reminder" />
|
|
1213
|
+
* )}
|
|
1214
|
+
* </View>
|
|
1215
|
+
* );
|
|
1216
|
+
* }
|
|
1217
|
+
* ```
|
|
1218
|
+
*/
|
|
1219
|
+
declare function useScheduledFunction<TInput = unknown>(functionId: string): UseScheduledFunctionReturn<TInput>;
|
|
695
1220
|
|
|
696
|
-
export { type AsyncStorageInterface, type MutationStatus, type QueryStatus, type UploadOptions, type UseAuthReturn, type UseBroadcastReturn, type UseCreateReturn, type UseDeleteReturn, type UseDownloadReturn, type UseFileReturn, type UseFilesReturn, type UseFunctionListReturn, type UseFunctionOptions, type UseFunctionReturn, type UseMutationReturn, type UsePaginatedQueryOptions, type UsePaginatedQueryReturn, type UsePresenceOptions, type UsePresenceReturn, type UseQueryOptions, type UseQueryReturn, type UseRpcReturn, type UseSubscriptionOptions, type UseSubscriptionReturn, type UseUpdateReturn, type UseUploadReturn, type UseUpsertReturn, type VaifContextValue, VaifProvider, type VaifProviderProps, useAuth, useBatchCreate, useBatchInvoke, useBroadcast, useCreate, useDelete, useDownload, useFile, useFiles, useFunction, useFunctionList, useFunctionQuery, usePaginatedQuery, usePresence, usePublicUrl, useQuery, useQueryById, useRealtimeConnection, useRpc, useSubscription, useUpdate, useUpload, useUpsert, useUser, useVaif, useVaifClient };
|
|
1221
|
+
export { type AsyncStorageInterface, type BroadcastMessage, type MutationStatus, type QueryStatus, type UploadOptions, type UseAuthReturn, type UseBatchDeleteReturn, type UseBatchUpdateReturn, type UseBroadcastReturn, type UseChannelOptions, type UseChannelReturn, type UseCountOptions, type UseCountReturn, type UseCreateReturn, type UseDeleteReturn, type UseDownloadReturn, type UseEmailVerificationReturn, type UseFileReturn, type UseFilesReturn, type UseFunctionListReturn, type UseFunctionOptions, type UseFunctionReturn, type UseInfiniteQueryOptions, type UseInfiniteQueryReturn, type UseMFAReturn, type UseMagicLinkReturn, type UseMutationReturn, type UseOAuthReturn, type UseOptimisticMutationReturn, type UsePaginatedQueryOptions, type UsePaginatedQueryReturn, type UsePasswordResetReturn, type UsePresenceOptions, type UsePresenceReturn, type UseQueryFirstReturn, type UseQueryOptions, type UseQueryReturn, type UseRpcReturn, type UseScheduledFunctionReturn, type UseSubscriptionOptions, type UseSubscriptionReturn, type UseUpdateReturn, type UseUploadReturn, type UseUpsertReturn, type VaifContextValue, VaifProvider, type VaifProviderProps, useAuth, useBatchCreate, useBatchDelete, useBatchInvoke, useBatchUpdate, useBroadcast, useChannel, useCount, useCreate, useDelete, useDownload, useEmailVerification, useFile, useFiles, useFunction, useFunctionList, useFunctionQuery, useInfiniteQuery, useMFA, useMagicLink, useOAuth, useOptimisticMutation, usePaginatedQuery, usePasswordReset, usePresence, usePublicUrl, useQuery, useQueryById, useQueryFirst, useRealtimeConnection, useRpc, useScheduledFunction, useSubscription, useToken, useUpdate, useUpload, useUpsert, useUser, useVaif, useVaifClient };
|