@reauth-dev/sdk 0.1.0 → 0.2.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/dist/index.js CHANGED
@@ -26,9 +26,27 @@ __export(src_exports, {
26
26
  });
27
27
  module.exports = __toCommonJS(src_exports);
28
28
 
29
+ // src/types.ts
30
+ var DEFAULT_TIMEOUT_MS = 1e4;
31
+
29
32
  // src/client.ts
33
+ function assertHttpsUrl(url) {
34
+ let parsed;
35
+ try {
36
+ parsed = new URL(url);
37
+ } catch {
38
+ throw new Error("URL must use HTTPS");
39
+ }
40
+ if (parsed.protocol !== "https:") {
41
+ throw new Error("URL must use HTTPS");
42
+ }
43
+ }
30
44
  function createReauthClient(config) {
31
45
  const { domain } = config;
46
+ if (config.timeout !== void 0 && (!Number.isFinite(config.timeout) || config.timeout <= 0)) {
47
+ throw new Error("timeout must be a positive finite number in milliseconds");
48
+ }
49
+ const timeoutMs = config.timeout ?? DEFAULT_TIMEOUT_MS;
32
50
  const baseUrl = `https://reauth.${domain}/api/public`;
33
51
  return {
34
52
  /**
@@ -47,35 +65,47 @@ function createReauthClient(config) {
47
65
  */
48
66
  async getSession() {
49
67
  const res = await fetch(`${baseUrl}/auth/session`, {
50
- credentials: "include"
68
+ credentials: "include",
69
+ signal: AbortSignal.timeout(timeoutMs)
51
70
  });
71
+ if (!res.ok) {
72
+ throw new Error(`Failed to get session: ${res.status}`);
73
+ }
52
74
  return res.json();
53
75
  },
54
76
  /**
55
77
  * Refresh the access token using the refresh token.
56
78
  * Call this when getSession() returns valid: false but no error_code.
57
- * @returns true if refresh succeeded, false otherwise
79
+ * @throws Error on failed refresh (401) or server error
58
80
  */
59
81
  async refresh() {
60
82
  const res = await fetch(`${baseUrl}/auth/refresh`, {
61
83
  method: "POST",
62
- credentials: "include"
84
+ credentials: "include",
85
+ signal: AbortSignal.timeout(timeoutMs)
63
86
  });
64
- return res.ok;
87
+ if (!res.ok) {
88
+ throw new Error(`Failed to refresh: ${res.status}`);
89
+ }
65
90
  },
66
91
  /**
67
92
  * Get an access token for Bearer authentication.
68
93
  * Use this when calling your own API that uses local token verification.
69
94
  *
70
- * @returns TokenResponse with access token, or null if not authenticated
95
+ * @returns TokenResponse with access token, or null if not authenticated or network unreachable
96
+ * @throws Error on server errors (non-401 HTTP status codes) or request timeout
71
97
  *
72
98
  * @example
73
99
  * ```typescript
74
- * const tokenResponse = await reauth.getToken();
75
- * if (tokenResponse) {
76
- * fetch('/api/data', {
77
- * headers: { Authorization: `Bearer ${tokenResponse.accessToken}` }
78
- * });
100
+ * try {
101
+ * const tokenResponse = await reauth.getToken();
102
+ * if (tokenResponse) {
103
+ * fetch('/api/data', {
104
+ * headers: { Authorization: `Bearer ${tokenResponse.accessToken}` }
105
+ * });
106
+ * }
107
+ * } catch (err) {
108
+ * // Server error or timeout — do not log the user out
79
109
  * }
80
110
  * ```
81
111
  */
@@ -83,7 +113,8 @@ function createReauthClient(config) {
83
113
  try {
84
114
  const res = await fetch(`${baseUrl}/auth/token`, {
85
115
  method: "GET",
86
- credentials: "include"
116
+ credentials: "include",
117
+ signal: AbortSignal.timeout(timeoutMs)
87
118
  });
88
119
  if (!res.ok) {
89
120
  if (res.status === 401) return null;
@@ -95,29 +126,38 @@ function createReauthClient(config) {
95
126
  expiresIn: data.expires_in,
96
127
  tokenType: data.token_type
97
128
  };
98
- } catch {
99
- return null;
129
+ } catch (err) {
130
+ if (err instanceof TypeError) return null;
131
+ throw err;
100
132
  }
101
133
  },
102
134
  /**
103
135
  * Log out the user by clearing all session cookies.
136
+ * @throws Error on server error
104
137
  */
105
138
  async logout() {
106
- await fetch(`${baseUrl}/auth/logout`, {
139
+ const res = await fetch(`${baseUrl}/auth/logout`, {
107
140
  method: "POST",
108
- credentials: "include"
141
+ credentials: "include",
142
+ signal: AbortSignal.timeout(timeoutMs)
109
143
  });
144
+ if (!res.ok) {
145
+ throw new Error(`Failed to logout: ${res.status}`);
146
+ }
110
147
  },
111
148
  /**
112
149
  * Delete the user's own account (self-service).
113
- * @returns true if deletion succeeded, false otherwise
150
+ * @throws Error on permission denied or server error
114
151
  */
115
152
  async deleteAccount() {
116
153
  const res = await fetch(`${baseUrl}/auth/account`, {
117
154
  method: "DELETE",
118
- credentials: "include"
155
+ credentials: "include",
156
+ signal: AbortSignal.timeout(timeoutMs)
119
157
  });
120
- return res.ok;
158
+ if (!res.ok) {
159
+ throw new Error(`Failed to delete account: ${res.status}`);
160
+ }
121
161
  },
122
162
  // ========================================================================
123
163
  // Billing Methods
@@ -125,12 +165,16 @@ function createReauthClient(config) {
125
165
  /**
126
166
  * Get available subscription plans for the domain.
127
167
  * Only returns public plans sorted by display order.
168
+ * @throws Error on server error
128
169
  */
129
170
  async getPlans() {
130
171
  const res = await fetch(`${baseUrl}/billing/plans`, {
131
- credentials: "include"
172
+ credentials: "include",
173
+ signal: AbortSignal.timeout(timeoutMs)
132
174
  });
133
- if (!res.ok) return [];
175
+ if (!res.ok) {
176
+ throw new Error(`Failed to get plans: ${res.status}`);
177
+ }
134
178
  const data = await res.json();
135
179
  return data.map(
136
180
  (p) => ({
@@ -143,8 +187,17 @@ function createReauthClient(config) {
143
187
  interval: p.interval,
144
188
  intervalCount: p.interval_count,
145
189
  trialDays: p.trial_days,
146
- features: p.features,
147
- displayOrder: p.display_order
190
+ features: p.features.map((f) => ({
191
+ code: f.code,
192
+ name: f.name,
193
+ featureType: f.feature_type,
194
+ numericValue: f.numeric_value,
195
+ unitLabel: f.unit_label
196
+ })),
197
+ displayOrder: p.display_order,
198
+ creditsAmount: p.credits_amount,
199
+ planType: p.plan_type,
200
+ contactUrl: p.contact_url
148
201
  })
149
202
  );
150
203
  },
@@ -153,8 +206,12 @@ function createReauthClient(config) {
153
206
  */
154
207
  async getSubscription() {
155
208
  const res = await fetch(`${baseUrl}/billing/subscription`, {
156
- credentials: "include"
209
+ credentials: "include",
210
+ signal: AbortSignal.timeout(timeoutMs)
157
211
  });
212
+ if (!res.ok) {
213
+ throw new Error(`Failed to get subscription: ${res.status}`);
214
+ }
158
215
  const data = await res.json();
159
216
  return {
160
217
  id: data.id,
@@ -178,6 +235,7 @@ function createReauthClient(config) {
178
235
  method: "POST",
179
236
  headers: { "Content-Type": "application/json" },
180
237
  credentials: "include",
238
+ signal: AbortSignal.timeout(timeoutMs),
181
239
  body: JSON.stringify({
182
240
  plan_code: planCode,
183
241
  success_url: successUrl,
@@ -206,6 +264,7 @@ function createReauthClient(config) {
206
264
  currentUrl,
207
265
  currentUrl
208
266
  );
267
+ assertHttpsUrl(checkoutUrl);
209
268
  window.location.href = checkoutUrl;
210
269
  },
211
270
  /**
@@ -220,6 +279,7 @@ function createReauthClient(config) {
220
279
  method: "POST",
221
280
  headers: { "Content-Type": "application/json" },
222
281
  credentials: "include",
282
+ signal: AbortSignal.timeout(timeoutMs),
223
283
  body: JSON.stringify({
224
284
  return_url: returnUrl || window.location.href
225
285
  })
@@ -228,18 +288,22 @@ function createReauthClient(config) {
228
288
  throw new Error("Failed to open billing portal");
229
289
  }
230
290
  const data = await res.json();
291
+ assertHttpsUrl(data.portal_url);
231
292
  window.location.href = data.portal_url;
232
293
  },
233
294
  /**
234
295
  * Cancel the user's subscription at period end.
235
- * @returns true if cancellation succeeded
296
+ * @throws Error on failure or server error
236
297
  */
237
298
  async cancelSubscription() {
238
299
  const res = await fetch(`${baseUrl}/billing/cancel`, {
239
300
  method: "POST",
240
- credentials: "include"
301
+ credentials: "include",
302
+ signal: AbortSignal.timeout(timeoutMs)
241
303
  });
242
- return res.ok;
304
+ if (!res.ok) {
305
+ throw new Error(`Failed to cancel subscription: ${res.status}`);
306
+ }
243
307
  },
244
308
  // ========================================================================
245
309
  // Balance Methods
@@ -250,13 +314,15 @@ function createReauthClient(config) {
250
314
  */
251
315
  async getBalance() {
252
316
  const res = await fetch(`${baseUrl}/balance`, {
253
- credentials: "include"
317
+ credentials: "include",
318
+ signal: AbortSignal.timeout(timeoutMs)
254
319
  });
255
320
  if (!res.ok) {
256
321
  if (res.status === 401) throw new Error("Not authenticated");
257
322
  throw new Error(`Failed to get balance: ${res.status}`);
258
323
  }
259
- return res.json();
324
+ const data = await res.json();
325
+ return { balance: data.balance };
260
326
  },
261
327
  /**
262
328
  * Get the current user's balance transaction history.
@@ -270,7 +336,7 @@ function createReauthClient(config) {
270
336
  const qs = params.toString();
271
337
  const res = await fetch(
272
338
  `${baseUrl}/balance/transactions${qs ? `?${qs}` : ""}`,
273
- { credentials: "include" }
339
+ { credentials: "include", signal: AbortSignal.timeout(timeoutMs) }
274
340
  );
275
341
  if (!res.ok) {
276
342
  if (res.status === 401) throw new Error("Not authenticated");
package/dist/index.mjs CHANGED
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  createReauthClient
3
- } from "./chunk-JX2J36FS.mjs";
3
+ } from "./chunk-DMNMTW2C.mjs";
4
+ import "./chunk-EY5LQCDG.mjs";
4
5
 
5
6
  // src/errors.ts
6
7
  var ReauthErrorCode = /* @__PURE__ */ ((ReauthErrorCode2) => {
@@ -1,14 +1,24 @@
1
- import { R as ReauthConfig, c as User } from '../types-D8oOYbeC.mjs';
1
+ import { R as ReauthConfig, c as User } from '../types-BqZzje-y.mjs';
2
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
3
3
  import { ReactNode } from 'react';
4
4
 
5
+ type UseAuthOptions = ReauthConfig & {
6
+ /**
7
+ * Interval in milliseconds to refresh the session. Set to 0 to disable.
8
+ * Default: 5 minutes (300000ms)
9
+ */
10
+ refreshInterval?: number;
11
+ };
5
12
  /**
6
13
  * React hook for authentication state management.
7
14
  *
8
15
  * @example
9
16
  * ```typescript
10
17
  * function MyComponent() {
11
- * const { user, loading, login, logout } = useAuth({ domain: 'yourdomain.com' });
18
+ * const { user, loading, login, logout } = useAuth({
19
+ * domain: 'yourdomain.com',
20
+ * refreshInterval: 60000, // Refresh every minute (optional, default: 5 min)
21
+ * });
12
22
  *
13
23
  * if (loading) return <div>Loading...</div>;
14
24
  * if (!user) return <button onClick={login}>Sign in</button>;
@@ -22,7 +32,7 @@ import { ReactNode } from 'react';
22
32
  * }
23
33
  * ```
24
34
  */
25
- declare function useAuth(config: ReauthConfig): {
35
+ declare function useAuth(config: UseAuthOptions): {
26
36
  login: () => void;
27
37
  logout: () => Promise<void>;
28
38
  refetch: () => Promise<void>;
@@ -44,7 +54,7 @@ type AuthContextType = {
44
54
  refetch: () => Promise<void>;
45
55
  };
46
56
  type AuthProviderProps = {
47
- config: ReauthConfig;
57
+ config: UseAuthOptions;
48
58
  children: ReactNode;
49
59
  };
50
60
  /**
@@ -120,4 +130,4 @@ type ProtectedRouteProps = {
120
130
  */
121
131
  declare function ProtectedRoute({ children, fallback, onUnauthenticated, onWaitlist, }: ProtectedRouteProps): react_jsx_runtime.JSX.Element | null;
122
132
 
123
- export { AuthProvider, ProtectedRoute, useAuth, useAuthContext };
133
+ export { AuthProvider, ProtectedRoute, type UseAuthOptions, useAuth, useAuthContext };
@@ -1,14 +1,24 @@
1
- import { R as ReauthConfig, c as User } from '../types-D8oOYbeC.js';
1
+ import { R as ReauthConfig, c as User } from '../types-BqZzje-y.js';
2
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
3
3
  import { ReactNode } from 'react';
4
4
 
5
+ type UseAuthOptions = ReauthConfig & {
6
+ /**
7
+ * Interval in milliseconds to refresh the session. Set to 0 to disable.
8
+ * Default: 5 minutes (300000ms)
9
+ */
10
+ refreshInterval?: number;
11
+ };
5
12
  /**
6
13
  * React hook for authentication state management.
7
14
  *
8
15
  * @example
9
16
  * ```typescript
10
17
  * function MyComponent() {
11
- * const { user, loading, login, logout } = useAuth({ domain: 'yourdomain.com' });
18
+ * const { user, loading, login, logout } = useAuth({
19
+ * domain: 'yourdomain.com',
20
+ * refreshInterval: 60000, // Refresh every minute (optional, default: 5 min)
21
+ * });
12
22
  *
13
23
  * if (loading) return <div>Loading...</div>;
14
24
  * if (!user) return <button onClick={login}>Sign in</button>;
@@ -22,7 +32,7 @@ import { ReactNode } from 'react';
22
32
  * }
23
33
  * ```
24
34
  */
25
- declare function useAuth(config: ReauthConfig): {
35
+ declare function useAuth(config: UseAuthOptions): {
26
36
  login: () => void;
27
37
  logout: () => Promise<void>;
28
38
  refetch: () => Promise<void>;
@@ -44,7 +54,7 @@ type AuthContextType = {
44
54
  refetch: () => Promise<void>;
45
55
  };
46
56
  type AuthProviderProps = {
47
- config: ReauthConfig;
57
+ config: UseAuthOptions;
48
58
  children: ReactNode;
49
59
  };
50
60
  /**
@@ -120,4 +130,4 @@ type ProtectedRouteProps = {
120
130
  */
121
131
  declare function ProtectedRoute({ children, fallback, onUnauthenticated, onWaitlist, }: ProtectedRouteProps): react_jsx_runtime.JSX.Element | null;
122
132
 
123
- export { AuthProvider, ProtectedRoute, useAuth, useAuthContext };
133
+ export { AuthProvider, ProtectedRoute, type UseAuthOptions, useAuth, useAuthContext };