@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/{chunk-JX2J36FS.mjs → chunk-DMNMTW2C.mjs} +96 -29
- package/dist/chunk-EY5LQCDG.mjs +6 -0
- package/dist/index.d.mts +22 -15
- package/dist/index.d.ts +22 -15
- package/dist/index.js +95 -29
- package/dist/index.mjs +2 -1
- package/dist/react/index.d.mts +15 -5
- package/dist/react/index.d.ts +15 -5
- package/dist/react/index.js +118 -34
- package/dist/react/index.mjs +27 -8
- package/dist/server.d.mts +20 -2
- package/dist/server.d.ts +20 -2
- package/dist/server.js +57 -12
- package/dist/server.mjs +53 -11
- package/dist/{types-D8oOYbeC.d.mts → types-BqZzje-y.d.mts} +21 -3
- package/dist/{types-D8oOYbeC.d.ts → types-BqZzje-y.d.ts} +21 -3
- package/dist/webhooks.js +7 -3
- package/dist/webhooks.mjs +7 -3
- package/package.json +5 -2
package/dist/server.mjs
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_TIMEOUT_MS
|
|
3
|
+
} from "./chunk-EY5LQCDG.mjs";
|
|
4
|
+
|
|
1
5
|
// src/server.ts
|
|
2
6
|
import { hkdf } from "crypto";
|
|
3
7
|
import * as jose from "jose";
|
|
@@ -11,6 +15,28 @@ async function deriveJwtSecret(apiKey, domainId) {
|
|
|
11
15
|
});
|
|
12
16
|
});
|
|
13
17
|
}
|
|
18
|
+
var VALID_SUBSCRIPTION_STATUSES = /* @__PURE__ */ new Set([
|
|
19
|
+
"active",
|
|
20
|
+
"past_due",
|
|
21
|
+
"canceled",
|
|
22
|
+
"trialing",
|
|
23
|
+
"incomplete",
|
|
24
|
+
"incomplete_expired",
|
|
25
|
+
"unpaid",
|
|
26
|
+
"paused",
|
|
27
|
+
"none"
|
|
28
|
+
]);
|
|
29
|
+
function isValidClaims(payload) {
|
|
30
|
+
if (typeof payload.sub !== "string") return false;
|
|
31
|
+
if (typeof payload.domain_id !== "string") return false;
|
|
32
|
+
if (typeof payload.domain !== "string") return false;
|
|
33
|
+
if (!Array.isArray(payload.roles) || !payload.roles.every((r) => typeof r === "string")) return false;
|
|
34
|
+
const subscription = payload.subscription;
|
|
35
|
+
if (typeof subscription !== "object" || subscription === null || Array.isArray(subscription)) return false;
|
|
36
|
+
const status = subscription.status;
|
|
37
|
+
if (typeof status !== "string" || !VALID_SUBSCRIPTION_STATUSES.has(status)) return false;
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
14
40
|
function transformSubscription(sub) {
|
|
15
41
|
return {
|
|
16
42
|
status: sub.status,
|
|
@@ -37,6 +63,10 @@ function parseCookies(cookieHeader) {
|
|
|
37
63
|
}
|
|
38
64
|
function createServerClient(config) {
|
|
39
65
|
const { domain, apiKey } = config;
|
|
66
|
+
if (config.timeout !== void 0 && (!Number.isFinite(config.timeout) || config.timeout <= 0)) {
|
|
67
|
+
throw new Error("timeout must be a positive finite number in milliseconds");
|
|
68
|
+
}
|
|
69
|
+
const timeoutMs = config.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
40
70
|
if (!apiKey) {
|
|
41
71
|
throw new Error(
|
|
42
72
|
"apiKey is required for createServerClient. Get one from the Reauth dashboard."
|
|
@@ -84,7 +114,11 @@ function createServerClient(config) {
|
|
|
84
114
|
// 60 seconds clock skew tolerance
|
|
85
115
|
}
|
|
86
116
|
);
|
|
87
|
-
const
|
|
117
|
+
const payloadRecord = payload;
|
|
118
|
+
if (!isValidClaims(payloadRecord)) {
|
|
119
|
+
return { valid: false, user: null, claims: null, error: "Invalid token claims: missing required fields" };
|
|
120
|
+
}
|
|
121
|
+
const claims = payloadRecord;
|
|
88
122
|
if (claims.domain !== domain) {
|
|
89
123
|
return { valid: false, user: null, claims: null, error: "Domain mismatch" };
|
|
90
124
|
}
|
|
@@ -207,10 +241,11 @@ function createServerClient(config) {
|
|
|
207
241
|
* ```
|
|
208
242
|
*/
|
|
209
243
|
async getUserById(userId) {
|
|
210
|
-
const res = await fetch(`${developerBaseUrl}/users/${userId}`, {
|
|
244
|
+
const res = await fetch(`${developerBaseUrl}/users/${encodeURIComponent(userId)}`, {
|
|
211
245
|
headers: {
|
|
212
246
|
Authorization: `Bearer ${apiKey}`
|
|
213
|
-
}
|
|
247
|
+
},
|
|
248
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
214
249
|
});
|
|
215
250
|
if (!res.ok) {
|
|
216
251
|
if (res.status === 401) {
|
|
@@ -243,16 +278,18 @@ function createServerClient(config) {
|
|
|
243
278
|
* @returns Object with the current balance
|
|
244
279
|
*/
|
|
245
280
|
async getBalance(userId) {
|
|
246
|
-
const res = await fetch(`${developerBaseUrl}/users/${userId}/balance`, {
|
|
281
|
+
const res = await fetch(`${developerBaseUrl}/users/${encodeURIComponent(userId)}/balance`, {
|
|
247
282
|
headers: {
|
|
248
283
|
Authorization: `Bearer ${apiKey}`
|
|
249
|
-
}
|
|
284
|
+
},
|
|
285
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
250
286
|
});
|
|
251
287
|
if (!res.ok) {
|
|
252
288
|
if (res.status === 401) throw new Error("Invalid API key");
|
|
253
289
|
throw new Error(`Failed to get balance: ${res.status}`);
|
|
254
290
|
}
|
|
255
|
-
|
|
291
|
+
const data = await res.json();
|
|
292
|
+
return { balance: data.balance };
|
|
256
293
|
},
|
|
257
294
|
/**
|
|
258
295
|
* Charge (deduct) credits from a user's balance.
|
|
@@ -263,12 +300,13 @@ function createServerClient(config) {
|
|
|
263
300
|
* @throws Error with status 402 if insufficient balance, 400 if invalid amount
|
|
264
301
|
*/
|
|
265
302
|
async charge(userId, opts) {
|
|
266
|
-
const res = await fetch(`${developerBaseUrl}/users/${userId}/charge`, {
|
|
303
|
+
const res = await fetch(`${developerBaseUrl}/users/${encodeURIComponent(userId)}/charge`, {
|
|
267
304
|
method: "POST",
|
|
268
305
|
headers: {
|
|
269
306
|
"Content-Type": "application/json",
|
|
270
307
|
Authorization: `Bearer ${apiKey}`
|
|
271
308
|
},
|
|
309
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
272
310
|
body: JSON.stringify({
|
|
273
311
|
amount: opts.amount,
|
|
274
312
|
request_uuid: opts.requestUuid,
|
|
@@ -292,12 +330,13 @@ function createServerClient(config) {
|
|
|
292
330
|
* @returns Object with the new balance after deposit
|
|
293
331
|
*/
|
|
294
332
|
async deposit(userId, opts) {
|
|
295
|
-
const res = await fetch(`${developerBaseUrl}/users/${userId}/deposit`, {
|
|
333
|
+
const res = await fetch(`${developerBaseUrl}/users/${encodeURIComponent(userId)}/deposit`, {
|
|
296
334
|
method: "POST",
|
|
297
335
|
headers: {
|
|
298
336
|
"Content-Type": "application/json",
|
|
299
337
|
Authorization: `Bearer ${apiKey}`
|
|
300
338
|
},
|
|
339
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
301
340
|
body: JSON.stringify({
|
|
302
341
|
amount: opts.amount,
|
|
303
342
|
request_uuid: opts.requestUuid,
|
|
@@ -325,11 +364,12 @@ function createServerClient(config) {
|
|
|
325
364
|
if (opts?.offset !== void 0) params.set("offset", String(opts.offset));
|
|
326
365
|
const qs = params.toString();
|
|
327
366
|
const res = await fetch(
|
|
328
|
-
`${developerBaseUrl}/users/${userId}/balance/transactions${qs ? `?${qs}` : ""}`,
|
|
367
|
+
`${developerBaseUrl}/users/${encodeURIComponent(userId)}/balance/transactions${qs ? `?${qs}` : ""}`,
|
|
329
368
|
{
|
|
330
369
|
headers: {
|
|
331
370
|
Authorization: `Bearer ${apiKey}`
|
|
332
|
-
}
|
|
371
|
+
},
|
|
372
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
333
373
|
}
|
|
334
374
|
);
|
|
335
375
|
if (!res.ok) {
|
|
@@ -352,5 +392,7 @@ function createServerClient(config) {
|
|
|
352
392
|
};
|
|
353
393
|
}
|
|
354
394
|
export {
|
|
355
|
-
createServerClient
|
|
395
|
+
createServerClient,
|
|
396
|
+
deriveJwtSecret,
|
|
397
|
+
parseCookies
|
|
356
398
|
};
|
|
@@ -5,8 +5,11 @@ type ReauthSession = {
|
|
|
5
5
|
email: string | null;
|
|
6
6
|
roles: string[] | null;
|
|
7
7
|
waitlist_position: number | null;
|
|
8
|
+
/** Whether the user has linked their Google account */
|
|
9
|
+
google_linked: boolean | null;
|
|
8
10
|
error: string | null;
|
|
9
|
-
|
|
11
|
+
/** Error code (e.g., "ACCOUNT_SUSPENDED", "SESSION_VERIFICATION_FAILED") */
|
|
12
|
+
error_code: string | null;
|
|
10
13
|
/** Subscription information (if billing is configured) */
|
|
11
14
|
subscription?: {
|
|
12
15
|
status: string;
|
|
@@ -62,6 +65,8 @@ type DomainEndUserClaims = {
|
|
|
62
65
|
type ReauthConfig = {
|
|
63
66
|
/** Your verified domain (e.g., "yourdomain.com") */
|
|
64
67
|
domain: string;
|
|
68
|
+
/** Request timeout in milliseconds. Defaults to 10 seconds if not specified. */
|
|
69
|
+
timeout?: number;
|
|
65
70
|
};
|
|
66
71
|
/** Configuration for server-side reauth client */
|
|
67
72
|
type ReauthServerConfig = ReauthConfig & {
|
|
@@ -112,6 +117,16 @@ type TokenResponse = {
|
|
|
112
117
|
/** Token type (always "Bearer") */
|
|
113
118
|
tokenType: string;
|
|
114
119
|
};
|
|
120
|
+
/** A single feature attached to a subscription plan */
|
|
121
|
+
type PlanFeature = {
|
|
122
|
+
code: string;
|
|
123
|
+
name: string;
|
|
124
|
+
featureType: "boolean" | "numeric";
|
|
125
|
+
numericValue: number | null;
|
|
126
|
+
unitLabel: string | null;
|
|
127
|
+
};
|
|
128
|
+
/** Plan type determines how a user subscribes */
|
|
129
|
+
type PlanType = "self_service" | "sales";
|
|
115
130
|
/** Subscription plan available for purchase */
|
|
116
131
|
type SubscriptionPlan = {
|
|
117
132
|
id: string;
|
|
@@ -123,8 +138,11 @@ type SubscriptionPlan = {
|
|
|
123
138
|
interval: "monthly" | "yearly" | "custom";
|
|
124
139
|
intervalCount: number;
|
|
125
140
|
trialDays: number;
|
|
126
|
-
features:
|
|
141
|
+
features: PlanFeature[];
|
|
127
142
|
displayOrder: number;
|
|
143
|
+
creditsAmount: number;
|
|
144
|
+
planType: PlanType;
|
|
145
|
+
contactUrl: string | null;
|
|
128
146
|
};
|
|
129
147
|
/** User's current subscription details */
|
|
130
148
|
type UserSubscription = {
|
|
@@ -166,4 +184,4 @@ type TransactionsPaginationOptions = {
|
|
|
166
184
|
offset?: number;
|
|
167
185
|
};
|
|
168
186
|
|
|
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 };
|
|
187
|
+
export type { AuthResult as A, BalanceTransaction as B, CheckoutSession as C, DomainEndUserClaims as D, PlanFeature as P, 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 };
|
|
@@ -5,8 +5,11 @@ type ReauthSession = {
|
|
|
5
5
|
email: string | null;
|
|
6
6
|
roles: string[] | null;
|
|
7
7
|
waitlist_position: number | null;
|
|
8
|
+
/** Whether the user has linked their Google account */
|
|
9
|
+
google_linked: boolean | null;
|
|
8
10
|
error: string | null;
|
|
9
|
-
|
|
11
|
+
/** Error code (e.g., "ACCOUNT_SUSPENDED", "SESSION_VERIFICATION_FAILED") */
|
|
12
|
+
error_code: string | null;
|
|
10
13
|
/** Subscription information (if billing is configured) */
|
|
11
14
|
subscription?: {
|
|
12
15
|
status: string;
|
|
@@ -62,6 +65,8 @@ type DomainEndUserClaims = {
|
|
|
62
65
|
type ReauthConfig = {
|
|
63
66
|
/** Your verified domain (e.g., "yourdomain.com") */
|
|
64
67
|
domain: string;
|
|
68
|
+
/** Request timeout in milliseconds. Defaults to 10 seconds if not specified. */
|
|
69
|
+
timeout?: number;
|
|
65
70
|
};
|
|
66
71
|
/** Configuration for server-side reauth client */
|
|
67
72
|
type ReauthServerConfig = ReauthConfig & {
|
|
@@ -112,6 +117,16 @@ type TokenResponse = {
|
|
|
112
117
|
/** Token type (always "Bearer") */
|
|
113
118
|
tokenType: string;
|
|
114
119
|
};
|
|
120
|
+
/** A single feature attached to a subscription plan */
|
|
121
|
+
type PlanFeature = {
|
|
122
|
+
code: string;
|
|
123
|
+
name: string;
|
|
124
|
+
featureType: "boolean" | "numeric";
|
|
125
|
+
numericValue: number | null;
|
|
126
|
+
unitLabel: string | null;
|
|
127
|
+
};
|
|
128
|
+
/** Plan type determines how a user subscribes */
|
|
129
|
+
type PlanType = "self_service" | "sales";
|
|
115
130
|
/** Subscription plan available for purchase */
|
|
116
131
|
type SubscriptionPlan = {
|
|
117
132
|
id: string;
|
|
@@ -123,8 +138,11 @@ type SubscriptionPlan = {
|
|
|
123
138
|
interval: "monthly" | "yearly" | "custom";
|
|
124
139
|
intervalCount: number;
|
|
125
140
|
trialDays: number;
|
|
126
|
-
features:
|
|
141
|
+
features: PlanFeature[];
|
|
127
142
|
displayOrder: number;
|
|
143
|
+
creditsAmount: number;
|
|
144
|
+
planType: PlanType;
|
|
145
|
+
contactUrl: string | null;
|
|
128
146
|
};
|
|
129
147
|
/** User's current subscription details */
|
|
130
148
|
type UserSubscription = {
|
|
@@ -166,4 +184,4 @@ type TransactionsPaginationOptions = {
|
|
|
166
184
|
offset?: number;
|
|
167
185
|
};
|
|
168
186
|
|
|
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 };
|
|
187
|
+
export type { AuthResult as A, BalanceTransaction as B, CheckoutSession as C, DomainEndUserClaims as D, PlanFeature as P, 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 };
|
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 [
|
|
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
|
-
|
|
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 [
|
|
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
|
-
|
|
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.
|
|
3
|
+
"version": "0.2.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",
|