@solvapay/auth 1.0.0-preview.18 → 1.0.0-preview.20

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.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 SolvaPay Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -21,27 +21,27 @@ pnpm add jose
21
21
  Extract user ID from Supabase JWT tokens:
22
22
 
23
23
  ```ts
24
- import { SupabaseAuthAdapter } from '@solvapay/auth/supabase';
24
+ import { SupabaseAuthAdapter } from '@solvapay/auth/supabase'
25
25
 
26
26
  const auth = new SupabaseAuthAdapter({
27
- jwtSecret: process.env.SUPABASE_JWT_SECRET!
28
- });
27
+ jwtSecret: process.env.SUPABASE_JWT_SECRET!,
28
+ })
29
29
 
30
30
  // In your API route
31
31
  export async function POST(request: Request) {
32
- const userId = await auth.getUserIdFromRequest(request);
33
-
32
+ const userId = await auth.getUserIdFromRequest(request)
33
+
34
34
  if (!userId) {
35
- return new Response('Unauthorized', { status: 401 });
35
+ return new Response('Unauthorized', { status: 401 })
36
36
  }
37
-
37
+
38
38
  // Use userId as cache key and externalRef
39
39
  // The ensureCustomer method returns the SolvaPay backend customer reference
40
- const solvaPay = createSolvaPay({ apiKey: process.env.SOLVAPAY_SECRET_KEY! });
41
- const ensuredCustomerRef = await solvaPay.ensureCustomer(userId, userId);
42
- const customer = await solvaPay.getCustomer({ customerRef: ensuredCustomerRef });
43
-
44
- return Response.json({ userId, customer });
40
+ const solvaPay = createSolvaPay({ apiKey: process.env.SOLVAPAY_SECRET_KEY! })
41
+ const ensuredCustomerRef = await solvaPay.ensureCustomer(userId, userId)
42
+ const customer = await solvaPay.getCustomer({ customerRef: ensuredCustomerRef })
43
+
44
+ return Response.json({ userId, customer })
45
45
  }
46
46
  ```
47
47
 
@@ -50,14 +50,14 @@ export async function POST(request: Request) {
50
50
  For testing and examples:
51
51
 
52
52
  ```ts
53
- import { MockAuthAdapter } from '@solvapay/auth/mock';
53
+ import { MockAuthAdapter } from '@solvapay/auth/mock'
54
54
 
55
- const auth = new MockAuthAdapter();
55
+ const auth = new MockAuthAdapter()
56
56
 
57
57
  // Set header: x-mock-user-id: user_123
58
58
  // Or set env: MOCK_USER_ID=user_123
59
59
 
60
- const userId = await auth.getUserIdFromRequest(request);
60
+ const userId = await auth.getUserIdFromRequest(request)
61
61
  ```
62
62
 
63
63
  ### Integration with SolvaPay Server SDK
@@ -65,27 +65,27 @@ const userId = await auth.getUserIdFromRequest(request);
65
65
  Use auth adapters with the `getCustomerRef` option:
66
66
 
67
67
  ```ts
68
- import { createSolvaPay } from '@solvapay/server';
69
- import { SupabaseAuthAdapter } from '@solvapay/auth/supabase';
68
+ import { createSolvaPay } from '@solvapay/server'
69
+ import { SupabaseAuthAdapter } from '@solvapay/auth/supabase'
70
70
 
71
71
  const auth = new SupabaseAuthAdapter({
72
- jwtSecret: process.env.SUPABASE_JWT_SECRET!
73
- });
72
+ jwtSecret: process.env.SUPABASE_JWT_SECRET!,
73
+ })
74
74
 
75
- const solvaPay = createSolvaPay({ apiKey: process.env.SOLVAPAY_SECRET_KEY! });
75
+ const solvaPay = createSolvaPay({ apiKey: process.env.SOLVAPAY_SECRET_KEY! })
76
76
 
77
77
  // Use with Next.js adapter
78
78
  export const POST = solvaPay.payable({ agent: 'my-api' }).next(
79
- async (args) => {
80
- return { result: 'success' };
79
+ async args => {
80
+ return { result: 'success' }
81
81
  },
82
82
  {
83
- getCustomerRef: async (req) => {
84
- const userId = await auth.getUserIdFromRequest(req);
85
- return userId ?? 'anonymous';
86
- }
87
- }
88
- );
83
+ getCustomerRef: async req => {
84
+ const userId = await auth.getUserIdFromRequest(req)
85
+ return userId ?? 'anonymous'
86
+ },
87
+ },
88
+ )
89
89
  ```
90
90
 
91
91
  ## Next.js Route Utilities
@@ -97,15 +97,15 @@ The package also provides helper functions for extracting user information in Ne
97
97
  Extract user ID from request headers (commonly set by middleware):
98
98
 
99
99
  ```ts
100
- import { getUserIdFromRequest } from '@solvapay/auth';
100
+ import { getUserIdFromRequest } from '@solvapay/auth'
101
101
 
102
102
  export async function GET(request: Request) {
103
- const userId = getUserIdFromRequest(request);
104
-
103
+ const userId = getUserIdFromRequest(request)
104
+
105
105
  if (!userId) {
106
- return new Response('Unauthorized', { status: 401 });
106
+ return new Response('Unauthorized', { status: 401 })
107
107
  }
108
-
108
+
109
109
  // Use userId...
110
110
  }
111
111
  ```
@@ -115,17 +115,17 @@ export async function GET(request: Request) {
115
115
  Require user ID or return error response:
116
116
 
117
117
  ```ts
118
- import { requireUserId } from '@solvapay/auth';
118
+ import { requireUserId } from '@solvapay/auth'
119
119
 
120
120
  export async function GET(request: Request) {
121
- const userIdOrError = requireUserId(request);
122
-
121
+ const userIdOrError = requireUserId(request)
122
+
123
123
  if (userIdOrError instanceof Response) {
124
- return userIdOrError; // Returns 401 error
124
+ return userIdOrError // Returns 401 error
125
125
  }
126
-
126
+
127
127
  // userIdOrError is now a string
128
- const userId = userIdOrError;
128
+ const userId = userIdOrError
129
129
  }
130
130
  ```
131
131
 
@@ -134,10 +134,10 @@ export async function GET(request: Request) {
134
134
  Extract email from Supabase JWT token in Authorization header:
135
135
 
136
136
  ```ts
137
- import { getUserEmailFromRequest } from '@solvapay/auth';
137
+ import { getUserEmailFromRequest } from '@solvapay/auth'
138
138
 
139
139
  export async function GET(request: Request) {
140
- const email = await getUserEmailFromRequest(request);
140
+ const email = await getUserEmailFromRequest(request)
141
141
  // Returns email string or null
142
142
  }
143
143
  ```
@@ -147,10 +147,10 @@ export async function GET(request: Request) {
147
147
  Extract name from Supabase JWT token in Authorization header:
148
148
 
149
149
  ```ts
150
- import { getUserNameFromRequest } from '@solvapay/auth';
150
+ import { getUserNameFromRequest } from '@solvapay/auth'
151
151
 
152
152
  export async function GET(request: Request) {
153
- const name = await getUserNameFromRequest(request);
153
+ const name = await getUserNameFromRequest(request)
154
154
  // Returns name string or null
155
155
  }
156
156
  ```
@@ -159,8 +159,8 @@ export async function GET(request: Request) {
159
159
 
160
160
  ```ts
161
161
  const email = await getUserEmailFromRequest(request, {
162
- jwtSecret: process.env.SUPABASE_JWT_SECRET!
163
- });
162
+ jwtSecret: process.env.SUPABASE_JWT_SECRET!,
163
+ })
164
164
  ```
165
165
 
166
166
  ## API Reference
@@ -169,7 +169,7 @@ const email = await getUserEmailFromRequest(request, {
169
169
 
170
170
  ```ts
171
171
  interface AuthAdapter {
172
- getUserIdFromRequest(req: Request | RequestLike): Promise<string | null>;
172
+ getUserIdFromRequest(req: Request | RequestLike): Promise<string | null>
173
173
  }
174
174
  ```
175
175
 
@@ -177,12 +177,13 @@ interface AuthAdapter {
177
177
 
178
178
  ```ts
179
179
  class SupabaseAuthAdapter implements AuthAdapter {
180
- constructor(config: { jwtSecret: string });
181
- getUserIdFromRequest(req: Request | RequestLike): Promise<string | null>;
180
+ constructor(config: { jwtSecret: string })
181
+ getUserIdFromRequest(req: Request | RequestLike): Promise<string | null>
182
182
  }
183
183
  ```
184
184
 
185
185
  **Configuration:**
186
+
186
187
  - `jwtSecret`: Supabase JWT secret from dashboard (Settings → API → JWT Secret)
187
188
 
188
189
  **Returns:** User ID from `sub` claim or `null` if missing/invalid
@@ -191,11 +192,12 @@ class SupabaseAuthAdapter implements AuthAdapter {
191
192
 
192
193
  ```ts
193
194
  class MockAuthAdapter implements AuthAdapter {
194
- getUserIdFromRequest(req: Request | RequestLike): Promise<string | null>;
195
+ getUserIdFromRequest(req: Request | RequestLike): Promise<string | null>
195
196
  }
196
197
  ```
197
198
 
198
199
  **Behavior:**
200
+
199
201
  1. Checks `x-mock-user-id` header
200
202
  2. Falls back to `MOCK_USER_ID` environment variable
201
203
  3. Returns `null` if neither is found
@@ -215,33 +217,32 @@ These utilities work seamlessly with Next.js middleware. Typically, you'll set t
215
217
 
216
218
  ```ts
217
219
  // middleware.ts
218
- import { NextResponse } from 'next/server';
219
- import type { NextRequest } from 'next/server';
220
+ import { NextResponse } from 'next/server'
221
+ import type { NextRequest } from 'next/server'
220
222
 
221
223
  export async function middleware(request: NextRequest) {
222
224
  // Extract user ID from your auth system (Supabase, Auth0, etc.)
223
- const userId = await getUserIdFromAuth(request);
224
-
225
+ const userId = await getUserIdFromAuth(request)
226
+
225
227
  // Clone the request and add user ID header
226
- const requestHeaders = new Headers(request.headers);
227
- requestHeaders.set('x-user-id', userId);
228
-
228
+ const requestHeaders = new Headers(request.headers)
229
+ requestHeaders.set('x-user-id', userId)
230
+
229
231
  return NextResponse.next({
230
232
  request: {
231
233
  headers: requestHeaders,
232
234
  },
233
- });
235
+ })
234
236
  }
235
237
  ```
236
238
 
237
239
  Then in your API routes, use the utilities:
238
240
 
239
241
  ```ts
240
- import { requireUserId } from '@solvapay/auth';
242
+ import { requireUserId } from '@solvapay/auth'
241
243
 
242
244
  export async function GET(request: Request) {
243
- const userId = requireUserId(request);
245
+ const userId = requireUserId(request)
244
246
  // userId is guaranteed to exist or an error response is returned
245
247
  }
246
248
  ```
247
-
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Auth Adapter Interface
3
+ *
4
+ * Defines the contract for authentication adapters that extract user IDs from requests.
5
+ * Implementations should never throw - return null if authentication fails or is missing.
6
+ */
7
+ /**
8
+ * Request-like object that has headers
9
+ */
10
+ interface RequestLike {
11
+ headers: Headers | {
12
+ get(name: string): string | null;
13
+ };
14
+ }
15
+ /**
16
+ * Authentication adapter interface for extracting user IDs from requests.
17
+ *
18
+ * This interface defines the contract for authentication adapters that can
19
+ * extract user IDs from various authentication systems (Supabase, custom JWT,
20
+ * session-based auth, etc.). Adapters should never throw - return null if
21
+ * authentication fails or is missing.
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * import type { AuthAdapter } from '@solvapay/auth';
26
+ *
27
+ * // Custom adapter implementation
28
+ * const myAdapter: AuthAdapter = {
29
+ * async getUserIdFromRequest(req) {
30
+ * // Extract user ID from request (JWT, session, etc.)
31
+ * const token = req.headers.get('authorization')?.replace('Bearer ', '');
32
+ * if (!token) return null;
33
+ *
34
+ * // Validate and extract user ID
35
+ * const payload = await verifyToken(token);
36
+ * return payload.userId || null;
37
+ * }
38
+ * };
39
+ * ```
40
+ *
41
+ * @see SupabaseAuthAdapter (from `@solvapay/auth/supabase`) for Supabase implementation
42
+ * @see {@link MockAuthAdapter} for testing implementation
43
+ * @since 1.0.0
44
+ */
45
+ interface AuthAdapter {
46
+ /**
47
+ * Extract the authenticated user ID from a request.
48
+ *
49
+ * This method should:
50
+ * - Never throw exceptions (return null on failure)
51
+ * - Handle missing/invalid authentication gracefully
52
+ * - Work with both Request objects and objects with headers
53
+ *
54
+ * @param req - Request object or object with headers
55
+ * @returns The user ID string if authenticated, null otherwise
56
+ *
57
+ * @remarks
58
+ * This method should never throw. If authentication fails or is missing,
59
+ * return null and let the caller decide how to handle unauthenticated requests.
60
+ */
61
+ getUserIdFromRequest(req: Request | RequestLike): Promise<string | null>;
62
+ }
63
+
64
+ export type { AuthAdapter as A, RequestLike as R };
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Auth Adapter Interface
3
+ *
4
+ * Defines the contract for authentication adapters that extract user IDs from requests.
5
+ * Implementations should never throw - return null if authentication fails or is missing.
6
+ */
7
+ /**
8
+ * Request-like object that has headers
9
+ */
10
+ interface RequestLike {
11
+ headers: Headers | {
12
+ get(name: string): string | null;
13
+ };
14
+ }
15
+ /**
16
+ * Authentication adapter interface for extracting user IDs from requests.
17
+ *
18
+ * This interface defines the contract for authentication adapters that can
19
+ * extract user IDs from various authentication systems (Supabase, custom JWT,
20
+ * session-based auth, etc.). Adapters should never throw - return null if
21
+ * authentication fails or is missing.
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * import type { AuthAdapter } from '@solvapay/auth';
26
+ *
27
+ * // Custom adapter implementation
28
+ * const myAdapter: AuthAdapter = {
29
+ * async getUserIdFromRequest(req) {
30
+ * // Extract user ID from request (JWT, session, etc.)
31
+ * const token = req.headers.get('authorization')?.replace('Bearer ', '');
32
+ * if (!token) return null;
33
+ *
34
+ * // Validate and extract user ID
35
+ * const payload = await verifyToken(token);
36
+ * return payload.userId || null;
37
+ * }
38
+ * };
39
+ * ```
40
+ *
41
+ * @see SupabaseAuthAdapter (from `@solvapay/auth/supabase`) for Supabase implementation
42
+ * @see {@link MockAuthAdapter} for testing implementation
43
+ * @since 1.0.0
44
+ */
45
+ interface AuthAdapter {
46
+ /**
47
+ * Extract the authenticated user ID from a request.
48
+ *
49
+ * This method should:
50
+ * - Never throw exceptions (return null on failure)
51
+ * - Handle missing/invalid authentication gracefully
52
+ * - Work with both Request objects and objects with headers
53
+ *
54
+ * @param req - Request object or object with headers
55
+ * @returns The user ID string if authenticated, null otherwise
56
+ *
57
+ * @remarks
58
+ * This method should never throw. If authentication fails or is missing,
59
+ * return null and let the caller decide how to handle unauthenticated requests.
60
+ */
61
+ getUserIdFromRequest(req: Request | RequestLike): Promise<string | null>;
62
+ }
63
+
64
+ export type { AuthAdapter as A, RequestLike as R };
@@ -46,7 +46,8 @@ async function getUserNameFromRequest(request, options) {
46
46
  const { payload } = await jwtVerify(token, secret, {
47
47
  algorithms: ["HS256"]
48
48
  });
49
- const name = payload.user_metadata?.full_name || payload.user_metadata?.name || payload.name || null;
49
+ const payloadWithMetadata = payload;
50
+ const name = payloadWithMetadata.user_metadata?.full_name || payloadWithMetadata.user_metadata?.name || payloadWithMetadata.name || null;
50
51
  return name ? String(name) : null;
51
52
  } catch {
52
53
  return null;
@@ -58,13 +59,10 @@ function requireUserId(request, options) {
58
59
  const errorDetails = options?.errorDetails || "User ID not found. Ensure middleware is configured.";
59
60
  const userId = request.headers.get(headerName);
60
61
  if (!userId) {
61
- return new Response(
62
- JSON.stringify({ error: errorMessage, details: errorDetails }),
63
- {
64
- status: 401,
65
- headers: { "Content-Type": "application/json" }
66
- }
67
- );
62
+ return new Response(JSON.stringify({ error: errorMessage, details: errorDetails }), {
63
+ status: 401,
64
+ headers: { "Content-Type": "application/json" }
65
+ });
68
66
  }
69
67
  return userId;
70
68
  }
package/dist/index.cjs CHANGED
@@ -31,6 +31,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
33
  MockAuthAdapter: () => MockAuthAdapter,
34
+ SolvapayAuthAdapter: () => SolvapayAuthAdapter,
35
+ SolvapayOAuthClient: () => SolvapayOAuthClient,
34
36
  getUserEmailFromRequest: () => getUserEmailFromRequest,
35
37
  getUserIdFromRequest: () => getUserIdFromRequest,
36
38
  getUserNameFromRequest: () => getUserNameFromRequest,
@@ -53,6 +55,125 @@ var MockAuthAdapter = class {
53
55
  }
54
56
  };
55
57
 
58
+ // src/solvapay.ts
59
+ var SolvapayAuthAdapter = class {
60
+ apiBaseUrl;
61
+ constructor(config) {
62
+ this.apiBaseUrl = config.apiBaseUrl.replace(/\/$/, "");
63
+ }
64
+ async getUserIdFromRequest(req) {
65
+ try {
66
+ const headers = "headers" in req ? req.headers : req;
67
+ const authHeader = headers.get("authorization");
68
+ if (!authHeader || !authHeader.startsWith("Bearer ")) {
69
+ return null;
70
+ }
71
+ const token = authHeader.slice(7);
72
+ if (!token) {
73
+ return null;
74
+ }
75
+ const response = await fetch(`${this.apiBaseUrl}/v1/oauth/userinfo`, {
76
+ method: "GET",
77
+ headers: {
78
+ Authorization: `Bearer ${token}`,
79
+ "Content-Type": "application/json"
80
+ }
81
+ });
82
+ if (!response.ok) {
83
+ return null;
84
+ }
85
+ const userInfo = await response.json();
86
+ return userInfo.sub || userInfo.id || userInfo.customerRef || null;
87
+ } catch {
88
+ return null;
89
+ }
90
+ }
91
+ };
92
+ var SolvapayOAuthClient = class {
93
+ constructor(config) {
94
+ this.config = config;
95
+ }
96
+ /**
97
+ * Get the URL to redirect the user to for login
98
+ */
99
+ getAuthorizationUrl(options = {}) {
100
+ const params = new URLSearchParams({
101
+ response_type: "code",
102
+ client_id: this.config.clientId,
103
+ redirect_uri: this.config.redirectUri
104
+ });
105
+ if (options.state) params.append("state", options.state);
106
+ if (options.scope) params.append("scope", options.scope);
107
+ return `${this.config.authUrl}?${params.toString()}`;
108
+ }
109
+ /**
110
+ * Exchange an authorization code for an access token
111
+ */
112
+ async exchangeCodeForToken(code) {
113
+ const body = new URLSearchParams({
114
+ grant_type: "authorization_code",
115
+ code,
116
+ client_id: this.config.clientId,
117
+ redirect_uri: this.config.redirectUri
118
+ });
119
+ if (this.config.clientSecret) {
120
+ body.append("client_secret", this.config.clientSecret);
121
+ }
122
+ const response = await fetch(this.config.tokenUrl, {
123
+ method: "POST",
124
+ headers: {
125
+ "Content-Type": "application/x-www-form-urlencoded",
126
+ Accept: "application/json"
127
+ },
128
+ body: body.toString()
129
+ });
130
+ if (!response.ok) {
131
+ const text = await response.text();
132
+ throw new Error(`Failed to exchange code: ${response.status} ${text}`);
133
+ }
134
+ return response.json();
135
+ }
136
+ /**
137
+ * Revoke a token (Sign Out)
138
+ */
139
+ async revokeToken(token) {
140
+ const revokeUrl = this.config.tokenUrl.replace("/token", "/revoke");
141
+ const body = new URLSearchParams({
142
+ token,
143
+ client_id: this.config.clientId
144
+ });
145
+ if (this.config.clientSecret) {
146
+ body.append("client_secret", this.config.clientSecret);
147
+ }
148
+ await fetch(revokeUrl, {
149
+ method: "POST",
150
+ headers: {
151
+ "Content-Type": "application/x-www-form-urlencoded"
152
+ },
153
+ body: body.toString()
154
+ });
155
+ }
156
+ /**
157
+ * Get user info using access token
158
+ */
159
+ async getUserInfo(accessToken, userInfoUrl) {
160
+ if (!userInfoUrl) {
161
+ throw new Error("userInfoUrl is required");
162
+ }
163
+ const response = await fetch(userInfoUrl, {
164
+ method: "GET",
165
+ headers: {
166
+ Authorization: `Bearer ${accessToken}`,
167
+ Accept: "application/json"
168
+ }
169
+ });
170
+ if (!response.ok) {
171
+ throw new Error(`Failed to fetch user info: ${response.status}`);
172
+ }
173
+ return response.json();
174
+ }
175
+ };
176
+
56
177
  // src/next-utils.ts
57
178
  function getUserIdFromRequest(request, options) {
58
179
  const headerName = options?.headerName || "x-user-id";
@@ -101,7 +222,8 @@ async function getUserNameFromRequest(request, options) {
101
222
  const { payload } = await jwtVerify(token, secret, {
102
223
  algorithms: ["HS256"]
103
224
  });
104
- const name = payload.user_metadata?.full_name || payload.user_metadata?.name || payload.name || null;
225
+ const payloadWithMetadata = payload;
226
+ const name = payloadWithMetadata.user_metadata?.full_name || payloadWithMetadata.user_metadata?.name || payloadWithMetadata.name || null;
105
227
  return name ? String(name) : null;
106
228
  } catch {
107
229
  return null;
@@ -113,19 +235,18 @@ function requireUserId(request, options) {
113
235
  const errorDetails = options?.errorDetails || "User ID not found. Ensure middleware is configured.";
114
236
  const userId = request.headers.get(headerName);
115
237
  if (!userId) {
116
- return new Response(
117
- JSON.stringify({ error: errorMessage, details: errorDetails }),
118
- {
119
- status: 401,
120
- headers: { "Content-Type": "application/json" }
121
- }
122
- );
238
+ return new Response(JSON.stringify({ error: errorMessage, details: errorDetails }), {
239
+ status: 401,
240
+ headers: { "Content-Type": "application/json" }
241
+ });
123
242
  }
124
243
  return userId;
125
244
  }
126
245
  // Annotate the CommonJS export names for ESM import in node:
127
246
  0 && (module.exports = {
128
247
  MockAuthAdapter,
248
+ SolvapayAuthAdapter,
249
+ SolvapayOAuthClient,
129
250
  getUserEmailFromRequest,
130
251
  getUserIdFromRequest,
131
252
  getUserNameFromRequest,
package/dist/index.d.cts CHANGED
@@ -1,3 +1,70 @@
1
- export { A as AuthAdapter, R as RequestLike } from './adapter-4HTpALyc.cjs';
1
+ import { A as AuthAdapter, R as RequestLike } from './adapter-Lx7F0MH7.cjs';
2
2
  export { MockAuthAdapter, MockAuthAdapter as MockAuthAdapterType } from './mock.cjs';
3
3
  export { getUserEmailFromRequest, getUserIdFromRequest, getUserNameFromRequest, requireUserId } from './next-utils.cjs';
4
+
5
+ /**
6
+ * SolvaPay Auth Adapter
7
+ *
8
+ * Validates SolvaPay OAuth tokens by calling the userinfo endpoint.
9
+ * Suitable for validating opaque tokens issued by SolvaPay's hosted OAuth service.
10
+ */
11
+
12
+ interface SolvapayAuthAdapterConfig {
13
+ /**
14
+ * SolvaPay API Base URL (e.g. https://api.solvapay.com)
15
+ */
16
+ apiBaseUrl: string;
17
+ }
18
+ /**
19
+ * SolvaPay authentication adapter
20
+ *
21
+ * Validates tokens by calling the SolvaPay userinfo endpoint.
22
+ * This is required for opaque tokens which cannot be verified offline.
23
+ */
24
+ declare class SolvapayAuthAdapter implements AuthAdapter {
25
+ private apiBaseUrl;
26
+ constructor(config: SolvapayAuthAdapterConfig);
27
+ getUserIdFromRequest(req: Request | RequestLike): Promise<string | null>;
28
+ }
29
+ /**
30
+ * SolvaPay OAuth Client Helpers
31
+ */
32
+ interface SolvapayOAuthConfig {
33
+ clientId: string;
34
+ clientSecret?: string;
35
+ authUrl: string;
36
+ tokenUrl: string;
37
+ redirectUri: string;
38
+ }
39
+ interface TokenResponse {
40
+ access_token: string;
41
+ token_type: string;
42
+ expires_in: number;
43
+ refresh_token?: string;
44
+ scope?: string;
45
+ }
46
+ declare class SolvapayOAuthClient {
47
+ private config;
48
+ constructor(config: SolvapayOAuthConfig);
49
+ /**
50
+ * Get the URL to redirect the user to for login
51
+ */
52
+ getAuthorizationUrl(options?: {
53
+ state?: string;
54
+ scope?: string;
55
+ }): string;
56
+ /**
57
+ * Exchange an authorization code for an access token
58
+ */
59
+ exchangeCodeForToken(code: string): Promise<TokenResponse>;
60
+ /**
61
+ * Revoke a token (Sign Out)
62
+ */
63
+ revokeToken(token: string): Promise<void>;
64
+ /**
65
+ * Get user info using access token
66
+ */
67
+ getUserInfo(accessToken: string, userInfoUrl?: string): Promise<Record<string, unknown>>;
68
+ }
69
+
70
+ export { AuthAdapter, RequestLike, SolvapayAuthAdapter, type SolvapayAuthAdapterConfig, SolvapayOAuthClient, type SolvapayOAuthConfig, type TokenResponse };