@reauth-dev/sdk 0.1.0 → 0.3.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/webhooks.js CHANGED
@@ -43,11 +43,15 @@ function parseSignatureHeader(header) {
43
43
  let timestamp = "";
44
44
  const signatures = [];
45
45
  for (const part of parts) {
46
- const [key, value] = part.split("=", 2);
46
+ const [rawKey, rawValue] = part.trim().split("=", 2);
47
+ const key = rawKey?.trim();
48
+ const value = rawValue?.trim();
47
49
  if (key === "t") {
48
- timestamp = value;
50
+ timestamp = value ?? "";
49
51
  } else if (key === "v1") {
50
- signatures.push(value);
52
+ if (value) {
53
+ signatures.push(value);
54
+ }
51
55
  }
52
56
  }
53
57
  return { timestamp, signatures };
package/dist/webhooks.mjs CHANGED
@@ -15,11 +15,15 @@ function parseSignatureHeader(header) {
15
15
  let timestamp = "";
16
16
  const signatures = [];
17
17
  for (const part of parts) {
18
- const [key, value] = part.split("=", 2);
18
+ const [rawKey, rawValue] = part.trim().split("=", 2);
19
+ const key = rawKey?.trim();
20
+ const value = rawValue?.trim();
19
21
  if (key === "t") {
20
- timestamp = value;
22
+ timestamp = value ?? "";
21
23
  } else if (key === "v1") {
22
- signatures.push(value);
24
+ if (value) {
25
+ signatures.push(value);
26
+ }
23
27
  }
24
28
  }
25
29
  return { timestamp, signatures };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reauth-dev/sdk",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "TypeScript SDK for reauth.dev authentication",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -38,6 +38,8 @@
38
38
  "scripts": {
39
39
  "build": "tsup",
40
40
  "dev": "tsup --watch",
41
+ "test": "vitest run",
42
+ "test:watch": "vitest",
41
43
  "typecheck": "tsc --noEmit",
42
44
  "format": "prettier --write src"
43
45
  },
@@ -58,7 +60,8 @@
58
60
  "prettier": "^3.8.1",
59
61
  "react": "^18.0.0",
60
62
  "tsup": "^8.0.0",
61
- "typescript": "^5.0.0"
63
+ "typescript": "^5.0.0",
64
+ "vitest": "^4.0.18"
62
65
  },
63
66
  "keywords": [
64
67
  "auth",
@@ -1,269 +0,0 @@
1
- // src/client.ts
2
- function createReauthClient(config) {
3
- const { domain } = config;
4
- const baseUrl = `https://reauth.${domain}/api/public`;
5
- return {
6
- /**
7
- * Redirect the user to the reauth.dev login page.
8
- * After successful login, they'll be redirected back to your configured redirect URL.
9
- */
10
- login() {
11
- if (typeof window === "undefined") {
12
- throw new Error("login() can only be called in browser");
13
- }
14
- window.location.href = `https://reauth.${domain}/`;
15
- },
16
- /**
17
- * Check if the user is authenticated.
18
- * Returns session info including user ID, email, and roles.
19
- */
20
- async getSession() {
21
- const res = await fetch(`${baseUrl}/auth/session`, {
22
- credentials: "include"
23
- });
24
- return res.json();
25
- },
26
- /**
27
- * Refresh the access token using the refresh token.
28
- * Call this when getSession() returns valid: false but no error_code.
29
- * @returns true if refresh succeeded, false otherwise
30
- */
31
- async refresh() {
32
- const res = await fetch(`${baseUrl}/auth/refresh`, {
33
- method: "POST",
34
- credentials: "include"
35
- });
36
- return res.ok;
37
- },
38
- /**
39
- * Get an access token for Bearer authentication.
40
- * Use this when calling your own API that uses local token verification.
41
- *
42
- * @returns TokenResponse with access token, or null if not authenticated
43
- *
44
- * @example
45
- * ```typescript
46
- * const tokenResponse = await reauth.getToken();
47
- * if (tokenResponse) {
48
- * fetch('/api/data', {
49
- * headers: { Authorization: `Bearer ${tokenResponse.accessToken}` }
50
- * });
51
- * }
52
- * ```
53
- */
54
- async getToken() {
55
- try {
56
- const res = await fetch(`${baseUrl}/auth/token`, {
57
- method: "GET",
58
- credentials: "include"
59
- });
60
- if (!res.ok) {
61
- if (res.status === 401) return null;
62
- throw new Error(`Failed to get token: ${res.status}`);
63
- }
64
- const data = await res.json();
65
- return {
66
- accessToken: data.access_token,
67
- expiresIn: data.expires_in,
68
- tokenType: data.token_type
69
- };
70
- } catch {
71
- return null;
72
- }
73
- },
74
- /**
75
- * Log out the user by clearing all session cookies.
76
- */
77
- async logout() {
78
- await fetch(`${baseUrl}/auth/logout`, {
79
- method: "POST",
80
- credentials: "include"
81
- });
82
- },
83
- /**
84
- * Delete the user's own account (self-service).
85
- * @returns true if deletion succeeded, false otherwise
86
- */
87
- async deleteAccount() {
88
- const res = await fetch(`${baseUrl}/auth/account`, {
89
- method: "DELETE",
90
- credentials: "include"
91
- });
92
- return res.ok;
93
- },
94
- // ========================================================================
95
- // Billing Methods
96
- // ========================================================================
97
- /**
98
- * Get available subscription plans for the domain.
99
- * Only returns public plans sorted by display order.
100
- */
101
- async getPlans() {
102
- const res = await fetch(`${baseUrl}/billing/plans`, {
103
- credentials: "include"
104
- });
105
- if (!res.ok) return [];
106
- const data = await res.json();
107
- return data.map(
108
- (p) => ({
109
- id: p.id,
110
- code: p.code,
111
- name: p.name,
112
- description: p.description,
113
- priceCents: p.price_cents,
114
- currency: p.currency,
115
- interval: p.interval,
116
- intervalCount: p.interval_count,
117
- trialDays: p.trial_days,
118
- features: p.features,
119
- displayOrder: p.display_order
120
- })
121
- );
122
- },
123
- /**
124
- * Get the current user's subscription status.
125
- */
126
- async getSubscription() {
127
- const res = await fetch(`${baseUrl}/billing/subscription`, {
128
- credentials: "include"
129
- });
130
- const data = await res.json();
131
- return {
132
- id: data.id,
133
- planCode: data.plan_code,
134
- planName: data.plan_name,
135
- status: data.status,
136
- currentPeriodEnd: data.current_period_end,
137
- trialEnd: data.trial_end,
138
- cancelAtPeriodEnd: data.cancel_at_period_end
139
- };
140
- },
141
- /**
142
- * Create a Stripe checkout session to subscribe to a plan.
143
- * @param planCode The plan code to subscribe to
144
- * @param successUrl URL to redirect to after successful payment
145
- * @param cancelUrl URL to redirect to if checkout is canceled
146
- * @returns Checkout session with URL to redirect the user to
147
- */
148
- async createCheckout(planCode, successUrl, cancelUrl) {
149
- const res = await fetch(`${baseUrl}/billing/checkout`, {
150
- method: "POST",
151
- headers: { "Content-Type": "application/json" },
152
- credentials: "include",
153
- body: JSON.stringify({
154
- plan_code: planCode,
155
- success_url: successUrl,
156
- cancel_url: cancelUrl
157
- })
158
- });
159
- if (!res.ok) {
160
- const err = await res.json().catch(() => ({}));
161
- throw new Error(err.message || "Failed to create checkout session");
162
- }
163
- const data = await res.json();
164
- return { checkoutUrl: data.checkout_url };
165
- },
166
- /**
167
- * Redirect user to subscribe to a plan.
168
- * Creates a checkout session and redirects to Stripe.
169
- * @param planCode The plan code to subscribe to
170
- */
171
- async subscribe(planCode) {
172
- if (typeof window === "undefined") {
173
- throw new Error("subscribe() can only be called in browser");
174
- }
175
- const currentUrl = window.location.href;
176
- const { checkoutUrl } = await this.createCheckout(
177
- planCode,
178
- currentUrl,
179
- currentUrl
180
- );
181
- window.location.href = checkoutUrl;
182
- },
183
- /**
184
- * Open the Stripe customer portal for managing subscription.
185
- * @param returnUrl URL to return to after leaving the portal
186
- */
187
- async openBillingPortal(returnUrl) {
188
- if (typeof window === "undefined") {
189
- throw new Error("openBillingPortal() can only be called in browser");
190
- }
191
- const res = await fetch(`${baseUrl}/billing/portal`, {
192
- method: "POST",
193
- headers: { "Content-Type": "application/json" },
194
- credentials: "include",
195
- body: JSON.stringify({
196
- return_url: returnUrl || window.location.href
197
- })
198
- });
199
- if (!res.ok) {
200
- throw new Error("Failed to open billing portal");
201
- }
202
- const data = await res.json();
203
- window.location.href = data.portal_url;
204
- },
205
- /**
206
- * Cancel the user's subscription at period end.
207
- * @returns true if cancellation succeeded
208
- */
209
- async cancelSubscription() {
210
- const res = await fetch(`${baseUrl}/billing/cancel`, {
211
- method: "POST",
212
- credentials: "include"
213
- });
214
- return res.ok;
215
- },
216
- // ========================================================================
217
- // Balance Methods
218
- // ========================================================================
219
- /**
220
- * Get the current user's balance.
221
- * @returns Object with the current balance
222
- */
223
- async getBalance() {
224
- const res = await fetch(`${baseUrl}/balance`, {
225
- credentials: "include"
226
- });
227
- if (!res.ok) {
228
- if (res.status === 401) throw new Error("Not authenticated");
229
- throw new Error(`Failed to get balance: ${res.status}`);
230
- }
231
- return res.json();
232
- },
233
- /**
234
- * Get the current user's balance transaction history.
235
- * @param opts - Optional pagination (limit, offset)
236
- * @returns Object with array of transactions (newest first)
237
- */
238
- async getTransactions(opts) {
239
- const params = new URLSearchParams();
240
- if (opts?.limit !== void 0) params.set("limit", String(opts.limit));
241
- if (opts?.offset !== void 0) params.set("offset", String(opts.offset));
242
- const qs = params.toString();
243
- const res = await fetch(
244
- `${baseUrl}/balance/transactions${qs ? `?${qs}` : ""}`,
245
- { credentials: "include" }
246
- );
247
- if (!res.ok) {
248
- if (res.status === 401) throw new Error("Not authenticated");
249
- throw new Error(`Failed to get transactions: ${res.status}`);
250
- }
251
- const data = await res.json();
252
- return {
253
- transactions: data.transactions.map(
254
- (t) => ({
255
- id: t.id,
256
- amountDelta: t.amount_delta,
257
- reason: t.reason,
258
- balanceAfter: t.balance_after,
259
- createdAt: t.created_at
260
- })
261
- )
262
- };
263
- }
264
- };
265
- }
266
-
267
- export {
268
- createReauthClient
269
- };
@@ -1,169 +0,0 @@
1
- /** Response from GET /api/public/auth/session */
2
- type ReauthSession = {
3
- valid: boolean;
4
- end_user_id: string | null;
5
- email: string | null;
6
- roles: string[] | null;
7
- waitlist_position: number | null;
8
- error: string | null;
9
- error_code: "ACCOUNT_SUSPENDED" | null;
10
- /** Subscription information (if billing is configured) */
11
- subscription?: {
12
- status: string;
13
- plan_code: string | null;
14
- plan_name: string | null;
15
- current_period_end: number | null;
16
- cancel_at_period_end: boolean | null;
17
- trial_ends_at: number | null;
18
- };
19
- };
20
- /** Authenticated user object (basic) */
21
- type User = {
22
- id: string;
23
- email: string;
24
- roles: string[];
25
- };
26
- /** Full user details (from Developer API) */
27
- type UserDetails = {
28
- id: string;
29
- email: string;
30
- roles: string[];
31
- emailVerifiedAt: string | null;
32
- lastLoginAt: string | null;
33
- isFrozen: boolean;
34
- isWhitelisted: boolean;
35
- createdAt: string | null;
36
- };
37
- /** JWT claims for domain end-user tokens */
38
- type DomainEndUserClaims = {
39
- /** User ID (subject) */
40
- sub: string;
41
- /** Domain ID */
42
- domain_id: string;
43
- /** Root domain (e.g., "example.com") */
44
- domain: string;
45
- /** User roles */
46
- roles: string[];
47
- /** Subscription information */
48
- subscription: {
49
- status: string;
50
- plan_code: string | null;
51
- plan_name: string | null;
52
- current_period_end: number | null;
53
- cancel_at_period_end: boolean | null;
54
- trial_ends_at: number | null;
55
- };
56
- /** Token expiration (Unix timestamp) */
57
- exp: number;
58
- /** Token issued at (Unix timestamp) */
59
- iat: number;
60
- };
61
- /** Configuration for browser-side reauth client */
62
- type ReauthConfig = {
63
- /** Your verified domain (e.g., "yourdomain.com") */
64
- domain: string;
65
- };
66
- /** Configuration for server-side reauth client */
67
- type ReauthServerConfig = ReauthConfig & {
68
- /** API key for server-to-server authentication (required, e.g., "sk_live_...") */
69
- apiKey: string;
70
- };
71
- /** Subscription status values */
72
- type SubscriptionStatus = "active" | "past_due" | "canceled" | "trialing" | "incomplete" | "incomplete_expired" | "unpaid" | "paused" | "none";
73
- /** Subscription info included in JWT claims */
74
- type SubscriptionInfo = {
75
- /** Current subscription status */
76
- status: SubscriptionStatus;
77
- /** Machine-readable plan identifier (e.g., "pro") */
78
- planCode: string | null;
79
- /** Human-readable plan name (e.g., "Pro Plan") */
80
- planName: string | null;
81
- /** Unix timestamp when current period ends */
82
- currentPeriodEnd: number | null;
83
- /** Whether subscription will cancel at period end */
84
- cancelAtPeriodEnd: boolean | null;
85
- /** Unix timestamp when trial ends (if applicable) */
86
- trialEndsAt: number | null;
87
- };
88
- /** Authentication result from verifyToken/authenticate */
89
- type AuthResult = {
90
- valid: boolean;
91
- user: {
92
- id: string;
93
- roles: string[];
94
- subscription: SubscriptionInfo;
95
- } | null;
96
- claims: DomainEndUserClaims | null;
97
- error?: string;
98
- };
99
- /** Request-like object for extractToken/authenticate */
100
- type RequestLike = {
101
- headers?: {
102
- authorization?: string;
103
- cookie?: string;
104
- };
105
- };
106
- /** Response from GET /auth/token endpoint */
107
- type TokenResponse = {
108
- /** The JWT access token */
109
- accessToken: string;
110
- /** Token expiration time in seconds */
111
- expiresIn: number;
112
- /** Token type (always "Bearer") */
113
- tokenType: string;
114
- };
115
- /** Subscription plan available for purchase */
116
- type SubscriptionPlan = {
117
- id: string;
118
- code: string;
119
- name: string;
120
- description: string | null;
121
- priceCents: number;
122
- currency: string;
123
- interval: "monthly" | "yearly" | "custom";
124
- intervalCount: number;
125
- trialDays: number;
126
- features: string[];
127
- displayOrder: number;
128
- };
129
- /** User's current subscription details */
130
- type UserSubscription = {
131
- id: string | null;
132
- planCode: string | null;
133
- planName: string | null;
134
- status: SubscriptionStatus;
135
- currentPeriodEnd: number | null;
136
- trialEnd: number | null;
137
- cancelAtPeriodEnd: boolean | null;
138
- };
139
- /** Checkout session response */
140
- type CheckoutSession = {
141
- checkoutUrl: string;
142
- };
143
- /** A single balance transaction record */
144
- type BalanceTransaction = {
145
- id: string;
146
- amountDelta: number;
147
- reason: Record<string, unknown>;
148
- balanceAfter: number;
149
- createdAt: string;
150
- };
151
- /** Options for charging a user's balance */
152
- type ChargeOptions = {
153
- amount: number;
154
- requestUuid: string;
155
- note?: string;
156
- };
157
- /** Options for depositing to a user's balance */
158
- type DepositOptions = {
159
- amount: number;
160
- requestUuid: string;
161
- note?: string;
162
- };
163
- /** Pagination options for transaction queries */
164
- type TransactionsPaginationOptions = {
165
- limit?: number;
166
- offset?: number;
167
- };
168
-
169
- export type { AuthResult as A, BalanceTransaction as B, CheckoutSession as C, DomainEndUserClaims as D, ReauthConfig as R, SubscriptionPlan as S, TokenResponse as T, UserSubscription as U, ReauthSession as a, TransactionsPaginationOptions as b, User as c, UserDetails as d, ReauthServerConfig as e, RequestLike as f, SubscriptionInfo as g, ChargeOptions as h, DepositOptions as i };
@@ -1,169 +0,0 @@
1
- /** Response from GET /api/public/auth/session */
2
- type ReauthSession = {
3
- valid: boolean;
4
- end_user_id: string | null;
5
- email: string | null;
6
- roles: string[] | null;
7
- waitlist_position: number | null;
8
- error: string | null;
9
- error_code: "ACCOUNT_SUSPENDED" | null;
10
- /** Subscription information (if billing is configured) */
11
- subscription?: {
12
- status: string;
13
- plan_code: string | null;
14
- plan_name: string | null;
15
- current_period_end: number | null;
16
- cancel_at_period_end: boolean | null;
17
- trial_ends_at: number | null;
18
- };
19
- };
20
- /** Authenticated user object (basic) */
21
- type User = {
22
- id: string;
23
- email: string;
24
- roles: string[];
25
- };
26
- /** Full user details (from Developer API) */
27
- type UserDetails = {
28
- id: string;
29
- email: string;
30
- roles: string[];
31
- emailVerifiedAt: string | null;
32
- lastLoginAt: string | null;
33
- isFrozen: boolean;
34
- isWhitelisted: boolean;
35
- createdAt: string | null;
36
- };
37
- /** JWT claims for domain end-user tokens */
38
- type DomainEndUserClaims = {
39
- /** User ID (subject) */
40
- sub: string;
41
- /** Domain ID */
42
- domain_id: string;
43
- /** Root domain (e.g., "example.com") */
44
- domain: string;
45
- /** User roles */
46
- roles: string[];
47
- /** Subscription information */
48
- subscription: {
49
- status: string;
50
- plan_code: string | null;
51
- plan_name: string | null;
52
- current_period_end: number | null;
53
- cancel_at_period_end: boolean | null;
54
- trial_ends_at: number | null;
55
- };
56
- /** Token expiration (Unix timestamp) */
57
- exp: number;
58
- /** Token issued at (Unix timestamp) */
59
- iat: number;
60
- };
61
- /** Configuration for browser-side reauth client */
62
- type ReauthConfig = {
63
- /** Your verified domain (e.g., "yourdomain.com") */
64
- domain: string;
65
- };
66
- /** Configuration for server-side reauth client */
67
- type ReauthServerConfig = ReauthConfig & {
68
- /** API key for server-to-server authentication (required, e.g., "sk_live_...") */
69
- apiKey: string;
70
- };
71
- /** Subscription status values */
72
- type SubscriptionStatus = "active" | "past_due" | "canceled" | "trialing" | "incomplete" | "incomplete_expired" | "unpaid" | "paused" | "none";
73
- /** Subscription info included in JWT claims */
74
- type SubscriptionInfo = {
75
- /** Current subscription status */
76
- status: SubscriptionStatus;
77
- /** Machine-readable plan identifier (e.g., "pro") */
78
- planCode: string | null;
79
- /** Human-readable plan name (e.g., "Pro Plan") */
80
- planName: string | null;
81
- /** Unix timestamp when current period ends */
82
- currentPeriodEnd: number | null;
83
- /** Whether subscription will cancel at period end */
84
- cancelAtPeriodEnd: boolean | null;
85
- /** Unix timestamp when trial ends (if applicable) */
86
- trialEndsAt: number | null;
87
- };
88
- /** Authentication result from verifyToken/authenticate */
89
- type AuthResult = {
90
- valid: boolean;
91
- user: {
92
- id: string;
93
- roles: string[];
94
- subscription: SubscriptionInfo;
95
- } | null;
96
- claims: DomainEndUserClaims | null;
97
- error?: string;
98
- };
99
- /** Request-like object for extractToken/authenticate */
100
- type RequestLike = {
101
- headers?: {
102
- authorization?: string;
103
- cookie?: string;
104
- };
105
- };
106
- /** Response from GET /auth/token endpoint */
107
- type TokenResponse = {
108
- /** The JWT access token */
109
- accessToken: string;
110
- /** Token expiration time in seconds */
111
- expiresIn: number;
112
- /** Token type (always "Bearer") */
113
- tokenType: string;
114
- };
115
- /** Subscription plan available for purchase */
116
- type SubscriptionPlan = {
117
- id: string;
118
- code: string;
119
- name: string;
120
- description: string | null;
121
- priceCents: number;
122
- currency: string;
123
- interval: "monthly" | "yearly" | "custom";
124
- intervalCount: number;
125
- trialDays: number;
126
- features: string[];
127
- displayOrder: number;
128
- };
129
- /** User's current subscription details */
130
- type UserSubscription = {
131
- id: string | null;
132
- planCode: string | null;
133
- planName: string | null;
134
- status: SubscriptionStatus;
135
- currentPeriodEnd: number | null;
136
- trialEnd: number | null;
137
- cancelAtPeriodEnd: boolean | null;
138
- };
139
- /** Checkout session response */
140
- type CheckoutSession = {
141
- checkoutUrl: string;
142
- };
143
- /** A single balance transaction record */
144
- type BalanceTransaction = {
145
- id: string;
146
- amountDelta: number;
147
- reason: Record<string, unknown>;
148
- balanceAfter: number;
149
- createdAt: string;
150
- };
151
- /** Options for charging a user's balance */
152
- type ChargeOptions = {
153
- amount: number;
154
- requestUuid: string;
155
- note?: string;
156
- };
157
- /** Options for depositing to a user's balance */
158
- type DepositOptions = {
159
- amount: number;
160
- requestUuid: string;
161
- note?: string;
162
- };
163
- /** Pagination options for transaction queries */
164
- type TransactionsPaginationOptions = {
165
- limit?: number;
166
- offset?: number;
167
- };
168
-
169
- export type { AuthResult as A, BalanceTransaction as B, CheckoutSession as C, DomainEndUserClaims as D, ReauthConfig as R, SubscriptionPlan as S, TokenResponse as T, UserSubscription as U, ReauthSession as a, TransactionsPaginationOptions as b, User as c, UserDetails as d, ReauthServerConfig as e, RequestLike as f, SubscriptionInfo as g, ChargeOptions as h, DepositOptions as i };