@solvapay/next 1.0.0-preview.9 → 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/dist/index.js CHANGED
@@ -1,39 +1,46 @@
1
+ import {
2
+ createAuthMiddleware,
3
+ createSupabaseAuthMiddleware
4
+ } from "./chunk-F7TBIH6W.js";
5
+
1
6
  // src/index.ts
2
- import { NextResponse } from "next/server";
7
+ import { NextResponse as NextResponse7 } from "next/server";
3
8
  import { createSolvaPay } from "@solvapay/server";
4
9
  import { SolvaPayError } from "@solvapay/core";
10
+
11
+ // src/cache.ts
5
12
  function createRequestDeduplicator(options = {}) {
6
- const {
7
- cacheTTL = 2e3,
8
- maxCacheSize = 1e3,
9
- cacheErrors = true
10
- } = options;
13
+ const { cacheTTL = 2e3, maxCacheSize = 1e3, cacheErrors = true } = options;
11
14
  const inFlightRequests = /* @__PURE__ */ new Map();
12
15
  const resultCache = /* @__PURE__ */ new Map();
13
16
  const cacheInvalidatedAt = /* @__PURE__ */ new Map();
14
- let cleanupInterval = null;
15
17
  if (cacheTTL > 0) {
16
- cleanupInterval = setInterval(() => {
17
- const now = Date.now();
18
- const entriesToDelete = [];
19
- for (const [key, cached] of resultCache.entries()) {
20
- if (now - cached.timestamp >= cacheTTL) {
21
- entriesToDelete.push(key);
18
+ setInterval(
19
+ () => {
20
+ const now = Date.now();
21
+ const entriesToDelete = [];
22
+ for (const [key, cached] of resultCache.entries()) {
23
+ if (now - cached.timestamp >= cacheTTL) {
24
+ entriesToDelete.push(key);
25
+ }
22
26
  }
23
- }
24
- for (const key of entriesToDelete) {
25
- resultCache.delete(key);
26
- cacheInvalidatedAt.delete(key);
27
- }
28
- if (resultCache.size > maxCacheSize) {
29
- const sortedEntries = Array.from(resultCache.entries()).sort((a, b) => a[1].timestamp - b[1].timestamp);
30
- const toRemove = sortedEntries.slice(0, resultCache.size - maxCacheSize);
31
- for (const [key] of toRemove) {
27
+ for (const key of entriesToDelete) {
32
28
  resultCache.delete(key);
33
29
  cacheInvalidatedAt.delete(key);
34
30
  }
35
- }
36
- }, Math.min(cacheTTL, 1e3));
31
+ if (resultCache.size > maxCacheSize) {
32
+ const sortedEntries = Array.from(resultCache.entries()).sort(
33
+ (a, b) => a[1].timestamp - b[1].timestamp
34
+ );
35
+ const toRemove = sortedEntries.slice(0, resultCache.size - maxCacheSize);
36
+ for (const [key] of toRemove) {
37
+ resultCache.delete(key);
38
+ cacheInvalidatedAt.delete(key);
39
+ }
40
+ }
41
+ },
42
+ Math.min(cacheTTL, 1e3)
43
+ );
37
44
  }
38
45
  const deduplicate = async (key, fn) => {
39
46
  if (cacheTTL > 0) {
@@ -103,10 +110,10 @@ function createRequestDeduplicator(options = {}) {
103
110
  getStats
104
111
  };
105
112
  }
106
- var sharedSubscriptionDeduplicator = null;
113
+ var sharedPurchaseDeduplicator = null;
107
114
  function getSharedDeduplicator(options) {
108
- if (!sharedSubscriptionDeduplicator) {
109
- sharedSubscriptionDeduplicator = createRequestDeduplicator({
115
+ if (!sharedPurchaseDeduplicator) {
116
+ sharedPurchaseDeduplicator = createRequestDeduplicator({
110
117
  cacheTTL: 2e3,
111
118
  // Cache results for 2 seconds
112
119
  maxCacheSize: 1e3,
@@ -116,89 +123,245 @@ function getSharedDeduplicator(options) {
116
123
  ...options
117
124
  });
118
125
  }
119
- return sharedSubscriptionDeduplicator;
126
+ return sharedPurchaseDeduplicator;
127
+ }
128
+ function clearPurchaseCache(userId) {
129
+ const deduplicator = getSharedDeduplicator();
130
+ deduplicator.clearCache(userId);
131
+ }
132
+ function clearAllPurchaseCache() {
133
+ const deduplicator = getSharedDeduplicator();
134
+ deduplicator.clearAllCache();
135
+ }
136
+ function getPurchaseCacheStats() {
137
+ const deduplicator = getSharedDeduplicator();
138
+ return deduplicator.getStats();
139
+ }
140
+
141
+ // src/helpers/auth.ts
142
+ import { NextResponse } from "next/server";
143
+ import {
144
+ getAuthenticatedUserCore,
145
+ isErrorResult
146
+ } from "@solvapay/server";
147
+ async function getAuthenticatedUser(request, options = {}) {
148
+ const result = await getAuthenticatedUserCore(request, options);
149
+ if (isErrorResult(result)) {
150
+ return NextResponse.json(
151
+ { error: result.error, details: result.details },
152
+ { status: result.status }
153
+ );
154
+ }
155
+ return result;
156
+ }
157
+
158
+ // src/helpers/customer.ts
159
+ import { NextResponse as NextResponse2 } from "next/server";
160
+ import { syncCustomerCore, isErrorResult as isErrorResult2 } from "@solvapay/server";
161
+ async function syncCustomer(request, options = {}) {
162
+ const result = await syncCustomerCore(request, options);
163
+ if (isErrorResult2(result)) {
164
+ return NextResponse2.json(
165
+ { error: result.error, details: result.details },
166
+ { status: result.status }
167
+ );
168
+ }
169
+ return result;
170
+ }
171
+
172
+ // src/helpers/payment.ts
173
+ import { NextResponse as NextResponse3 } from "next/server";
174
+ import {
175
+ createPaymentIntentCore,
176
+ processPaymentIntentCore,
177
+ isErrorResult as isErrorResult3
178
+ } from "@solvapay/server";
179
+ import { getAuthenticatedUserCore as getAuthenticatedUserCore2 } from "@solvapay/server";
180
+ async function createPaymentIntent(request, body, options = {}) {
181
+ const result = await createPaymentIntentCore(request, body, options);
182
+ if (isErrorResult3(result)) {
183
+ return NextResponse3.json(
184
+ { error: result.error, details: result.details },
185
+ { status: result.status }
186
+ );
187
+ }
188
+ try {
189
+ const userResult = await getAuthenticatedUserCore2(request);
190
+ if (!isErrorResult3(userResult)) {
191
+ clearPurchaseCache(userResult.userId);
192
+ }
193
+ } catch {
194
+ }
195
+ return result;
196
+ }
197
+ async function processPaymentIntent(request, body, options = {}) {
198
+ const result = await processPaymentIntentCore(request, body, options);
199
+ if (isErrorResult3(result)) {
200
+ return NextResponse3.json(
201
+ { error: result.error, details: result.details },
202
+ { status: result.status }
203
+ );
204
+ }
205
+ try {
206
+ const userResult = await getAuthenticatedUserCore2(request);
207
+ if (!isErrorResult3(userResult)) {
208
+ clearPurchaseCache(userResult.userId);
209
+ }
210
+ } catch {
211
+ }
212
+ return result;
213
+ }
214
+
215
+ // src/helpers/checkout.ts
216
+ import { NextResponse as NextResponse4 } from "next/server";
217
+ import {
218
+ createCheckoutSessionCore,
219
+ createCustomerSessionCore,
220
+ isErrorResult as isErrorResult4
221
+ } from "@solvapay/server";
222
+ async function createCheckoutSession(request, body, options = {}) {
223
+ const result = await createCheckoutSessionCore(request, body, options);
224
+ if (isErrorResult4(result)) {
225
+ return NextResponse4.json(
226
+ { error: result.error, details: result.details },
227
+ { status: result.status }
228
+ );
229
+ }
230
+ return result;
231
+ }
232
+ async function createCustomerSession(request, options = {}) {
233
+ const result = await createCustomerSessionCore(request, options);
234
+ if (isErrorResult4(result)) {
235
+ return NextResponse4.json(
236
+ { error: result.error, details: result.details },
237
+ { status: result.status }
238
+ );
239
+ }
240
+ return result;
241
+ }
242
+
243
+ // src/helpers/renewal.ts
244
+ import { NextResponse as NextResponse5 } from "next/server";
245
+ import { cancelPurchaseCore, isErrorResult as isErrorResult5 } from "@solvapay/server";
246
+ import { getAuthenticatedUserCore as getAuthenticatedUserCore3 } from "@solvapay/server";
247
+ async function cancelRenewal(request, body, options = {}) {
248
+ const result = await cancelPurchaseCore(request, body, options);
249
+ if (isErrorResult5(result)) {
250
+ return NextResponse5.json(
251
+ { error: result.error, details: result.details },
252
+ { status: result.status }
253
+ );
254
+ }
255
+ try {
256
+ const userResult = await getAuthenticatedUserCore3(request);
257
+ if (!isErrorResult5(userResult)) {
258
+ clearPurchaseCache(userResult.userId);
259
+ }
260
+ } catch {
261
+ }
262
+ return result;
120
263
  }
121
- async function checkSubscription(request, options = {}) {
264
+
265
+ // src/helpers/plans.ts
266
+ import { NextResponse as NextResponse6 } from "next/server";
267
+ import { listPlansCore, isErrorResult as isErrorResult6 } from "@solvapay/server";
268
+ async function listPlans(request) {
269
+ const result = await listPlansCore(request);
270
+ if (isErrorResult6(result)) {
271
+ return NextResponse6.json(
272
+ { error: result.error, details: result.details },
273
+ { status: result.status }
274
+ );
275
+ }
276
+ return result;
277
+ }
278
+
279
+ // src/index.ts
280
+ async function checkPurchase(request, options = {}) {
122
281
  try {
123
282
  const { requireUserId, getUserEmailFromRequest, getUserNameFromRequest } = await import("@solvapay/auth");
124
283
  const userIdOrError = requireUserId(request);
125
284
  if (userIdOrError instanceof Response) {
126
285
  const clonedResponse = userIdOrError.clone();
127
286
  const body = await clonedResponse.json().catch(() => ({ error: "Unauthorized" }));
128
- return NextResponse.json(body, { status: userIdOrError.status });
287
+ return NextResponse7.json(body, { status: userIdOrError.status });
129
288
  }
130
289
  const userId = userIdOrError;
131
290
  const email = options.includeEmail !== false ? await getUserEmailFromRequest(request) : null;
132
291
  const name = options.includeName !== false ? await getUserNameFromRequest(request) : null;
292
+ const cachedCustomerRef = request.headers.get("x-solvapay-customer-ref");
293
+ const solvaPay = options.solvaPay || createSolvaPay();
294
+ if (cachedCustomerRef) {
295
+ try {
296
+ const customer = await solvaPay.getCustomer({ customerRef: cachedCustomerRef });
297
+ if (customer && customer.customerRef) {
298
+ if (customer.externalRef && customer.externalRef === userId) {
299
+ const filteredPurchases = (customer.purchases || []).filter(
300
+ (p) => p.status === "active"
301
+ );
302
+ return {
303
+ customerRef: customer.customerRef,
304
+ email: customer.email,
305
+ name: customer.name,
306
+ purchases: filteredPurchases
307
+ };
308
+ }
309
+ }
310
+ } catch {
311
+ }
312
+ }
133
313
  const deduplicator = getSharedDeduplicator(options.deduplication);
134
314
  const response = await deduplicator.deduplicate(userId, async () => {
135
315
  try {
136
- const solvaPay = options.solvaPay || createSolvaPay();
137
316
  const ensuredCustomerRef = await solvaPay.ensureCustomer(userId, userId, {
138
317
  email: email || void 0,
139
318
  name: name || void 0
140
319
  });
141
320
  const customer = await solvaPay.getCustomer({ customerRef: ensuredCustomerRef });
142
- const now = /* @__PURE__ */ new Date();
143
- const filteredSubscriptions = (customer.subscriptions || []).filter((sub) => {
144
- const subAny = sub;
145
- const isCancelled = sub.status === "cancelled" || subAny.cancelledAt;
146
- if (!isCancelled) {
147
- return true;
148
- }
149
- if (isCancelled && subAny.endDate) {
150
- const endDate = new Date(subAny.endDate);
151
- const isFuture = endDate > now;
152
- return isFuture;
153
- }
154
- return false;
155
- });
321
+ const filteredPurchases = (customer.purchases || []).filter(
322
+ (p) => p.status === "active"
323
+ );
156
324
  const result = {
157
325
  customerRef: customer.customerRef || userId,
158
326
  email: customer.email,
159
327
  name: customer.name,
160
- subscriptions: filteredSubscriptions
328
+ purchases: filteredPurchases
161
329
  };
162
330
  return result;
163
331
  } catch (error) {
164
- console.error("[checkSubscription] Error fetching customer:", error);
332
+ console.error("[checkPurchase] Error fetching customer:", error);
165
333
  return {
166
334
  customerRef: userId,
167
- subscriptions: []
335
+ purchases: []
168
336
  };
169
337
  }
170
338
  });
171
339
  return response;
172
340
  } catch (error) {
173
- console.error("Check subscription failed:", error);
341
+ console.error("Check purchase failed:", error);
174
342
  if (error instanceof SolvaPayError) {
175
- return NextResponse.json(
176
- { error: error.message },
177
- { status: 500 }
178
- );
343
+ return NextResponse7.json({ error: error.message }, { status: 500 });
179
344
  }
180
345
  const errorMessage = error instanceof Error ? error.message : "Unknown error";
181
- return NextResponse.json(
182
- { error: "Failed to check subscription", details: errorMessage },
346
+ return NextResponse7.json(
347
+ { error: "Failed to check purchase", details: errorMessage },
183
348
  { status: 500 }
184
349
  );
185
350
  }
186
351
  }
187
- function clearSubscriptionCache(userId) {
188
- const deduplicator = getSharedDeduplicator();
189
- deduplicator.clearCache(userId);
190
- }
191
- function clearAllSubscriptionCache() {
192
- const deduplicator = getSharedDeduplicator();
193
- deduplicator.clearAllCache();
194
- }
195
- function getSubscriptionCacheStats() {
196
- const deduplicator = getSharedDeduplicator();
197
- return deduplicator.getStats();
198
- }
199
352
  export {
200
- checkSubscription,
201
- clearAllSubscriptionCache,
202
- clearSubscriptionCache,
203
- getSubscriptionCacheStats
353
+ cancelRenewal,
354
+ checkPurchase,
355
+ clearAllPurchaseCache,
356
+ clearPurchaseCache,
357
+ createAuthMiddleware,
358
+ createCheckoutSession,
359
+ createCustomerSession,
360
+ createPaymentIntent,
361
+ createSupabaseAuthMiddleware,
362
+ getAuthenticatedUser,
363
+ getPurchaseCacheStats,
364
+ listPlans,
365
+ processPaymentIntent,
366
+ syncCustomer
204
367
  };
@@ -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 };