@solvapay/next 1.0.1-preview.1 → 1.0.1-preview.2
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/README.md +6 -6
- package/dist/chunk-F7TBIH6W.js +74 -0
- package/dist/index.d.cts +4 -177
- package/dist/index.d.ts +4 -177
- package/dist/index.js +9 -74
- package/dist/middleware.cjs +111 -0
- package/dist/middleware.d.cts +178 -0
- package/dist/middleware.d.ts +178 -0
- package/dist/middleware.js +8 -0
- package/package.json +10 -5
package/README.md
CHANGED
|
@@ -274,7 +274,7 @@ export const config = {
|
|
|
274
274
|
|
|
275
275
|
```typescript
|
|
276
276
|
// src/proxy.ts (in src/ folder, not project root)
|
|
277
|
-
import { createSupabaseAuthMiddleware } from '@solvapay/next'
|
|
277
|
+
import { createSupabaseAuthMiddleware } from '@solvapay/next/middleware'
|
|
278
278
|
|
|
279
279
|
// Use 'proxy' export for Next.js 16 (no deprecation warning)
|
|
280
280
|
export const proxy = createSupabaseAuthMiddleware({
|
|
@@ -289,21 +289,21 @@ export const config = {
|
|
|
289
289
|
**File Location Notes:**
|
|
290
290
|
|
|
291
291
|
- **Next.js 15**: Place `middleware.ts` at project root
|
|
292
|
-
- **Next.js 16 without `src/` folder**: Place `
|
|
293
|
-
- **Next.js 16 with `src/` folder**: Place `src/proxy.ts`
|
|
292
|
+
- **Next.js 16 without `src/` folder**: Place `proxy.ts` at project root
|
|
293
|
+
- **Next.js 16 with `src/` folder**: Place `src/proxy.ts` (in `src/` folder, not root)
|
|
294
294
|
|
|
295
|
-
> **Note:** Next.js 16 renamed "middleware" to "proxy".
|
|
295
|
+
> **Note:** Next.js 16 renamed "middleware" to "proxy". Use `proxy` to avoid deprecation warnings.
|
|
296
296
|
|
|
297
297
|
### Custom Middleware
|
|
298
298
|
|
|
299
299
|
Alternatively, you can create your own middleware:
|
|
300
300
|
|
|
301
301
|
```typescript
|
|
302
|
-
//
|
|
302
|
+
// proxy.ts (or src/proxy.ts for Next.js 16)
|
|
303
303
|
import { NextResponse } from 'next/server'
|
|
304
304
|
import type { NextRequest } from 'next/server'
|
|
305
305
|
|
|
306
|
-
export async function
|
|
306
|
+
export async function proxy(request: NextRequest) {
|
|
307
307
|
// Extract user ID from your auth system
|
|
308
308
|
const userId = await getUserIdFromAuth(request)
|
|
309
309
|
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// src/helpers/middleware.ts
|
|
2
|
+
import { NextResponse } from "next/server";
|
|
3
|
+
function createAuthMiddleware(options) {
|
|
4
|
+
const { adapter, publicRoutes = [], userIdHeader = "x-user-id" } = options;
|
|
5
|
+
return async function middleware(request) {
|
|
6
|
+
const req = request;
|
|
7
|
+
const { pathname } = req.nextUrl;
|
|
8
|
+
if (!pathname.startsWith("/api")) {
|
|
9
|
+
return NextResponse.next();
|
|
10
|
+
}
|
|
11
|
+
const isPublicRoute = publicRoutes.some((route) => pathname.startsWith(route));
|
|
12
|
+
const userId = await adapter.getUserIdFromRequest(req);
|
|
13
|
+
if (isPublicRoute) {
|
|
14
|
+
const requestHeaders2 = new Headers(req.headers);
|
|
15
|
+
if (userId) {
|
|
16
|
+
requestHeaders2.set(userIdHeader, userId);
|
|
17
|
+
}
|
|
18
|
+
return NextResponse.next({
|
|
19
|
+
request: {
|
|
20
|
+
headers: requestHeaders2
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
if (!userId) {
|
|
25
|
+
return NextResponse.json(
|
|
26
|
+
{ error: "Unauthorized", details: "Valid authentication required" },
|
|
27
|
+
{ status: 401 }
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
const requestHeaders = new Headers(req.headers);
|
|
31
|
+
requestHeaders.set(userIdHeader, userId);
|
|
32
|
+
return NextResponse.next({
|
|
33
|
+
request: {
|
|
34
|
+
headers: requestHeaders
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function createSupabaseAuthMiddleware(options = {}) {
|
|
40
|
+
const { jwtSecret, publicRoutes = [], userIdHeader = "x-user-id" } = options;
|
|
41
|
+
let authAdapter = null;
|
|
42
|
+
let adapterPromise = null;
|
|
43
|
+
const lazyAdapter = {
|
|
44
|
+
async getUserIdFromRequest(req) {
|
|
45
|
+
if (!authAdapter) {
|
|
46
|
+
if (!adapterPromise) {
|
|
47
|
+
adapterPromise = (async () => {
|
|
48
|
+
const secret = jwtSecret || process.env.SUPABASE_JWT_SECRET;
|
|
49
|
+
if (!secret) {
|
|
50
|
+
throw new Error(
|
|
51
|
+
"SUPABASE_JWT_SECRET environment variable is required. Please set it in your .env.local file. Get it from: Supabase Dashboard \u2192 Settings \u2192 API \u2192 JWT Secret"
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
const { SupabaseAuthAdapter } = await import("@solvapay/auth/supabase");
|
|
55
|
+
authAdapter = new SupabaseAuthAdapter({ jwtSecret: secret });
|
|
56
|
+
return authAdapter;
|
|
57
|
+
})();
|
|
58
|
+
}
|
|
59
|
+
authAdapter = await adapterPromise;
|
|
60
|
+
}
|
|
61
|
+
return authAdapter.getUserIdFromRequest(req);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
return createAuthMiddleware({
|
|
65
|
+
adapter: lazyAdapter,
|
|
66
|
+
publicRoutes,
|
|
67
|
+
userIdHeader
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export {
|
|
72
|
+
createAuthMiddleware,
|
|
73
|
+
createSupabaseAuthMiddleware
|
|
74
|
+
};
|
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { NextResponse
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
2
|
import * as _solvapay_server from '@solvapay/server';
|
|
3
3
|
import { AuthenticatedUser, SolvaPay } from '@solvapay/server';
|
|
4
|
-
|
|
4
|
+
export { AuthMiddlewareOptions, SupabaseAuthMiddlewareOptions, createAuthMiddleware, createSupabaseAuthMiddleware } from './middleware.cjs';
|
|
5
|
+
import '@solvapay/auth';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Purchase Cache Utilities
|
|
@@ -274,180 +275,6 @@ declare function listPlans(request: globalThis.Request): Promise<{
|
|
|
274
275
|
productRef: string;
|
|
275
276
|
} | NextResponse>;
|
|
276
277
|
|
|
277
|
-
/**
|
|
278
|
-
* Next.js Middleware Helpers
|
|
279
|
-
*
|
|
280
|
-
* Helpers for creating authentication middleware in Next.js.
|
|
281
|
-
* Works with any AuthAdapter implementation (Supabase, custom, etc.)
|
|
282
|
-
*/
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* Configuration options for authentication middleware
|
|
286
|
-
*/
|
|
287
|
-
interface AuthMiddlewareOptions {
|
|
288
|
-
/**
|
|
289
|
-
* Auth adapter instance to use for extracting user IDs from requests
|
|
290
|
-
* You can use SupabaseAuthAdapter, MockAuthAdapter, or create your own
|
|
291
|
-
*/
|
|
292
|
-
adapter: AuthAdapter;
|
|
293
|
-
/**
|
|
294
|
-
* Public routes that don't require authentication
|
|
295
|
-
* Routes are matched using pathname.startsWith()
|
|
296
|
-
*/
|
|
297
|
-
publicRoutes?: string[];
|
|
298
|
-
/**
|
|
299
|
-
* Header name to store the user ID (default: 'x-user-id')
|
|
300
|
-
*/
|
|
301
|
-
userIdHeader?: string;
|
|
302
|
-
}
|
|
303
|
-
/**
|
|
304
|
-
* Creates a Next.js middleware function for authentication
|
|
305
|
-
*
|
|
306
|
-
* This helper:
|
|
307
|
-
* 1. Uses the provided AuthAdapter to extract userId from requests
|
|
308
|
-
* 2. Handles public vs protected routes
|
|
309
|
-
* 3. Adds userId to request headers for downstream routes
|
|
310
|
-
* 4. Returns appropriate error responses for auth failures
|
|
311
|
-
*
|
|
312
|
-
* @param options - Configuration options
|
|
313
|
-
* @returns Next.js middleware function (can be exported as `middleware` or `proxy`)
|
|
314
|
-
*
|
|
315
|
-
* @example Next.js 15
|
|
316
|
-
* ```typescript
|
|
317
|
-
* // middleware.ts (at project root)
|
|
318
|
-
* import { createAuthMiddleware } from '@solvapay/next';
|
|
319
|
-
* import { SupabaseAuthAdapter } from '@solvapay/auth/supabase';
|
|
320
|
-
*
|
|
321
|
-
* const adapter = new SupabaseAuthAdapter({
|
|
322
|
-
* jwtSecret: process.env.SUPABASE_JWT_SECRET!,
|
|
323
|
-
* });
|
|
324
|
-
*
|
|
325
|
-
* export const middleware = createAuthMiddleware({
|
|
326
|
-
* adapter,
|
|
327
|
-
* publicRoutes: ['/api/list-plans'],
|
|
328
|
-
* });
|
|
329
|
-
*
|
|
330
|
-
* export const config = {
|
|
331
|
-
* matcher: ['/api/:path*'],
|
|
332
|
-
* };
|
|
333
|
-
* ```
|
|
334
|
-
*
|
|
335
|
-
* @example Next.js 16 with src/ folder
|
|
336
|
-
* ```typescript
|
|
337
|
-
* // src/proxy.ts (in src/ folder, not project root)
|
|
338
|
-
* import { createAuthMiddleware } from '@solvapay/next';
|
|
339
|
-
* import { SupabaseAuthAdapter } from '@solvapay/auth/supabase';
|
|
340
|
-
*
|
|
341
|
-
* const adapter = new SupabaseAuthAdapter({
|
|
342
|
-
* jwtSecret: process.env.SUPABASE_JWT_SECRET!,
|
|
343
|
-
* });
|
|
344
|
-
*
|
|
345
|
-
* // Use 'proxy' export for Next.js 16 (no deprecation warning)
|
|
346
|
-
* export const proxy = createAuthMiddleware({
|
|
347
|
-
* adapter,
|
|
348
|
-
* publicRoutes: ['/api/list-plans'],
|
|
349
|
-
* });
|
|
350
|
-
*
|
|
351
|
-
* export const config = {
|
|
352
|
-
* matcher: ['/api/:path*'],
|
|
353
|
-
* };
|
|
354
|
-
* ```
|
|
355
|
-
*
|
|
356
|
-
* @example Custom adapter
|
|
357
|
-
* ```typescript
|
|
358
|
-
* import { createAuthMiddleware } from '@solvapay/next';
|
|
359
|
-
* import type { AuthAdapter } from '@solvapay/auth';
|
|
360
|
-
*
|
|
361
|
-
* const myAdapter: AuthAdapter = {
|
|
362
|
-
* async getUserIdFromRequest(req) {
|
|
363
|
-
* // Your custom auth logic
|
|
364
|
-
* return userId;
|
|
365
|
-
* },
|
|
366
|
-
* };
|
|
367
|
-
*
|
|
368
|
-
* export const middleware = createAuthMiddleware({
|
|
369
|
-
* adapter: myAdapter,
|
|
370
|
-
* });
|
|
371
|
-
* ```
|
|
372
|
-
*
|
|
373
|
-
* **File Location Notes:**
|
|
374
|
-
* - **Next.js 15**: Place `middleware.ts` at project root
|
|
375
|
-
* - **Next.js 16 without `src/` folder**: Place `middleware.ts` or `proxy.ts` at project root
|
|
376
|
-
* - **Next.js 16 with `src/` folder**: Place `src/proxy.ts` or `src/middleware.ts` (in `src/` folder, not root)
|
|
377
|
-
*
|
|
378
|
-
* **Note:** Next.js 16 renamed "middleware" to "proxy". You can export the return value as either
|
|
379
|
-
* `middleware` or `proxy` - both work, but `proxy` is recommended to avoid deprecation warnings.
|
|
380
|
-
*/
|
|
381
|
-
declare function createAuthMiddleware(options: AuthMiddlewareOptions): (request: NextRequest) => Promise<NextResponse<unknown>>;
|
|
382
|
-
/**
|
|
383
|
-
* Configuration options for Supabase authentication middleware
|
|
384
|
-
*/
|
|
385
|
-
interface SupabaseAuthMiddlewareOptions {
|
|
386
|
-
/**
|
|
387
|
-
* Supabase JWT secret (from Supabase dashboard: Settings → API → JWT Secret)
|
|
388
|
-
* If not provided, will use SUPABASE_JWT_SECRET environment variable
|
|
389
|
-
*/
|
|
390
|
-
jwtSecret?: string;
|
|
391
|
-
/**
|
|
392
|
-
* Public routes that don't require authentication
|
|
393
|
-
* Routes are matched using pathname.startsWith()
|
|
394
|
-
*/
|
|
395
|
-
publicRoutes?: string[];
|
|
396
|
-
/**
|
|
397
|
-
* Header name to store the user ID (default: 'x-user-id')
|
|
398
|
-
*/
|
|
399
|
-
userIdHeader?: string;
|
|
400
|
-
}
|
|
401
|
-
/**
|
|
402
|
-
* Creates a Next.js middleware function for Supabase authentication
|
|
403
|
-
*
|
|
404
|
-
* Convenience function that creates a SupabaseAuthAdapter and wraps it with createAuthMiddleware.
|
|
405
|
-
* Only use this if you're using Supabase - otherwise use createAuthMiddleware with your own adapter.
|
|
406
|
-
*
|
|
407
|
-
* Uses dynamic import to avoid requiring Supabase as a dependency in @solvapay/next.
|
|
408
|
-
*
|
|
409
|
-
* @param options - Configuration options
|
|
410
|
-
* @returns Next.js middleware function (can be exported as `middleware` or `proxy`)
|
|
411
|
-
*
|
|
412
|
-
* @example Next.js 15
|
|
413
|
-
* ```typescript
|
|
414
|
-
* // middleware.ts (at project root)
|
|
415
|
-
* import { createSupabaseAuthMiddleware } from '@solvapay/next';
|
|
416
|
-
*
|
|
417
|
-
* export const middleware = createSupabaseAuthMiddleware({
|
|
418
|
-
* publicRoutes: ['/api/list-plans'],
|
|
419
|
-
* });
|
|
420
|
-
*
|
|
421
|
-
* export const config = {
|
|
422
|
-
* matcher: ['/api/:path*'],
|
|
423
|
-
* };
|
|
424
|
-
* ```
|
|
425
|
-
*
|
|
426
|
-
* @example Next.js 16 with src/ folder
|
|
427
|
-
* ```typescript
|
|
428
|
-
* // src/proxy.ts (in src/ folder, not project root)
|
|
429
|
-
* import { createSupabaseAuthMiddleware } from '@solvapay/next';
|
|
430
|
-
*
|
|
431
|
-
* // Use 'proxy' export for Next.js 16 (no deprecation warning)
|
|
432
|
-
* export const proxy = createSupabaseAuthMiddleware({
|
|
433
|
-
* publicRoutes: ['/api/list-plans'],
|
|
434
|
-
* });
|
|
435
|
-
*
|
|
436
|
-
* export const config = {
|
|
437
|
-
* matcher: ['/api/:path*'],
|
|
438
|
-
* };
|
|
439
|
-
* ```
|
|
440
|
-
*
|
|
441
|
-
* **File Location Notes:**
|
|
442
|
-
* - **Next.js 15**: Place `middleware.ts` at project root
|
|
443
|
-
* - **Next.js 16 without `src/` folder**: Place `middleware.ts` or `proxy.ts` at project root
|
|
444
|
-
* - **Next.js 16 with `src/` folder**: Place `src/proxy.ts` or `src/middleware.ts` (in `src/` folder, not root)
|
|
445
|
-
*
|
|
446
|
-
* **Note:** Next.js 16 renamed "middleware" to "proxy". You can export the return value as either
|
|
447
|
-
* `middleware` or `proxy` - both work, but `proxy` is recommended to avoid deprecation warnings.
|
|
448
|
-
*/
|
|
449
|
-
declare function createSupabaseAuthMiddleware(options?: SupabaseAuthMiddlewareOptions): (request: NextRequest) => Promise<NextResponse<unknown>>;
|
|
450
|
-
|
|
451
278
|
/**
|
|
452
279
|
* SolvaPay Next.js SDK
|
|
453
280
|
*
|
|
@@ -531,4 +358,4 @@ interface CheckPurchaseOptions {
|
|
|
531
358
|
*/
|
|
532
359
|
declare function checkPurchase(request: Request, options?: CheckPurchaseOptions): Promise<PurchaseCheckResult | NextResponse>;
|
|
533
360
|
|
|
534
|
-
export { type
|
|
361
|
+
export { type CheckPurchaseOptions, type PurchaseCheckResult, type RequestDeduplicationOptions, cancelRenewal, checkPurchase, clearAllPurchaseCache, clearPurchaseCache, createCheckoutSession, createCustomerSession, createPaymentIntent, getAuthenticatedUser, getPurchaseCacheStats, listPlans, processPaymentIntent, syncCustomer };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { NextResponse
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
2
|
import * as _solvapay_server from '@solvapay/server';
|
|
3
3
|
import { AuthenticatedUser, SolvaPay } from '@solvapay/server';
|
|
4
|
-
|
|
4
|
+
export { AuthMiddlewareOptions, SupabaseAuthMiddlewareOptions, createAuthMiddleware, createSupabaseAuthMiddleware } from './middleware.js';
|
|
5
|
+
import '@solvapay/auth';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Purchase Cache Utilities
|
|
@@ -274,180 +275,6 @@ declare function listPlans(request: globalThis.Request): Promise<{
|
|
|
274
275
|
productRef: string;
|
|
275
276
|
} | NextResponse>;
|
|
276
277
|
|
|
277
|
-
/**
|
|
278
|
-
* Next.js Middleware Helpers
|
|
279
|
-
*
|
|
280
|
-
* Helpers for creating authentication middleware in Next.js.
|
|
281
|
-
* Works with any AuthAdapter implementation (Supabase, custom, etc.)
|
|
282
|
-
*/
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* Configuration options for authentication middleware
|
|
286
|
-
*/
|
|
287
|
-
interface AuthMiddlewareOptions {
|
|
288
|
-
/**
|
|
289
|
-
* Auth adapter instance to use for extracting user IDs from requests
|
|
290
|
-
* You can use SupabaseAuthAdapter, MockAuthAdapter, or create your own
|
|
291
|
-
*/
|
|
292
|
-
adapter: AuthAdapter;
|
|
293
|
-
/**
|
|
294
|
-
* Public routes that don't require authentication
|
|
295
|
-
* Routes are matched using pathname.startsWith()
|
|
296
|
-
*/
|
|
297
|
-
publicRoutes?: string[];
|
|
298
|
-
/**
|
|
299
|
-
* Header name to store the user ID (default: 'x-user-id')
|
|
300
|
-
*/
|
|
301
|
-
userIdHeader?: string;
|
|
302
|
-
}
|
|
303
|
-
/**
|
|
304
|
-
* Creates a Next.js middleware function for authentication
|
|
305
|
-
*
|
|
306
|
-
* This helper:
|
|
307
|
-
* 1. Uses the provided AuthAdapter to extract userId from requests
|
|
308
|
-
* 2. Handles public vs protected routes
|
|
309
|
-
* 3. Adds userId to request headers for downstream routes
|
|
310
|
-
* 4. Returns appropriate error responses for auth failures
|
|
311
|
-
*
|
|
312
|
-
* @param options - Configuration options
|
|
313
|
-
* @returns Next.js middleware function (can be exported as `middleware` or `proxy`)
|
|
314
|
-
*
|
|
315
|
-
* @example Next.js 15
|
|
316
|
-
* ```typescript
|
|
317
|
-
* // middleware.ts (at project root)
|
|
318
|
-
* import { createAuthMiddleware } from '@solvapay/next';
|
|
319
|
-
* import { SupabaseAuthAdapter } from '@solvapay/auth/supabase';
|
|
320
|
-
*
|
|
321
|
-
* const adapter = new SupabaseAuthAdapter({
|
|
322
|
-
* jwtSecret: process.env.SUPABASE_JWT_SECRET!,
|
|
323
|
-
* });
|
|
324
|
-
*
|
|
325
|
-
* export const middleware = createAuthMiddleware({
|
|
326
|
-
* adapter,
|
|
327
|
-
* publicRoutes: ['/api/list-plans'],
|
|
328
|
-
* });
|
|
329
|
-
*
|
|
330
|
-
* export const config = {
|
|
331
|
-
* matcher: ['/api/:path*'],
|
|
332
|
-
* };
|
|
333
|
-
* ```
|
|
334
|
-
*
|
|
335
|
-
* @example Next.js 16 with src/ folder
|
|
336
|
-
* ```typescript
|
|
337
|
-
* // src/proxy.ts (in src/ folder, not project root)
|
|
338
|
-
* import { createAuthMiddleware } from '@solvapay/next';
|
|
339
|
-
* import { SupabaseAuthAdapter } from '@solvapay/auth/supabase';
|
|
340
|
-
*
|
|
341
|
-
* const adapter = new SupabaseAuthAdapter({
|
|
342
|
-
* jwtSecret: process.env.SUPABASE_JWT_SECRET!,
|
|
343
|
-
* });
|
|
344
|
-
*
|
|
345
|
-
* // Use 'proxy' export for Next.js 16 (no deprecation warning)
|
|
346
|
-
* export const proxy = createAuthMiddleware({
|
|
347
|
-
* adapter,
|
|
348
|
-
* publicRoutes: ['/api/list-plans'],
|
|
349
|
-
* });
|
|
350
|
-
*
|
|
351
|
-
* export const config = {
|
|
352
|
-
* matcher: ['/api/:path*'],
|
|
353
|
-
* };
|
|
354
|
-
* ```
|
|
355
|
-
*
|
|
356
|
-
* @example Custom adapter
|
|
357
|
-
* ```typescript
|
|
358
|
-
* import { createAuthMiddleware } from '@solvapay/next';
|
|
359
|
-
* import type { AuthAdapter } from '@solvapay/auth';
|
|
360
|
-
*
|
|
361
|
-
* const myAdapter: AuthAdapter = {
|
|
362
|
-
* async getUserIdFromRequest(req) {
|
|
363
|
-
* // Your custom auth logic
|
|
364
|
-
* return userId;
|
|
365
|
-
* },
|
|
366
|
-
* };
|
|
367
|
-
*
|
|
368
|
-
* export const middleware = createAuthMiddleware({
|
|
369
|
-
* adapter: myAdapter,
|
|
370
|
-
* });
|
|
371
|
-
* ```
|
|
372
|
-
*
|
|
373
|
-
* **File Location Notes:**
|
|
374
|
-
* - **Next.js 15**: Place `middleware.ts` at project root
|
|
375
|
-
* - **Next.js 16 without `src/` folder**: Place `middleware.ts` or `proxy.ts` at project root
|
|
376
|
-
* - **Next.js 16 with `src/` folder**: Place `src/proxy.ts` or `src/middleware.ts` (in `src/` folder, not root)
|
|
377
|
-
*
|
|
378
|
-
* **Note:** Next.js 16 renamed "middleware" to "proxy". You can export the return value as either
|
|
379
|
-
* `middleware` or `proxy` - both work, but `proxy` is recommended to avoid deprecation warnings.
|
|
380
|
-
*/
|
|
381
|
-
declare function createAuthMiddleware(options: AuthMiddlewareOptions): (request: NextRequest) => Promise<NextResponse<unknown>>;
|
|
382
|
-
/**
|
|
383
|
-
* Configuration options for Supabase authentication middleware
|
|
384
|
-
*/
|
|
385
|
-
interface SupabaseAuthMiddlewareOptions {
|
|
386
|
-
/**
|
|
387
|
-
* Supabase JWT secret (from Supabase dashboard: Settings → API → JWT Secret)
|
|
388
|
-
* If not provided, will use SUPABASE_JWT_SECRET environment variable
|
|
389
|
-
*/
|
|
390
|
-
jwtSecret?: string;
|
|
391
|
-
/**
|
|
392
|
-
* Public routes that don't require authentication
|
|
393
|
-
* Routes are matched using pathname.startsWith()
|
|
394
|
-
*/
|
|
395
|
-
publicRoutes?: string[];
|
|
396
|
-
/**
|
|
397
|
-
* Header name to store the user ID (default: 'x-user-id')
|
|
398
|
-
*/
|
|
399
|
-
userIdHeader?: string;
|
|
400
|
-
}
|
|
401
|
-
/**
|
|
402
|
-
* Creates a Next.js middleware function for Supabase authentication
|
|
403
|
-
*
|
|
404
|
-
* Convenience function that creates a SupabaseAuthAdapter and wraps it with createAuthMiddleware.
|
|
405
|
-
* Only use this if you're using Supabase - otherwise use createAuthMiddleware with your own adapter.
|
|
406
|
-
*
|
|
407
|
-
* Uses dynamic import to avoid requiring Supabase as a dependency in @solvapay/next.
|
|
408
|
-
*
|
|
409
|
-
* @param options - Configuration options
|
|
410
|
-
* @returns Next.js middleware function (can be exported as `middleware` or `proxy`)
|
|
411
|
-
*
|
|
412
|
-
* @example Next.js 15
|
|
413
|
-
* ```typescript
|
|
414
|
-
* // middleware.ts (at project root)
|
|
415
|
-
* import { createSupabaseAuthMiddleware } from '@solvapay/next';
|
|
416
|
-
*
|
|
417
|
-
* export const middleware = createSupabaseAuthMiddleware({
|
|
418
|
-
* publicRoutes: ['/api/list-plans'],
|
|
419
|
-
* });
|
|
420
|
-
*
|
|
421
|
-
* export const config = {
|
|
422
|
-
* matcher: ['/api/:path*'],
|
|
423
|
-
* };
|
|
424
|
-
* ```
|
|
425
|
-
*
|
|
426
|
-
* @example Next.js 16 with src/ folder
|
|
427
|
-
* ```typescript
|
|
428
|
-
* // src/proxy.ts (in src/ folder, not project root)
|
|
429
|
-
* import { createSupabaseAuthMiddleware } from '@solvapay/next';
|
|
430
|
-
*
|
|
431
|
-
* // Use 'proxy' export for Next.js 16 (no deprecation warning)
|
|
432
|
-
* export const proxy = createSupabaseAuthMiddleware({
|
|
433
|
-
* publicRoutes: ['/api/list-plans'],
|
|
434
|
-
* });
|
|
435
|
-
*
|
|
436
|
-
* export const config = {
|
|
437
|
-
* matcher: ['/api/:path*'],
|
|
438
|
-
* };
|
|
439
|
-
* ```
|
|
440
|
-
*
|
|
441
|
-
* **File Location Notes:**
|
|
442
|
-
* - **Next.js 15**: Place `middleware.ts` at project root
|
|
443
|
-
* - **Next.js 16 without `src/` folder**: Place `middleware.ts` or `proxy.ts` at project root
|
|
444
|
-
* - **Next.js 16 with `src/` folder**: Place `src/proxy.ts` or `src/middleware.ts` (in `src/` folder, not root)
|
|
445
|
-
*
|
|
446
|
-
* **Note:** Next.js 16 renamed "middleware" to "proxy". You can export the return value as either
|
|
447
|
-
* `middleware` or `proxy` - both work, but `proxy` is recommended to avoid deprecation warnings.
|
|
448
|
-
*/
|
|
449
|
-
declare function createSupabaseAuthMiddleware(options?: SupabaseAuthMiddlewareOptions): (request: NextRequest) => Promise<NextResponse<unknown>>;
|
|
450
|
-
|
|
451
278
|
/**
|
|
452
279
|
* SolvaPay Next.js SDK
|
|
453
280
|
*
|
|
@@ -531,4 +358,4 @@ interface CheckPurchaseOptions {
|
|
|
531
358
|
*/
|
|
532
359
|
declare function checkPurchase(request: Request, options?: CheckPurchaseOptions): Promise<PurchaseCheckResult | NextResponse>;
|
|
533
360
|
|
|
534
|
-
export { type
|
|
361
|
+
export { type CheckPurchaseOptions, type PurchaseCheckResult, type RequestDeduplicationOptions, cancelRenewal, checkPurchase, clearAllPurchaseCache, clearPurchaseCache, createCheckoutSession, createCustomerSession, createPaymentIntent, getAuthenticatedUser, getPurchaseCacheStats, listPlans, processPaymentIntent, syncCustomer };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createAuthMiddleware,
|
|
3
|
+
createSupabaseAuthMiddleware
|
|
4
|
+
} from "./chunk-F7TBIH6W.js";
|
|
5
|
+
|
|
1
6
|
// src/index.ts
|
|
2
|
-
import { NextResponse as
|
|
7
|
+
import { NextResponse as NextResponse7 } from "next/server";
|
|
3
8
|
import { createSolvaPay } from "@solvapay/server";
|
|
4
9
|
import { SolvaPayError } from "@solvapay/core";
|
|
5
10
|
|
|
@@ -271,76 +276,6 @@ async function listPlans(request) {
|
|
|
271
276
|
return result;
|
|
272
277
|
}
|
|
273
278
|
|
|
274
|
-
// src/helpers/middleware.ts
|
|
275
|
-
import { NextResponse as NextResponse7 } from "next/server";
|
|
276
|
-
function createAuthMiddleware(options) {
|
|
277
|
-
const { adapter, publicRoutes = [], userIdHeader = "x-user-id" } = options;
|
|
278
|
-
return async function middleware(request) {
|
|
279
|
-
const req = request;
|
|
280
|
-
const { pathname } = req.nextUrl;
|
|
281
|
-
if (!pathname.startsWith("/api")) {
|
|
282
|
-
return NextResponse7.next();
|
|
283
|
-
}
|
|
284
|
-
const isPublicRoute = publicRoutes.some((route) => pathname.startsWith(route));
|
|
285
|
-
const userId = await adapter.getUserIdFromRequest(req);
|
|
286
|
-
if (isPublicRoute) {
|
|
287
|
-
const requestHeaders2 = new Headers(req.headers);
|
|
288
|
-
if (userId) {
|
|
289
|
-
requestHeaders2.set(userIdHeader, userId);
|
|
290
|
-
}
|
|
291
|
-
return NextResponse7.next({
|
|
292
|
-
request: {
|
|
293
|
-
headers: requestHeaders2
|
|
294
|
-
}
|
|
295
|
-
});
|
|
296
|
-
}
|
|
297
|
-
if (!userId) {
|
|
298
|
-
return NextResponse7.json(
|
|
299
|
-
{ error: "Unauthorized", details: "Valid authentication required" },
|
|
300
|
-
{ status: 401 }
|
|
301
|
-
);
|
|
302
|
-
}
|
|
303
|
-
const requestHeaders = new Headers(req.headers);
|
|
304
|
-
requestHeaders.set(userIdHeader, userId);
|
|
305
|
-
return NextResponse7.next({
|
|
306
|
-
request: {
|
|
307
|
-
headers: requestHeaders
|
|
308
|
-
}
|
|
309
|
-
});
|
|
310
|
-
};
|
|
311
|
-
}
|
|
312
|
-
function createSupabaseAuthMiddleware(options = {}) {
|
|
313
|
-
const { jwtSecret, publicRoutes = [], userIdHeader = "x-user-id" } = options;
|
|
314
|
-
let authAdapter = null;
|
|
315
|
-
let adapterPromise = null;
|
|
316
|
-
const lazyAdapter = {
|
|
317
|
-
async getUserIdFromRequest(req) {
|
|
318
|
-
if (!authAdapter) {
|
|
319
|
-
if (!adapterPromise) {
|
|
320
|
-
adapterPromise = (async () => {
|
|
321
|
-
const secret = jwtSecret || process.env.SUPABASE_JWT_SECRET;
|
|
322
|
-
if (!secret) {
|
|
323
|
-
throw new Error(
|
|
324
|
-
"SUPABASE_JWT_SECRET environment variable is required. Please set it in your .env.local file. Get it from: Supabase Dashboard \u2192 Settings \u2192 API \u2192 JWT Secret"
|
|
325
|
-
);
|
|
326
|
-
}
|
|
327
|
-
const { SupabaseAuthAdapter } = await import("@solvapay/auth/supabase");
|
|
328
|
-
authAdapter = new SupabaseAuthAdapter({ jwtSecret: secret });
|
|
329
|
-
return authAdapter;
|
|
330
|
-
})();
|
|
331
|
-
}
|
|
332
|
-
authAdapter = await adapterPromise;
|
|
333
|
-
}
|
|
334
|
-
return authAdapter.getUserIdFromRequest(req);
|
|
335
|
-
}
|
|
336
|
-
};
|
|
337
|
-
return createAuthMiddleware({
|
|
338
|
-
adapter: lazyAdapter,
|
|
339
|
-
publicRoutes,
|
|
340
|
-
userIdHeader
|
|
341
|
-
});
|
|
342
|
-
}
|
|
343
|
-
|
|
344
279
|
// src/index.ts
|
|
345
280
|
async function checkPurchase(request, options = {}) {
|
|
346
281
|
try {
|
|
@@ -349,7 +284,7 @@ async function checkPurchase(request, options = {}) {
|
|
|
349
284
|
if (userIdOrError instanceof Response) {
|
|
350
285
|
const clonedResponse = userIdOrError.clone();
|
|
351
286
|
const body = await clonedResponse.json().catch(() => ({ error: "Unauthorized" }));
|
|
352
|
-
return
|
|
287
|
+
return NextResponse7.json(body, { status: userIdOrError.status });
|
|
353
288
|
}
|
|
354
289
|
const userId = userIdOrError;
|
|
355
290
|
const email = options.includeEmail !== false ? await getUserEmailFromRequest(request) : null;
|
|
@@ -405,10 +340,10 @@ async function checkPurchase(request, options = {}) {
|
|
|
405
340
|
} catch (error) {
|
|
406
341
|
console.error("Check purchase failed:", error);
|
|
407
342
|
if (error instanceof SolvaPayError) {
|
|
408
|
-
return
|
|
343
|
+
return NextResponse7.json({ error: error.message }, { status: 500 });
|
|
409
344
|
}
|
|
410
345
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
411
|
-
return
|
|
346
|
+
return NextResponse7.json(
|
|
412
347
|
{ error: "Failed to check purchase", details: errorMessage },
|
|
413
348
|
{ status: 500 }
|
|
414
349
|
);
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/middleware.ts
|
|
31
|
+
var middleware_exports = {};
|
|
32
|
+
__export(middleware_exports, {
|
|
33
|
+
createAuthMiddleware: () => createAuthMiddleware,
|
|
34
|
+
createSupabaseAuthMiddleware: () => createSupabaseAuthMiddleware
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(middleware_exports);
|
|
37
|
+
|
|
38
|
+
// src/helpers/middleware.ts
|
|
39
|
+
var import_server = require("next/server");
|
|
40
|
+
function createAuthMiddleware(options) {
|
|
41
|
+
const { adapter, publicRoutes = [], userIdHeader = "x-user-id" } = options;
|
|
42
|
+
return async function middleware(request) {
|
|
43
|
+
const req = request;
|
|
44
|
+
const { pathname } = req.nextUrl;
|
|
45
|
+
if (!pathname.startsWith("/api")) {
|
|
46
|
+
return import_server.NextResponse.next();
|
|
47
|
+
}
|
|
48
|
+
const isPublicRoute = publicRoutes.some((route) => pathname.startsWith(route));
|
|
49
|
+
const userId = await adapter.getUserIdFromRequest(req);
|
|
50
|
+
if (isPublicRoute) {
|
|
51
|
+
const requestHeaders2 = new Headers(req.headers);
|
|
52
|
+
if (userId) {
|
|
53
|
+
requestHeaders2.set(userIdHeader, userId);
|
|
54
|
+
}
|
|
55
|
+
return import_server.NextResponse.next({
|
|
56
|
+
request: {
|
|
57
|
+
headers: requestHeaders2
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
if (!userId) {
|
|
62
|
+
return import_server.NextResponse.json(
|
|
63
|
+
{ error: "Unauthorized", details: "Valid authentication required" },
|
|
64
|
+
{ status: 401 }
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
const requestHeaders = new Headers(req.headers);
|
|
68
|
+
requestHeaders.set(userIdHeader, userId);
|
|
69
|
+
return import_server.NextResponse.next({
|
|
70
|
+
request: {
|
|
71
|
+
headers: requestHeaders
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function createSupabaseAuthMiddleware(options = {}) {
|
|
77
|
+
const { jwtSecret, publicRoutes = [], userIdHeader = "x-user-id" } = options;
|
|
78
|
+
let authAdapter = null;
|
|
79
|
+
let adapterPromise = null;
|
|
80
|
+
const lazyAdapter = {
|
|
81
|
+
async getUserIdFromRequest(req) {
|
|
82
|
+
if (!authAdapter) {
|
|
83
|
+
if (!adapterPromise) {
|
|
84
|
+
adapterPromise = (async () => {
|
|
85
|
+
const secret = jwtSecret || process.env.SUPABASE_JWT_SECRET;
|
|
86
|
+
if (!secret) {
|
|
87
|
+
throw new Error(
|
|
88
|
+
"SUPABASE_JWT_SECRET environment variable is required. Please set it in your .env.local file. Get it from: Supabase Dashboard \u2192 Settings \u2192 API \u2192 JWT Secret"
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
const { SupabaseAuthAdapter } = await import("@solvapay/auth/supabase");
|
|
92
|
+
authAdapter = new SupabaseAuthAdapter({ jwtSecret: secret });
|
|
93
|
+
return authAdapter;
|
|
94
|
+
})();
|
|
95
|
+
}
|
|
96
|
+
authAdapter = await adapterPromise;
|
|
97
|
+
}
|
|
98
|
+
return authAdapter.getUserIdFromRequest(req);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
return createAuthMiddleware({
|
|
102
|
+
adapter: lazyAdapter,
|
|
103
|
+
publicRoutes,
|
|
104
|
+
userIdHeader
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
108
|
+
0 && (module.exports = {
|
|
109
|
+
createAuthMiddleware,
|
|
110
|
+
createSupabaseAuthMiddleware
|
|
111
|
+
});
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { AuthAdapter } from '@solvapay/auth';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Next.js Middleware Helpers
|
|
6
|
+
*
|
|
7
|
+
* Helpers for creating authentication middleware in Next.js.
|
|
8
|
+
* Works with any AuthAdapter implementation (Supabase, custom, etc.)
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Configuration options for authentication middleware
|
|
13
|
+
*/
|
|
14
|
+
interface AuthMiddlewareOptions {
|
|
15
|
+
/**
|
|
16
|
+
* Auth adapter instance to use for extracting user IDs from requests
|
|
17
|
+
* You can use SupabaseAuthAdapter, MockAuthAdapter, or create your own
|
|
18
|
+
*/
|
|
19
|
+
adapter: AuthAdapter;
|
|
20
|
+
/**
|
|
21
|
+
* Public routes that don't require authentication
|
|
22
|
+
* Routes are matched using pathname.startsWith()
|
|
23
|
+
*/
|
|
24
|
+
publicRoutes?: string[];
|
|
25
|
+
/**
|
|
26
|
+
* Header name to store the user ID (default: 'x-user-id')
|
|
27
|
+
*/
|
|
28
|
+
userIdHeader?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Creates a Next.js middleware function for authentication
|
|
32
|
+
*
|
|
33
|
+
* This helper:
|
|
34
|
+
* 1. Uses the provided AuthAdapter to extract userId from requests
|
|
35
|
+
* 2. Handles public vs protected routes
|
|
36
|
+
* 3. Adds userId to request headers for downstream routes
|
|
37
|
+
* 4. Returns appropriate error responses for auth failures
|
|
38
|
+
*
|
|
39
|
+
* @param options - Configuration options
|
|
40
|
+
* @returns Next.js middleware function (can be exported as `middleware` or `proxy`)
|
|
41
|
+
*
|
|
42
|
+
* @example Next.js 15
|
|
43
|
+
* ```typescript
|
|
44
|
+
* // middleware.ts (at project root)
|
|
45
|
+
* import { createAuthMiddleware } from '@solvapay/next';
|
|
46
|
+
* import { SupabaseAuthAdapter } from '@solvapay/auth/supabase';
|
|
47
|
+
*
|
|
48
|
+
* const adapter = new SupabaseAuthAdapter({
|
|
49
|
+
* jwtSecret: process.env.SUPABASE_JWT_SECRET!,
|
|
50
|
+
* });
|
|
51
|
+
*
|
|
52
|
+
* export const middleware = createAuthMiddleware({
|
|
53
|
+
* adapter,
|
|
54
|
+
* publicRoutes: ['/api/list-plans'],
|
|
55
|
+
* });
|
|
56
|
+
*
|
|
57
|
+
* export const config = {
|
|
58
|
+
* matcher: ['/api/:path*'],
|
|
59
|
+
* };
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* @example Next.js 16 with src/ folder
|
|
63
|
+
* ```typescript
|
|
64
|
+
* // src/proxy.ts (in src/ folder, not project root)
|
|
65
|
+
* import { createAuthMiddleware } from '@solvapay/next';
|
|
66
|
+
* import { SupabaseAuthAdapter } from '@solvapay/auth/supabase';
|
|
67
|
+
*
|
|
68
|
+
* const adapter = new SupabaseAuthAdapter({
|
|
69
|
+
* jwtSecret: process.env.SUPABASE_JWT_SECRET!,
|
|
70
|
+
* });
|
|
71
|
+
*
|
|
72
|
+
* // Use 'proxy' export for Next.js 16 (no deprecation warning)
|
|
73
|
+
* export const proxy = createAuthMiddleware({
|
|
74
|
+
* adapter,
|
|
75
|
+
* publicRoutes: ['/api/list-plans'],
|
|
76
|
+
* });
|
|
77
|
+
*
|
|
78
|
+
* export const config = {
|
|
79
|
+
* matcher: ['/api/:path*'],
|
|
80
|
+
* };
|
|
81
|
+
* ```
|
|
82
|
+
*
|
|
83
|
+
* @example Custom adapter
|
|
84
|
+
* ```typescript
|
|
85
|
+
* import { createAuthMiddleware } from '@solvapay/next';
|
|
86
|
+
* import type { AuthAdapter } from '@solvapay/auth';
|
|
87
|
+
*
|
|
88
|
+
* const myAdapter: AuthAdapter = {
|
|
89
|
+
* async getUserIdFromRequest(req) {
|
|
90
|
+
* // Your custom auth logic
|
|
91
|
+
* return userId;
|
|
92
|
+
* },
|
|
93
|
+
* };
|
|
94
|
+
*
|
|
95
|
+
* export const middleware = createAuthMiddleware({
|
|
96
|
+
* adapter: myAdapter,
|
|
97
|
+
* });
|
|
98
|
+
* ```
|
|
99
|
+
*
|
|
100
|
+
* **File Location Notes:**
|
|
101
|
+
* - **Next.js 15**: Place `middleware.ts` at project root
|
|
102
|
+
* - **Next.js 16 without `src/` folder**: Place `middleware.ts` or `proxy.ts` at project root
|
|
103
|
+
* - **Next.js 16 with `src/` folder**: Place `src/proxy.ts` or `src/middleware.ts` (in `src/` folder, not root)
|
|
104
|
+
*
|
|
105
|
+
* **Note:** Next.js 16 renamed "middleware" to "proxy". You can export the return value as either
|
|
106
|
+
* `middleware` or `proxy` - both work, but `proxy` is recommended to avoid deprecation warnings.
|
|
107
|
+
*/
|
|
108
|
+
declare function createAuthMiddleware(options: AuthMiddlewareOptions): (request: NextRequest) => Promise<NextResponse<unknown>>;
|
|
109
|
+
/**
|
|
110
|
+
* Configuration options for Supabase authentication middleware
|
|
111
|
+
*/
|
|
112
|
+
interface SupabaseAuthMiddlewareOptions {
|
|
113
|
+
/**
|
|
114
|
+
* Supabase JWT secret (from Supabase dashboard: Settings → API → JWT Secret)
|
|
115
|
+
* If not provided, will use SUPABASE_JWT_SECRET environment variable
|
|
116
|
+
*/
|
|
117
|
+
jwtSecret?: string;
|
|
118
|
+
/**
|
|
119
|
+
* Public routes that don't require authentication
|
|
120
|
+
* Routes are matched using pathname.startsWith()
|
|
121
|
+
*/
|
|
122
|
+
publicRoutes?: string[];
|
|
123
|
+
/**
|
|
124
|
+
* Header name to store the user ID (default: 'x-user-id')
|
|
125
|
+
*/
|
|
126
|
+
userIdHeader?: string;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Creates a Next.js middleware function for Supabase authentication
|
|
130
|
+
*
|
|
131
|
+
* Convenience function that creates a SupabaseAuthAdapter and wraps it with createAuthMiddleware.
|
|
132
|
+
* Only use this if you're using Supabase - otherwise use createAuthMiddleware with your own adapter.
|
|
133
|
+
*
|
|
134
|
+
* Uses dynamic import to avoid requiring Supabase as a dependency in @solvapay/next.
|
|
135
|
+
*
|
|
136
|
+
* @param options - Configuration options
|
|
137
|
+
* @returns Next.js middleware function (can be exported as `middleware` or `proxy`)
|
|
138
|
+
*
|
|
139
|
+
* @example Next.js 15
|
|
140
|
+
* ```typescript
|
|
141
|
+
* // middleware.ts (at project root)
|
|
142
|
+
* import { createSupabaseAuthMiddleware } from '@solvapay/next';
|
|
143
|
+
*
|
|
144
|
+
* export const middleware = createSupabaseAuthMiddleware({
|
|
145
|
+
* publicRoutes: ['/api/list-plans'],
|
|
146
|
+
* });
|
|
147
|
+
*
|
|
148
|
+
* export const config = {
|
|
149
|
+
* matcher: ['/api/:path*'],
|
|
150
|
+
* };
|
|
151
|
+
* ```
|
|
152
|
+
*
|
|
153
|
+
* @example Next.js 16 with src/ folder
|
|
154
|
+
* ```typescript
|
|
155
|
+
* // src/proxy.ts (in src/ folder, not project root)
|
|
156
|
+
* import { createSupabaseAuthMiddleware } from '@solvapay/next';
|
|
157
|
+
*
|
|
158
|
+
* // Use 'proxy' export for Next.js 16 (no deprecation warning)
|
|
159
|
+
* export const proxy = createSupabaseAuthMiddleware({
|
|
160
|
+
* publicRoutes: ['/api/list-plans'],
|
|
161
|
+
* });
|
|
162
|
+
*
|
|
163
|
+
* export const config = {
|
|
164
|
+
* matcher: ['/api/:path*'],
|
|
165
|
+
* };
|
|
166
|
+
* ```
|
|
167
|
+
*
|
|
168
|
+
* **File Location Notes:**
|
|
169
|
+
* - **Next.js 15**: Place `middleware.ts` at project root
|
|
170
|
+
* - **Next.js 16 without `src/` folder**: Place `middleware.ts` or `proxy.ts` at project root
|
|
171
|
+
* - **Next.js 16 with `src/` folder**: Place `src/proxy.ts` or `src/middleware.ts` (in `src/` folder, not root)
|
|
172
|
+
*
|
|
173
|
+
* **Note:** Next.js 16 renamed "middleware" to "proxy". You can export the return value as either
|
|
174
|
+
* `middleware` or `proxy` - both work, but `proxy` is recommended to avoid deprecation warnings.
|
|
175
|
+
*/
|
|
176
|
+
declare function createSupabaseAuthMiddleware(options?: SupabaseAuthMiddlewareOptions): (request: NextRequest) => Promise<NextResponse<unknown>>;
|
|
177
|
+
|
|
178
|
+
export { type AuthMiddlewareOptions, type SupabaseAuthMiddlewareOptions, createAuthMiddleware, createSupabaseAuthMiddleware };
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { AuthAdapter } from '@solvapay/auth';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Next.js Middleware Helpers
|
|
6
|
+
*
|
|
7
|
+
* Helpers for creating authentication middleware in Next.js.
|
|
8
|
+
* Works with any AuthAdapter implementation (Supabase, custom, etc.)
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Configuration options for authentication middleware
|
|
13
|
+
*/
|
|
14
|
+
interface AuthMiddlewareOptions {
|
|
15
|
+
/**
|
|
16
|
+
* Auth adapter instance to use for extracting user IDs from requests
|
|
17
|
+
* You can use SupabaseAuthAdapter, MockAuthAdapter, or create your own
|
|
18
|
+
*/
|
|
19
|
+
adapter: AuthAdapter;
|
|
20
|
+
/**
|
|
21
|
+
* Public routes that don't require authentication
|
|
22
|
+
* Routes are matched using pathname.startsWith()
|
|
23
|
+
*/
|
|
24
|
+
publicRoutes?: string[];
|
|
25
|
+
/**
|
|
26
|
+
* Header name to store the user ID (default: 'x-user-id')
|
|
27
|
+
*/
|
|
28
|
+
userIdHeader?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Creates a Next.js middleware function for authentication
|
|
32
|
+
*
|
|
33
|
+
* This helper:
|
|
34
|
+
* 1. Uses the provided AuthAdapter to extract userId from requests
|
|
35
|
+
* 2. Handles public vs protected routes
|
|
36
|
+
* 3. Adds userId to request headers for downstream routes
|
|
37
|
+
* 4. Returns appropriate error responses for auth failures
|
|
38
|
+
*
|
|
39
|
+
* @param options - Configuration options
|
|
40
|
+
* @returns Next.js middleware function (can be exported as `middleware` or `proxy`)
|
|
41
|
+
*
|
|
42
|
+
* @example Next.js 15
|
|
43
|
+
* ```typescript
|
|
44
|
+
* // middleware.ts (at project root)
|
|
45
|
+
* import { createAuthMiddleware } from '@solvapay/next';
|
|
46
|
+
* import { SupabaseAuthAdapter } from '@solvapay/auth/supabase';
|
|
47
|
+
*
|
|
48
|
+
* const adapter = new SupabaseAuthAdapter({
|
|
49
|
+
* jwtSecret: process.env.SUPABASE_JWT_SECRET!,
|
|
50
|
+
* });
|
|
51
|
+
*
|
|
52
|
+
* export const middleware = createAuthMiddleware({
|
|
53
|
+
* adapter,
|
|
54
|
+
* publicRoutes: ['/api/list-plans'],
|
|
55
|
+
* });
|
|
56
|
+
*
|
|
57
|
+
* export const config = {
|
|
58
|
+
* matcher: ['/api/:path*'],
|
|
59
|
+
* };
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* @example Next.js 16 with src/ folder
|
|
63
|
+
* ```typescript
|
|
64
|
+
* // src/proxy.ts (in src/ folder, not project root)
|
|
65
|
+
* import { createAuthMiddleware } from '@solvapay/next';
|
|
66
|
+
* import { SupabaseAuthAdapter } from '@solvapay/auth/supabase';
|
|
67
|
+
*
|
|
68
|
+
* const adapter = new SupabaseAuthAdapter({
|
|
69
|
+
* jwtSecret: process.env.SUPABASE_JWT_SECRET!,
|
|
70
|
+
* });
|
|
71
|
+
*
|
|
72
|
+
* // Use 'proxy' export for Next.js 16 (no deprecation warning)
|
|
73
|
+
* export const proxy = createAuthMiddleware({
|
|
74
|
+
* adapter,
|
|
75
|
+
* publicRoutes: ['/api/list-plans'],
|
|
76
|
+
* });
|
|
77
|
+
*
|
|
78
|
+
* export const config = {
|
|
79
|
+
* matcher: ['/api/:path*'],
|
|
80
|
+
* };
|
|
81
|
+
* ```
|
|
82
|
+
*
|
|
83
|
+
* @example Custom adapter
|
|
84
|
+
* ```typescript
|
|
85
|
+
* import { createAuthMiddleware } from '@solvapay/next';
|
|
86
|
+
* import type { AuthAdapter } from '@solvapay/auth';
|
|
87
|
+
*
|
|
88
|
+
* const myAdapter: AuthAdapter = {
|
|
89
|
+
* async getUserIdFromRequest(req) {
|
|
90
|
+
* // Your custom auth logic
|
|
91
|
+
* return userId;
|
|
92
|
+
* },
|
|
93
|
+
* };
|
|
94
|
+
*
|
|
95
|
+
* export const middleware = createAuthMiddleware({
|
|
96
|
+
* adapter: myAdapter,
|
|
97
|
+
* });
|
|
98
|
+
* ```
|
|
99
|
+
*
|
|
100
|
+
* **File Location Notes:**
|
|
101
|
+
* - **Next.js 15**: Place `middleware.ts` at project root
|
|
102
|
+
* - **Next.js 16 without `src/` folder**: Place `middleware.ts` or `proxy.ts` at project root
|
|
103
|
+
* - **Next.js 16 with `src/` folder**: Place `src/proxy.ts` or `src/middleware.ts` (in `src/` folder, not root)
|
|
104
|
+
*
|
|
105
|
+
* **Note:** Next.js 16 renamed "middleware" to "proxy". You can export the return value as either
|
|
106
|
+
* `middleware` or `proxy` - both work, but `proxy` is recommended to avoid deprecation warnings.
|
|
107
|
+
*/
|
|
108
|
+
declare function createAuthMiddleware(options: AuthMiddlewareOptions): (request: NextRequest) => Promise<NextResponse<unknown>>;
|
|
109
|
+
/**
|
|
110
|
+
* Configuration options for Supabase authentication middleware
|
|
111
|
+
*/
|
|
112
|
+
interface SupabaseAuthMiddlewareOptions {
|
|
113
|
+
/**
|
|
114
|
+
* Supabase JWT secret (from Supabase dashboard: Settings → API → JWT Secret)
|
|
115
|
+
* If not provided, will use SUPABASE_JWT_SECRET environment variable
|
|
116
|
+
*/
|
|
117
|
+
jwtSecret?: string;
|
|
118
|
+
/**
|
|
119
|
+
* Public routes that don't require authentication
|
|
120
|
+
* Routes are matched using pathname.startsWith()
|
|
121
|
+
*/
|
|
122
|
+
publicRoutes?: string[];
|
|
123
|
+
/**
|
|
124
|
+
* Header name to store the user ID (default: 'x-user-id')
|
|
125
|
+
*/
|
|
126
|
+
userIdHeader?: string;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Creates a Next.js middleware function for Supabase authentication
|
|
130
|
+
*
|
|
131
|
+
* Convenience function that creates a SupabaseAuthAdapter and wraps it with createAuthMiddleware.
|
|
132
|
+
* Only use this if you're using Supabase - otherwise use createAuthMiddleware with your own adapter.
|
|
133
|
+
*
|
|
134
|
+
* Uses dynamic import to avoid requiring Supabase as a dependency in @solvapay/next.
|
|
135
|
+
*
|
|
136
|
+
* @param options - Configuration options
|
|
137
|
+
* @returns Next.js middleware function (can be exported as `middleware` or `proxy`)
|
|
138
|
+
*
|
|
139
|
+
* @example Next.js 15
|
|
140
|
+
* ```typescript
|
|
141
|
+
* // middleware.ts (at project root)
|
|
142
|
+
* import { createSupabaseAuthMiddleware } from '@solvapay/next';
|
|
143
|
+
*
|
|
144
|
+
* export const middleware = createSupabaseAuthMiddleware({
|
|
145
|
+
* publicRoutes: ['/api/list-plans'],
|
|
146
|
+
* });
|
|
147
|
+
*
|
|
148
|
+
* export const config = {
|
|
149
|
+
* matcher: ['/api/:path*'],
|
|
150
|
+
* };
|
|
151
|
+
* ```
|
|
152
|
+
*
|
|
153
|
+
* @example Next.js 16 with src/ folder
|
|
154
|
+
* ```typescript
|
|
155
|
+
* // src/proxy.ts (in src/ folder, not project root)
|
|
156
|
+
* import { createSupabaseAuthMiddleware } from '@solvapay/next';
|
|
157
|
+
*
|
|
158
|
+
* // Use 'proxy' export for Next.js 16 (no deprecation warning)
|
|
159
|
+
* export const proxy = createSupabaseAuthMiddleware({
|
|
160
|
+
* publicRoutes: ['/api/list-plans'],
|
|
161
|
+
* });
|
|
162
|
+
*
|
|
163
|
+
* export const config = {
|
|
164
|
+
* matcher: ['/api/:path*'],
|
|
165
|
+
* };
|
|
166
|
+
* ```
|
|
167
|
+
*
|
|
168
|
+
* **File Location Notes:**
|
|
169
|
+
* - **Next.js 15**: Place `middleware.ts` at project root
|
|
170
|
+
* - **Next.js 16 without `src/` folder**: Place `middleware.ts` or `proxy.ts` at project root
|
|
171
|
+
* - **Next.js 16 with `src/` folder**: Place `src/proxy.ts` or `src/middleware.ts` (in `src/` folder, not root)
|
|
172
|
+
*
|
|
173
|
+
* **Note:** Next.js 16 renamed "middleware" to "proxy". You can export the return value as either
|
|
174
|
+
* `middleware` or `proxy` - both work, but `proxy` is recommended to avoid deprecation warnings.
|
|
175
|
+
*/
|
|
176
|
+
declare function createSupabaseAuthMiddleware(options?: SupabaseAuthMiddlewareOptions): (request: NextRequest) => Promise<NextResponse<unknown>>;
|
|
177
|
+
|
|
178
|
+
export { type AuthMiddlewareOptions, type SupabaseAuthMiddlewareOptions, createAuthMiddleware, createSupabaseAuthMiddleware };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solvapay/next",
|
|
3
|
-
"version": "1.0.1-preview.
|
|
3
|
+
"version": "1.0.1-preview.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -10,6 +10,11 @@
|
|
|
10
10
|
"types": "./dist/index.d.ts",
|
|
11
11
|
"import": "./dist/index.js",
|
|
12
12
|
"require": "./dist/index.cjs"
|
|
13
|
+
},
|
|
14
|
+
"./middleware": {
|
|
15
|
+
"types": "./dist/middleware.d.ts",
|
|
16
|
+
"import": "./dist/middleware.js",
|
|
17
|
+
"require": "./dist/middleware.cjs"
|
|
13
18
|
}
|
|
14
19
|
},
|
|
15
20
|
"files": [
|
|
@@ -29,9 +34,9 @@
|
|
|
29
34
|
},
|
|
30
35
|
"sideEffects": false,
|
|
31
36
|
"dependencies": {
|
|
32
|
-
"@solvapay/
|
|
33
|
-
"@solvapay/
|
|
34
|
-
"@solvapay/
|
|
37
|
+
"@solvapay/auth": "1.0.1-preview.2",
|
|
38
|
+
"@solvapay/core": "1.0.1-preview.2",
|
|
39
|
+
"@solvapay/server": "1.0.1-preview.2"
|
|
35
40
|
},
|
|
36
41
|
"peerDependencies": {
|
|
37
42
|
"next": ">=13.0.0"
|
|
@@ -44,7 +49,7 @@
|
|
|
44
49
|
"@solvapay/test-utils": "0.0.0"
|
|
45
50
|
},
|
|
46
51
|
"scripts": {
|
|
47
|
-
"build": "tsup src/index.ts --format esm,cjs --dts --tsconfig tsconfig.build.json --external next",
|
|
52
|
+
"build": "tsup src/index.ts src/middleware.ts --format esm,cjs --dts --tsconfig tsconfig.build.json --external next",
|
|
48
53
|
"test": "vitest run || exit 0",
|
|
49
54
|
"test:watch": "vitest",
|
|
50
55
|
"lint": "eslint src",
|