@solvapay/next 1.0.0-preview.19 → 1.0.0-preview.21
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 +30 -30
- package/dist/index.cjs +38 -38
- package/dist/index.d.cts +62 -94
- package/dist/index.d.ts +62 -94
- package/dist/index.js +34 -34
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -14,23 +14,23 @@ npm install @solvapay/next @solvapay/server next
|
|
|
14
14
|
|
|
15
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
|
-
### Check
|
|
17
|
+
### Check Purchase
|
|
18
18
|
|
|
19
|
-
Check user
|
|
19
|
+
Check user purchase status with built-in request deduplication and caching:
|
|
20
20
|
|
|
21
21
|
```typescript
|
|
22
22
|
import { NextRequest, NextResponse } from 'next/server'
|
|
23
|
-
import {
|
|
23
|
+
import { checkPurchase } from '@solvapay/next'
|
|
24
24
|
|
|
25
25
|
export async function GET(request: NextRequest) {
|
|
26
|
-
const result = await
|
|
26
|
+
const result = await checkPurchase(request)
|
|
27
27
|
|
|
28
28
|
// If result is a NextResponse, it's an error response - return it
|
|
29
29
|
if (result instanceof NextResponse) {
|
|
30
30
|
return result
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
// Otherwise, return the
|
|
33
|
+
// Otherwise, return the purchase data
|
|
34
34
|
return NextResponse.json(result)
|
|
35
35
|
}
|
|
36
36
|
```
|
|
@@ -70,13 +70,13 @@ import { NextRequest, NextResponse } from 'next/server'
|
|
|
70
70
|
import { createPaymentIntent } from '@solvapay/next'
|
|
71
71
|
|
|
72
72
|
export async function POST(request: NextRequest) {
|
|
73
|
-
const { planRef,
|
|
73
|
+
const { planRef, productRef } = await request.json()
|
|
74
74
|
|
|
75
|
-
if (!planRef || !
|
|
75
|
+
if (!planRef || !productRef) {
|
|
76
76
|
return NextResponse.json({ error: 'Missing required parameters' }, { status: 400 })
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
const result = await createPaymentIntent(request, { planRef,
|
|
79
|
+
const result = await createPaymentIntent(request, { planRef, productRef })
|
|
80
80
|
return result instanceof NextResponse ? result : NextResponse.json(result)
|
|
81
81
|
}
|
|
82
82
|
```
|
|
@@ -90,13 +90,13 @@ import { NextRequest, NextResponse } from 'next/server'
|
|
|
90
90
|
import { processPayment } from '@solvapay/next'
|
|
91
91
|
|
|
92
92
|
export async function POST(request: NextRequest) {
|
|
93
|
-
const { paymentIntentId,
|
|
93
|
+
const { paymentIntentId, productRef, planRef } = await request.json()
|
|
94
94
|
|
|
95
|
-
if (!paymentIntentId || !
|
|
95
|
+
if (!paymentIntentId || !productRef) {
|
|
96
96
|
return NextResponse.json({ error: 'Missing required parameters' }, { status: 400 })
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
const result = await processPayment(request, { paymentIntentId,
|
|
99
|
+
const result = await processPayment(request, { paymentIntentId, productRef, planRef })
|
|
100
100
|
return result instanceof NextResponse ? result : NextResponse.json(result)
|
|
101
101
|
}
|
|
102
102
|
```
|
|
@@ -115,22 +115,22 @@ export async function GET(request: NextRequest) {
|
|
|
115
115
|
}
|
|
116
116
|
```
|
|
117
117
|
|
|
118
|
-
### Cancel
|
|
118
|
+
### Cancel Renewal
|
|
119
119
|
|
|
120
|
-
Cancel a user's
|
|
120
|
+
Cancel renewal of a user's purchase:
|
|
121
121
|
|
|
122
122
|
```typescript
|
|
123
123
|
import { NextRequest, NextResponse } from 'next/server'
|
|
124
|
-
import {
|
|
124
|
+
import { cancelRenewal } from '@solvapay/next'
|
|
125
125
|
|
|
126
126
|
export async function POST(request: NextRequest) {
|
|
127
|
-
const {
|
|
127
|
+
const { purchaseRef, reason } = await request.json()
|
|
128
128
|
|
|
129
|
-
if (!
|
|
130
|
-
return NextResponse.json({ error: 'Missing
|
|
129
|
+
if (!purchaseRef) {
|
|
130
|
+
return NextResponse.json({ error: 'Missing purchaseRef' }, { status: 400 })
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
-
const result = await
|
|
133
|
+
const result = await cancelRenewal(request, { purchaseRef, reason })
|
|
134
134
|
return result instanceof NextResponse ? result : NextResponse.json(result)
|
|
135
135
|
}
|
|
136
136
|
```
|
|
@@ -144,13 +144,13 @@ import { NextRequest, NextResponse } from 'next/server'
|
|
|
144
144
|
import { createCheckoutSession } from '@solvapay/next'
|
|
145
145
|
|
|
146
146
|
export async function POST(request: NextRequest) {
|
|
147
|
-
const {
|
|
147
|
+
const { productRef, planRef } = await request.json()
|
|
148
148
|
|
|
149
|
-
if (!
|
|
150
|
-
return NextResponse.json({ error: 'Missing
|
|
149
|
+
if (!productRef) {
|
|
150
|
+
return NextResponse.json({ error: 'Missing productRef' }, { status: 400 })
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
-
const result = await createCheckoutSession(request, {
|
|
153
|
+
const result = await createCheckoutSession(request, { productRef, planRef })
|
|
154
154
|
return result instanceof NextResponse ? result : NextResponse.json(result)
|
|
155
155
|
}
|
|
156
156
|
```
|
|
@@ -195,19 +195,19 @@ export async function GET(request: NextRequest) {
|
|
|
195
195
|
|
|
196
196
|
```typescript
|
|
197
197
|
import {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
198
|
+
clearPurchaseCache,
|
|
199
|
+
clearAllPurchaseCache,
|
|
200
|
+
getPurchaseCacheStats,
|
|
201
201
|
} from '@solvapay/next'
|
|
202
202
|
|
|
203
203
|
// Clear cache for a specific user
|
|
204
|
-
|
|
204
|
+
clearPurchaseCache(userId)
|
|
205
205
|
|
|
206
206
|
// Clear all cache entries
|
|
207
|
-
|
|
207
|
+
clearAllPurchaseCache()
|
|
208
208
|
|
|
209
209
|
// Get cache statistics
|
|
210
|
-
const stats =
|
|
210
|
+
const stats = getPurchaseCacheStats()
|
|
211
211
|
console.log(`In-flight: ${stats.inFlight}, Cached: ${stats.cached}`)
|
|
212
212
|
```
|
|
213
213
|
|
|
@@ -222,12 +222,12 @@ All helper functions follow the same pattern:
|
|
|
222
222
|
|
|
223
223
|
**Available Helpers:**
|
|
224
224
|
|
|
225
|
-
- `
|
|
225
|
+
- `checkPurchase(request, options?)` - Check purchase with caching
|
|
226
226
|
- `syncCustomer(request, options?)` - Sync customer with backend
|
|
227
227
|
- `createPaymentIntent(request, body, options?)` - Create payment intent
|
|
228
228
|
- `processPayment(request, body, options?)` - Process payment
|
|
229
229
|
- `listPlans(request)` - List available plans (public)
|
|
230
|
-
- `
|
|
230
|
+
- `cancelRenewal(request, body, options?)` - Cancel renewal
|
|
231
231
|
- `createCheckoutSession(request, body, options?)` - Create hosted checkout
|
|
232
232
|
- `createCustomerSession(request, options?)` - Create customer portal
|
|
233
233
|
- `getAuthenticatedUser(request, options?)` - Get user info
|
package/dist/index.cjs
CHANGED
|
@@ -30,19 +30,19 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
cancelRenewal: () => cancelRenewal,
|
|
34
|
+
checkPurchase: () => checkPurchase,
|
|
35
|
+
clearAllPurchaseCache: () => clearAllPurchaseCache,
|
|
36
|
+
clearPurchaseCache: () => clearPurchaseCache,
|
|
37
37
|
createAuthMiddleware: () => createAuthMiddleware,
|
|
38
38
|
createCheckoutSession: () => createCheckoutSession,
|
|
39
39
|
createCustomerSession: () => createCustomerSession,
|
|
40
40
|
createPaymentIntent: () => createPaymentIntent,
|
|
41
41
|
createSupabaseAuthMiddleware: () => createSupabaseAuthMiddleware,
|
|
42
42
|
getAuthenticatedUser: () => getAuthenticatedUser,
|
|
43
|
-
|
|
43
|
+
getPurchaseCacheStats: () => getPurchaseCacheStats,
|
|
44
44
|
listPlans: () => listPlans,
|
|
45
|
-
|
|
45
|
+
processPaymentIntent: () => processPaymentIntent,
|
|
46
46
|
syncCustomer: () => syncCustomer
|
|
47
47
|
});
|
|
48
48
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -152,10 +152,10 @@ function createRequestDeduplicator(options = {}) {
|
|
|
152
152
|
getStats
|
|
153
153
|
};
|
|
154
154
|
}
|
|
155
|
-
var
|
|
155
|
+
var sharedPurchaseDeduplicator = null;
|
|
156
156
|
function getSharedDeduplicator(options) {
|
|
157
|
-
if (!
|
|
158
|
-
|
|
157
|
+
if (!sharedPurchaseDeduplicator) {
|
|
158
|
+
sharedPurchaseDeduplicator = createRequestDeduplicator({
|
|
159
159
|
cacheTTL: 2e3,
|
|
160
160
|
// Cache results for 2 seconds
|
|
161
161
|
maxCacheSize: 1e3,
|
|
@@ -165,17 +165,17 @@ function getSharedDeduplicator(options) {
|
|
|
165
165
|
...options
|
|
166
166
|
});
|
|
167
167
|
}
|
|
168
|
-
return
|
|
168
|
+
return sharedPurchaseDeduplicator;
|
|
169
169
|
}
|
|
170
|
-
function
|
|
170
|
+
function clearPurchaseCache(userId) {
|
|
171
171
|
const deduplicator = getSharedDeduplicator();
|
|
172
172
|
deduplicator.clearCache(userId);
|
|
173
173
|
}
|
|
174
|
-
function
|
|
174
|
+
function clearAllPurchaseCache() {
|
|
175
175
|
const deduplicator = getSharedDeduplicator();
|
|
176
176
|
deduplicator.clearAllCache();
|
|
177
177
|
}
|
|
178
|
-
function
|
|
178
|
+
function getPurchaseCacheStats() {
|
|
179
179
|
const deduplicator = getSharedDeduplicator();
|
|
180
180
|
return deduplicator.getStats();
|
|
181
181
|
}
|
|
@@ -223,14 +223,14 @@ async function createPaymentIntent(request, body, options = {}) {
|
|
|
223
223
|
try {
|
|
224
224
|
const userResult = await (0, import_server7.getAuthenticatedUserCore)(request);
|
|
225
225
|
if (!(0, import_server6.isErrorResult)(userResult)) {
|
|
226
|
-
|
|
226
|
+
clearPurchaseCache(userResult.userId);
|
|
227
227
|
}
|
|
228
228
|
} catch {
|
|
229
229
|
}
|
|
230
230
|
return result;
|
|
231
231
|
}
|
|
232
|
-
async function
|
|
233
|
-
const result = await (0, import_server6.
|
|
232
|
+
async function processPaymentIntent(request, body, options = {}) {
|
|
233
|
+
const result = await (0, import_server6.processPaymentIntentCore)(request, body, options);
|
|
234
234
|
if ((0, import_server6.isErrorResult)(result)) {
|
|
235
235
|
return import_server5.NextResponse.json(
|
|
236
236
|
{ error: result.error, details: result.details },
|
|
@@ -240,7 +240,7 @@ async function processPayment(request, body, options = {}) {
|
|
|
240
240
|
try {
|
|
241
241
|
const userResult = await (0, import_server7.getAuthenticatedUserCore)(request);
|
|
242
242
|
if (!(0, import_server6.isErrorResult)(userResult)) {
|
|
243
|
-
|
|
243
|
+
clearPurchaseCache(userResult.userId);
|
|
244
244
|
}
|
|
245
245
|
} catch {
|
|
246
246
|
}
|
|
@@ -271,12 +271,12 @@ async function createCustomerSession(request, options = {}) {
|
|
|
271
271
|
return result;
|
|
272
272
|
}
|
|
273
273
|
|
|
274
|
-
// src/helpers/
|
|
274
|
+
// src/helpers/renewal.ts
|
|
275
275
|
var import_server10 = require("next/server");
|
|
276
276
|
var import_server11 = require("@solvapay/server");
|
|
277
277
|
var import_server12 = require("@solvapay/server");
|
|
278
|
-
async function
|
|
279
|
-
const result = await (0, import_server11.
|
|
278
|
+
async function cancelRenewal(request, body, options = {}) {
|
|
279
|
+
const result = await (0, import_server11.cancelPurchaseCore)(request, body, options);
|
|
280
280
|
if ((0, import_server11.isErrorResult)(result)) {
|
|
281
281
|
return import_server10.NextResponse.json(
|
|
282
282
|
{ error: result.error, details: result.details },
|
|
@@ -286,7 +286,7 @@ async function cancelSubscription(request, body, options = {}) {
|
|
|
286
286
|
try {
|
|
287
287
|
const userResult = await (0, import_server12.getAuthenticatedUserCore)(request);
|
|
288
288
|
if (!(0, import_server11.isErrorResult)(userResult)) {
|
|
289
|
-
|
|
289
|
+
clearPurchaseCache(userResult.userId);
|
|
290
290
|
}
|
|
291
291
|
} catch {
|
|
292
292
|
}
|
|
@@ -378,7 +378,7 @@ function createSupabaseAuthMiddleware(options = {}) {
|
|
|
378
378
|
}
|
|
379
379
|
|
|
380
380
|
// src/index.ts
|
|
381
|
-
async function
|
|
381
|
+
async function checkPurchase(request, options = {}) {
|
|
382
382
|
try {
|
|
383
383
|
const { requireUserId, getUserEmailFromRequest, getUserNameFromRequest } = await import("@solvapay/auth");
|
|
384
384
|
const userIdOrError = requireUserId(request);
|
|
@@ -397,14 +397,14 @@ async function checkSubscription(request, options = {}) {
|
|
|
397
397
|
const customer = await solvaPay.getCustomer({ customerRef: cachedCustomerRef });
|
|
398
398
|
if (customer && customer.customerRef) {
|
|
399
399
|
if (customer.externalRef && customer.externalRef === userId) {
|
|
400
|
-
const
|
|
401
|
-
(
|
|
400
|
+
const filteredPurchases = (customer.purchases || []).filter(
|
|
401
|
+
(p) => p.status === "active"
|
|
402
402
|
);
|
|
403
403
|
return {
|
|
404
404
|
customerRef: customer.customerRef,
|
|
405
405
|
email: customer.email,
|
|
406
406
|
name: customer.name,
|
|
407
|
-
|
|
407
|
+
purchases: filteredPurchases
|
|
408
408
|
};
|
|
409
409
|
}
|
|
410
410
|
}
|
|
@@ -419,51 +419,51 @@ async function checkSubscription(request, options = {}) {
|
|
|
419
419
|
name: name || void 0
|
|
420
420
|
});
|
|
421
421
|
const customer = await solvaPay.getCustomer({ customerRef: ensuredCustomerRef });
|
|
422
|
-
const
|
|
423
|
-
(
|
|
422
|
+
const filteredPurchases = (customer.purchases || []).filter(
|
|
423
|
+
(p) => p.status === "active"
|
|
424
424
|
);
|
|
425
425
|
const result = {
|
|
426
426
|
customerRef: customer.customerRef || userId,
|
|
427
427
|
email: customer.email,
|
|
428
428
|
name: customer.name,
|
|
429
|
-
|
|
429
|
+
purchases: filteredPurchases
|
|
430
430
|
};
|
|
431
431
|
return result;
|
|
432
432
|
} catch (error) {
|
|
433
|
-
console.error("[
|
|
433
|
+
console.error("[checkPurchase] Error fetching customer:", error);
|
|
434
434
|
return {
|
|
435
435
|
customerRef: userId,
|
|
436
|
-
|
|
436
|
+
purchases: []
|
|
437
437
|
};
|
|
438
438
|
}
|
|
439
439
|
});
|
|
440
440
|
return response;
|
|
441
441
|
} catch (error) {
|
|
442
|
-
console.error("Check
|
|
442
|
+
console.error("Check purchase failed:", error);
|
|
443
443
|
if (error instanceof import_core.SolvaPayError) {
|
|
444
444
|
return import_server16.NextResponse.json({ error: error.message }, { status: 500 });
|
|
445
445
|
}
|
|
446
446
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
447
447
|
return import_server16.NextResponse.json(
|
|
448
|
-
{ error: "Failed to check
|
|
448
|
+
{ error: "Failed to check purchase", details: errorMessage },
|
|
449
449
|
{ status: 500 }
|
|
450
450
|
);
|
|
451
451
|
}
|
|
452
452
|
}
|
|
453
453
|
// Annotate the CommonJS export names for ESM import in node:
|
|
454
454
|
0 && (module.exports = {
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
455
|
+
cancelRenewal,
|
|
456
|
+
checkPurchase,
|
|
457
|
+
clearAllPurchaseCache,
|
|
458
|
+
clearPurchaseCache,
|
|
459
459
|
createAuthMiddleware,
|
|
460
460
|
createCheckoutSession,
|
|
461
461
|
createCustomerSession,
|
|
462
462
|
createPaymentIntent,
|
|
463
463
|
createSupabaseAuthMiddleware,
|
|
464
464
|
getAuthenticatedUser,
|
|
465
|
-
|
|
465
|
+
getPurchaseCacheStats,
|
|
466
466
|
listPlans,
|
|
467
|
-
|
|
467
|
+
processPaymentIntent,
|
|
468
468
|
syncCustomer
|
|
469
469
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -4,9 +4,9 @@ import { AuthenticatedUser, SolvaPay } from '@solvapay/server';
|
|
|
4
4
|
import { AuthAdapter } from '@solvapay/auth';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* Purchase Cache Utilities
|
|
8
8
|
*
|
|
9
|
-
* Cache management functions for
|
|
9
|
+
* Cache management functions for purchase data.
|
|
10
10
|
* Separated from index.ts to avoid circular dependencies.
|
|
11
11
|
*/
|
|
12
12
|
/**
|
|
@@ -30,46 +30,58 @@ interface RequestDeduplicationOptions {
|
|
|
30
30
|
cacheErrors?: boolean;
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
|
-
*
|
|
33
|
+
* Purchase check result
|
|
34
34
|
*/
|
|
35
|
-
interface
|
|
35
|
+
interface PurchaseCheckResult {
|
|
36
36
|
customerRef: string;
|
|
37
37
|
email?: string;
|
|
38
38
|
name?: string;
|
|
39
|
-
|
|
39
|
+
purchases: Array<{
|
|
40
40
|
reference: string;
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
productName?: string;
|
|
42
|
+
productReference?: string;
|
|
43
43
|
status?: string;
|
|
44
44
|
startDate?: string;
|
|
45
|
+
planSnapshot?: {
|
|
46
|
+
meterId?: string;
|
|
47
|
+
limit?: number;
|
|
48
|
+
freeUnits?: number;
|
|
49
|
+
};
|
|
50
|
+
usage?: {
|
|
51
|
+
used?: number;
|
|
52
|
+
overageUnits?: number;
|
|
53
|
+
overageCost?: number;
|
|
54
|
+
periodStart?: string;
|
|
55
|
+
periodEnd?: string;
|
|
56
|
+
};
|
|
45
57
|
[key: string]: unknown;
|
|
46
58
|
}>;
|
|
47
59
|
}
|
|
48
60
|
/**
|
|
49
|
-
* Clear
|
|
61
|
+
* Clear purchase cache for a specific user.
|
|
50
62
|
*
|
|
51
|
-
* Useful when you know
|
|
52
|
-
* checkout,
|
|
53
|
-
* `
|
|
63
|
+
* Useful when you know purchase status has changed (e.g., after a successful
|
|
64
|
+
* checkout, purchase update, or cancellation). This forces the next
|
|
65
|
+
* `checkPurchase()` call to fetch fresh data from the backend.
|
|
54
66
|
*
|
|
55
67
|
* @param userId - User ID to clear cache for
|
|
56
68
|
*
|
|
57
69
|
* @example
|
|
58
70
|
* ```typescript
|
|
59
|
-
* import {
|
|
71
|
+
* import { clearPurchaseCache } from '@solvapay/next';
|
|
60
72
|
*
|
|
61
73
|
* // After successful payment
|
|
62
74
|
* await processPayment(request, body);
|
|
63
|
-
*
|
|
75
|
+
* clearPurchaseCache(userId); // Force refresh on next check
|
|
64
76
|
* ```
|
|
65
77
|
*
|
|
66
|
-
* @see {@link
|
|
67
|
-
* @see {@link
|
|
78
|
+
* @see {@link checkPurchase} for purchase checking
|
|
79
|
+
* @see {@link clearAllPurchaseCache} to clear all cache entries
|
|
68
80
|
* @since 1.0.0
|
|
69
81
|
*/
|
|
70
|
-
declare function
|
|
82
|
+
declare function clearPurchaseCache(userId: string): void;
|
|
71
83
|
/**
|
|
72
|
-
* Clear all
|
|
84
|
+
* Clear all purchase cache entries.
|
|
73
85
|
*
|
|
74
86
|
* Useful for testing, debugging, or when you need to force fresh lookups
|
|
75
87
|
* for all users. This clears both the in-flight request cache and the
|
|
@@ -77,23 +89,23 @@ declare function clearSubscriptionCache(userId: string): void;
|
|
|
77
89
|
*
|
|
78
90
|
* @example
|
|
79
91
|
* ```typescript
|
|
80
|
-
* import {
|
|
92
|
+
* import { clearAllPurchaseCache } from '@solvapay/next';
|
|
81
93
|
*
|
|
82
94
|
* // In a test setup
|
|
83
95
|
* beforeEach(() => {
|
|
84
|
-
*
|
|
96
|
+
* clearAllPurchaseCache();
|
|
85
97
|
* });
|
|
86
98
|
* ```
|
|
87
99
|
*
|
|
88
|
-
* @see {@link
|
|
89
|
-
* @see {@link
|
|
100
|
+
* @see {@link clearPurchaseCache} to clear cache for a specific user
|
|
101
|
+
* @see {@link getPurchaseCacheStats} for cache monitoring
|
|
90
102
|
* @since 1.0.0
|
|
91
103
|
*/
|
|
92
|
-
declare function
|
|
104
|
+
declare function clearAllPurchaseCache(): void;
|
|
93
105
|
/**
|
|
94
|
-
* Get
|
|
106
|
+
* Get purchase cache statistics for monitoring and debugging.
|
|
95
107
|
*
|
|
96
|
-
* Returns the current state of the
|
|
108
|
+
* Returns the current state of the purchase cache, including:
|
|
97
109
|
* - Number of in-flight requests (being deduplicated)
|
|
98
110
|
* - Number of cached results
|
|
99
111
|
*
|
|
@@ -103,11 +115,11 @@ declare function clearAllSubscriptionCache(): void;
|
|
|
103
115
|
*
|
|
104
116
|
* @example
|
|
105
117
|
* ```typescript
|
|
106
|
-
* import {
|
|
118
|
+
* import { getPurchaseCacheStats } from '@solvapay/next';
|
|
107
119
|
*
|
|
108
120
|
* // In a monitoring endpoint
|
|
109
121
|
* export async function GET() {
|
|
110
|
-
* const stats =
|
|
122
|
+
* const stats = getPurchaseCacheStats();
|
|
111
123
|
* return Response.json({
|
|
112
124
|
* cache: {
|
|
113
125
|
* inFlight: stats.inFlight,
|
|
@@ -117,10 +129,10 @@ declare function clearAllSubscriptionCache(): void;
|
|
|
117
129
|
* }
|
|
118
130
|
* ```
|
|
119
131
|
*
|
|
120
|
-
* @see {@link
|
|
132
|
+
* @see {@link checkPurchase} for purchase checking
|
|
121
133
|
* @since 1.0.0
|
|
122
134
|
*/
|
|
123
|
-
declare function
|
|
135
|
+
declare function getPurchaseCacheStats(): {
|
|
124
136
|
inFlight: number;
|
|
125
137
|
cached: number;
|
|
126
138
|
};
|
|
@@ -188,17 +200,9 @@ declare function syncCustomer(request: globalThis.Request, options?: {
|
|
|
188
200
|
includeName?: boolean;
|
|
189
201
|
}): Promise<string | NextResponse>;
|
|
190
202
|
|
|
191
|
-
/**
|
|
192
|
-
* Create payment intent - Next.js wrapper
|
|
193
|
-
*
|
|
194
|
-
* @param request - Next.js request object
|
|
195
|
-
* @param body - Payment intent parameters
|
|
196
|
-
* @param options - Configuration options
|
|
197
|
-
* @returns Payment intent response or NextResponse error
|
|
198
|
-
*/
|
|
199
203
|
declare function createPaymentIntent(request: globalThis.Request, body: {
|
|
200
204
|
planRef: string;
|
|
201
|
-
|
|
205
|
+
productRef: string;
|
|
202
206
|
}, options?: {
|
|
203
207
|
solvaPay?: SolvaPay;
|
|
204
208
|
includeEmail?: boolean;
|
|
@@ -210,17 +214,9 @@ declare function createPaymentIntent(request: globalThis.Request, body: {
|
|
|
210
214
|
accountId?: string;
|
|
211
215
|
customerRef: string;
|
|
212
216
|
} | NextResponse>;
|
|
213
|
-
|
|
214
|
-
* Process payment - Next.js wrapper
|
|
215
|
-
*
|
|
216
|
-
* @param request - Next.js request object
|
|
217
|
-
* @param body - Payment processing parameters
|
|
218
|
-
* @param options - Configuration options
|
|
219
|
-
* @returns Process payment result or NextResponse error
|
|
220
|
-
*/
|
|
221
|
-
declare function processPayment(request: globalThis.Request, body: {
|
|
217
|
+
declare function processPaymentIntent(request: globalThis.Request, body: {
|
|
222
218
|
paymentIntentId: string;
|
|
223
|
-
|
|
219
|
+
productRef: string;
|
|
224
220
|
planRef?: string;
|
|
225
221
|
}, options?: {
|
|
226
222
|
solvaPay?: SolvaPay;
|
|
@@ -228,20 +224,10 @@ declare function processPayment(request: globalThis.Request, body: {
|
|
|
228
224
|
|
|
229
225
|
/**
|
|
230
226
|
* Next.js Checkout Helpers
|
|
231
|
-
*
|
|
232
|
-
* Next.js-specific wrappers for checkout helpers.
|
|
233
227
|
*/
|
|
234
228
|
|
|
235
|
-
/**
|
|
236
|
-
* Create checkout session - Next.js wrapper
|
|
237
|
-
*
|
|
238
|
-
* @param request - Next.js request object
|
|
239
|
-
* @param body - Checkout session parameters
|
|
240
|
-
* @param options - Configuration options
|
|
241
|
-
* @returns Checkout session response or NextResponse error
|
|
242
|
-
*/
|
|
243
229
|
declare function createCheckoutSession(request: globalThis.Request, body: {
|
|
244
|
-
|
|
230
|
+
productRef: string;
|
|
245
231
|
planRef?: string;
|
|
246
232
|
returnUrl?: string;
|
|
247
233
|
}, options?: {
|
|
@@ -253,13 +239,6 @@ declare function createCheckoutSession(request: globalThis.Request, body: {
|
|
|
253
239
|
sessionId: string;
|
|
254
240
|
checkoutUrl: string;
|
|
255
241
|
} | NextResponse>;
|
|
256
|
-
/**
|
|
257
|
-
* Create customer session - Next.js wrapper
|
|
258
|
-
*
|
|
259
|
-
* @param request - Next.js request object
|
|
260
|
-
* @param options - Configuration options
|
|
261
|
-
* @returns Customer session response or NextResponse error
|
|
262
|
-
*/
|
|
263
242
|
declare function createCustomerSession(request: globalThis.Request, options?: {
|
|
264
243
|
solvaPay?: SolvaPay;
|
|
265
244
|
includeEmail?: boolean;
|
|
@@ -270,20 +249,18 @@ declare function createCustomerSession(request: globalThis.Request, options?: {
|
|
|
270
249
|
} | NextResponse>;
|
|
271
250
|
|
|
272
251
|
/**
|
|
273
|
-
* Next.js
|
|
274
|
-
*
|
|
275
|
-
* Next.js-specific wrappers for subscription helpers.
|
|
252
|
+
* Next.js Purchase Cancellation Helpers
|
|
276
253
|
*/
|
|
277
254
|
/**
|
|
278
|
-
* Cancel
|
|
255
|
+
* Cancel purchase - Next.js wrapper
|
|
279
256
|
*
|
|
280
257
|
* @param request - Next.js request object
|
|
281
258
|
* @param body - Cancellation parameters
|
|
282
259
|
* @param options - Configuration options
|
|
283
|
-
* @returns Cancelled
|
|
260
|
+
* @returns Cancelled purchase response or NextResponse error
|
|
284
261
|
*/
|
|
285
|
-
declare function
|
|
286
|
-
|
|
262
|
+
declare function cancelRenewal(request: globalThis.Request, body: {
|
|
263
|
+
purchaseRef: string;
|
|
287
264
|
reason?: string;
|
|
288
265
|
}, options?: {
|
|
289
266
|
solvaPay?: SolvaPay;
|
|
@@ -291,19 +268,10 @@ declare function cancelSubscription(request: globalThis.Request, body: {
|
|
|
291
268
|
|
|
292
269
|
/**
|
|
293
270
|
* Next.js Plans Helper
|
|
294
|
-
*
|
|
295
|
-
* Next.js-specific wrapper for plans helper.
|
|
296
|
-
* This is a public route - no authentication required.
|
|
297
|
-
*/
|
|
298
|
-
/**
|
|
299
|
-
* List plans - Next.js wrapper
|
|
300
|
-
*
|
|
301
|
-
* @param request - Next.js request object
|
|
302
|
-
* @returns Plans response or NextResponse error
|
|
303
271
|
*/
|
|
304
272
|
declare function listPlans(request: globalThis.Request): Promise<{
|
|
305
273
|
plans: Array<Record<string, unknown>>;
|
|
306
|
-
|
|
274
|
+
productRef: string;
|
|
307
275
|
} | NextResponse>;
|
|
308
276
|
|
|
309
277
|
/**
|
|
@@ -489,9 +457,9 @@ declare function createSupabaseAuthMiddleware(options?: SupabaseAuthMiddlewareOp
|
|
|
489
457
|
*/
|
|
490
458
|
|
|
491
459
|
/**
|
|
492
|
-
* Options for checking
|
|
460
|
+
* Options for checking purchases
|
|
493
461
|
*/
|
|
494
|
-
interface
|
|
462
|
+
interface CheckPurchaseOptions {
|
|
495
463
|
/**
|
|
496
464
|
* Request deduplication options
|
|
497
465
|
*
|
|
@@ -518,9 +486,9 @@ interface CheckSubscriptionOptions {
|
|
|
518
486
|
includeName?: boolean;
|
|
519
487
|
}
|
|
520
488
|
/**
|
|
521
|
-
* Check user
|
|
489
|
+
* Check user purchase status with automatic deduplication and caching.
|
|
522
490
|
*
|
|
523
|
-
* This Next.js helper function provides optimized
|
|
491
|
+
* This Next.js helper function provides optimized purchase checking with:
|
|
524
492
|
* - Automatic request deduplication (concurrent requests share the same promise)
|
|
525
493
|
* - Short-term caching (2 seconds) to prevent duplicate sequential requests
|
|
526
494
|
* - Fast path optimization using cached customer references from client
|
|
@@ -531,7 +499,7 @@ interface CheckSubscriptionOptions {
|
|
|
531
499
|
* 2. Gets user email and name from Supabase JWT token (if available)
|
|
532
500
|
* 3. Validates cached customer reference (if provided via header)
|
|
533
501
|
* 4. Ensures customer exists in SolvaPay backend
|
|
534
|
-
* 5. Returns customer
|
|
502
|
+
* 5. Returns customer purchase information
|
|
535
503
|
*
|
|
536
504
|
* @param request - Next.js request object (NextRequest extends Request)
|
|
537
505
|
* @param options - Configuration options
|
|
@@ -539,15 +507,15 @@ interface CheckSubscriptionOptions {
|
|
|
539
507
|
* @param options.solvaPay - Optional SolvaPay instance (creates new one if not provided)
|
|
540
508
|
* @param options.includeEmail - Whether to include email in response (default: true)
|
|
541
509
|
* @param options.includeName - Whether to include name in response (default: true)
|
|
542
|
-
* @returns
|
|
510
|
+
* @returns Purchase check result with customer data and purchases, or NextResponse error
|
|
543
511
|
*
|
|
544
512
|
* @example
|
|
545
513
|
* ```typescript
|
|
546
514
|
* import { NextRequest, NextResponse } from 'next/server';
|
|
547
|
-
* import {
|
|
515
|
+
* import { checkPurchase } from '@solvapay/next';
|
|
548
516
|
*
|
|
549
517
|
* export async function GET(request: NextRequest) {
|
|
550
|
-
* const result = await
|
|
518
|
+
* const result = await checkPurchase(request);
|
|
551
519
|
*
|
|
552
520
|
* if (result instanceof NextResponse) {
|
|
553
521
|
* return result; // Error response
|
|
@@ -557,10 +525,10 @@ interface CheckSubscriptionOptions {
|
|
|
557
525
|
* }
|
|
558
526
|
* ```
|
|
559
527
|
*
|
|
560
|
-
* @see {@link
|
|
561
|
-
* @see {@link
|
|
528
|
+
* @see {@link clearPurchaseCache} for cache management
|
|
529
|
+
* @see {@link getPurchaseCacheStats} for cache monitoring
|
|
562
530
|
* @since 1.0.0
|
|
563
531
|
*/
|
|
564
|
-
declare function
|
|
532
|
+
declare function checkPurchase(request: Request, options?: CheckPurchaseOptions): Promise<PurchaseCheckResult | NextResponse>;
|
|
565
533
|
|
|
566
|
-
export { type AuthMiddlewareOptions, type
|
|
534
|
+
export { type AuthMiddlewareOptions, type CheckPurchaseOptions, type PurchaseCheckResult, type RequestDeduplicationOptions, type SupabaseAuthMiddlewareOptions, cancelRenewal, checkPurchase, clearAllPurchaseCache, clearPurchaseCache, createAuthMiddleware, createCheckoutSession, createCustomerSession, createPaymentIntent, createSupabaseAuthMiddleware, getAuthenticatedUser, getPurchaseCacheStats, listPlans, processPaymentIntent, syncCustomer };
|
package/dist/index.d.ts
CHANGED
|
@@ -4,9 +4,9 @@ import { AuthenticatedUser, SolvaPay } from '@solvapay/server';
|
|
|
4
4
|
import { AuthAdapter } from '@solvapay/auth';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* Purchase Cache Utilities
|
|
8
8
|
*
|
|
9
|
-
* Cache management functions for
|
|
9
|
+
* Cache management functions for purchase data.
|
|
10
10
|
* Separated from index.ts to avoid circular dependencies.
|
|
11
11
|
*/
|
|
12
12
|
/**
|
|
@@ -30,46 +30,58 @@ interface RequestDeduplicationOptions {
|
|
|
30
30
|
cacheErrors?: boolean;
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
|
-
*
|
|
33
|
+
* Purchase check result
|
|
34
34
|
*/
|
|
35
|
-
interface
|
|
35
|
+
interface PurchaseCheckResult {
|
|
36
36
|
customerRef: string;
|
|
37
37
|
email?: string;
|
|
38
38
|
name?: string;
|
|
39
|
-
|
|
39
|
+
purchases: Array<{
|
|
40
40
|
reference: string;
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
productName?: string;
|
|
42
|
+
productReference?: string;
|
|
43
43
|
status?: string;
|
|
44
44
|
startDate?: string;
|
|
45
|
+
planSnapshot?: {
|
|
46
|
+
meterId?: string;
|
|
47
|
+
limit?: number;
|
|
48
|
+
freeUnits?: number;
|
|
49
|
+
};
|
|
50
|
+
usage?: {
|
|
51
|
+
used?: number;
|
|
52
|
+
overageUnits?: number;
|
|
53
|
+
overageCost?: number;
|
|
54
|
+
periodStart?: string;
|
|
55
|
+
periodEnd?: string;
|
|
56
|
+
};
|
|
45
57
|
[key: string]: unknown;
|
|
46
58
|
}>;
|
|
47
59
|
}
|
|
48
60
|
/**
|
|
49
|
-
* Clear
|
|
61
|
+
* Clear purchase cache for a specific user.
|
|
50
62
|
*
|
|
51
|
-
* Useful when you know
|
|
52
|
-
* checkout,
|
|
53
|
-
* `
|
|
63
|
+
* Useful when you know purchase status has changed (e.g., after a successful
|
|
64
|
+
* checkout, purchase update, or cancellation). This forces the next
|
|
65
|
+
* `checkPurchase()` call to fetch fresh data from the backend.
|
|
54
66
|
*
|
|
55
67
|
* @param userId - User ID to clear cache for
|
|
56
68
|
*
|
|
57
69
|
* @example
|
|
58
70
|
* ```typescript
|
|
59
|
-
* import {
|
|
71
|
+
* import { clearPurchaseCache } from '@solvapay/next';
|
|
60
72
|
*
|
|
61
73
|
* // After successful payment
|
|
62
74
|
* await processPayment(request, body);
|
|
63
|
-
*
|
|
75
|
+
* clearPurchaseCache(userId); // Force refresh on next check
|
|
64
76
|
* ```
|
|
65
77
|
*
|
|
66
|
-
* @see {@link
|
|
67
|
-
* @see {@link
|
|
78
|
+
* @see {@link checkPurchase} for purchase checking
|
|
79
|
+
* @see {@link clearAllPurchaseCache} to clear all cache entries
|
|
68
80
|
* @since 1.0.0
|
|
69
81
|
*/
|
|
70
|
-
declare function
|
|
82
|
+
declare function clearPurchaseCache(userId: string): void;
|
|
71
83
|
/**
|
|
72
|
-
* Clear all
|
|
84
|
+
* Clear all purchase cache entries.
|
|
73
85
|
*
|
|
74
86
|
* Useful for testing, debugging, or when you need to force fresh lookups
|
|
75
87
|
* for all users. This clears both the in-flight request cache and the
|
|
@@ -77,23 +89,23 @@ declare function clearSubscriptionCache(userId: string): void;
|
|
|
77
89
|
*
|
|
78
90
|
* @example
|
|
79
91
|
* ```typescript
|
|
80
|
-
* import {
|
|
92
|
+
* import { clearAllPurchaseCache } from '@solvapay/next';
|
|
81
93
|
*
|
|
82
94
|
* // In a test setup
|
|
83
95
|
* beforeEach(() => {
|
|
84
|
-
*
|
|
96
|
+
* clearAllPurchaseCache();
|
|
85
97
|
* });
|
|
86
98
|
* ```
|
|
87
99
|
*
|
|
88
|
-
* @see {@link
|
|
89
|
-
* @see {@link
|
|
100
|
+
* @see {@link clearPurchaseCache} to clear cache for a specific user
|
|
101
|
+
* @see {@link getPurchaseCacheStats} for cache monitoring
|
|
90
102
|
* @since 1.0.0
|
|
91
103
|
*/
|
|
92
|
-
declare function
|
|
104
|
+
declare function clearAllPurchaseCache(): void;
|
|
93
105
|
/**
|
|
94
|
-
* Get
|
|
106
|
+
* Get purchase cache statistics for monitoring and debugging.
|
|
95
107
|
*
|
|
96
|
-
* Returns the current state of the
|
|
108
|
+
* Returns the current state of the purchase cache, including:
|
|
97
109
|
* - Number of in-flight requests (being deduplicated)
|
|
98
110
|
* - Number of cached results
|
|
99
111
|
*
|
|
@@ -103,11 +115,11 @@ declare function clearAllSubscriptionCache(): void;
|
|
|
103
115
|
*
|
|
104
116
|
* @example
|
|
105
117
|
* ```typescript
|
|
106
|
-
* import {
|
|
118
|
+
* import { getPurchaseCacheStats } from '@solvapay/next';
|
|
107
119
|
*
|
|
108
120
|
* // In a monitoring endpoint
|
|
109
121
|
* export async function GET() {
|
|
110
|
-
* const stats =
|
|
122
|
+
* const stats = getPurchaseCacheStats();
|
|
111
123
|
* return Response.json({
|
|
112
124
|
* cache: {
|
|
113
125
|
* inFlight: stats.inFlight,
|
|
@@ -117,10 +129,10 @@ declare function clearAllSubscriptionCache(): void;
|
|
|
117
129
|
* }
|
|
118
130
|
* ```
|
|
119
131
|
*
|
|
120
|
-
* @see {@link
|
|
132
|
+
* @see {@link checkPurchase} for purchase checking
|
|
121
133
|
* @since 1.0.0
|
|
122
134
|
*/
|
|
123
|
-
declare function
|
|
135
|
+
declare function getPurchaseCacheStats(): {
|
|
124
136
|
inFlight: number;
|
|
125
137
|
cached: number;
|
|
126
138
|
};
|
|
@@ -188,17 +200,9 @@ declare function syncCustomer(request: globalThis.Request, options?: {
|
|
|
188
200
|
includeName?: boolean;
|
|
189
201
|
}): Promise<string | NextResponse>;
|
|
190
202
|
|
|
191
|
-
/**
|
|
192
|
-
* Create payment intent - Next.js wrapper
|
|
193
|
-
*
|
|
194
|
-
* @param request - Next.js request object
|
|
195
|
-
* @param body - Payment intent parameters
|
|
196
|
-
* @param options - Configuration options
|
|
197
|
-
* @returns Payment intent response or NextResponse error
|
|
198
|
-
*/
|
|
199
203
|
declare function createPaymentIntent(request: globalThis.Request, body: {
|
|
200
204
|
planRef: string;
|
|
201
|
-
|
|
205
|
+
productRef: string;
|
|
202
206
|
}, options?: {
|
|
203
207
|
solvaPay?: SolvaPay;
|
|
204
208
|
includeEmail?: boolean;
|
|
@@ -210,17 +214,9 @@ declare function createPaymentIntent(request: globalThis.Request, body: {
|
|
|
210
214
|
accountId?: string;
|
|
211
215
|
customerRef: string;
|
|
212
216
|
} | NextResponse>;
|
|
213
|
-
|
|
214
|
-
* Process payment - Next.js wrapper
|
|
215
|
-
*
|
|
216
|
-
* @param request - Next.js request object
|
|
217
|
-
* @param body - Payment processing parameters
|
|
218
|
-
* @param options - Configuration options
|
|
219
|
-
* @returns Process payment result or NextResponse error
|
|
220
|
-
*/
|
|
221
|
-
declare function processPayment(request: globalThis.Request, body: {
|
|
217
|
+
declare function processPaymentIntent(request: globalThis.Request, body: {
|
|
222
218
|
paymentIntentId: string;
|
|
223
|
-
|
|
219
|
+
productRef: string;
|
|
224
220
|
planRef?: string;
|
|
225
221
|
}, options?: {
|
|
226
222
|
solvaPay?: SolvaPay;
|
|
@@ -228,20 +224,10 @@ declare function processPayment(request: globalThis.Request, body: {
|
|
|
228
224
|
|
|
229
225
|
/**
|
|
230
226
|
* Next.js Checkout Helpers
|
|
231
|
-
*
|
|
232
|
-
* Next.js-specific wrappers for checkout helpers.
|
|
233
227
|
*/
|
|
234
228
|
|
|
235
|
-
/**
|
|
236
|
-
* Create checkout session - Next.js wrapper
|
|
237
|
-
*
|
|
238
|
-
* @param request - Next.js request object
|
|
239
|
-
* @param body - Checkout session parameters
|
|
240
|
-
* @param options - Configuration options
|
|
241
|
-
* @returns Checkout session response or NextResponse error
|
|
242
|
-
*/
|
|
243
229
|
declare function createCheckoutSession(request: globalThis.Request, body: {
|
|
244
|
-
|
|
230
|
+
productRef: string;
|
|
245
231
|
planRef?: string;
|
|
246
232
|
returnUrl?: string;
|
|
247
233
|
}, options?: {
|
|
@@ -253,13 +239,6 @@ declare function createCheckoutSession(request: globalThis.Request, body: {
|
|
|
253
239
|
sessionId: string;
|
|
254
240
|
checkoutUrl: string;
|
|
255
241
|
} | NextResponse>;
|
|
256
|
-
/**
|
|
257
|
-
* Create customer session - Next.js wrapper
|
|
258
|
-
*
|
|
259
|
-
* @param request - Next.js request object
|
|
260
|
-
* @param options - Configuration options
|
|
261
|
-
* @returns Customer session response or NextResponse error
|
|
262
|
-
*/
|
|
263
242
|
declare function createCustomerSession(request: globalThis.Request, options?: {
|
|
264
243
|
solvaPay?: SolvaPay;
|
|
265
244
|
includeEmail?: boolean;
|
|
@@ -270,20 +249,18 @@ declare function createCustomerSession(request: globalThis.Request, options?: {
|
|
|
270
249
|
} | NextResponse>;
|
|
271
250
|
|
|
272
251
|
/**
|
|
273
|
-
* Next.js
|
|
274
|
-
*
|
|
275
|
-
* Next.js-specific wrappers for subscription helpers.
|
|
252
|
+
* Next.js Purchase Cancellation Helpers
|
|
276
253
|
*/
|
|
277
254
|
/**
|
|
278
|
-
* Cancel
|
|
255
|
+
* Cancel purchase - Next.js wrapper
|
|
279
256
|
*
|
|
280
257
|
* @param request - Next.js request object
|
|
281
258
|
* @param body - Cancellation parameters
|
|
282
259
|
* @param options - Configuration options
|
|
283
|
-
* @returns Cancelled
|
|
260
|
+
* @returns Cancelled purchase response or NextResponse error
|
|
284
261
|
*/
|
|
285
|
-
declare function
|
|
286
|
-
|
|
262
|
+
declare function cancelRenewal(request: globalThis.Request, body: {
|
|
263
|
+
purchaseRef: string;
|
|
287
264
|
reason?: string;
|
|
288
265
|
}, options?: {
|
|
289
266
|
solvaPay?: SolvaPay;
|
|
@@ -291,19 +268,10 @@ declare function cancelSubscription(request: globalThis.Request, body: {
|
|
|
291
268
|
|
|
292
269
|
/**
|
|
293
270
|
* Next.js Plans Helper
|
|
294
|
-
*
|
|
295
|
-
* Next.js-specific wrapper for plans helper.
|
|
296
|
-
* This is a public route - no authentication required.
|
|
297
|
-
*/
|
|
298
|
-
/**
|
|
299
|
-
* List plans - Next.js wrapper
|
|
300
|
-
*
|
|
301
|
-
* @param request - Next.js request object
|
|
302
|
-
* @returns Plans response or NextResponse error
|
|
303
271
|
*/
|
|
304
272
|
declare function listPlans(request: globalThis.Request): Promise<{
|
|
305
273
|
plans: Array<Record<string, unknown>>;
|
|
306
|
-
|
|
274
|
+
productRef: string;
|
|
307
275
|
} | NextResponse>;
|
|
308
276
|
|
|
309
277
|
/**
|
|
@@ -489,9 +457,9 @@ declare function createSupabaseAuthMiddleware(options?: SupabaseAuthMiddlewareOp
|
|
|
489
457
|
*/
|
|
490
458
|
|
|
491
459
|
/**
|
|
492
|
-
* Options for checking
|
|
460
|
+
* Options for checking purchases
|
|
493
461
|
*/
|
|
494
|
-
interface
|
|
462
|
+
interface CheckPurchaseOptions {
|
|
495
463
|
/**
|
|
496
464
|
* Request deduplication options
|
|
497
465
|
*
|
|
@@ -518,9 +486,9 @@ interface CheckSubscriptionOptions {
|
|
|
518
486
|
includeName?: boolean;
|
|
519
487
|
}
|
|
520
488
|
/**
|
|
521
|
-
* Check user
|
|
489
|
+
* Check user purchase status with automatic deduplication and caching.
|
|
522
490
|
*
|
|
523
|
-
* This Next.js helper function provides optimized
|
|
491
|
+
* This Next.js helper function provides optimized purchase checking with:
|
|
524
492
|
* - Automatic request deduplication (concurrent requests share the same promise)
|
|
525
493
|
* - Short-term caching (2 seconds) to prevent duplicate sequential requests
|
|
526
494
|
* - Fast path optimization using cached customer references from client
|
|
@@ -531,7 +499,7 @@ interface CheckSubscriptionOptions {
|
|
|
531
499
|
* 2. Gets user email and name from Supabase JWT token (if available)
|
|
532
500
|
* 3. Validates cached customer reference (if provided via header)
|
|
533
501
|
* 4. Ensures customer exists in SolvaPay backend
|
|
534
|
-
* 5. Returns customer
|
|
502
|
+
* 5. Returns customer purchase information
|
|
535
503
|
*
|
|
536
504
|
* @param request - Next.js request object (NextRequest extends Request)
|
|
537
505
|
* @param options - Configuration options
|
|
@@ -539,15 +507,15 @@ interface CheckSubscriptionOptions {
|
|
|
539
507
|
* @param options.solvaPay - Optional SolvaPay instance (creates new one if not provided)
|
|
540
508
|
* @param options.includeEmail - Whether to include email in response (default: true)
|
|
541
509
|
* @param options.includeName - Whether to include name in response (default: true)
|
|
542
|
-
* @returns
|
|
510
|
+
* @returns Purchase check result with customer data and purchases, or NextResponse error
|
|
543
511
|
*
|
|
544
512
|
* @example
|
|
545
513
|
* ```typescript
|
|
546
514
|
* import { NextRequest, NextResponse } from 'next/server';
|
|
547
|
-
* import {
|
|
515
|
+
* import { checkPurchase } from '@solvapay/next';
|
|
548
516
|
*
|
|
549
517
|
* export async function GET(request: NextRequest) {
|
|
550
|
-
* const result = await
|
|
518
|
+
* const result = await checkPurchase(request);
|
|
551
519
|
*
|
|
552
520
|
* if (result instanceof NextResponse) {
|
|
553
521
|
* return result; // Error response
|
|
@@ -557,10 +525,10 @@ interface CheckSubscriptionOptions {
|
|
|
557
525
|
* }
|
|
558
526
|
* ```
|
|
559
527
|
*
|
|
560
|
-
* @see {@link
|
|
561
|
-
* @see {@link
|
|
528
|
+
* @see {@link clearPurchaseCache} for cache management
|
|
529
|
+
* @see {@link getPurchaseCacheStats} for cache monitoring
|
|
562
530
|
* @since 1.0.0
|
|
563
531
|
*/
|
|
564
|
-
declare function
|
|
532
|
+
declare function checkPurchase(request: Request, options?: CheckPurchaseOptions): Promise<PurchaseCheckResult | NextResponse>;
|
|
565
533
|
|
|
566
|
-
export { type AuthMiddlewareOptions, type
|
|
534
|
+
export { type AuthMiddlewareOptions, type CheckPurchaseOptions, type PurchaseCheckResult, type RequestDeduplicationOptions, type SupabaseAuthMiddlewareOptions, cancelRenewal, checkPurchase, clearAllPurchaseCache, clearPurchaseCache, createAuthMiddleware, createCheckoutSession, createCustomerSession, createPaymentIntent, createSupabaseAuthMiddleware, getAuthenticatedUser, getPurchaseCacheStats, listPlans, processPaymentIntent, syncCustomer };
|
package/dist/index.js
CHANGED
|
@@ -105,10 +105,10 @@ function createRequestDeduplicator(options = {}) {
|
|
|
105
105
|
getStats
|
|
106
106
|
};
|
|
107
107
|
}
|
|
108
|
-
var
|
|
108
|
+
var sharedPurchaseDeduplicator = null;
|
|
109
109
|
function getSharedDeduplicator(options) {
|
|
110
|
-
if (!
|
|
111
|
-
|
|
110
|
+
if (!sharedPurchaseDeduplicator) {
|
|
111
|
+
sharedPurchaseDeduplicator = createRequestDeduplicator({
|
|
112
112
|
cacheTTL: 2e3,
|
|
113
113
|
// Cache results for 2 seconds
|
|
114
114
|
maxCacheSize: 1e3,
|
|
@@ -118,17 +118,17 @@ function getSharedDeduplicator(options) {
|
|
|
118
118
|
...options
|
|
119
119
|
});
|
|
120
120
|
}
|
|
121
|
-
return
|
|
121
|
+
return sharedPurchaseDeduplicator;
|
|
122
122
|
}
|
|
123
|
-
function
|
|
123
|
+
function clearPurchaseCache(userId) {
|
|
124
124
|
const deduplicator = getSharedDeduplicator();
|
|
125
125
|
deduplicator.clearCache(userId);
|
|
126
126
|
}
|
|
127
|
-
function
|
|
127
|
+
function clearAllPurchaseCache() {
|
|
128
128
|
const deduplicator = getSharedDeduplicator();
|
|
129
129
|
deduplicator.clearAllCache();
|
|
130
130
|
}
|
|
131
|
-
function
|
|
131
|
+
function getPurchaseCacheStats() {
|
|
132
132
|
const deduplicator = getSharedDeduplicator();
|
|
133
133
|
return deduplicator.getStats();
|
|
134
134
|
}
|
|
@@ -168,7 +168,7 @@ async function syncCustomer(request, options = {}) {
|
|
|
168
168
|
import { NextResponse as NextResponse3 } from "next/server";
|
|
169
169
|
import {
|
|
170
170
|
createPaymentIntentCore,
|
|
171
|
-
|
|
171
|
+
processPaymentIntentCore,
|
|
172
172
|
isErrorResult as isErrorResult3
|
|
173
173
|
} from "@solvapay/server";
|
|
174
174
|
import { getAuthenticatedUserCore as getAuthenticatedUserCore2 } from "@solvapay/server";
|
|
@@ -183,14 +183,14 @@ async function createPaymentIntent(request, body, options = {}) {
|
|
|
183
183
|
try {
|
|
184
184
|
const userResult = await getAuthenticatedUserCore2(request);
|
|
185
185
|
if (!isErrorResult3(userResult)) {
|
|
186
|
-
|
|
186
|
+
clearPurchaseCache(userResult.userId);
|
|
187
187
|
}
|
|
188
188
|
} catch {
|
|
189
189
|
}
|
|
190
190
|
return result;
|
|
191
191
|
}
|
|
192
|
-
async function
|
|
193
|
-
const result = await
|
|
192
|
+
async function processPaymentIntent(request, body, options = {}) {
|
|
193
|
+
const result = await processPaymentIntentCore(request, body, options);
|
|
194
194
|
if (isErrorResult3(result)) {
|
|
195
195
|
return NextResponse3.json(
|
|
196
196
|
{ error: result.error, details: result.details },
|
|
@@ -200,7 +200,7 @@ async function processPayment(request, body, options = {}) {
|
|
|
200
200
|
try {
|
|
201
201
|
const userResult = await getAuthenticatedUserCore2(request);
|
|
202
202
|
if (!isErrorResult3(userResult)) {
|
|
203
|
-
|
|
203
|
+
clearPurchaseCache(userResult.userId);
|
|
204
204
|
}
|
|
205
205
|
} catch {
|
|
206
206
|
}
|
|
@@ -235,12 +235,12 @@ async function createCustomerSession(request, options = {}) {
|
|
|
235
235
|
return result;
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
-
// src/helpers/
|
|
238
|
+
// src/helpers/renewal.ts
|
|
239
239
|
import { NextResponse as NextResponse5 } from "next/server";
|
|
240
|
-
import {
|
|
240
|
+
import { cancelPurchaseCore, isErrorResult as isErrorResult5 } from "@solvapay/server";
|
|
241
241
|
import { getAuthenticatedUserCore as getAuthenticatedUserCore3 } from "@solvapay/server";
|
|
242
|
-
async function
|
|
243
|
-
const result = await
|
|
242
|
+
async function cancelRenewal(request, body, options = {}) {
|
|
243
|
+
const result = await cancelPurchaseCore(request, body, options);
|
|
244
244
|
if (isErrorResult5(result)) {
|
|
245
245
|
return NextResponse5.json(
|
|
246
246
|
{ error: result.error, details: result.details },
|
|
@@ -250,7 +250,7 @@ async function cancelSubscription(request, body, options = {}) {
|
|
|
250
250
|
try {
|
|
251
251
|
const userResult = await getAuthenticatedUserCore3(request);
|
|
252
252
|
if (!isErrorResult5(userResult)) {
|
|
253
|
-
|
|
253
|
+
clearPurchaseCache(userResult.userId);
|
|
254
254
|
}
|
|
255
255
|
} catch {
|
|
256
256
|
}
|
|
@@ -342,7 +342,7 @@ function createSupabaseAuthMiddleware(options = {}) {
|
|
|
342
342
|
}
|
|
343
343
|
|
|
344
344
|
// src/index.ts
|
|
345
|
-
async function
|
|
345
|
+
async function checkPurchase(request, options = {}) {
|
|
346
346
|
try {
|
|
347
347
|
const { requireUserId, getUserEmailFromRequest, getUserNameFromRequest } = await import("@solvapay/auth");
|
|
348
348
|
const userIdOrError = requireUserId(request);
|
|
@@ -361,14 +361,14 @@ async function checkSubscription(request, options = {}) {
|
|
|
361
361
|
const customer = await solvaPay.getCustomer({ customerRef: cachedCustomerRef });
|
|
362
362
|
if (customer && customer.customerRef) {
|
|
363
363
|
if (customer.externalRef && customer.externalRef === userId) {
|
|
364
|
-
const
|
|
365
|
-
(
|
|
364
|
+
const filteredPurchases = (customer.purchases || []).filter(
|
|
365
|
+
(p) => p.status === "active"
|
|
366
366
|
);
|
|
367
367
|
return {
|
|
368
368
|
customerRef: customer.customerRef,
|
|
369
369
|
email: customer.email,
|
|
370
370
|
name: customer.name,
|
|
371
|
-
|
|
371
|
+
purchases: filteredPurchases
|
|
372
372
|
};
|
|
373
373
|
}
|
|
374
374
|
}
|
|
@@ -383,50 +383,50 @@ async function checkSubscription(request, options = {}) {
|
|
|
383
383
|
name: name || void 0
|
|
384
384
|
});
|
|
385
385
|
const customer = await solvaPay.getCustomer({ customerRef: ensuredCustomerRef });
|
|
386
|
-
const
|
|
387
|
-
(
|
|
386
|
+
const filteredPurchases = (customer.purchases || []).filter(
|
|
387
|
+
(p) => p.status === "active"
|
|
388
388
|
);
|
|
389
389
|
const result = {
|
|
390
390
|
customerRef: customer.customerRef || userId,
|
|
391
391
|
email: customer.email,
|
|
392
392
|
name: customer.name,
|
|
393
|
-
|
|
393
|
+
purchases: filteredPurchases
|
|
394
394
|
};
|
|
395
395
|
return result;
|
|
396
396
|
} catch (error) {
|
|
397
|
-
console.error("[
|
|
397
|
+
console.error("[checkPurchase] Error fetching customer:", error);
|
|
398
398
|
return {
|
|
399
399
|
customerRef: userId,
|
|
400
|
-
|
|
400
|
+
purchases: []
|
|
401
401
|
};
|
|
402
402
|
}
|
|
403
403
|
});
|
|
404
404
|
return response;
|
|
405
405
|
} catch (error) {
|
|
406
|
-
console.error("Check
|
|
406
|
+
console.error("Check purchase failed:", error);
|
|
407
407
|
if (error instanceof SolvaPayError) {
|
|
408
408
|
return NextResponse8.json({ error: error.message }, { status: 500 });
|
|
409
409
|
}
|
|
410
410
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
411
411
|
return NextResponse8.json(
|
|
412
|
-
{ error: "Failed to check
|
|
412
|
+
{ error: "Failed to check purchase", details: errorMessage },
|
|
413
413
|
{ status: 500 }
|
|
414
414
|
);
|
|
415
415
|
}
|
|
416
416
|
}
|
|
417
417
|
export {
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
418
|
+
cancelRenewal,
|
|
419
|
+
checkPurchase,
|
|
420
|
+
clearAllPurchaseCache,
|
|
421
|
+
clearPurchaseCache,
|
|
422
422
|
createAuthMiddleware,
|
|
423
423
|
createCheckoutSession,
|
|
424
424
|
createCustomerSession,
|
|
425
425
|
createPaymentIntent,
|
|
426
426
|
createSupabaseAuthMiddleware,
|
|
427
427
|
getAuthenticatedUser,
|
|
428
|
-
|
|
428
|
+
getPurchaseCacheStats,
|
|
429
429
|
listPlans,
|
|
430
|
-
|
|
430
|
+
processPaymentIntent,
|
|
431
431
|
syncCustomer
|
|
432
432
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solvapay/next",
|
|
3
|
-
"version": "1.0.0-preview.
|
|
3
|
+
"version": "1.0.0-preview.21",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
},
|
|
30
30
|
"sideEffects": false,
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@solvapay/auth": "1.0.0-preview.
|
|
33
|
-
"@solvapay/
|
|
34
|
-
"@solvapay/
|
|
32
|
+
"@solvapay/auth": "1.0.0-preview.21",
|
|
33
|
+
"@solvapay/server": "1.0.0-preview.21",
|
|
34
|
+
"@solvapay/core": "1.0.0-preview.21"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
37
|
"next": ">=13.0.0"
|