@gately/react 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +277 -0
- package/dist/context.d.ts +35 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +199 -0
- package/dist/context.mjs +193 -0
- package/dist/hooks/context.d.ts +35 -0
- package/dist/hooks/context.d.ts.map +1 -0
- package/dist/hooks/hooks/index.d.ts +11 -0
- package/dist/hooks/hooks/index.d.ts.map +1 -0
- package/dist/hooks/hooks/useAuth.d.ts +38 -0
- package/dist/hooks/hooks/useAuth.d.ts.map +1 -0
- package/dist/hooks/hooks/useProtected.d.ts +29 -0
- package/dist/hooks/hooks/useProtected.d.ts.map +1 -0
- package/dist/hooks/hooks/useUser.d.ts +42 -0
- package/dist/hooks/hooks/useUser.d.ts.map +1 -0
- package/dist/hooks/index.d.ts +11 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +212 -0
- package/dist/hooks/index.mjs +208 -0
- package/dist/hooks/useAuth.d.ts +38 -0
- package/dist/hooks/useAuth.d.ts.map +1 -0
- package/dist/hooks/useProtected.d.ts +29 -0
- package/dist/hooks/useProtected.d.ts.map +1 -0
- package/dist/hooks/useUser.d.ts +42 -0
- package/dist/hooks/useUser.d.ts.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +397 -0
- package/dist/index.mjs +391 -0
- package/package.json +73 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
import React, { createContext, useState, useEffect, useCallback, useContext } from 'react';
|
|
2
|
+
import { GatelyClient } from '@gately/sdk';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Gately React Context
|
|
6
|
+
* Provides authentication state and methods to React components
|
|
7
|
+
*/
|
|
8
|
+
const GatelyContext = createContext(undefined);
|
|
9
|
+
function GatelyProvider({ projectId, apiUrl, children, autoRefresh = true }) {
|
|
10
|
+
const [client] = useState(() => {
|
|
11
|
+
if (typeof window === 'undefined')
|
|
12
|
+
return null;
|
|
13
|
+
try {
|
|
14
|
+
return new GatelyClient(projectId, { apiUrl, autoRefresh });
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
console.error('Failed to initialize Gately client:', error);
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
const [user, setUser] = useState(null);
|
|
22
|
+
const [session, setSession] = useState(null);
|
|
23
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
24
|
+
const [error, setError] = useState(null);
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (!client)
|
|
27
|
+
return;
|
|
28
|
+
setIsLoading(true);
|
|
29
|
+
setUser(client.getUser());
|
|
30
|
+
setSession(client.getSession());
|
|
31
|
+
setIsLoading(false);
|
|
32
|
+
const handleAuthStateChange = (newUser, newSession) => {
|
|
33
|
+
setUser(newUser);
|
|
34
|
+
setSession(newSession);
|
|
35
|
+
setError(null);
|
|
36
|
+
};
|
|
37
|
+
client.onAuthStateChange(handleAuthStateChange);
|
|
38
|
+
return () => {
|
|
39
|
+
client.offAuthStateChange(handleAuthStateChange);
|
|
40
|
+
};
|
|
41
|
+
}, [client]);
|
|
42
|
+
const login = useCallback(async (email, password) => {
|
|
43
|
+
if (!client)
|
|
44
|
+
throw new Error('Gately client not initialized');
|
|
45
|
+
setError(null);
|
|
46
|
+
try {
|
|
47
|
+
return await client.login(email, password);
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
51
|
+
setError(error);
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
}, [client]);
|
|
55
|
+
const signup = useCallback(async (email, password, metadata) => {
|
|
56
|
+
if (!client)
|
|
57
|
+
throw new Error('Gately client not initialized');
|
|
58
|
+
setError(null);
|
|
59
|
+
try {
|
|
60
|
+
return await client.signup(email, password, metadata);
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
64
|
+
setError(error);
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
}, [client]);
|
|
68
|
+
const logout = useCallback(async () => {
|
|
69
|
+
if (!client)
|
|
70
|
+
throw new Error('Gately client not initialized');
|
|
71
|
+
setError(null);
|
|
72
|
+
try {
|
|
73
|
+
await client.logout();
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
77
|
+
setError(error);
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
}, [client]);
|
|
81
|
+
const sendMagicLink = useCallback(async (email, redirectTo) => {
|
|
82
|
+
if (!client)
|
|
83
|
+
throw new Error('Gately client not initialized');
|
|
84
|
+
setError(null);
|
|
85
|
+
try {
|
|
86
|
+
await client.sendMagicLink(email, { redirectTo });
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
90
|
+
setError(error);
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
}, [client]);
|
|
94
|
+
const resetPassword = useCallback(async (email) => {
|
|
95
|
+
if (!client)
|
|
96
|
+
throw new Error('Gately client not initialized');
|
|
97
|
+
setError(null);
|
|
98
|
+
try {
|
|
99
|
+
await client.resetPassword(email);
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
103
|
+
setError(error);
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
}, [client]);
|
|
107
|
+
const fetchSession = useCallback(async () => {
|
|
108
|
+
if (!client)
|
|
109
|
+
throw new Error('Gately client not initialized');
|
|
110
|
+
setError(null);
|
|
111
|
+
try {
|
|
112
|
+
return await client.fetchSession();
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
116
|
+
setError(error);
|
|
117
|
+
throw error;
|
|
118
|
+
}
|
|
119
|
+
}, [client]);
|
|
120
|
+
const getUserProfile = useCallback(async () => {
|
|
121
|
+
if (!client)
|
|
122
|
+
throw new Error('Gately client not initialized');
|
|
123
|
+
setError(null);
|
|
124
|
+
try {
|
|
125
|
+
return await client.getUserProfile();
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
129
|
+
setError(error);
|
|
130
|
+
throw error;
|
|
131
|
+
}
|
|
132
|
+
}, [client]);
|
|
133
|
+
const updateUserProfile = useCallback(async (updates) => {
|
|
134
|
+
if (!client)
|
|
135
|
+
throw new Error('Gately client not initialized');
|
|
136
|
+
setError(null);
|
|
137
|
+
try {
|
|
138
|
+
return await client.updateUserProfile(updates);
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
142
|
+
setError(error);
|
|
143
|
+
throw error;
|
|
144
|
+
}
|
|
145
|
+
}, [client]);
|
|
146
|
+
const deleteUserAccount = useCallback(async () => {
|
|
147
|
+
if (!client)
|
|
148
|
+
throw new Error('Gately client not initialized');
|
|
149
|
+
setError(null);
|
|
150
|
+
try {
|
|
151
|
+
await client.deleteUserAccount();
|
|
152
|
+
}
|
|
153
|
+
catch (err) {
|
|
154
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
155
|
+
setError(error);
|
|
156
|
+
throw error;
|
|
157
|
+
}
|
|
158
|
+
}, [client]);
|
|
159
|
+
const changePassword = useCallback(async (current, newPassword) => {
|
|
160
|
+
if (!client)
|
|
161
|
+
throw new Error('Gately client not initialized');
|
|
162
|
+
setError(null);
|
|
163
|
+
try {
|
|
164
|
+
await client.changePassword(current, newPassword);
|
|
165
|
+
}
|
|
166
|
+
catch (err) {
|
|
167
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
168
|
+
setError(error);
|
|
169
|
+
throw error;
|
|
170
|
+
}
|
|
171
|
+
}, [client]);
|
|
172
|
+
const value = {
|
|
173
|
+
user,
|
|
174
|
+
session,
|
|
175
|
+
isLoading,
|
|
176
|
+
isAuthenticated: !!session && new Date(session.expires_at) > new Date(),
|
|
177
|
+
error,
|
|
178
|
+
login,
|
|
179
|
+
signup,
|
|
180
|
+
logout,
|
|
181
|
+
sendMagicLink,
|
|
182
|
+
resetPassword,
|
|
183
|
+
fetchSession,
|
|
184
|
+
getUserProfile,
|
|
185
|
+
updateUserProfile,
|
|
186
|
+
deleteUserAccount,
|
|
187
|
+
changePassword,
|
|
188
|
+
client
|
|
189
|
+
};
|
|
190
|
+
return React.createElement(GatelyContext.Provider, { value }, children);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* useAuth Hook
|
|
195
|
+
* Main hook for accessing Gately auth context
|
|
196
|
+
*/
|
|
197
|
+
/**
|
|
198
|
+
* Hook to access Gately authentication context
|
|
199
|
+
* Must be used inside a GatelyProvider
|
|
200
|
+
*
|
|
201
|
+
* @returns {GatelyContextValue} Auth context with user, session, and auth methods
|
|
202
|
+
*
|
|
203
|
+
* @example
|
|
204
|
+
* ```tsx
|
|
205
|
+
* function LoginForm() {
|
|
206
|
+
* const { login, isLoading, error } = useAuth()
|
|
207
|
+
*
|
|
208
|
+
* const handleSubmit = async (email, password) => {
|
|
209
|
+
* try {
|
|
210
|
+
* await login(email, password)
|
|
211
|
+
* } catch (err) {
|
|
212
|
+
* console.error(err)
|
|
213
|
+
* }
|
|
214
|
+
* }
|
|
215
|
+
*
|
|
216
|
+
* return (
|
|
217
|
+
* <>
|
|
218
|
+
* {error && <p>{error.message}</p>}
|
|
219
|
+
* <button disabled={isLoading} onClick={() => handleSubmit('test@example.com', 'pass')}>
|
|
220
|
+
* {isLoading ? 'Logging in...' : 'Log In'}
|
|
221
|
+
* </button>
|
|
222
|
+
* </>
|
|
223
|
+
* )
|
|
224
|
+
* }
|
|
225
|
+
* ```
|
|
226
|
+
*/
|
|
227
|
+
function useAuth() {
|
|
228
|
+
const context = useContext(GatelyContext);
|
|
229
|
+
if (context === undefined) {
|
|
230
|
+
throw new Error('useAuth must be used within a GatelyProvider');
|
|
231
|
+
}
|
|
232
|
+
return context;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* useUser Hook
|
|
237
|
+
* Dedicated hook for accessing user information
|
|
238
|
+
*/
|
|
239
|
+
/**
|
|
240
|
+
* Hook to access and manage user information
|
|
241
|
+
*
|
|
242
|
+
* @returns {UseUserReturn} User data with loading and error states
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* ```tsx
|
|
246
|
+
* function UserProfile() {
|
|
247
|
+
* const { user, profile, isLoading, error, update } = useUser()
|
|
248
|
+
*
|
|
249
|
+
* if (isLoading) return <p>Loading...</p>
|
|
250
|
+
* if (error) return <p>Error: {error.message}</p>
|
|
251
|
+
* if (!user) return <p>Not logged in</p>
|
|
252
|
+
*
|
|
253
|
+
* return (
|
|
254
|
+
* <div>
|
|
255
|
+
* <p>Email: {user.email}</p>
|
|
256
|
+
* <button onClick={() => update({ name: 'New Name' })}>
|
|
257
|
+
* Update Profile
|
|
258
|
+
* </button>
|
|
259
|
+
* </div>
|
|
260
|
+
* )
|
|
261
|
+
* }
|
|
262
|
+
* ```
|
|
263
|
+
*/
|
|
264
|
+
function useUser() {
|
|
265
|
+
const { user, isAuthenticated, getUserProfile, updateUserProfile, deleteUserAccount } = useAuth();
|
|
266
|
+
const [profile, setProfile] = useState(null);
|
|
267
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
268
|
+
const [error, setError] = useState(null);
|
|
269
|
+
// Fetch user profile on mount or when auth state changes
|
|
270
|
+
useEffect(() => {
|
|
271
|
+
if (!isAuthenticated || !user) {
|
|
272
|
+
setProfile(null);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
const fetchProfile = async () => {
|
|
276
|
+
setIsLoading(true);
|
|
277
|
+
setError(null);
|
|
278
|
+
try {
|
|
279
|
+
const profileData = await getUserProfile();
|
|
280
|
+
setProfile(profileData);
|
|
281
|
+
}
|
|
282
|
+
catch (err) {
|
|
283
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
284
|
+
setProfile(null);
|
|
285
|
+
}
|
|
286
|
+
finally {
|
|
287
|
+
setIsLoading(false);
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
fetchProfile();
|
|
291
|
+
}, [isAuthenticated, user, getUserProfile]);
|
|
292
|
+
const refetch = useCallback(async () => {
|
|
293
|
+
if (!isAuthenticated) {
|
|
294
|
+
throw new Error('User must be authenticated to fetch profile');
|
|
295
|
+
}
|
|
296
|
+
setIsLoading(true);
|
|
297
|
+
setError(null);
|
|
298
|
+
try {
|
|
299
|
+
const profileData = await getUserProfile();
|
|
300
|
+
setProfile(profileData);
|
|
301
|
+
}
|
|
302
|
+
catch (err) {
|
|
303
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
304
|
+
setError(error);
|
|
305
|
+
throw error;
|
|
306
|
+
}
|
|
307
|
+
finally {
|
|
308
|
+
setIsLoading(false);
|
|
309
|
+
}
|
|
310
|
+
}, [isAuthenticated, getUserProfile]);
|
|
311
|
+
const update = useCallback(async (updates) => {
|
|
312
|
+
if (!isAuthenticated) {
|
|
313
|
+
throw new Error('User must be authenticated to update profile');
|
|
314
|
+
}
|
|
315
|
+
setIsLoading(true);
|
|
316
|
+
setError(null);
|
|
317
|
+
try {
|
|
318
|
+
const updatedProfile = await updateUserProfile(updates);
|
|
319
|
+
setProfile(updatedProfile);
|
|
320
|
+
return updatedProfile;
|
|
321
|
+
}
|
|
322
|
+
catch (err) {
|
|
323
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
324
|
+
setError(error);
|
|
325
|
+
throw error;
|
|
326
|
+
}
|
|
327
|
+
finally {
|
|
328
|
+
setIsLoading(false);
|
|
329
|
+
}
|
|
330
|
+
}, [isAuthenticated, updateUserProfile]);
|
|
331
|
+
const deleteUser = useCallback(async () => {
|
|
332
|
+
if (!isAuthenticated) {
|
|
333
|
+
throw new Error('User must be authenticated to delete account');
|
|
334
|
+
}
|
|
335
|
+
setIsLoading(true);
|
|
336
|
+
setError(null);
|
|
337
|
+
try {
|
|
338
|
+
await deleteUserAccount();
|
|
339
|
+
setProfile(null);
|
|
340
|
+
}
|
|
341
|
+
catch (err) {
|
|
342
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
343
|
+
setError(error);
|
|
344
|
+
throw error;
|
|
345
|
+
}
|
|
346
|
+
finally {
|
|
347
|
+
setIsLoading(false);
|
|
348
|
+
}
|
|
349
|
+
}, [isAuthenticated, deleteUserAccount]);
|
|
350
|
+
return {
|
|
351
|
+
user,
|
|
352
|
+
profile,
|
|
353
|
+
isLoading,
|
|
354
|
+
error,
|
|
355
|
+
refetch,
|
|
356
|
+
update,
|
|
357
|
+
delete: deleteUser
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* useProtected Hook
|
|
363
|
+
* Hook for protecting components that require authentication
|
|
364
|
+
*/
|
|
365
|
+
/**
|
|
366
|
+
* Hook to check if user is authenticated and protect a component
|
|
367
|
+
*
|
|
368
|
+
* @returns {UseProtectedReturn} Authentication status
|
|
369
|
+
*
|
|
370
|
+
* @example
|
|
371
|
+
* ```tsx
|
|
372
|
+
* function ProtectedPage() {
|
|
373
|
+
* const { isAuthenticated, isLoading } = useProtected()
|
|
374
|
+
*
|
|
375
|
+
* if (isLoading) return <p>Loading...</p>
|
|
376
|
+
* if (!isAuthenticated) return <p>Please log in to access this page</p>
|
|
377
|
+
*
|
|
378
|
+
* return <div>Protected content</div>
|
|
379
|
+
* }
|
|
380
|
+
* ```
|
|
381
|
+
*/
|
|
382
|
+
function useProtected() {
|
|
383
|
+
const { isAuthenticated, isLoading, user } = useAuth();
|
|
384
|
+
return {
|
|
385
|
+
isAuthenticated,
|
|
386
|
+
isLoading,
|
|
387
|
+
user
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
export { GatelyContext, GatelyProvider, useAuth, useProtected, useUser };
|
package/package.json
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gately/react",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "React SDK for Gately - authentication, user management, and more",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"module": "dist/index.mjs",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.mjs",
|
|
13
|
+
"require": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./context": {
|
|
16
|
+
"types": "./dist/context.d.ts",
|
|
17
|
+
"import": "./dist/context.mjs",
|
|
18
|
+
"require": "./dist/context.js"
|
|
19
|
+
},
|
|
20
|
+
"./hooks": {
|
|
21
|
+
"types": "./dist/hooks/index.d.ts",
|
|
22
|
+
"import": "./dist/hooks/index.mjs",
|
|
23
|
+
"require": "./dist/hooks/index.js"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist/**/*"
|
|
28
|
+
],
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "rollup -c",
|
|
31
|
+
"build:watch": "rollup -c -w",
|
|
32
|
+
"type-check": "tsc --noEmit",
|
|
33
|
+
"lint": "eslint src/**/*.{ts,tsx}",
|
|
34
|
+
"test": "jest",
|
|
35
|
+
"clean": "rimraf dist"
|
|
36
|
+
},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"gately",
|
|
39
|
+
"authentication",
|
|
40
|
+
"react",
|
|
41
|
+
"hooks",
|
|
42
|
+
"auth",
|
|
43
|
+
"user-management"
|
|
44
|
+
],
|
|
45
|
+
"author": "Gately Team",
|
|
46
|
+
"license": "MIT",
|
|
47
|
+
"peerDependencies": {
|
|
48
|
+
"react": ">=16.8.0",
|
|
49
|
+
"react-dom": ">=16.8.0"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"@gately/sdk": "^2.0.0"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@rollup/plugin-commonjs": "^25.0.0",
|
|
56
|
+
"@rollup/plugin-node-resolve": "^15.0.0",
|
|
57
|
+
"@rollup/plugin-typescript": "^11.0.0",
|
|
58
|
+
"@types/react": "^18.0.0",
|
|
59
|
+
"@types/react-dom": "^18.0.0",
|
|
60
|
+
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
61
|
+
"@typescript-eslint/parser": "^6.0.0",
|
|
62
|
+
"eslint": "^8.0.0",
|
|
63
|
+
"react": "^18.0.0",
|
|
64
|
+
"react-dom": "^18.0.0",
|
|
65
|
+
"rollup": "^3.0.0",
|
|
66
|
+
"rollup-plugin-dts": "^5.0.0",
|
|
67
|
+
"tslib": "^2.8.1",
|
|
68
|
+
"typescript": "^5.9.2"
|
|
69
|
+
},
|
|
70
|
+
"engines": {
|
|
71
|
+
"node": ">=16.0.0"
|
|
72
|
+
}
|
|
73
|
+
}
|