@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/dist/index.cjs CHANGED
@@ -30,47 +30,59 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
- checkSubscription: () => checkSubscription,
34
- clearAllSubscriptionCache: () => clearAllSubscriptionCache,
35
- clearSubscriptionCache: () => clearSubscriptionCache,
36
- getSubscriptionCacheStats: () => getSubscriptionCacheStats
33
+ cancelRenewal: () => cancelRenewal,
34
+ checkPurchase: () => checkPurchase,
35
+ clearAllPurchaseCache: () => clearAllPurchaseCache,
36
+ clearPurchaseCache: () => clearPurchaseCache,
37
+ createAuthMiddleware: () => createAuthMiddleware,
38
+ createCheckoutSession: () => createCheckoutSession,
39
+ createCustomerSession: () => createCustomerSession,
40
+ createPaymentIntent: () => createPaymentIntent,
41
+ createSupabaseAuthMiddleware: () => createSupabaseAuthMiddleware,
42
+ getAuthenticatedUser: () => getAuthenticatedUser,
43
+ getPurchaseCacheStats: () => getPurchaseCacheStats,
44
+ listPlans: () => listPlans,
45
+ processPaymentIntent: () => processPaymentIntent,
46
+ syncCustomer: () => syncCustomer
37
47
  });
38
48
  module.exports = __toCommonJS(index_exports);
39
- var import_server = require("next/server");
40
- var import_server2 = require("@solvapay/server");
49
+ var import_server16 = require("next/server");
50
+ var import_server17 = require("@solvapay/server");
41
51
  var import_core = require("@solvapay/core");
52
+
53
+ // src/cache.ts
42
54
  function createRequestDeduplicator(options = {}) {
43
- const {
44
- cacheTTL = 2e3,
45
- maxCacheSize = 1e3,
46
- cacheErrors = true
47
- } = options;
55
+ const { cacheTTL = 2e3, maxCacheSize = 1e3, cacheErrors = true } = options;
48
56
  const inFlightRequests = /* @__PURE__ */ new Map();
49
57
  const resultCache = /* @__PURE__ */ new Map();
50
58
  const cacheInvalidatedAt = /* @__PURE__ */ new Map();
51
- let cleanupInterval = null;
52
59
  if (cacheTTL > 0) {
53
- cleanupInterval = setInterval(() => {
54
- const now = Date.now();
55
- const entriesToDelete = [];
56
- for (const [key, cached] of resultCache.entries()) {
57
- if (now - cached.timestamp >= cacheTTL) {
58
- entriesToDelete.push(key);
60
+ setInterval(
61
+ () => {
62
+ const now = Date.now();
63
+ const entriesToDelete = [];
64
+ for (const [key, cached] of resultCache.entries()) {
65
+ if (now - cached.timestamp >= cacheTTL) {
66
+ entriesToDelete.push(key);
67
+ }
59
68
  }
60
- }
61
- for (const key of entriesToDelete) {
62
- resultCache.delete(key);
63
- cacheInvalidatedAt.delete(key);
64
- }
65
- if (resultCache.size > maxCacheSize) {
66
- const sortedEntries = Array.from(resultCache.entries()).sort((a, b) => a[1].timestamp - b[1].timestamp);
67
- const toRemove = sortedEntries.slice(0, resultCache.size - maxCacheSize);
68
- for (const [key] of toRemove) {
69
+ for (const key of entriesToDelete) {
69
70
  resultCache.delete(key);
70
71
  cacheInvalidatedAt.delete(key);
71
72
  }
72
- }
73
- }, Math.min(cacheTTL, 1e3));
73
+ if (resultCache.size > maxCacheSize) {
74
+ const sortedEntries = Array.from(resultCache.entries()).sort(
75
+ (a, b) => a[1].timestamp - b[1].timestamp
76
+ );
77
+ const toRemove = sortedEntries.slice(0, resultCache.size - maxCacheSize);
78
+ for (const [key] of toRemove) {
79
+ resultCache.delete(key);
80
+ cacheInvalidatedAt.delete(key);
81
+ }
82
+ }
83
+ },
84
+ Math.min(cacheTTL, 1e3)
85
+ );
74
86
  }
75
87
  const deduplicate = async (key, fn) => {
76
88
  if (cacheTTL > 0) {
@@ -140,10 +152,10 @@ function createRequestDeduplicator(options = {}) {
140
152
  getStats
141
153
  };
142
154
  }
143
- var sharedSubscriptionDeduplicator = null;
155
+ var sharedPurchaseDeduplicator = null;
144
156
  function getSharedDeduplicator(options) {
145
- if (!sharedSubscriptionDeduplicator) {
146
- sharedSubscriptionDeduplicator = createRequestDeduplicator({
157
+ if (!sharedPurchaseDeduplicator) {
158
+ sharedPurchaseDeduplicator = createRequestDeduplicator({
147
159
  cacheTTL: 2e3,
148
160
  // Cache results for 2 seconds
149
161
  maxCacheSize: 1e3,
@@ -153,90 +165,305 @@ function getSharedDeduplicator(options) {
153
165
  ...options
154
166
  });
155
167
  }
156
- return sharedSubscriptionDeduplicator;
168
+ return sharedPurchaseDeduplicator;
169
+ }
170
+ function clearPurchaseCache(userId) {
171
+ const deduplicator = getSharedDeduplicator();
172
+ deduplicator.clearCache(userId);
173
+ }
174
+ function clearAllPurchaseCache() {
175
+ const deduplicator = getSharedDeduplicator();
176
+ deduplicator.clearAllCache();
177
+ }
178
+ function getPurchaseCacheStats() {
179
+ const deduplicator = getSharedDeduplicator();
180
+ return deduplicator.getStats();
181
+ }
182
+
183
+ // src/helpers/auth.ts
184
+ var import_server = require("next/server");
185
+ var import_server2 = require("@solvapay/server");
186
+ async function getAuthenticatedUser(request, options = {}) {
187
+ const result = await (0, import_server2.getAuthenticatedUserCore)(request, options);
188
+ if ((0, import_server2.isErrorResult)(result)) {
189
+ return import_server.NextResponse.json(
190
+ { error: result.error, details: result.details },
191
+ { status: result.status }
192
+ );
193
+ }
194
+ return result;
195
+ }
196
+
197
+ // src/helpers/customer.ts
198
+ var import_server3 = require("next/server");
199
+ var import_server4 = require("@solvapay/server");
200
+ async function syncCustomer(request, options = {}) {
201
+ const result = await (0, import_server4.syncCustomerCore)(request, options);
202
+ if ((0, import_server4.isErrorResult)(result)) {
203
+ return import_server3.NextResponse.json(
204
+ { error: result.error, details: result.details },
205
+ { status: result.status }
206
+ );
207
+ }
208
+ return result;
209
+ }
210
+
211
+ // src/helpers/payment.ts
212
+ var import_server5 = require("next/server");
213
+ var import_server6 = require("@solvapay/server");
214
+ var import_server7 = require("@solvapay/server");
215
+ async function createPaymentIntent(request, body, options = {}) {
216
+ const result = await (0, import_server6.createPaymentIntentCore)(request, body, options);
217
+ if ((0, import_server6.isErrorResult)(result)) {
218
+ return import_server5.NextResponse.json(
219
+ { error: result.error, details: result.details },
220
+ { status: result.status }
221
+ );
222
+ }
223
+ try {
224
+ const userResult = await (0, import_server7.getAuthenticatedUserCore)(request);
225
+ if (!(0, import_server6.isErrorResult)(userResult)) {
226
+ clearPurchaseCache(userResult.userId);
227
+ }
228
+ } catch {
229
+ }
230
+ return result;
231
+ }
232
+ async function processPaymentIntent(request, body, options = {}) {
233
+ const result = await (0, import_server6.processPaymentIntentCore)(request, body, options);
234
+ if ((0, import_server6.isErrorResult)(result)) {
235
+ return import_server5.NextResponse.json(
236
+ { error: result.error, details: result.details },
237
+ { status: result.status }
238
+ );
239
+ }
240
+ try {
241
+ const userResult = await (0, import_server7.getAuthenticatedUserCore)(request);
242
+ if (!(0, import_server6.isErrorResult)(userResult)) {
243
+ clearPurchaseCache(userResult.userId);
244
+ }
245
+ } catch {
246
+ }
247
+ return result;
248
+ }
249
+
250
+ // src/helpers/checkout.ts
251
+ var import_server8 = require("next/server");
252
+ var import_server9 = require("@solvapay/server");
253
+ async function createCheckoutSession(request, body, options = {}) {
254
+ const result = await (0, import_server9.createCheckoutSessionCore)(request, body, options);
255
+ if ((0, import_server9.isErrorResult)(result)) {
256
+ return import_server8.NextResponse.json(
257
+ { error: result.error, details: result.details },
258
+ { status: result.status }
259
+ );
260
+ }
261
+ return result;
262
+ }
263
+ async function createCustomerSession(request, options = {}) {
264
+ const result = await (0, import_server9.createCustomerSessionCore)(request, options);
265
+ if ((0, import_server9.isErrorResult)(result)) {
266
+ return import_server8.NextResponse.json(
267
+ { error: result.error, details: result.details },
268
+ { status: result.status }
269
+ );
270
+ }
271
+ return result;
272
+ }
273
+
274
+ // src/helpers/renewal.ts
275
+ var import_server10 = require("next/server");
276
+ var import_server11 = require("@solvapay/server");
277
+ var import_server12 = require("@solvapay/server");
278
+ async function cancelRenewal(request, body, options = {}) {
279
+ const result = await (0, import_server11.cancelPurchaseCore)(request, body, options);
280
+ if ((0, import_server11.isErrorResult)(result)) {
281
+ return import_server10.NextResponse.json(
282
+ { error: result.error, details: result.details },
283
+ { status: result.status }
284
+ );
285
+ }
286
+ try {
287
+ const userResult = await (0, import_server12.getAuthenticatedUserCore)(request);
288
+ if (!(0, import_server11.isErrorResult)(userResult)) {
289
+ clearPurchaseCache(userResult.userId);
290
+ }
291
+ } catch {
292
+ }
293
+ return result;
294
+ }
295
+
296
+ // src/helpers/plans.ts
297
+ var import_server13 = require("next/server");
298
+ var import_server14 = require("@solvapay/server");
299
+ async function listPlans(request) {
300
+ const result = await (0, import_server14.listPlansCore)(request);
301
+ if ((0, import_server14.isErrorResult)(result)) {
302
+ return import_server13.NextResponse.json(
303
+ { error: result.error, details: result.details },
304
+ { status: result.status }
305
+ );
306
+ }
307
+ return result;
308
+ }
309
+
310
+ // src/helpers/middleware.ts
311
+ var import_server15 = require("next/server");
312
+ function createAuthMiddleware(options) {
313
+ const { adapter, publicRoutes = [], userIdHeader = "x-user-id" } = options;
314
+ return async function middleware(request) {
315
+ const req = request;
316
+ const { pathname } = req.nextUrl;
317
+ if (!pathname.startsWith("/api")) {
318
+ return import_server15.NextResponse.next();
319
+ }
320
+ const isPublicRoute = publicRoutes.some((route) => pathname.startsWith(route));
321
+ const userId = await adapter.getUserIdFromRequest(req);
322
+ if (isPublicRoute) {
323
+ const requestHeaders2 = new Headers(req.headers);
324
+ if (userId) {
325
+ requestHeaders2.set(userIdHeader, userId);
326
+ }
327
+ return import_server15.NextResponse.next({
328
+ request: {
329
+ headers: requestHeaders2
330
+ }
331
+ });
332
+ }
333
+ if (!userId) {
334
+ return import_server15.NextResponse.json(
335
+ { error: "Unauthorized", details: "Valid authentication required" },
336
+ { status: 401 }
337
+ );
338
+ }
339
+ const requestHeaders = new Headers(req.headers);
340
+ requestHeaders.set(userIdHeader, userId);
341
+ return import_server15.NextResponse.next({
342
+ request: {
343
+ headers: requestHeaders
344
+ }
345
+ });
346
+ };
347
+ }
348
+ function createSupabaseAuthMiddleware(options = {}) {
349
+ const { jwtSecret, publicRoutes = [], userIdHeader = "x-user-id" } = options;
350
+ let authAdapter = null;
351
+ let adapterPromise = null;
352
+ const lazyAdapter = {
353
+ async getUserIdFromRequest(req) {
354
+ if (!authAdapter) {
355
+ if (!adapterPromise) {
356
+ adapterPromise = (async () => {
357
+ const secret = jwtSecret || process.env.SUPABASE_JWT_SECRET;
358
+ if (!secret) {
359
+ throw new Error(
360
+ "SUPABASE_JWT_SECRET environment variable is required. Please set it in your .env.local file. Get it from: Supabase Dashboard \u2192 Settings \u2192 API \u2192 JWT Secret"
361
+ );
362
+ }
363
+ const { SupabaseAuthAdapter } = await import("@solvapay/auth/supabase");
364
+ authAdapter = new SupabaseAuthAdapter({ jwtSecret: secret });
365
+ return authAdapter;
366
+ })();
367
+ }
368
+ authAdapter = await adapterPromise;
369
+ }
370
+ return authAdapter.getUserIdFromRequest(req);
371
+ }
372
+ };
373
+ return createAuthMiddleware({
374
+ adapter: lazyAdapter,
375
+ publicRoutes,
376
+ userIdHeader
377
+ });
157
378
  }
158
- async function checkSubscription(request, options = {}) {
379
+
380
+ // src/index.ts
381
+ async function checkPurchase(request, options = {}) {
159
382
  try {
160
383
  const { requireUserId, getUserEmailFromRequest, getUserNameFromRequest } = await import("@solvapay/auth");
161
384
  const userIdOrError = requireUserId(request);
162
385
  if (userIdOrError instanceof Response) {
163
386
  const clonedResponse = userIdOrError.clone();
164
387
  const body = await clonedResponse.json().catch(() => ({ error: "Unauthorized" }));
165
- return import_server.NextResponse.json(body, { status: userIdOrError.status });
388
+ return import_server16.NextResponse.json(body, { status: userIdOrError.status });
166
389
  }
167
390
  const userId = userIdOrError;
168
391
  const email = options.includeEmail !== false ? await getUserEmailFromRequest(request) : null;
169
392
  const name = options.includeName !== false ? await getUserNameFromRequest(request) : null;
393
+ const cachedCustomerRef = request.headers.get("x-solvapay-customer-ref");
394
+ const solvaPay = options.solvaPay || (0, import_server17.createSolvaPay)();
395
+ if (cachedCustomerRef) {
396
+ try {
397
+ const customer = await solvaPay.getCustomer({ customerRef: cachedCustomerRef });
398
+ if (customer && customer.customerRef) {
399
+ if (customer.externalRef && customer.externalRef === userId) {
400
+ const filteredPurchases = (customer.purchases || []).filter(
401
+ (p) => p.status === "active"
402
+ );
403
+ return {
404
+ customerRef: customer.customerRef,
405
+ email: customer.email,
406
+ name: customer.name,
407
+ purchases: filteredPurchases
408
+ };
409
+ }
410
+ }
411
+ } catch {
412
+ }
413
+ }
170
414
  const deduplicator = getSharedDeduplicator(options.deduplication);
171
415
  const response = await deduplicator.deduplicate(userId, async () => {
172
416
  try {
173
- const solvaPay = options.solvaPay || (0, import_server2.createSolvaPay)();
174
417
  const ensuredCustomerRef = await solvaPay.ensureCustomer(userId, userId, {
175
418
  email: email || void 0,
176
419
  name: name || void 0
177
420
  });
178
421
  const customer = await solvaPay.getCustomer({ customerRef: ensuredCustomerRef });
179
- const now = /* @__PURE__ */ new Date();
180
- const filteredSubscriptions = (customer.subscriptions || []).filter((sub) => {
181
- const subAny = sub;
182
- const isCancelled = sub.status === "cancelled" || subAny.cancelledAt;
183
- if (!isCancelled) {
184
- return true;
185
- }
186
- if (isCancelled && subAny.endDate) {
187
- const endDate = new Date(subAny.endDate);
188
- const isFuture = endDate > now;
189
- return isFuture;
190
- }
191
- return false;
192
- });
422
+ const filteredPurchases = (customer.purchases || []).filter(
423
+ (p) => p.status === "active"
424
+ );
193
425
  const result = {
194
426
  customerRef: customer.customerRef || userId,
195
427
  email: customer.email,
196
428
  name: customer.name,
197
- subscriptions: filteredSubscriptions
429
+ purchases: filteredPurchases
198
430
  };
199
431
  return result;
200
432
  } catch (error) {
201
- console.error("[checkSubscription] Error fetching customer:", error);
433
+ console.error("[checkPurchase] Error fetching customer:", error);
202
434
  return {
203
435
  customerRef: userId,
204
- subscriptions: []
436
+ purchases: []
205
437
  };
206
438
  }
207
439
  });
208
440
  return response;
209
441
  } catch (error) {
210
- console.error("Check subscription failed:", error);
442
+ console.error("Check purchase failed:", error);
211
443
  if (error instanceof import_core.SolvaPayError) {
212
- return import_server.NextResponse.json(
213
- { error: error.message },
214
- { status: 500 }
215
- );
444
+ return import_server16.NextResponse.json({ error: error.message }, { status: 500 });
216
445
  }
217
446
  const errorMessage = error instanceof Error ? error.message : "Unknown error";
218
- return import_server.NextResponse.json(
219
- { error: "Failed to check subscription", details: errorMessage },
447
+ return import_server16.NextResponse.json(
448
+ { error: "Failed to check purchase", details: errorMessage },
220
449
  { status: 500 }
221
450
  );
222
451
  }
223
452
  }
224
- function clearSubscriptionCache(userId) {
225
- const deduplicator = getSharedDeduplicator();
226
- deduplicator.clearCache(userId);
227
- }
228
- function clearAllSubscriptionCache() {
229
- const deduplicator = getSharedDeduplicator();
230
- deduplicator.clearAllCache();
231
- }
232
- function getSubscriptionCacheStats() {
233
- const deduplicator = getSharedDeduplicator();
234
- return deduplicator.getStats();
235
- }
236
453
  // Annotate the CommonJS export names for ESM import in node:
237
454
  0 && (module.exports = {
238
- checkSubscription,
239
- clearAllSubscriptionCache,
240
- clearSubscriptionCache,
241
- getSubscriptionCacheStats
455
+ cancelRenewal,
456
+ checkPurchase,
457
+ clearAllPurchaseCache,
458
+ clearPurchaseCache,
459
+ createAuthMiddleware,
460
+ createCheckoutSession,
461
+ createCustomerSession,
462
+ createPaymentIntent,
463
+ createSupabaseAuthMiddleware,
464
+ getAuthenticatedUser,
465
+ getPurchaseCacheStats,
466
+ listPlans,
467
+ processPaymentIntent,
468
+ syncCustomer
242
469
  });