@reauth-dev/sdk 0.1.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/LICENSE +21 -0
- package/README.md +252 -0
- package/dist/chunk-JX2J36FS.mjs +269 -0
- package/dist/index.d.mts +127 -0
- package/dist/index.d.ts +127 -0
- package/dist/index.js +308 -0
- package/dist/index.mjs +17 -0
- package/dist/react/index.d.mts +123 -0
- package/dist/react/index.d.ts +123 -0
- package/dist/react/index.js +448 -0
- package/dist/react/index.mjs +154 -0
- package/dist/server.d.mts +188 -0
- package/dist/server.d.ts +188 -0
- package/dist/server.js +391 -0
- package/dist/server.mjs +356 -0
- package/dist/types-D8oOYbeC.d.mts +169 -0
- package/dist/types-D8oOYbeC.d.ts +169 -0
- package/dist/webhooks.d.mts +23 -0
- package/dist/webhooks.d.ts +23 -0
- package/dist/webhooks.js +123 -0
- package/dist/webhooks.mjs +94 -0
- package/package.json +78 -0
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/react/index.ts
|
|
21
|
+
var react_exports = {};
|
|
22
|
+
__export(react_exports, {
|
|
23
|
+
AuthProvider: () => AuthProvider,
|
|
24
|
+
ProtectedRoute: () => ProtectedRoute,
|
|
25
|
+
useAuth: () => useAuth,
|
|
26
|
+
useAuthContext: () => useAuthContext
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(react_exports);
|
|
29
|
+
|
|
30
|
+
// src/react/useAuth.ts
|
|
31
|
+
var import_react = require("react");
|
|
32
|
+
|
|
33
|
+
// src/client.ts
|
|
34
|
+
function createReauthClient(config) {
|
|
35
|
+
const { domain } = config;
|
|
36
|
+
const baseUrl = `https://reauth.${domain}/api/public`;
|
|
37
|
+
return {
|
|
38
|
+
/**
|
|
39
|
+
* Redirect the user to the reauth.dev login page.
|
|
40
|
+
* After successful login, they'll be redirected back to your configured redirect URL.
|
|
41
|
+
*/
|
|
42
|
+
login() {
|
|
43
|
+
if (typeof window === "undefined") {
|
|
44
|
+
throw new Error("login() can only be called in browser");
|
|
45
|
+
}
|
|
46
|
+
window.location.href = `https://reauth.${domain}/`;
|
|
47
|
+
},
|
|
48
|
+
/**
|
|
49
|
+
* Check if the user is authenticated.
|
|
50
|
+
* Returns session info including user ID, email, and roles.
|
|
51
|
+
*/
|
|
52
|
+
async getSession() {
|
|
53
|
+
const res = await fetch(`${baseUrl}/auth/session`, {
|
|
54
|
+
credentials: "include"
|
|
55
|
+
});
|
|
56
|
+
return res.json();
|
|
57
|
+
},
|
|
58
|
+
/**
|
|
59
|
+
* Refresh the access token using the refresh token.
|
|
60
|
+
* Call this when getSession() returns valid: false but no error_code.
|
|
61
|
+
* @returns true if refresh succeeded, false otherwise
|
|
62
|
+
*/
|
|
63
|
+
async refresh() {
|
|
64
|
+
const res = await fetch(`${baseUrl}/auth/refresh`, {
|
|
65
|
+
method: "POST",
|
|
66
|
+
credentials: "include"
|
|
67
|
+
});
|
|
68
|
+
return res.ok;
|
|
69
|
+
},
|
|
70
|
+
/**
|
|
71
|
+
* Get an access token for Bearer authentication.
|
|
72
|
+
* Use this when calling your own API that uses local token verification.
|
|
73
|
+
*
|
|
74
|
+
* @returns TokenResponse with access token, or null if not authenticated
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```typescript
|
|
78
|
+
* const tokenResponse = await reauth.getToken();
|
|
79
|
+
* if (tokenResponse) {
|
|
80
|
+
* fetch('/api/data', {
|
|
81
|
+
* headers: { Authorization: `Bearer ${tokenResponse.accessToken}` }
|
|
82
|
+
* });
|
|
83
|
+
* }
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
async getToken() {
|
|
87
|
+
try {
|
|
88
|
+
const res = await fetch(`${baseUrl}/auth/token`, {
|
|
89
|
+
method: "GET",
|
|
90
|
+
credentials: "include"
|
|
91
|
+
});
|
|
92
|
+
if (!res.ok) {
|
|
93
|
+
if (res.status === 401) return null;
|
|
94
|
+
throw new Error(`Failed to get token: ${res.status}`);
|
|
95
|
+
}
|
|
96
|
+
const data = await res.json();
|
|
97
|
+
return {
|
|
98
|
+
accessToken: data.access_token,
|
|
99
|
+
expiresIn: data.expires_in,
|
|
100
|
+
tokenType: data.token_type
|
|
101
|
+
};
|
|
102
|
+
} catch {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
/**
|
|
107
|
+
* Log out the user by clearing all session cookies.
|
|
108
|
+
*/
|
|
109
|
+
async logout() {
|
|
110
|
+
await fetch(`${baseUrl}/auth/logout`, {
|
|
111
|
+
method: "POST",
|
|
112
|
+
credentials: "include"
|
|
113
|
+
});
|
|
114
|
+
},
|
|
115
|
+
/**
|
|
116
|
+
* Delete the user's own account (self-service).
|
|
117
|
+
* @returns true if deletion succeeded, false otherwise
|
|
118
|
+
*/
|
|
119
|
+
async deleteAccount() {
|
|
120
|
+
const res = await fetch(`${baseUrl}/auth/account`, {
|
|
121
|
+
method: "DELETE",
|
|
122
|
+
credentials: "include"
|
|
123
|
+
});
|
|
124
|
+
return res.ok;
|
|
125
|
+
},
|
|
126
|
+
// ========================================================================
|
|
127
|
+
// Billing Methods
|
|
128
|
+
// ========================================================================
|
|
129
|
+
/**
|
|
130
|
+
* Get available subscription plans for the domain.
|
|
131
|
+
* Only returns public plans sorted by display order.
|
|
132
|
+
*/
|
|
133
|
+
async getPlans() {
|
|
134
|
+
const res = await fetch(`${baseUrl}/billing/plans`, {
|
|
135
|
+
credentials: "include"
|
|
136
|
+
});
|
|
137
|
+
if (!res.ok) return [];
|
|
138
|
+
const data = await res.json();
|
|
139
|
+
return data.map(
|
|
140
|
+
(p) => ({
|
|
141
|
+
id: p.id,
|
|
142
|
+
code: p.code,
|
|
143
|
+
name: p.name,
|
|
144
|
+
description: p.description,
|
|
145
|
+
priceCents: p.price_cents,
|
|
146
|
+
currency: p.currency,
|
|
147
|
+
interval: p.interval,
|
|
148
|
+
intervalCount: p.interval_count,
|
|
149
|
+
trialDays: p.trial_days,
|
|
150
|
+
features: p.features,
|
|
151
|
+
displayOrder: p.display_order
|
|
152
|
+
})
|
|
153
|
+
);
|
|
154
|
+
},
|
|
155
|
+
/**
|
|
156
|
+
* Get the current user's subscription status.
|
|
157
|
+
*/
|
|
158
|
+
async getSubscription() {
|
|
159
|
+
const res = await fetch(`${baseUrl}/billing/subscription`, {
|
|
160
|
+
credentials: "include"
|
|
161
|
+
});
|
|
162
|
+
const data = await res.json();
|
|
163
|
+
return {
|
|
164
|
+
id: data.id,
|
|
165
|
+
planCode: data.plan_code,
|
|
166
|
+
planName: data.plan_name,
|
|
167
|
+
status: data.status,
|
|
168
|
+
currentPeriodEnd: data.current_period_end,
|
|
169
|
+
trialEnd: data.trial_end,
|
|
170
|
+
cancelAtPeriodEnd: data.cancel_at_period_end
|
|
171
|
+
};
|
|
172
|
+
},
|
|
173
|
+
/**
|
|
174
|
+
* Create a Stripe checkout session to subscribe to a plan.
|
|
175
|
+
* @param planCode The plan code to subscribe to
|
|
176
|
+
* @param successUrl URL to redirect to after successful payment
|
|
177
|
+
* @param cancelUrl URL to redirect to if checkout is canceled
|
|
178
|
+
* @returns Checkout session with URL to redirect the user to
|
|
179
|
+
*/
|
|
180
|
+
async createCheckout(planCode, successUrl, cancelUrl) {
|
|
181
|
+
const res = await fetch(`${baseUrl}/billing/checkout`, {
|
|
182
|
+
method: "POST",
|
|
183
|
+
headers: { "Content-Type": "application/json" },
|
|
184
|
+
credentials: "include",
|
|
185
|
+
body: JSON.stringify({
|
|
186
|
+
plan_code: planCode,
|
|
187
|
+
success_url: successUrl,
|
|
188
|
+
cancel_url: cancelUrl
|
|
189
|
+
})
|
|
190
|
+
});
|
|
191
|
+
if (!res.ok) {
|
|
192
|
+
const err = await res.json().catch(() => ({}));
|
|
193
|
+
throw new Error(err.message || "Failed to create checkout session");
|
|
194
|
+
}
|
|
195
|
+
const data = await res.json();
|
|
196
|
+
return { checkoutUrl: data.checkout_url };
|
|
197
|
+
},
|
|
198
|
+
/**
|
|
199
|
+
* Redirect user to subscribe to a plan.
|
|
200
|
+
* Creates a checkout session and redirects to Stripe.
|
|
201
|
+
* @param planCode The plan code to subscribe to
|
|
202
|
+
*/
|
|
203
|
+
async subscribe(planCode) {
|
|
204
|
+
if (typeof window === "undefined") {
|
|
205
|
+
throw new Error("subscribe() can only be called in browser");
|
|
206
|
+
}
|
|
207
|
+
const currentUrl = window.location.href;
|
|
208
|
+
const { checkoutUrl } = await this.createCheckout(
|
|
209
|
+
planCode,
|
|
210
|
+
currentUrl,
|
|
211
|
+
currentUrl
|
|
212
|
+
);
|
|
213
|
+
window.location.href = checkoutUrl;
|
|
214
|
+
},
|
|
215
|
+
/**
|
|
216
|
+
* Open the Stripe customer portal for managing subscription.
|
|
217
|
+
* @param returnUrl URL to return to after leaving the portal
|
|
218
|
+
*/
|
|
219
|
+
async openBillingPortal(returnUrl) {
|
|
220
|
+
if (typeof window === "undefined") {
|
|
221
|
+
throw new Error("openBillingPortal() can only be called in browser");
|
|
222
|
+
}
|
|
223
|
+
const res = await fetch(`${baseUrl}/billing/portal`, {
|
|
224
|
+
method: "POST",
|
|
225
|
+
headers: { "Content-Type": "application/json" },
|
|
226
|
+
credentials: "include",
|
|
227
|
+
body: JSON.stringify({
|
|
228
|
+
return_url: returnUrl || window.location.href
|
|
229
|
+
})
|
|
230
|
+
});
|
|
231
|
+
if (!res.ok) {
|
|
232
|
+
throw new Error("Failed to open billing portal");
|
|
233
|
+
}
|
|
234
|
+
const data = await res.json();
|
|
235
|
+
window.location.href = data.portal_url;
|
|
236
|
+
},
|
|
237
|
+
/**
|
|
238
|
+
* Cancel the user's subscription at period end.
|
|
239
|
+
* @returns true if cancellation succeeded
|
|
240
|
+
*/
|
|
241
|
+
async cancelSubscription() {
|
|
242
|
+
const res = await fetch(`${baseUrl}/billing/cancel`, {
|
|
243
|
+
method: "POST",
|
|
244
|
+
credentials: "include"
|
|
245
|
+
});
|
|
246
|
+
return res.ok;
|
|
247
|
+
},
|
|
248
|
+
// ========================================================================
|
|
249
|
+
// Balance Methods
|
|
250
|
+
// ========================================================================
|
|
251
|
+
/**
|
|
252
|
+
* Get the current user's balance.
|
|
253
|
+
* @returns Object with the current balance
|
|
254
|
+
*/
|
|
255
|
+
async getBalance() {
|
|
256
|
+
const res = await fetch(`${baseUrl}/balance`, {
|
|
257
|
+
credentials: "include"
|
|
258
|
+
});
|
|
259
|
+
if (!res.ok) {
|
|
260
|
+
if (res.status === 401) throw new Error("Not authenticated");
|
|
261
|
+
throw new Error(`Failed to get balance: ${res.status}`);
|
|
262
|
+
}
|
|
263
|
+
return res.json();
|
|
264
|
+
},
|
|
265
|
+
/**
|
|
266
|
+
* Get the current user's balance transaction history.
|
|
267
|
+
* @param opts - Optional pagination (limit, offset)
|
|
268
|
+
* @returns Object with array of transactions (newest first)
|
|
269
|
+
*/
|
|
270
|
+
async getTransactions(opts) {
|
|
271
|
+
const params = new URLSearchParams();
|
|
272
|
+
if (opts?.limit !== void 0) params.set("limit", String(opts.limit));
|
|
273
|
+
if (opts?.offset !== void 0) params.set("offset", String(opts.offset));
|
|
274
|
+
const qs = params.toString();
|
|
275
|
+
const res = await fetch(
|
|
276
|
+
`${baseUrl}/balance/transactions${qs ? `?${qs}` : ""}`,
|
|
277
|
+
{ credentials: "include" }
|
|
278
|
+
);
|
|
279
|
+
if (!res.ok) {
|
|
280
|
+
if (res.status === 401) throw new Error("Not authenticated");
|
|
281
|
+
throw new Error(`Failed to get transactions: ${res.status}`);
|
|
282
|
+
}
|
|
283
|
+
const data = await res.json();
|
|
284
|
+
return {
|
|
285
|
+
transactions: data.transactions.map(
|
|
286
|
+
(t) => ({
|
|
287
|
+
id: t.id,
|
|
288
|
+
amountDelta: t.amount_delta,
|
|
289
|
+
reason: t.reason,
|
|
290
|
+
balanceAfter: t.balance_after,
|
|
291
|
+
createdAt: t.created_at
|
|
292
|
+
})
|
|
293
|
+
)
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// src/react/useAuth.ts
|
|
300
|
+
function useAuth(config) {
|
|
301
|
+
const client = (0, import_react.useMemo)(() => createReauthClient(config), [config.domain]);
|
|
302
|
+
const [state, setState] = (0, import_react.useState)({
|
|
303
|
+
user: null,
|
|
304
|
+
loading: true,
|
|
305
|
+
error: null,
|
|
306
|
+
isOnWaitlist: false,
|
|
307
|
+
waitlistPosition: null
|
|
308
|
+
});
|
|
309
|
+
const checkSession = (0, import_react.useCallback)(async () => {
|
|
310
|
+
try {
|
|
311
|
+
let session = await client.getSession();
|
|
312
|
+
if (!session.valid && !session.error_code && !session.end_user_id) {
|
|
313
|
+
const refreshed = await client.refresh();
|
|
314
|
+
if (refreshed) {
|
|
315
|
+
session = await client.getSession();
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
if (session.error_code === "ACCOUNT_SUSPENDED") {
|
|
319
|
+
setState({
|
|
320
|
+
user: null,
|
|
321
|
+
loading: false,
|
|
322
|
+
error: "Account suspended",
|
|
323
|
+
isOnWaitlist: false,
|
|
324
|
+
waitlistPosition: null
|
|
325
|
+
});
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
if (session.valid && session.waitlist_position) {
|
|
329
|
+
setState({
|
|
330
|
+
user: {
|
|
331
|
+
id: session.end_user_id,
|
|
332
|
+
email: session.email,
|
|
333
|
+
roles: session.roles || []
|
|
334
|
+
},
|
|
335
|
+
loading: false,
|
|
336
|
+
error: null,
|
|
337
|
+
isOnWaitlist: true,
|
|
338
|
+
waitlistPosition: session.waitlist_position
|
|
339
|
+
});
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
if (session.valid && session.end_user_id) {
|
|
343
|
+
setState({
|
|
344
|
+
user: {
|
|
345
|
+
id: session.end_user_id,
|
|
346
|
+
email: session.email,
|
|
347
|
+
roles: session.roles || []
|
|
348
|
+
},
|
|
349
|
+
loading: false,
|
|
350
|
+
error: null,
|
|
351
|
+
isOnWaitlist: false,
|
|
352
|
+
waitlistPosition: null
|
|
353
|
+
});
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
setState({
|
|
357
|
+
user: null,
|
|
358
|
+
loading: false,
|
|
359
|
+
error: null,
|
|
360
|
+
isOnWaitlist: false,
|
|
361
|
+
waitlistPosition: null
|
|
362
|
+
});
|
|
363
|
+
} catch {
|
|
364
|
+
setState({
|
|
365
|
+
user: null,
|
|
366
|
+
loading: false,
|
|
367
|
+
error: "Auth check failed",
|
|
368
|
+
isOnWaitlist: false,
|
|
369
|
+
waitlistPosition: null
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
}, [client]);
|
|
373
|
+
(0, import_react.useEffect)(() => {
|
|
374
|
+
checkSession();
|
|
375
|
+
}, [checkSession]);
|
|
376
|
+
const logout = (0, import_react.useCallback)(async () => {
|
|
377
|
+
await client.logout();
|
|
378
|
+
setState({
|
|
379
|
+
user: null,
|
|
380
|
+
loading: false,
|
|
381
|
+
error: null,
|
|
382
|
+
isOnWaitlist: false,
|
|
383
|
+
waitlistPosition: null
|
|
384
|
+
});
|
|
385
|
+
}, [client]);
|
|
386
|
+
return {
|
|
387
|
+
...state,
|
|
388
|
+
login: client.login,
|
|
389
|
+
logout,
|
|
390
|
+
refetch: checkSession
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// src/react/AuthProvider.tsx
|
|
395
|
+
var import_react2 = require("react");
|
|
396
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
397
|
+
var AuthContext = (0, import_react2.createContext)(null);
|
|
398
|
+
function AuthProvider({ config, children }) {
|
|
399
|
+
const auth = useAuth(config);
|
|
400
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AuthContext.Provider, { value: auth, children });
|
|
401
|
+
}
|
|
402
|
+
function useAuthContext() {
|
|
403
|
+
const context = (0, import_react2.useContext)(AuthContext);
|
|
404
|
+
if (!context) {
|
|
405
|
+
throw new Error("useAuthContext must be used within AuthProvider");
|
|
406
|
+
}
|
|
407
|
+
return context;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// src/react/ProtectedRoute.tsx
|
|
411
|
+
var import_react3 = require("react");
|
|
412
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
413
|
+
function ProtectedRoute({
|
|
414
|
+
children,
|
|
415
|
+
fallback = null,
|
|
416
|
+
onUnauthenticated,
|
|
417
|
+
onWaitlist
|
|
418
|
+
}) {
|
|
419
|
+
const { user, loading, isOnWaitlist, login } = useAuthContext();
|
|
420
|
+
(0, import_react3.useEffect)(() => {
|
|
421
|
+
if (!loading && !user) {
|
|
422
|
+
if (onUnauthenticated) {
|
|
423
|
+
onUnauthenticated();
|
|
424
|
+
} else {
|
|
425
|
+
login();
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}, [loading, user, login, onUnauthenticated]);
|
|
429
|
+
(0, import_react3.useEffect)(() => {
|
|
430
|
+
if (!loading && isOnWaitlist && onWaitlist) {
|
|
431
|
+
onWaitlist();
|
|
432
|
+
}
|
|
433
|
+
}, [loading, isOnWaitlist, onWaitlist]);
|
|
434
|
+
if (loading) {
|
|
435
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: fallback });
|
|
436
|
+
}
|
|
437
|
+
if (!user || isOnWaitlist) {
|
|
438
|
+
return null;
|
|
439
|
+
}
|
|
440
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children });
|
|
441
|
+
}
|
|
442
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
443
|
+
0 && (module.exports = {
|
|
444
|
+
AuthProvider,
|
|
445
|
+
ProtectedRoute,
|
|
446
|
+
useAuth,
|
|
447
|
+
useAuthContext
|
|
448
|
+
});
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createReauthClient
|
|
3
|
+
} from "../chunk-JX2J36FS.mjs";
|
|
4
|
+
|
|
5
|
+
// src/react/useAuth.ts
|
|
6
|
+
import { useState, useEffect, useCallback, useMemo } from "react";
|
|
7
|
+
function useAuth(config) {
|
|
8
|
+
const client = useMemo(() => createReauthClient(config), [config.domain]);
|
|
9
|
+
const [state, setState] = useState({
|
|
10
|
+
user: null,
|
|
11
|
+
loading: true,
|
|
12
|
+
error: null,
|
|
13
|
+
isOnWaitlist: false,
|
|
14
|
+
waitlistPosition: null
|
|
15
|
+
});
|
|
16
|
+
const checkSession = useCallback(async () => {
|
|
17
|
+
try {
|
|
18
|
+
let session = await client.getSession();
|
|
19
|
+
if (!session.valid && !session.error_code && !session.end_user_id) {
|
|
20
|
+
const refreshed = await client.refresh();
|
|
21
|
+
if (refreshed) {
|
|
22
|
+
session = await client.getSession();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (session.error_code === "ACCOUNT_SUSPENDED") {
|
|
26
|
+
setState({
|
|
27
|
+
user: null,
|
|
28
|
+
loading: false,
|
|
29
|
+
error: "Account suspended",
|
|
30
|
+
isOnWaitlist: false,
|
|
31
|
+
waitlistPosition: null
|
|
32
|
+
});
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (session.valid && session.waitlist_position) {
|
|
36
|
+
setState({
|
|
37
|
+
user: {
|
|
38
|
+
id: session.end_user_id,
|
|
39
|
+
email: session.email,
|
|
40
|
+
roles: session.roles || []
|
|
41
|
+
},
|
|
42
|
+
loading: false,
|
|
43
|
+
error: null,
|
|
44
|
+
isOnWaitlist: true,
|
|
45
|
+
waitlistPosition: session.waitlist_position
|
|
46
|
+
});
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (session.valid && session.end_user_id) {
|
|
50
|
+
setState({
|
|
51
|
+
user: {
|
|
52
|
+
id: session.end_user_id,
|
|
53
|
+
email: session.email,
|
|
54
|
+
roles: session.roles || []
|
|
55
|
+
},
|
|
56
|
+
loading: false,
|
|
57
|
+
error: null,
|
|
58
|
+
isOnWaitlist: false,
|
|
59
|
+
waitlistPosition: null
|
|
60
|
+
});
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
setState({
|
|
64
|
+
user: null,
|
|
65
|
+
loading: false,
|
|
66
|
+
error: null,
|
|
67
|
+
isOnWaitlist: false,
|
|
68
|
+
waitlistPosition: null
|
|
69
|
+
});
|
|
70
|
+
} catch {
|
|
71
|
+
setState({
|
|
72
|
+
user: null,
|
|
73
|
+
loading: false,
|
|
74
|
+
error: "Auth check failed",
|
|
75
|
+
isOnWaitlist: false,
|
|
76
|
+
waitlistPosition: null
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}, [client]);
|
|
80
|
+
useEffect(() => {
|
|
81
|
+
checkSession();
|
|
82
|
+
}, [checkSession]);
|
|
83
|
+
const logout = useCallback(async () => {
|
|
84
|
+
await client.logout();
|
|
85
|
+
setState({
|
|
86
|
+
user: null,
|
|
87
|
+
loading: false,
|
|
88
|
+
error: null,
|
|
89
|
+
isOnWaitlist: false,
|
|
90
|
+
waitlistPosition: null
|
|
91
|
+
});
|
|
92
|
+
}, [client]);
|
|
93
|
+
return {
|
|
94
|
+
...state,
|
|
95
|
+
login: client.login,
|
|
96
|
+
logout,
|
|
97
|
+
refetch: checkSession
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// src/react/AuthProvider.tsx
|
|
102
|
+
import { createContext, useContext } from "react";
|
|
103
|
+
import { jsx } from "react/jsx-runtime";
|
|
104
|
+
var AuthContext = createContext(null);
|
|
105
|
+
function AuthProvider({ config, children }) {
|
|
106
|
+
const auth = useAuth(config);
|
|
107
|
+
return /* @__PURE__ */ jsx(AuthContext.Provider, { value: auth, children });
|
|
108
|
+
}
|
|
109
|
+
function useAuthContext() {
|
|
110
|
+
const context = useContext(AuthContext);
|
|
111
|
+
if (!context) {
|
|
112
|
+
throw new Error("useAuthContext must be used within AuthProvider");
|
|
113
|
+
}
|
|
114
|
+
return context;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// src/react/ProtectedRoute.tsx
|
|
118
|
+
import { useEffect as useEffect2 } from "react";
|
|
119
|
+
import { Fragment, jsx as jsx2 } from "react/jsx-runtime";
|
|
120
|
+
function ProtectedRoute({
|
|
121
|
+
children,
|
|
122
|
+
fallback = null,
|
|
123
|
+
onUnauthenticated,
|
|
124
|
+
onWaitlist
|
|
125
|
+
}) {
|
|
126
|
+
const { user, loading, isOnWaitlist, login } = useAuthContext();
|
|
127
|
+
useEffect2(() => {
|
|
128
|
+
if (!loading && !user) {
|
|
129
|
+
if (onUnauthenticated) {
|
|
130
|
+
onUnauthenticated();
|
|
131
|
+
} else {
|
|
132
|
+
login();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}, [loading, user, login, onUnauthenticated]);
|
|
136
|
+
useEffect2(() => {
|
|
137
|
+
if (!loading && isOnWaitlist && onWaitlist) {
|
|
138
|
+
onWaitlist();
|
|
139
|
+
}
|
|
140
|
+
}, [loading, isOnWaitlist, onWaitlist]);
|
|
141
|
+
if (loading) {
|
|
142
|
+
return /* @__PURE__ */ jsx2(Fragment, { children: fallback });
|
|
143
|
+
}
|
|
144
|
+
if (!user || isOnWaitlist) {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
return /* @__PURE__ */ jsx2(Fragment, { children });
|
|
148
|
+
}
|
|
149
|
+
export {
|
|
150
|
+
AuthProvider,
|
|
151
|
+
ProtectedRoute,
|
|
152
|
+
useAuth,
|
|
153
|
+
useAuthContext
|
|
154
|
+
};
|