@solvapay/next 1.0.0-preview.10
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 +284 -0
- package/dist/index.cjs +477 -0
- package/dist/index.d.cts +406 -0
- package/dist/index.d.ts +406 -0
- package/dist/index.js +449 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
# @solvapay/next
|
|
2
|
+
|
|
3
|
+
Next.js-specific utilities and helpers for SolvaPay SDK.
|
|
4
|
+
|
|
5
|
+
This package provides framework-specific helpers for Next.js API routes with built-in optimizations like request deduplication and caching.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @solvapay/next @solvapay/server next
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
All helpers return either a success result or a `NextResponse` error, making them easy to use in Next.js API routes.
|
|
16
|
+
|
|
17
|
+
### Check Subscription
|
|
18
|
+
|
|
19
|
+
Check user subscription status with built-in request deduplication and caching:
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
23
|
+
import { checkSubscription } from '@solvapay/next';
|
|
24
|
+
|
|
25
|
+
export async function GET(request: NextRequest) {
|
|
26
|
+
const result = await checkSubscription(request);
|
|
27
|
+
|
|
28
|
+
// If result is a NextResponse, it's an error response - return it
|
|
29
|
+
if (result instanceof NextResponse) {
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Otherwise, return the subscription data
|
|
34
|
+
return NextResponse.json(result);
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Features:**
|
|
39
|
+
- **Automatic Deduplication**: Prevents duplicate API calls by deduplicating concurrent requests
|
|
40
|
+
- **Caching**: Caches results for 2 seconds to prevent duplicate sequential requests
|
|
41
|
+
- **Automatic Cleanup**: Expired cache entries are automatically cleaned up
|
|
42
|
+
- **Memory Safe**: Maximum cache size limits prevent memory issues
|
|
43
|
+
|
|
44
|
+
### Sync Customer
|
|
45
|
+
|
|
46
|
+
Sync customer with SolvaPay backend (ensures customer exists and returns customer reference):
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
50
|
+
import { syncCustomer } from '@solvapay/next';
|
|
51
|
+
|
|
52
|
+
export async function POST(request: NextRequest) {
|
|
53
|
+
const result = await syncCustomer(request);
|
|
54
|
+
|
|
55
|
+
if (result instanceof NextResponse) {
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return NextResponse.json({ customerRef: result });
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Create Payment Intent
|
|
64
|
+
|
|
65
|
+
Create a Stripe payment intent for checkout:
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
69
|
+
import { createPaymentIntent } from '@solvapay/next';
|
|
70
|
+
|
|
71
|
+
export async function POST(request: NextRequest) {
|
|
72
|
+
const { planRef, agentRef } = await request.json();
|
|
73
|
+
|
|
74
|
+
if (!planRef || !agentRef) {
|
|
75
|
+
return NextResponse.json(
|
|
76
|
+
{ error: 'Missing required parameters' },
|
|
77
|
+
{ status: 400 }
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const result = await createPaymentIntent(request, { planRef, agentRef });
|
|
82
|
+
return result instanceof NextResponse ? result : NextResponse.json(result);
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Process Payment
|
|
87
|
+
|
|
88
|
+
Process payment after Stripe confirmation:
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
92
|
+
import { processPayment } from '@solvapay/next';
|
|
93
|
+
|
|
94
|
+
export async function POST(request: NextRequest) {
|
|
95
|
+
const { paymentIntentId, agentRef, planRef } = await request.json();
|
|
96
|
+
|
|
97
|
+
if (!paymentIntentId || !agentRef) {
|
|
98
|
+
return NextResponse.json(
|
|
99
|
+
{ error: 'Missing required parameters' },
|
|
100
|
+
{ status: 400 }
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const result = await processPayment(request, { paymentIntentId, agentRef, planRef });
|
|
105
|
+
return result instanceof NextResponse ? result : NextResponse.json(result);
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### List Plans
|
|
110
|
+
|
|
111
|
+
List available plans (public route, no authentication required):
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
115
|
+
import { listPlans } from '@solvapay/next';
|
|
116
|
+
|
|
117
|
+
export async function GET(request: NextRequest) {
|
|
118
|
+
const result = await listPlans(request);
|
|
119
|
+
return result instanceof NextResponse ? result : NextResponse.json(result);
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Cancel Subscription
|
|
124
|
+
|
|
125
|
+
Cancel a user's subscription:
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
129
|
+
import { cancelSubscription } from '@solvapay/next';
|
|
130
|
+
|
|
131
|
+
export async function POST(request: NextRequest) {
|
|
132
|
+
const { subscriptionRef, reason } = await request.json();
|
|
133
|
+
|
|
134
|
+
if (!subscriptionRef) {
|
|
135
|
+
return NextResponse.json(
|
|
136
|
+
{ error: 'Missing subscriptionRef' },
|
|
137
|
+
{ status: 400 }
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const result = await cancelSubscription(request, { subscriptionRef, reason });
|
|
142
|
+
return result instanceof NextResponse ? result : NextResponse.json(result);
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Create Checkout Session
|
|
147
|
+
|
|
148
|
+
Create a hosted checkout session:
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
152
|
+
import { createCheckoutSession } from '@solvapay/next';
|
|
153
|
+
|
|
154
|
+
export async function POST(request: NextRequest) {
|
|
155
|
+
const { agentRef, planRef } = await request.json();
|
|
156
|
+
|
|
157
|
+
if (!agentRef) {
|
|
158
|
+
return NextResponse.json(
|
|
159
|
+
{ error: 'Missing agentRef' },
|
|
160
|
+
{ status: 400 }
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const result = await createCheckoutSession(request, { agentRef, planRef });
|
|
165
|
+
return result instanceof NextResponse ? result : NextResponse.json(result);
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Create Customer Session
|
|
170
|
+
|
|
171
|
+
Create a customer portal session:
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
175
|
+
import { createCustomerSession } from '@solvapay/next';
|
|
176
|
+
|
|
177
|
+
export async function POST(request: NextRequest) {
|
|
178
|
+
const result = await createCustomerSession(request);
|
|
179
|
+
return result instanceof NextResponse ? result : NextResponse.json(result);
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Get Authenticated User
|
|
184
|
+
|
|
185
|
+
Get authenticated user information (userId, email, name):
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
189
|
+
import { getAuthenticatedUser } from '@solvapay/next';
|
|
190
|
+
|
|
191
|
+
export async function GET(request: NextRequest) {
|
|
192
|
+
const result = await getAuthenticatedUser(request, {
|
|
193
|
+
includeEmail: true,
|
|
194
|
+
includeName: true,
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
if (result instanceof NextResponse) {
|
|
198
|
+
return result;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return NextResponse.json(result);
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Cache Management
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
import {
|
|
209
|
+
clearSubscriptionCache,
|
|
210
|
+
clearAllSubscriptionCache,
|
|
211
|
+
getSubscriptionCacheStats
|
|
212
|
+
} from '@solvapay/next';
|
|
213
|
+
|
|
214
|
+
// Clear cache for a specific user
|
|
215
|
+
clearSubscriptionCache(userId);
|
|
216
|
+
|
|
217
|
+
// Clear all cache entries
|
|
218
|
+
clearAllSubscriptionCache();
|
|
219
|
+
|
|
220
|
+
// Get cache statistics
|
|
221
|
+
const stats = getSubscriptionCacheStats();
|
|
222
|
+
console.log(`In-flight: ${stats.inFlight}, Cached: ${stats.cached}`);
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## Helper Functions Reference
|
|
226
|
+
|
|
227
|
+
All helper functions follow the same pattern:
|
|
228
|
+
- Take a `Request` or `NextRequest` as the first parameter
|
|
229
|
+
- Return either the success result or a `NextResponse` error
|
|
230
|
+
- Automatically extract user information from request headers (set by middleware)
|
|
231
|
+
- Support optional configuration options
|
|
232
|
+
|
|
233
|
+
**Available Helpers:**
|
|
234
|
+
- `checkSubscription(request, options?)` - Check subscription with caching
|
|
235
|
+
- `syncCustomer(request, options?)` - Sync customer with backend
|
|
236
|
+
- `createPaymentIntent(request, body, options?)` - Create payment intent
|
|
237
|
+
- `processPayment(request, body, options?)` - Process payment
|
|
238
|
+
- `listPlans(request)` - List available plans (public)
|
|
239
|
+
- `cancelSubscription(request, body, options?)` - Cancel subscription
|
|
240
|
+
- `createCheckoutSession(request, body, options?)` - Create hosted checkout
|
|
241
|
+
- `createCustomerSession(request, options?)` - Create customer portal
|
|
242
|
+
- `getAuthenticatedUser(request, options?)` - Get user info
|
|
243
|
+
|
|
244
|
+
**Common Options:**
|
|
245
|
+
- `solvaPay?: SolvaPay` - Custom SolvaPay instance
|
|
246
|
+
- `includeEmail?: boolean` - Include user email (default: true)
|
|
247
|
+
- `includeName?: boolean` - Include user name (default: true)
|
|
248
|
+
|
|
249
|
+
## Requirements
|
|
250
|
+
|
|
251
|
+
- Next.js >= 13.0.0
|
|
252
|
+
- Node.js >= 18.17
|
|
253
|
+
|
|
254
|
+
## Why a Separate Package?
|
|
255
|
+
|
|
256
|
+
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.
|
|
257
|
+
|
|
258
|
+
## Middleware Setup
|
|
259
|
+
|
|
260
|
+
These helpers expect the user ID to be set in the `x-user-id` header by your Next.js middleware:
|
|
261
|
+
|
|
262
|
+
```typescript
|
|
263
|
+
// middleware.ts
|
|
264
|
+
import { NextResponse } from 'next/server';
|
|
265
|
+
import type { NextRequest } from 'next/server';
|
|
266
|
+
|
|
267
|
+
export async function middleware(request: NextRequest) {
|
|
268
|
+
// Extract user ID from your auth system
|
|
269
|
+
const userId = await getUserIdFromAuth(request);
|
|
270
|
+
|
|
271
|
+
// Clone request and add user ID header
|
|
272
|
+
const requestHeaders = new Headers(request.headers);
|
|
273
|
+
requestHeaders.set('x-user-id', userId);
|
|
274
|
+
|
|
275
|
+
return NextResponse.next({
|
|
276
|
+
request: {
|
|
277
|
+
headers: requestHeaders,
|
|
278
|
+
},
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Alternatively, you can use the `requireUserId` utility from `@solvapay/auth` in your middleware.
|
|
284
|
+
|