@solvapay/next 1.0.0-preview.9 → 1.0.1-preview.1

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
@@ -12,54 +12,232 @@ npm install @solvapay/next @solvapay/server next
12
12
 
13
13
  ## Usage
14
14
 
15
- ### Check Subscription
15
+ All helpers return either a success result or a `NextResponse` error, making them easy to use in Next.js API routes.
16
16
 
17
- The `checkSubscription` helper provides a simple way to check user subscription status in Next.js API routes with built-in request deduplication:
17
+ ### Check Purchase
18
+
19
+ Check user purchase status with built-in request deduplication and caching:
18
20
 
19
21
  ```typescript
20
- import { NextRequest, NextResponse } from 'next/server';
21
- import { checkSubscription } from '@solvapay/next';
22
+ import { NextRequest, NextResponse } from 'next/server'
23
+ import { checkPurchase } from '@solvapay/next'
22
24
 
23
25
  export async function GET(request: NextRequest) {
24
- const result = await checkSubscription(request);
25
-
26
+ const result = await checkPurchase(request)
27
+
26
28
  // If result is a NextResponse, it's an error response - return it
27
29
  if (result instanceof NextResponse) {
28
- return result;
30
+ return result
29
31
  }
30
-
31
- // Otherwise, return the subscription data
32
- return NextResponse.json(result);
32
+
33
+ // Otherwise, return the purchase data
34
+ return NextResponse.json(result)
33
35
  }
34
36
  ```
35
37
 
36
- ### Features
38
+ **Features:**
37
39
 
38
40
  - **Automatic Deduplication**: Prevents duplicate API calls by deduplicating concurrent requests
39
41
  - **Caching**: Caches results for 2 seconds to prevent duplicate sequential requests
40
42
  - **Automatic Cleanup**: Expired cache entries are automatically cleaned up
41
43
  - **Memory Safe**: Maximum cache size limits prevent memory issues
42
44
 
45
+ ### Sync Customer
46
+
47
+ Sync customer with SolvaPay backend (ensures customer exists and returns customer reference):
48
+
49
+ ```typescript
50
+ import { NextRequest, NextResponse } from 'next/server'
51
+ import { syncCustomer } from '@solvapay/next'
52
+
53
+ export async function POST(request: NextRequest) {
54
+ const result = await syncCustomer(request)
55
+
56
+ if (result instanceof NextResponse) {
57
+ return result
58
+ }
59
+
60
+ return NextResponse.json({ customerRef: result })
61
+ }
62
+ ```
63
+
64
+ ### Create Payment Intent
65
+
66
+ Create a Stripe payment intent for checkout:
67
+
68
+ ```typescript
69
+ import { NextRequest, NextResponse } from 'next/server'
70
+ import { createPaymentIntent } from '@solvapay/next'
71
+
72
+ export async function POST(request: NextRequest) {
73
+ const { planRef, productRef } = await request.json()
74
+
75
+ if (!planRef || !productRef) {
76
+ return NextResponse.json({ error: 'Missing required parameters' }, { status: 400 })
77
+ }
78
+
79
+ const result = await createPaymentIntent(request, { planRef, productRef })
80
+ return result instanceof NextResponse ? result : NextResponse.json(result)
81
+ }
82
+ ```
83
+
84
+ ### Process Payment
85
+
86
+ Process payment after Stripe confirmation:
87
+
88
+ ```typescript
89
+ import { NextRequest, NextResponse } from 'next/server'
90
+ import { processPayment } from '@solvapay/next'
91
+
92
+ export async function POST(request: NextRequest) {
93
+ const { paymentIntentId, productRef, planRef } = await request.json()
94
+
95
+ if (!paymentIntentId || !productRef) {
96
+ return NextResponse.json({ error: 'Missing required parameters' }, { status: 400 })
97
+ }
98
+
99
+ const result = await processPayment(request, { paymentIntentId, productRef, planRef })
100
+ return result instanceof NextResponse ? result : NextResponse.json(result)
101
+ }
102
+ ```
103
+
104
+ ### List Plans
105
+
106
+ List available plans (public route, no authentication required):
107
+
108
+ ```typescript
109
+ import { NextRequest, NextResponse } from 'next/server'
110
+ import { listPlans } from '@solvapay/next'
111
+
112
+ export async function GET(request: NextRequest) {
113
+ const result = await listPlans(request)
114
+ return result instanceof NextResponse ? result : NextResponse.json(result)
115
+ }
116
+ ```
117
+
118
+ ### Cancel Renewal
119
+
120
+ Cancel renewal of a user's purchase:
121
+
122
+ ```typescript
123
+ import { NextRequest, NextResponse } from 'next/server'
124
+ import { cancelRenewal } from '@solvapay/next'
125
+
126
+ export async function POST(request: NextRequest) {
127
+ const { purchaseRef, reason } = await request.json()
128
+
129
+ if (!purchaseRef) {
130
+ return NextResponse.json({ error: 'Missing purchaseRef' }, { status: 400 })
131
+ }
132
+
133
+ const result = await cancelRenewal(request, { purchaseRef, reason })
134
+ return result instanceof NextResponse ? result : NextResponse.json(result)
135
+ }
136
+ ```
137
+
138
+ ### Create Checkout Session
139
+
140
+ Create a hosted checkout session:
141
+
142
+ ```typescript
143
+ import { NextRequest, NextResponse } from 'next/server'
144
+ import { createCheckoutSession } from '@solvapay/next'
145
+
146
+ export async function POST(request: NextRequest) {
147
+ const { productRef, planRef } = await request.json()
148
+
149
+ if (!productRef) {
150
+ return NextResponse.json({ error: 'Missing productRef' }, { status: 400 })
151
+ }
152
+
153
+ const result = await createCheckoutSession(request, { productRef, planRef })
154
+ return result instanceof NextResponse ? result : NextResponse.json(result)
155
+ }
156
+ ```
157
+
158
+ ### Create Customer Session
159
+
160
+ Create a customer portal session:
161
+
162
+ ```typescript
163
+ import { NextRequest, NextResponse } from 'next/server'
164
+ import { createCustomerSession } from '@solvapay/next'
165
+
166
+ export async function POST(request: NextRequest) {
167
+ const result = await createCustomerSession(request)
168
+ return result instanceof NextResponse ? result : NextResponse.json(result)
169
+ }
170
+ ```
171
+
172
+ ### Get Authenticated User
173
+
174
+ Get authenticated user information (userId, email, name):
175
+
176
+ ```typescript
177
+ import { NextRequest, NextResponse } from 'next/server'
178
+ import { getAuthenticatedUser } from '@solvapay/next'
179
+
180
+ export async function GET(request: NextRequest) {
181
+ const result = await getAuthenticatedUser(request, {
182
+ includeEmail: true,
183
+ includeName: true,
184
+ })
185
+
186
+ if (result instanceof NextResponse) {
187
+ return result
188
+ }
189
+
190
+ return NextResponse.json(result)
191
+ }
192
+ ```
193
+
43
194
  ### Cache Management
44
195
 
45
196
  ```typescript
46
- import {
47
- clearSubscriptionCache,
48
- clearAllSubscriptionCache,
49
- getSubscriptionCacheStats
50
- } from '@solvapay/next';
197
+ import {
198
+ clearPurchaseCache,
199
+ clearAllPurchaseCache,
200
+ getPurchaseCacheStats,
201
+ } from '@solvapay/next'
51
202
 
52
203
  // Clear cache for a specific user
53
- clearSubscriptionCache(userId);
204
+ clearPurchaseCache(userId)
54
205
 
55
206
  // Clear all cache entries
56
- clearAllSubscriptionCache();
207
+ clearAllPurchaseCache()
57
208
 
58
209
  // Get cache statistics
59
- const stats = getSubscriptionCacheStats();
60
- console.log(`In-flight: ${stats.inFlight}, Cached: ${stats.cached}`);
210
+ const stats = getPurchaseCacheStats()
211
+ console.log(`In-flight: ${stats.inFlight}, Cached: ${stats.cached}`)
61
212
  ```
62
213
 
214
+ ## Helper Functions Reference
215
+
216
+ All helper functions follow the same pattern:
217
+
218
+ - Take a `Request` or `NextRequest` as the first parameter
219
+ - Return either the success result or a `NextResponse` error
220
+ - Automatically extract user information from request headers (set by middleware)
221
+ - Support optional configuration options
222
+
223
+ **Available Helpers:**
224
+
225
+ - `checkPurchase(request, options?)` - Check purchase with caching
226
+ - `syncCustomer(request, options?)` - Sync customer with backend
227
+ - `createPaymentIntent(request, body, options?)` - Create payment intent
228
+ - `processPayment(request, body, options?)` - Process payment
229
+ - `listPlans(request)` - List available plans (public)
230
+ - `cancelRenewal(request, body, options?)` - Cancel renewal
231
+ - `createCheckoutSession(request, body, options?)` - Create hosted checkout
232
+ - `createCustomerSession(request, options?)` - Create customer portal
233
+ - `getAuthenticatedUser(request, options?)` - Get user info
234
+
235
+ **Common Options:**
236
+
237
+ - `solvaPay?: SolvaPay` - Custom SolvaPay instance
238
+ - `includeEmail?: boolean` - Include user email (default: true)
239
+ - `includeName?: boolean` - Include user name (default: true)
240
+
63
241
  ## Requirements
64
242
 
65
243
  - Next.js >= 13.0.0
@@ -69,3 +247,76 @@ console.log(`In-flight: ${stats.inFlight}, Cached: ${stats.cached}`);
69
247
 
70
248
  This package is separate from `@solvapay/server` to keep the server package framework-agnostic. Users who use Express, Fastify, or other frameworks don't need Next.js as a dependency.
71
249
 
250
+ ## Middleware Setup
251
+
252
+ These helpers expect the user ID to be set in the `x-user-id` header by your Next.js middleware/proxy.
253
+
254
+ ### Quick Setup with Supabase
255
+
256
+ The easiest way is to use `createSupabaseAuthMiddleware`:
257
+
258
+ **For Next.js 15:**
259
+
260
+ ```typescript
261
+ // middleware.ts (at project root)
262
+ import { createSupabaseAuthMiddleware } from '@solvapay/next'
263
+
264
+ export const middleware = createSupabaseAuthMiddleware({
265
+ publicRoutes: ['/api/list-plans'],
266
+ })
267
+
268
+ export const config = {
269
+ matcher: ['/api/:path*'],
270
+ }
271
+ ```
272
+
273
+ **For Next.js 16 with `src/` folder:**
274
+
275
+ ```typescript
276
+ // src/proxy.ts (in src/ folder, not project root)
277
+ import { createSupabaseAuthMiddleware } from '@solvapay/next'
278
+
279
+ // Use 'proxy' export for Next.js 16 (no deprecation warning)
280
+ export const proxy = createSupabaseAuthMiddleware({
281
+ publicRoutes: ['/api/list-plans'],
282
+ })
283
+
284
+ export const config = {
285
+ matcher: ['/api/:path*'],
286
+ }
287
+ ```
288
+
289
+ **File Location Notes:**
290
+
291
+ - **Next.js 15**: Place `middleware.ts` at project root
292
+ - **Next.js 16 without `src/` folder**: Place `middleware.ts` or `proxy.ts` at project root
293
+ - **Next.js 16 with `src/` folder**: Place `src/proxy.ts` or `src/middleware.ts` (in `src/` folder, not root)
294
+
295
+ > **Note:** Next.js 16 renamed "middleware" to "proxy". You can use either export name, but `proxy` is recommended to avoid deprecation warnings.
296
+
297
+ ### Custom Middleware
298
+
299
+ Alternatively, you can create your own middleware:
300
+
301
+ ```typescript
302
+ // middleware.ts (or src/proxy.ts for Next.js 16)
303
+ import { NextResponse } from 'next/server'
304
+ import type { NextRequest } from 'next/server'
305
+
306
+ export async function middleware(request: NextRequest) {
307
+ // Extract user ID from your auth system
308
+ const userId = await getUserIdFromAuth(request)
309
+
310
+ // Clone request and add user ID header
311
+ const requestHeaders = new Headers(request.headers)
312
+ requestHeaders.set('x-user-id', userId)
313
+
314
+ return NextResponse.next({
315
+ request: {
316
+ headers: requestHeaders,
317
+ },
318
+ })
319
+ }
320
+ ```
321
+
322
+ You can also use the `requireUserId` utility from `@solvapay/auth` in your middleware.