@solvapay/next 1.0.0-preview.18 → 1.0.0-preview.20

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
@@ -3,6 +3,136 @@ import { NextResponse as NextResponse8 } from "next/server";
3
3
  import { createSolvaPay } from "@solvapay/server";
4
4
  import { SolvaPayError } from "@solvapay/core";
5
5
 
6
+ // src/cache.ts
7
+ function createRequestDeduplicator(options = {}) {
8
+ const { cacheTTL = 2e3, maxCacheSize = 1e3, cacheErrors = true } = options;
9
+ const inFlightRequests = /* @__PURE__ */ new Map();
10
+ const resultCache = /* @__PURE__ */ new Map();
11
+ const cacheInvalidatedAt = /* @__PURE__ */ new Map();
12
+ if (cacheTTL > 0) {
13
+ setInterval(
14
+ () => {
15
+ const now = Date.now();
16
+ const entriesToDelete = [];
17
+ for (const [key, cached] of resultCache.entries()) {
18
+ if (now - cached.timestamp >= cacheTTL) {
19
+ entriesToDelete.push(key);
20
+ }
21
+ }
22
+ for (const key of entriesToDelete) {
23
+ resultCache.delete(key);
24
+ cacheInvalidatedAt.delete(key);
25
+ }
26
+ if (resultCache.size > maxCacheSize) {
27
+ const sortedEntries = Array.from(resultCache.entries()).sort(
28
+ (a, b) => a[1].timestamp - b[1].timestamp
29
+ );
30
+ const toRemove = sortedEntries.slice(0, resultCache.size - maxCacheSize);
31
+ for (const [key] of toRemove) {
32
+ resultCache.delete(key);
33
+ cacheInvalidatedAt.delete(key);
34
+ }
35
+ }
36
+ },
37
+ Math.min(cacheTTL, 1e3)
38
+ );
39
+ }
40
+ const deduplicate = async (key, fn) => {
41
+ if (cacheTTL > 0) {
42
+ const cached = resultCache.get(key);
43
+ if (cached && Date.now() - cached.timestamp < cacheTTL) {
44
+ return cached.data;
45
+ } else if (cached) {
46
+ resultCache.delete(key);
47
+ }
48
+ }
49
+ let requestPromise = inFlightRequests.get(key);
50
+ if (!requestPromise) {
51
+ const requestStartTime = Date.now();
52
+ requestPromise = (async () => {
53
+ try {
54
+ const result = await fn();
55
+ const invalidatedAt = cacheInvalidatedAt.get(key);
56
+ const shouldCache = !invalidatedAt || invalidatedAt < requestStartTime;
57
+ if (cacheTTL > 0 && shouldCache) {
58
+ resultCache.set(key, {
59
+ data: result,
60
+ timestamp: Date.now()
61
+ });
62
+ }
63
+ return result;
64
+ } catch (error) {
65
+ const invalidatedAt = cacheInvalidatedAt.get(key);
66
+ const shouldCache = !invalidatedAt || invalidatedAt < requestStartTime;
67
+ if (cacheTTL > 0 && cacheErrors && shouldCache) {
68
+ resultCache.set(key, {
69
+ data: error,
70
+ timestamp: Date.now()
71
+ });
72
+ }
73
+ throw error;
74
+ } finally {
75
+ inFlightRequests.delete(key);
76
+ }
77
+ })();
78
+ const existingPromise = inFlightRequests.get(key);
79
+ if (existingPromise) {
80
+ requestPromise = existingPromise;
81
+ } else {
82
+ inFlightRequests.set(key, requestPromise);
83
+ }
84
+ }
85
+ return requestPromise;
86
+ };
87
+ const clearCache = (key) => {
88
+ resultCache.delete(key);
89
+ cacheInvalidatedAt.set(key, Date.now());
90
+ inFlightRequests.delete(key);
91
+ };
92
+ const clearAllCache = () => {
93
+ resultCache.clear();
94
+ cacheInvalidatedAt.clear();
95
+ inFlightRequests.clear();
96
+ };
97
+ const getStats = () => ({
98
+ inFlight: inFlightRequests.size,
99
+ cached: resultCache.size
100
+ });
101
+ return {
102
+ deduplicate,
103
+ clearCache,
104
+ clearAllCache,
105
+ getStats
106
+ };
107
+ }
108
+ var sharedPurchaseDeduplicator = null;
109
+ function getSharedDeduplicator(options) {
110
+ if (!sharedPurchaseDeduplicator) {
111
+ sharedPurchaseDeduplicator = createRequestDeduplicator({
112
+ cacheTTL: 2e3,
113
+ // Cache results for 2 seconds
114
+ maxCacheSize: 1e3,
115
+ // Maximum cache entries
116
+ cacheErrors: true,
117
+ // Cache error results too
118
+ ...options
119
+ });
120
+ }
121
+ return sharedPurchaseDeduplicator;
122
+ }
123
+ function clearPurchaseCache(userId) {
124
+ const deduplicator = getSharedDeduplicator();
125
+ deduplicator.clearCache(userId);
126
+ }
127
+ function clearAllPurchaseCache() {
128
+ const deduplicator = getSharedDeduplicator();
129
+ deduplicator.clearAllCache();
130
+ }
131
+ function getPurchaseCacheStats() {
132
+ const deduplicator = getSharedDeduplicator();
133
+ return deduplicator.getStats();
134
+ }
135
+
6
136
  // src/helpers/auth.ts
7
137
  import { NextResponse } from "next/server";
8
138
  import {
@@ -22,10 +152,7 @@ async function getAuthenticatedUser(request, options = {}) {
22
152
 
23
153
  // src/helpers/customer.ts
24
154
  import { NextResponse as NextResponse2 } from "next/server";
25
- import {
26
- syncCustomerCore,
27
- isErrorResult as isErrorResult2
28
- } from "@solvapay/server";
155
+ import { syncCustomerCore, isErrorResult as isErrorResult2 } from "@solvapay/server";
29
156
  async function syncCustomer(request, options = {}) {
30
157
  const result = await syncCustomerCore(request, options);
31
158
  if (isErrorResult2(result)) {
@@ -41,7 +168,7 @@ async function syncCustomer(request, options = {}) {
41
168
  import { NextResponse as NextResponse3 } from "next/server";
42
169
  import {
43
170
  createPaymentIntentCore,
44
- processPaymentCore,
171
+ processPaymentIntentCore,
45
172
  isErrorResult as isErrorResult3
46
173
  } from "@solvapay/server";
47
174
  import { getAuthenticatedUserCore as getAuthenticatedUserCore2 } from "@solvapay/server";
@@ -56,14 +183,14 @@ async function createPaymentIntent(request, body, options = {}) {
56
183
  try {
57
184
  const userResult = await getAuthenticatedUserCore2(request);
58
185
  if (!isErrorResult3(userResult)) {
59
- clearSubscriptionCache(userResult.userId);
186
+ clearPurchaseCache(userResult.userId);
60
187
  }
61
188
  } catch {
62
189
  }
63
190
  return result;
64
191
  }
65
- async function processPayment(request, body, options = {}) {
66
- const result = await processPaymentCore(request, body, options);
192
+ async function processPaymentIntent(request, body, options = {}) {
193
+ const result = await processPaymentIntentCore(request, body, options);
67
194
  if (isErrorResult3(result)) {
68
195
  return NextResponse3.json(
69
196
  { error: result.error, details: result.details },
@@ -73,7 +200,7 @@ async function processPayment(request, body, options = {}) {
73
200
  try {
74
201
  const userResult = await getAuthenticatedUserCore2(request);
75
202
  if (!isErrorResult3(userResult)) {
76
- clearSubscriptionCache(userResult.userId);
203
+ clearPurchaseCache(userResult.userId);
77
204
  }
78
205
  } catch {
79
206
  }
@@ -108,15 +235,12 @@ async function createCustomerSession(request, options = {}) {
108
235
  return result;
109
236
  }
110
237
 
111
- // src/helpers/subscription.ts
238
+ // src/helpers/renewal.ts
112
239
  import { NextResponse as NextResponse5 } from "next/server";
113
- import {
114
- cancelSubscriptionCore,
115
- isErrorResult as isErrorResult5
116
- } from "@solvapay/server";
240
+ import { cancelPurchaseCore, isErrorResult as isErrorResult5 } from "@solvapay/server";
117
241
  import { getAuthenticatedUserCore as getAuthenticatedUserCore3 } from "@solvapay/server";
118
- async function cancelSubscription(request, body, options = {}) {
119
- const result = await cancelSubscriptionCore(request, body, options);
242
+ async function cancelRenewal(request, body, options = {}) {
243
+ const result = await cancelPurchaseCore(request, body, options);
120
244
  if (isErrorResult5(result)) {
121
245
  return NextResponse5.json(
122
246
  { error: result.error, details: result.details },
@@ -126,7 +250,7 @@ async function cancelSubscription(request, body, options = {}) {
126
250
  try {
127
251
  const userResult = await getAuthenticatedUserCore3(request);
128
252
  if (!isErrorResult5(userResult)) {
129
- clearSubscriptionCache(userResult.userId);
253
+ clearPurchaseCache(userResult.userId);
130
254
  }
131
255
  } catch {
132
256
  }
@@ -135,10 +259,7 @@ async function cancelSubscription(request, body, options = {}) {
135
259
 
136
260
  // src/helpers/plans.ts
137
261
  import { NextResponse as NextResponse6 } from "next/server";
138
- import {
139
- listPlansCore,
140
- isErrorResult as isErrorResult6
141
- } from "@solvapay/server";
262
+ import { listPlansCore, isErrorResult as isErrorResult6 } from "@solvapay/server";
142
263
  async function listPlans(request) {
143
264
  const result = await listPlansCore(request);
144
265
  if (isErrorResult6(result)) {
@@ -153,20 +274,17 @@ async function listPlans(request) {
153
274
  // src/helpers/middleware.ts
154
275
  import { NextResponse as NextResponse7 } from "next/server";
155
276
  function createAuthMiddleware(options) {
156
- const {
157
- adapter,
158
- publicRoutes = [],
159
- userIdHeader = "x-user-id"
160
- } = options;
277
+ const { adapter, publicRoutes = [], userIdHeader = "x-user-id" } = options;
161
278
  return async function middleware(request) {
162
- const { pathname } = request.nextUrl;
279
+ const req = request;
280
+ const { pathname } = req.nextUrl;
163
281
  if (!pathname.startsWith("/api")) {
164
282
  return NextResponse7.next();
165
283
  }
166
284
  const isPublicRoute = publicRoutes.some((route) => pathname.startsWith(route));
167
- const userId = await adapter.getUserIdFromRequest(request);
285
+ const userId = await adapter.getUserIdFromRequest(req);
168
286
  if (isPublicRoute) {
169
- const requestHeaders2 = new Headers(request.headers);
287
+ const requestHeaders2 = new Headers(req.headers);
170
288
  if (userId) {
171
289
  requestHeaders2.set(userIdHeader, userId);
172
290
  }
@@ -182,7 +300,7 @@ function createAuthMiddleware(options) {
182
300
  { status: 401 }
183
301
  );
184
302
  }
185
- const requestHeaders = new Headers(request.headers);
303
+ const requestHeaders = new Headers(req.headers);
186
304
  requestHeaders.set(userIdHeader, userId);
187
305
  return NextResponse7.next({
188
306
  request: {
@@ -192,11 +310,7 @@ function createAuthMiddleware(options) {
192
310
  };
193
311
  }
194
312
  function createSupabaseAuthMiddleware(options = {}) {
195
- const {
196
- jwtSecret,
197
- publicRoutes = [],
198
- userIdHeader = "x-user-id"
199
- } = options;
313
+ const { jwtSecret, publicRoutes = [], userIdHeader = "x-user-id" } = options;
200
314
  let authAdapter = null;
201
315
  let adapterPromise = null;
202
316
  const lazyAdapter = {
@@ -228,123 +342,7 @@ function createSupabaseAuthMiddleware(options = {}) {
228
342
  }
229
343
 
230
344
  // src/index.ts
231
- function createRequestDeduplicator(options = {}) {
232
- const {
233
- cacheTTL = 2e3,
234
- maxCacheSize = 1e3,
235
- cacheErrors = true
236
- } = options;
237
- const inFlightRequests = /* @__PURE__ */ new Map();
238
- const resultCache = /* @__PURE__ */ new Map();
239
- const cacheInvalidatedAt = /* @__PURE__ */ new Map();
240
- let cleanupInterval = null;
241
- if (cacheTTL > 0) {
242
- cleanupInterval = setInterval(() => {
243
- const now = Date.now();
244
- const entriesToDelete = [];
245
- for (const [key, cached] of resultCache.entries()) {
246
- if (now - cached.timestamp >= cacheTTL) {
247
- entriesToDelete.push(key);
248
- }
249
- }
250
- for (const key of entriesToDelete) {
251
- resultCache.delete(key);
252
- cacheInvalidatedAt.delete(key);
253
- }
254
- if (resultCache.size > maxCacheSize) {
255
- const sortedEntries = Array.from(resultCache.entries()).sort((a, b) => a[1].timestamp - b[1].timestamp);
256
- const toRemove = sortedEntries.slice(0, resultCache.size - maxCacheSize);
257
- for (const [key] of toRemove) {
258
- resultCache.delete(key);
259
- cacheInvalidatedAt.delete(key);
260
- }
261
- }
262
- }, Math.min(cacheTTL, 1e3));
263
- }
264
- const deduplicate = async (key, fn) => {
265
- if (cacheTTL > 0) {
266
- const cached = resultCache.get(key);
267
- if (cached && Date.now() - cached.timestamp < cacheTTL) {
268
- return cached.data;
269
- } else if (cached) {
270
- resultCache.delete(key);
271
- }
272
- }
273
- let requestPromise = inFlightRequests.get(key);
274
- if (!requestPromise) {
275
- const requestStartTime = Date.now();
276
- requestPromise = (async () => {
277
- try {
278
- const result = await fn();
279
- const invalidatedAt = cacheInvalidatedAt.get(key);
280
- const shouldCache = !invalidatedAt || invalidatedAt < requestStartTime;
281
- if (cacheTTL > 0 && shouldCache) {
282
- resultCache.set(key, {
283
- data: result,
284
- timestamp: Date.now()
285
- });
286
- }
287
- return result;
288
- } catch (error) {
289
- const invalidatedAt = cacheInvalidatedAt.get(key);
290
- const shouldCache = !invalidatedAt || invalidatedAt < requestStartTime;
291
- if (cacheTTL > 0 && cacheErrors && shouldCache) {
292
- resultCache.set(key, {
293
- data: error,
294
- timestamp: Date.now()
295
- });
296
- }
297
- throw error;
298
- } finally {
299
- inFlightRequests.delete(key);
300
- }
301
- })();
302
- const existingPromise = inFlightRequests.get(key);
303
- if (existingPromise) {
304
- requestPromise = existingPromise;
305
- } else {
306
- inFlightRequests.set(key, requestPromise);
307
- }
308
- }
309
- return requestPromise;
310
- };
311
- const clearCache = (key) => {
312
- resultCache.delete(key);
313
- cacheInvalidatedAt.set(key, Date.now());
314
- inFlightRequests.delete(key);
315
- };
316
- const clearAllCache = () => {
317
- resultCache.clear();
318
- cacheInvalidatedAt.clear();
319
- inFlightRequests.clear();
320
- };
321
- const getStats = () => ({
322
- inFlight: inFlightRequests.size,
323
- cached: resultCache.size
324
- });
325
- return {
326
- deduplicate,
327
- clearCache,
328
- clearAllCache,
329
- getStats
330
- };
331
- }
332
- var sharedSubscriptionDeduplicator = null;
333
- function getSharedDeduplicator(options) {
334
- if (!sharedSubscriptionDeduplicator) {
335
- sharedSubscriptionDeduplicator = createRequestDeduplicator({
336
- cacheTTL: 2e3,
337
- // Cache results for 2 seconds
338
- maxCacheSize: 1e3,
339
- // Maximum cache entries
340
- cacheErrors: true,
341
- // Cache error results too
342
- ...options
343
- });
344
- }
345
- return sharedSubscriptionDeduplicator;
346
- }
347
- async function checkSubscription(request, options = {}) {
345
+ async function checkPurchase(request, options = {}) {
348
346
  try {
349
347
  const { requireUserId, getUserEmailFromRequest, getUserNameFromRequest } = await import("@solvapay/auth");
350
348
  const userIdOrError = requireUserId(request);
@@ -363,18 +361,18 @@ async function checkSubscription(request, options = {}) {
363
361
  const customer = await solvaPay.getCustomer({ customerRef: cachedCustomerRef });
364
362
  if (customer && customer.customerRef) {
365
363
  if (customer.externalRef && customer.externalRef === userId) {
366
- const filteredSubscriptions = (customer.subscriptions || []).filter(
367
- (sub) => sub.status === "active"
364
+ const filteredPurchases = (customer.purchases || []).filter(
365
+ (p) => p.status === "active"
368
366
  );
369
367
  return {
370
368
  customerRef: customer.customerRef,
371
369
  email: customer.email,
372
370
  name: customer.name,
373
- subscriptions: filteredSubscriptions
371
+ purchases: filteredPurchases
374
372
  };
375
373
  }
376
374
  }
377
- } catch (error) {
375
+ } catch {
378
376
  }
379
377
  }
380
378
  const deduplicator = getSharedDeduplicator(options.deduplication);
@@ -385,65 +383,50 @@ async function checkSubscription(request, options = {}) {
385
383
  name: name || void 0
386
384
  });
387
385
  const customer = await solvaPay.getCustomer({ customerRef: ensuredCustomerRef });
388
- const filteredSubscriptions = (customer.subscriptions || []).filter(
389
- (sub) => sub.status === "active"
386
+ const filteredPurchases = (customer.purchases || []).filter(
387
+ (p) => p.status === "active"
390
388
  );
391
389
  const result = {
392
390
  customerRef: customer.customerRef || userId,
393
391
  email: customer.email,
394
392
  name: customer.name,
395
- subscriptions: filteredSubscriptions
393
+ purchases: filteredPurchases
396
394
  };
397
395
  return result;
398
396
  } catch (error) {
399
- console.error("[checkSubscription] Error fetching customer:", error);
397
+ console.error("[checkPurchase] Error fetching customer:", error);
400
398
  return {
401
399
  customerRef: userId,
402
- subscriptions: []
400
+ purchases: []
403
401
  };
404
402
  }
405
403
  });
406
404
  return response;
407
405
  } catch (error) {
408
- console.error("Check subscription failed:", error);
406
+ console.error("Check purchase failed:", error);
409
407
  if (error instanceof SolvaPayError) {
410
- return NextResponse8.json(
411
- { error: error.message },
412
- { status: 500 }
413
- );
408
+ return NextResponse8.json({ error: error.message }, { status: 500 });
414
409
  }
415
410
  const errorMessage = error instanceof Error ? error.message : "Unknown error";
416
411
  return NextResponse8.json(
417
- { error: "Failed to check subscription", details: errorMessage },
412
+ { error: "Failed to check purchase", details: errorMessage },
418
413
  { status: 500 }
419
414
  );
420
415
  }
421
416
  }
422
- function clearSubscriptionCache(userId) {
423
- const deduplicator = getSharedDeduplicator();
424
- deduplicator.clearCache(userId);
425
- }
426
- function clearAllSubscriptionCache() {
427
- const deduplicator = getSharedDeduplicator();
428
- deduplicator.clearAllCache();
429
- }
430
- function getSubscriptionCacheStats() {
431
- const deduplicator = getSharedDeduplicator();
432
- return deduplicator.getStats();
433
- }
434
417
  export {
435
- cancelSubscription,
436
- checkSubscription,
437
- clearAllSubscriptionCache,
438
- clearSubscriptionCache,
418
+ cancelRenewal,
419
+ checkPurchase,
420
+ clearAllPurchaseCache,
421
+ clearPurchaseCache,
439
422
  createAuthMiddleware,
440
423
  createCheckoutSession,
441
424
  createCustomerSession,
442
425
  createPaymentIntent,
443
426
  createSupabaseAuthMiddleware,
444
427
  getAuthenticatedUser,
445
- getSubscriptionCacheStats,
428
+ getPurchaseCacheStats,
446
429
  listPlans,
447
- processPayment,
430
+ processPaymentIntent,
448
431
  syncCustomer
449
432
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solvapay/next",
3
- "version": "1.0.0-preview.18",
3
+ "version": "1.0.0-preview.20",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
@@ -29,15 +29,15 @@
29
29
  },
30
30
  "sideEffects": false,
31
31
  "dependencies": {
32
- "@solvapay/auth": "1.0.0-preview.18",
33
- "@solvapay/server": "1.0.0-preview.18",
34
- "@solvapay/core": "1.0.0-preview.18"
32
+ "@solvapay/auth": "1.0.0-preview.20",
33
+ "@solvapay/core": "1.0.0-preview.20",
34
+ "@solvapay/server": "1.0.0-preview.20"
35
35
  },
36
36
  "peerDependencies": {
37
37
  "next": ">=13.0.0"
38
38
  },
39
39
  "devDependencies": {
40
- "next": "^14.0.0",
40
+ "next": "^15.5.7",
41
41
  "tsup": "^8.0.1",
42
42
  "typescript": "^5.5.4",
43
43
  "vitest": "^2.0.5",
@@ -47,6 +47,7 @@
47
47
  "build": "tsup src/index.ts --format esm,cjs --dts --tsconfig tsconfig.build.json --external next",
48
48
  "test": "vitest run || exit 0",
49
49
  "test:watch": "vitest",
50
- "lint": "echo 'no lint yet'"
50
+ "lint": "eslint src",
51
+ "lint:fix": "eslint src --fix"
51
52
  }
52
53
  }