@vaiftech/sdk-expo 1.0.1 → 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/dist/index.d.mts +526 -2
- package/dist/index.d.ts +526 -2
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
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 '@vaiftech/client';
|
|
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
4
|
export { AuthResponse, ConnectionState, DbChangeEvent, DbOperation, FileMetadata, InvokeResult, OrderByClause, PresenceState, QueryOptions, UploadResult, User, VaifClient, VaifClientConfig, VaifFunction, WhereFilter } from '@vaiftech/client';
|
|
5
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';
|
|
6
6
|
|
|
@@ -72,6 +72,43 @@ interface UseAuthReturn {
|
|
|
72
72
|
updateProfile: (updates: Record<string, unknown>) => Promise<User>;
|
|
73
73
|
changePassword: (currentPassword: string, newPassword: string) => Promise<void>;
|
|
74
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
|
+
}
|
|
75
112
|
/**
|
|
76
113
|
* Hook for authentication
|
|
77
114
|
*
|
|
@@ -101,6 +138,150 @@ declare function useAuth(): UseAuthReturn;
|
|
|
101
138
|
* Hook to get just the current user
|
|
102
139
|
*/
|
|
103
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;
|
|
104
285
|
|
|
105
286
|
type QueryStatus = "idle" | "loading" | "success" | "error";
|
|
106
287
|
interface UseQueryOptions extends Omit<QueryOptions, "where" | "orderBy"> {
|
|
@@ -122,6 +303,18 @@ interface UseQueryReturn<T> {
|
|
|
122
303
|
error: Error | null;
|
|
123
304
|
refetch: () => Promise<void>;
|
|
124
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
|
+
}
|
|
125
318
|
interface UsePaginatedQueryOptions extends UseQueryOptions {
|
|
126
319
|
pageSize?: number;
|
|
127
320
|
initialPage?: number;
|
|
@@ -137,6 +330,50 @@ interface UsePaginatedQueryReturn<T> extends UseQueryReturn<T> {
|
|
|
137
330
|
previousPage: () => void;
|
|
138
331
|
goToPage: (page: number) => void;
|
|
139
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
|
+
}
|
|
140
377
|
/**
|
|
141
378
|
* Hook for querying data from a table
|
|
142
379
|
*
|
|
@@ -180,6 +417,76 @@ declare function useQueryById<T extends Record<string, unknown> = Record<string,
|
|
|
180
417
|
* Hook for paginated queries
|
|
181
418
|
*/
|
|
182
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;
|
|
183
490
|
|
|
184
491
|
type MutationStatus = "idle" | "loading" | "success" | "error";
|
|
185
492
|
interface UseMutationReturn<T, TInput = Partial<T>> {
|
|
@@ -324,6 +631,121 @@ declare function useBatchCreate<T extends Record<string, unknown> = Record<strin
|
|
|
324
631
|
isError: boolean;
|
|
325
632
|
error: Error | null;
|
|
326
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>;
|
|
327
749
|
|
|
328
750
|
interface UseSubscriptionOptions<T> {
|
|
329
751
|
/** Filter by operation type */
|
|
@@ -375,6 +797,29 @@ interface UseBroadcastReturn<T> {
|
|
|
375
797
|
/** Connection state */
|
|
376
798
|
isConnected: boolean;
|
|
377
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
|
+
}
|
|
378
823
|
/**
|
|
379
824
|
* Hook for realtime database subscriptions
|
|
380
825
|
*
|
|
@@ -446,6 +891,35 @@ declare function usePresence<T extends PresenceState = PresenceState>(channelNam
|
|
|
446
891
|
* ```
|
|
447
892
|
*/
|
|
448
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>;
|
|
449
923
|
/**
|
|
450
924
|
* Hook for realtime connection state
|
|
451
925
|
*/
|
|
@@ -602,6 +1076,22 @@ interface UseFunctionListReturn {
|
|
|
602
1076
|
error: Error | null;
|
|
603
1077
|
refetch: () => Promise<void>;
|
|
604
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
|
+
}
|
|
605
1095
|
/**
|
|
606
1096
|
* Hook for invoking serverless functions
|
|
607
1097
|
*
|
|
@@ -693,5 +1183,39 @@ declare function useBatchInvoke<TOutput = unknown>(): {
|
|
|
693
1183
|
isLoading: boolean;
|
|
694
1184
|
errors: (Error | null)[];
|
|
695
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>;
|
|
696
1220
|
|
|
697
|
-
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 };
|