@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.
@@ -1,6 +1,25 @@
1
+ import {
2
+ DEFAULT_TIMEOUT_MS
3
+ } from "./chunk-EY5LQCDG.mjs";
4
+
1
5
  // src/client.ts
6
+ function assertHttpsUrl(url) {
7
+ let parsed;
8
+ try {
9
+ parsed = new URL(url);
10
+ } catch {
11
+ throw new Error("URL must use HTTPS");
12
+ }
13
+ if (parsed.protocol !== "https:") {
14
+ throw new Error("URL must use HTTPS");
15
+ }
16
+ }
2
17
  function createReauthClient(config) {
3
18
  const { domain } = config;
19
+ if (config.timeout !== void 0 && (!Number.isFinite(config.timeout) || config.timeout <= 0)) {
20
+ throw new Error("timeout must be a positive finite number in milliseconds");
21
+ }
22
+ const timeoutMs = config.timeout ?? DEFAULT_TIMEOUT_MS;
4
23
  const baseUrl = `https://reauth.${domain}/api/public`;
5
24
  return {
6
25
  /**
@@ -19,35 +38,47 @@ function createReauthClient(config) {
19
38
  */
20
39
  async getSession() {
21
40
  const res = await fetch(`${baseUrl}/auth/session`, {
22
- credentials: "include"
41
+ credentials: "include",
42
+ signal: AbortSignal.timeout(timeoutMs)
23
43
  });
44
+ if (!res.ok) {
45
+ throw new Error(`Failed to get session: ${res.status}`);
46
+ }
24
47
  return res.json();
25
48
  },
26
49
  /**
27
50
  * Refresh the access token using the refresh token.
28
51
  * Call this when getSession() returns valid: false but no error_code.
29
- * @returns true if refresh succeeded, false otherwise
52
+ * @throws Error on failed refresh (401) or server error
30
53
  */
31
54
  async refresh() {
32
55
  const res = await fetch(`${baseUrl}/auth/refresh`, {
33
56
  method: "POST",
34
- credentials: "include"
57
+ credentials: "include",
58
+ signal: AbortSignal.timeout(timeoutMs)
35
59
  });
36
- return res.ok;
60
+ if (!res.ok) {
61
+ throw new Error(`Failed to refresh: ${res.status}`);
62
+ }
37
63
  },
38
64
  /**
39
65
  * Get an access token for Bearer authentication.
40
66
  * Use this when calling your own API that uses local token verification.
41
67
  *
42
- * @returns TokenResponse with access token, or null if not authenticated
68
+ * @returns TokenResponse with access token, or null if not authenticated or network unreachable
69
+ * @throws Error on server errors (non-401 HTTP status codes) or request timeout
43
70
  *
44
71
  * @example
45
72
  * ```typescript
46
- * const tokenResponse = await reauth.getToken();
47
- * if (tokenResponse) {
48
- * fetch('/api/data', {
49
- * headers: { Authorization: `Bearer ${tokenResponse.accessToken}` }
50
- * });
73
+ * try {
74
+ * const tokenResponse = await reauth.getToken();
75
+ * if (tokenResponse) {
76
+ * fetch('/api/data', {
77
+ * headers: { Authorization: `Bearer ${tokenResponse.accessToken}` }
78
+ * });
79
+ * }
80
+ * } catch (err) {
81
+ * // Server error or timeout — do not log the user out
51
82
  * }
52
83
  * ```
53
84
  */
@@ -55,7 +86,8 @@ function createReauthClient(config) {
55
86
  try {
56
87
  const res = await fetch(`${baseUrl}/auth/token`, {
57
88
  method: "GET",
58
- credentials: "include"
89
+ credentials: "include",
90
+ signal: AbortSignal.timeout(timeoutMs)
59
91
  });
60
92
  if (!res.ok) {
61
93
  if (res.status === 401) return null;
@@ -67,29 +99,38 @@ function createReauthClient(config) {
67
99
  expiresIn: data.expires_in,
68
100
  tokenType: data.token_type
69
101
  };
70
- } catch {
71
- return null;
102
+ } catch (err) {
103
+ if (err instanceof TypeError) return null;
104
+ throw err;
72
105
  }
73
106
  },
74
107
  /**
75
108
  * Log out the user by clearing all session cookies.
109
+ * @throws Error on server error
76
110
  */
77
111
  async logout() {
78
- await fetch(`${baseUrl}/auth/logout`, {
112
+ const res = await fetch(`${baseUrl}/auth/logout`, {
79
113
  method: "POST",
80
- credentials: "include"
114
+ credentials: "include",
115
+ signal: AbortSignal.timeout(timeoutMs)
81
116
  });
117
+ if (!res.ok) {
118
+ throw new Error(`Failed to logout: ${res.status}`);
119
+ }
82
120
  },
83
121
  /**
84
122
  * Delete the user's own account (self-service).
85
- * @returns true if deletion succeeded, false otherwise
123
+ * @throws Error on permission denied or server error
86
124
  */
87
125
  async deleteAccount() {
88
126
  const res = await fetch(`${baseUrl}/auth/account`, {
89
127
  method: "DELETE",
90
- credentials: "include"
128
+ credentials: "include",
129
+ signal: AbortSignal.timeout(timeoutMs)
91
130
  });
92
- return res.ok;
131
+ if (!res.ok) {
132
+ throw new Error(`Failed to delete account: ${res.status}`);
133
+ }
93
134
  },
94
135
  // ========================================================================
95
136
  // Billing Methods
@@ -97,12 +138,16 @@ function createReauthClient(config) {
97
138
  /**
98
139
  * Get available subscription plans for the domain.
99
140
  * Only returns public plans sorted by display order.
141
+ * @throws Error on server error
100
142
  */
101
143
  async getPlans() {
102
144
  const res = await fetch(`${baseUrl}/billing/plans`, {
103
- credentials: "include"
145
+ credentials: "include",
146
+ signal: AbortSignal.timeout(timeoutMs)
104
147
  });
105
- if (!res.ok) return [];
148
+ if (!res.ok) {
149
+ throw new Error(`Failed to get plans: ${res.status}`);
150
+ }
106
151
  const data = await res.json();
107
152
  return data.map(
108
153
  (p) => ({
@@ -115,8 +160,17 @@ function createReauthClient(config) {
115
160
  interval: p.interval,
116
161
  intervalCount: p.interval_count,
117
162
  trialDays: p.trial_days,
118
- features: p.features,
119
- displayOrder: p.display_order
163
+ features: p.features.map((f) => ({
164
+ code: f.code,
165
+ name: f.name,
166
+ featureType: f.feature_type,
167
+ numericValue: f.numeric_value,
168
+ unitLabel: f.unit_label
169
+ })),
170
+ displayOrder: p.display_order,
171
+ creditsAmount: p.credits_amount,
172
+ planType: p.plan_type,
173
+ contactUrl: p.contact_url
120
174
  })
121
175
  );
122
176
  },
@@ -125,8 +179,12 @@ function createReauthClient(config) {
125
179
  */
126
180
  async getSubscription() {
127
181
  const res = await fetch(`${baseUrl}/billing/subscription`, {
128
- credentials: "include"
182
+ credentials: "include",
183
+ signal: AbortSignal.timeout(timeoutMs)
129
184
  });
185
+ if (!res.ok) {
186
+ throw new Error(`Failed to get subscription: ${res.status}`);
187
+ }
130
188
  const data = await res.json();
131
189
  return {
132
190
  id: data.id,
@@ -150,6 +208,7 @@ function createReauthClient(config) {
150
208
  method: "POST",
151
209
  headers: { "Content-Type": "application/json" },
152
210
  credentials: "include",
211
+ signal: AbortSignal.timeout(timeoutMs),
153
212
  body: JSON.stringify({
154
213
  plan_code: planCode,
155
214
  success_url: successUrl,
@@ -178,6 +237,7 @@ function createReauthClient(config) {
178
237
  currentUrl,
179
238
  currentUrl
180
239
  );
240
+ assertHttpsUrl(checkoutUrl);
181
241
  window.location.href = checkoutUrl;
182
242
  },
183
243
  /**
@@ -192,6 +252,7 @@ function createReauthClient(config) {
192
252
  method: "POST",
193
253
  headers: { "Content-Type": "application/json" },
194
254
  credentials: "include",
255
+ signal: AbortSignal.timeout(timeoutMs),
195
256
  body: JSON.stringify({
196
257
  return_url: returnUrl || window.location.href
197
258
  })
@@ -200,18 +261,22 @@ function createReauthClient(config) {
200
261
  throw new Error("Failed to open billing portal");
201
262
  }
202
263
  const data = await res.json();
264
+ assertHttpsUrl(data.portal_url);
203
265
  window.location.href = data.portal_url;
204
266
  },
205
267
  /**
206
268
  * Cancel the user's subscription at period end.
207
- * @returns true if cancellation succeeded
269
+ * @throws Error on failure or server error
208
270
  */
209
271
  async cancelSubscription() {
210
272
  const res = await fetch(`${baseUrl}/billing/cancel`, {
211
273
  method: "POST",
212
- credentials: "include"
274
+ credentials: "include",
275
+ signal: AbortSignal.timeout(timeoutMs)
213
276
  });
214
- return res.ok;
277
+ if (!res.ok) {
278
+ throw new Error(`Failed to cancel subscription: ${res.status}`);
279
+ }
215
280
  },
216
281
  // ========================================================================
217
282
  // Balance Methods
@@ -222,13 +287,15 @@ function createReauthClient(config) {
222
287
  */
223
288
  async getBalance() {
224
289
  const res = await fetch(`${baseUrl}/balance`, {
225
- credentials: "include"
290
+ credentials: "include",
291
+ signal: AbortSignal.timeout(timeoutMs)
226
292
  });
227
293
  if (!res.ok) {
228
294
  if (res.status === 401) throw new Error("Not authenticated");
229
295
  throw new Error(`Failed to get balance: ${res.status}`);
230
296
  }
231
- return res.json();
297
+ const data = await res.json();
298
+ return { balance: data.balance };
232
299
  },
233
300
  /**
234
301
  * Get the current user's balance transaction history.
@@ -242,7 +309,7 @@ function createReauthClient(config) {
242
309
  const qs = params.toString();
243
310
  const res = await fetch(
244
311
  `${baseUrl}/balance/transactions${qs ? `?${qs}` : ""}`,
245
- { credentials: "include" }
312
+ { credentials: "include", signal: AbortSignal.timeout(timeoutMs) }
246
313
  );
247
314
  if (!res.ok) {
248
315
  if (res.status === 401) throw new Error("Not authenticated");
@@ -0,0 +1,6 @@
1
+ // src/types.ts
2
+ var DEFAULT_TIMEOUT_MS = 1e4;
3
+
4
+ export {
5
+ DEFAULT_TIMEOUT_MS
6
+ };
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { R as ReauthConfig, a as ReauthSession, T as TokenResponse, S as SubscriptionPlan, U as UserSubscription, C as CheckoutSession, b as TransactionsPaginationOptions, B as BalanceTransaction } from './types-D8oOYbeC.mjs';
2
- export { A as AuthResult, h as ChargeOptions, i as DepositOptions, D as DomainEndUserClaims, e as ReauthServerConfig, f as RequestLike, g as SubscriptionInfo, c as User, d as UserDetails } from './types-D8oOYbeC.mjs';
1
+ import { R as ReauthConfig, a as ReauthSession, T as TokenResponse, S as SubscriptionPlan, U as UserSubscription, C as CheckoutSession, b as TransactionsPaginationOptions, B as BalanceTransaction } from './types-BqZzje-y.mjs';
2
+ export { A as AuthResult, h as ChargeOptions, i as DepositOptions, D as DomainEndUserClaims, P as PlanFeature, e as ReauthServerConfig, f as RequestLike, g as SubscriptionInfo, c as User, d as UserDetails } from './types-BqZzje-y.mjs';
3
3
 
4
4
  /**
5
5
  * Create a reauth client for browser-side authentication.
@@ -32,38 +32,45 @@ declare function createReauthClient(config: ReauthConfig): {
32
32
  /**
33
33
  * Refresh the access token using the refresh token.
34
34
  * Call this when getSession() returns valid: false but no error_code.
35
- * @returns true if refresh succeeded, false otherwise
35
+ * @throws Error on failed refresh (401) or server error
36
36
  */
37
- refresh(): Promise<boolean>;
37
+ refresh(): Promise<void>;
38
38
  /**
39
39
  * Get an access token for Bearer authentication.
40
40
  * Use this when calling your own API that uses local token verification.
41
41
  *
42
- * @returns TokenResponse with access token, or null if not authenticated
42
+ * @returns TokenResponse with access token, or null if not authenticated or network unreachable
43
+ * @throws Error on server errors (non-401 HTTP status codes) or request timeout
43
44
  *
44
45
  * @example
45
46
  * ```typescript
46
- * const tokenResponse = await reauth.getToken();
47
- * if (tokenResponse) {
48
- * fetch('/api/data', {
49
- * headers: { Authorization: `Bearer ${tokenResponse.accessToken}` }
50
- * });
47
+ * try {
48
+ * const tokenResponse = await reauth.getToken();
49
+ * if (tokenResponse) {
50
+ * fetch('/api/data', {
51
+ * headers: { Authorization: `Bearer ${tokenResponse.accessToken}` }
52
+ * });
53
+ * }
54
+ * } catch (err) {
55
+ * // Server error or timeout — do not log the user out
51
56
  * }
52
57
  * ```
53
58
  */
54
59
  getToken(): Promise<TokenResponse | null>;
55
60
  /**
56
61
  * Log out the user by clearing all session cookies.
62
+ * @throws Error on server error
57
63
  */
58
64
  logout(): Promise<void>;
59
65
  /**
60
66
  * Delete the user's own account (self-service).
61
- * @returns true if deletion succeeded, false otherwise
67
+ * @throws Error on permission denied or server error
62
68
  */
63
- deleteAccount(): Promise<boolean>;
69
+ deleteAccount(): Promise<void>;
64
70
  /**
65
71
  * Get available subscription plans for the domain.
66
72
  * Only returns public plans sorted by display order.
73
+ * @throws Error on server error
67
74
  */
68
75
  getPlans(): Promise<SubscriptionPlan[]>;
69
76
  /**
@@ -91,9 +98,9 @@ declare function createReauthClient(config: ReauthConfig): {
91
98
  openBillingPortal(returnUrl?: string): Promise<void>;
92
99
  /**
93
100
  * Cancel the user's subscription at period end.
94
- * @returns true if cancellation succeeded
101
+ * @throws Error on failure or server error
95
102
  */
96
- cancelSubscription(): Promise<boolean>;
103
+ cancelSubscription(): Promise<void>;
97
104
  /**
98
105
  * Get the current user's balance.
99
106
  * @returns Object with the current balance
@@ -124,4 +131,4 @@ type ReauthError = {
124
131
  };
125
132
  declare function requiresOAuthRestart(error: ReauthError | null | undefined): boolean;
126
133
 
127
- export { BalanceTransaction, type ReauthClient, ReauthConfig, type ReauthError, ReauthErrorCode, ReauthSession, TokenResponse, TransactionsPaginationOptions, createReauthClient, requiresOAuthRestart };
134
+ export { BalanceTransaction, type ReauthClient, ReauthConfig, type ReauthError, ReauthErrorCode, ReauthSession, SubscriptionPlan, TokenResponse, TransactionsPaginationOptions, createReauthClient, requiresOAuthRestart };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { R as ReauthConfig, a as ReauthSession, T as TokenResponse, S as SubscriptionPlan, U as UserSubscription, C as CheckoutSession, b as TransactionsPaginationOptions, B as BalanceTransaction } from './types-D8oOYbeC.js';
2
- export { A as AuthResult, h as ChargeOptions, i as DepositOptions, D as DomainEndUserClaims, e as ReauthServerConfig, f as RequestLike, g as SubscriptionInfo, c as User, d as UserDetails } from './types-D8oOYbeC.js';
1
+ import { R as ReauthConfig, a as ReauthSession, T as TokenResponse, S as SubscriptionPlan, U as UserSubscription, C as CheckoutSession, b as TransactionsPaginationOptions, B as BalanceTransaction } from './types-BqZzje-y.js';
2
+ export { A as AuthResult, h as ChargeOptions, i as DepositOptions, D as DomainEndUserClaims, P as PlanFeature, e as ReauthServerConfig, f as RequestLike, g as SubscriptionInfo, c as User, d as UserDetails } from './types-BqZzje-y.js';
3
3
 
4
4
  /**
5
5
  * Create a reauth client for browser-side authentication.
@@ -32,38 +32,45 @@ declare function createReauthClient(config: ReauthConfig): {
32
32
  /**
33
33
  * Refresh the access token using the refresh token.
34
34
  * Call this when getSession() returns valid: false but no error_code.
35
- * @returns true if refresh succeeded, false otherwise
35
+ * @throws Error on failed refresh (401) or server error
36
36
  */
37
- refresh(): Promise<boolean>;
37
+ refresh(): Promise<void>;
38
38
  /**
39
39
  * Get an access token for Bearer authentication.
40
40
  * Use this when calling your own API that uses local token verification.
41
41
  *
42
- * @returns TokenResponse with access token, or null if not authenticated
42
+ * @returns TokenResponse with access token, or null if not authenticated or network unreachable
43
+ * @throws Error on server errors (non-401 HTTP status codes) or request timeout
43
44
  *
44
45
  * @example
45
46
  * ```typescript
46
- * const tokenResponse = await reauth.getToken();
47
- * if (tokenResponse) {
48
- * fetch('/api/data', {
49
- * headers: { Authorization: `Bearer ${tokenResponse.accessToken}` }
50
- * });
47
+ * try {
48
+ * const tokenResponse = await reauth.getToken();
49
+ * if (tokenResponse) {
50
+ * fetch('/api/data', {
51
+ * headers: { Authorization: `Bearer ${tokenResponse.accessToken}` }
52
+ * });
53
+ * }
54
+ * } catch (err) {
55
+ * // Server error or timeout — do not log the user out
51
56
  * }
52
57
  * ```
53
58
  */
54
59
  getToken(): Promise<TokenResponse | null>;
55
60
  /**
56
61
  * Log out the user by clearing all session cookies.
62
+ * @throws Error on server error
57
63
  */
58
64
  logout(): Promise<void>;
59
65
  /**
60
66
  * Delete the user's own account (self-service).
61
- * @returns true if deletion succeeded, false otherwise
67
+ * @throws Error on permission denied or server error
62
68
  */
63
- deleteAccount(): Promise<boolean>;
69
+ deleteAccount(): Promise<void>;
64
70
  /**
65
71
  * Get available subscription plans for the domain.
66
72
  * Only returns public plans sorted by display order.
73
+ * @throws Error on server error
67
74
  */
68
75
  getPlans(): Promise<SubscriptionPlan[]>;
69
76
  /**
@@ -91,9 +98,9 @@ declare function createReauthClient(config: ReauthConfig): {
91
98
  openBillingPortal(returnUrl?: string): Promise<void>;
92
99
  /**
93
100
  * Cancel the user's subscription at period end.
94
- * @returns true if cancellation succeeded
101
+ * @throws Error on failure or server error
95
102
  */
96
- cancelSubscription(): Promise<boolean>;
103
+ cancelSubscription(): Promise<void>;
97
104
  /**
98
105
  * Get the current user's balance.
99
106
  * @returns Object with the current balance
@@ -124,4 +131,4 @@ type ReauthError = {
124
131
  };
125
132
  declare function requiresOAuthRestart(error: ReauthError | null | undefined): boolean;
126
133
 
127
- export { BalanceTransaction, type ReauthClient, ReauthConfig, type ReauthError, ReauthErrorCode, ReauthSession, TokenResponse, TransactionsPaginationOptions, createReauthClient, requiresOAuthRestart };
134
+ export { BalanceTransaction, type ReauthClient, ReauthConfig, type ReauthError, ReauthErrorCode, ReauthSession, SubscriptionPlan, TokenResponse, TransactionsPaginationOptions, createReauthClient, requiresOAuthRestart };