@solvapay/next 1.0.6 → 1.0.9-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,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ activatePlan: () => activatePlan,
33
34
  cancelRenewal: () => cancelRenewal,
34
35
  checkPurchase: () => checkPurchase,
35
36
  clearAllPurchaseCache: () => clearAllPurchaseCache,
@@ -39,16 +40,19 @@ __export(index_exports, {
39
40
  createCustomerSession: () => createCustomerSession,
40
41
  createPaymentIntent: () => createPaymentIntent,
41
42
  createSupabaseAuthMiddleware: () => createSupabaseAuthMiddleware,
43
+ createTopupPaymentIntent: () => createTopupPaymentIntent,
42
44
  getAuthenticatedUser: () => getAuthenticatedUser,
45
+ getCustomerBalance: () => getCustomerBalance,
43
46
  getPurchaseCacheStats: () => getPurchaseCacheStats,
44
47
  listPlans: () => listPlans,
45
48
  processPaymentIntent: () => processPaymentIntent,
46
- syncCustomer: () => syncCustomer
49
+ reactivateRenewal: () => reactivateRenewal,
50
+ syncCustomer: () => syncCustomer,
51
+ trackUsage: () => trackUsage
47
52
  });
48
53
  module.exports = __toCommonJS(index_exports);
49
- var import_server16 = require("next/server");
50
- var import_server17 = require("@solvapay/server");
51
- var import_core = require("@solvapay/core");
54
+ var import_server20 = require("next/server");
55
+ var import_server21 = require("@solvapay/server");
52
56
 
53
57
  // src/cache.ts
54
58
  function createRequestDeduplicator(options = {}) {
@@ -207,6 +211,16 @@ async function syncCustomer(request, options = {}) {
207
211
  }
208
212
  return result;
209
213
  }
214
+ async function getCustomerBalance(request, options = {}) {
215
+ const result = await (0, import_server4.getCustomerBalanceCore)(request, options);
216
+ if ((0, import_server4.isErrorResult)(result)) {
217
+ return import_server3.NextResponse.json(
218
+ { error: result.error, details: result.details },
219
+ { status: result.status }
220
+ );
221
+ }
222
+ return result;
223
+ }
210
224
 
211
225
  // src/helpers/payment.ts
212
226
  var import_server5 = require("next/server");
@@ -229,6 +243,23 @@ async function createPaymentIntent(request, body, options = {}) {
229
243
  }
230
244
  return result;
231
245
  }
246
+ async function createTopupPaymentIntent(request, body, options = {}) {
247
+ const result = await (0, import_server6.createTopupPaymentIntentCore)(request, body, options);
248
+ if ((0, import_server6.isErrorResult)(result)) {
249
+ return import_server5.NextResponse.json(
250
+ { error: result.error, details: result.details },
251
+ { status: result.status }
252
+ );
253
+ }
254
+ try {
255
+ const userResult = await (0, import_server7.getAuthenticatedUserCore)(request);
256
+ if (!(0, import_server6.isErrorResult)(userResult)) {
257
+ clearPurchaseCache(userResult.userId);
258
+ }
259
+ } catch {
260
+ }
261
+ return result;
262
+ }
232
263
  async function processPaymentIntent(request, body, options = {}) {
233
264
  const result = await (0, import_server6.processPaymentIntentCore)(request, body, options);
234
265
  if ((0, import_server6.isErrorResult)(result)) {
@@ -271,12 +302,12 @@ async function createCustomerSession(request, options = {}) {
271
302
  return result;
272
303
  }
273
304
 
274
- // src/helpers/renewal.ts
305
+ // src/helpers/activation.ts
275
306
  var import_server10 = require("next/server");
276
307
  var import_server11 = require("@solvapay/server");
277
308
  var import_server12 = require("@solvapay/server");
278
- async function cancelRenewal(request, body, options = {}) {
279
- const result = await (0, import_server11.cancelPurchaseCore)(request, body, options);
309
+ async function activatePlan(request, body, options = {}) {
310
+ const result = await (0, import_server11.activatePlanCore)(request, body, options);
280
311
  if ((0, import_server11.isErrorResult)(result)) {
281
312
  return import_server10.NextResponse.json(
282
313
  { error: result.error, details: result.details },
@@ -293,29 +324,81 @@ async function cancelRenewal(request, body, options = {}) {
293
324
  return result;
294
325
  }
295
326
 
296
- // src/helpers/plans.ts
327
+ // src/helpers/renewal.ts
297
328
  var import_server13 = require("next/server");
298
329
  var import_server14 = require("@solvapay/server");
299
- async function listPlans(request) {
300
- const result = await (0, import_server14.listPlansCore)(request);
330
+ async function cancelRenewal(request, body, options = {}) {
331
+ const result = await (0, import_server14.cancelPurchaseCore)(request, body, options);
301
332
  if ((0, import_server14.isErrorResult)(result)) {
302
333
  return import_server13.NextResponse.json(
303
334
  { error: result.error, details: result.details },
304
335
  { status: result.status }
305
336
  );
306
337
  }
338
+ try {
339
+ const userResult = await (0, import_server14.getAuthenticatedUserCore)(request);
340
+ if (!(0, import_server14.isErrorResult)(userResult)) {
341
+ clearPurchaseCache(userResult.userId);
342
+ }
343
+ } catch {
344
+ }
345
+ return result;
346
+ }
347
+ async function reactivateRenewal(request, body, options = {}) {
348
+ const result = await (0, import_server14.reactivatePurchaseCore)(request, body, options);
349
+ if ((0, import_server14.isErrorResult)(result)) {
350
+ return import_server13.NextResponse.json(
351
+ { error: result.error, details: result.details },
352
+ { status: result.status }
353
+ );
354
+ }
355
+ try {
356
+ const userResult = await (0, import_server14.getAuthenticatedUserCore)(request);
357
+ if (!(0, import_server14.isErrorResult)(userResult)) {
358
+ clearPurchaseCache(userResult.userId);
359
+ }
360
+ } catch {
361
+ }
307
362
  return result;
308
363
  }
309
364
 
310
- // src/helpers/middleware.ts
365
+ // src/helpers/plans.ts
311
366
  var import_server15 = require("next/server");
367
+ var import_server16 = require("@solvapay/server");
368
+ async function listPlans(request) {
369
+ const result = await (0, import_server16.listPlansCore)(request);
370
+ if ((0, import_server16.isErrorResult)(result)) {
371
+ return import_server15.NextResponse.json(
372
+ { error: result.error, details: result.details },
373
+ { status: result.status }
374
+ );
375
+ }
376
+ return result;
377
+ }
378
+
379
+ // src/helpers/usage.ts
380
+ var import_server17 = require("next/server");
381
+ var import_server18 = require("@solvapay/server");
382
+ async function trackUsage(request, body, options = {}) {
383
+ const result = await (0, import_server18.trackUsageCore)(request, body, options);
384
+ if ((0, import_server18.isErrorResult)(result)) {
385
+ return import_server17.NextResponse.json(
386
+ { error: result.error, details: result.details },
387
+ { status: result.status }
388
+ );
389
+ }
390
+ return import_server17.NextResponse.json(result);
391
+ }
392
+
393
+ // src/helpers/middleware.ts
394
+ var import_server19 = require("next/server");
312
395
  function createAuthMiddleware(options) {
313
396
  const { adapter, publicRoutes = [], userIdHeader = "x-user-id" } = options;
314
397
  return async function middleware(request) {
315
398
  const req = request;
316
399
  const { pathname } = req.nextUrl;
317
400
  if (!pathname.startsWith("/api")) {
318
- return import_server15.NextResponse.next();
401
+ return import_server19.NextResponse.next();
319
402
  }
320
403
  const isPublicRoute = publicRoutes.some((route) => pathname.startsWith(route));
321
404
  const userId = await adapter.getUserIdFromRequest(req);
@@ -324,21 +407,21 @@ function createAuthMiddleware(options) {
324
407
  if (userId) {
325
408
  requestHeaders2.set(userIdHeader, userId);
326
409
  }
327
- return import_server15.NextResponse.next({
410
+ return import_server19.NextResponse.next({
328
411
  request: {
329
412
  headers: requestHeaders2
330
413
  }
331
414
  });
332
415
  }
333
416
  if (!userId) {
334
- return import_server15.NextResponse.json(
417
+ return import_server19.NextResponse.json(
335
418
  { error: "Unauthorized", details: "Valid authentication required" },
336
419
  { status: 401 }
337
420
  );
338
421
  }
339
422
  const requestHeaders = new Headers(req.headers);
340
423
  requestHeaders.set(userIdHeader, userId);
341
- return import_server15.NextResponse.next({
424
+ return import_server19.NextResponse.next({
342
425
  request: {
343
426
  headers: requestHeaders
344
427
  }
@@ -379,72 +462,37 @@ function createSupabaseAuthMiddleware(options = {}) {
379
462
 
380
463
  // src/index.ts
381
464
  async function checkPurchase(request, options = {}) {
465
+ const deduplicator = getSharedDeduplicator(options.deduplication);
382
466
  try {
383
- const { requireUserId, getUserEmailFromRequest, getUserNameFromRequest } = await import("@solvapay/auth");
467
+ const { requireUserId } = await import("@solvapay/auth");
384
468
  const userIdOrError = requireUserId(request);
385
469
  if (userIdOrError instanceof Response) {
386
470
  const clonedResponse = userIdOrError.clone();
387
471
  const body = await clonedResponse.json().catch(() => ({ error: "Unauthorized" }));
388
- return import_server16.NextResponse.json(body, { status: userIdOrError.status });
472
+ return import_server20.NextResponse.json(body, { status: userIdOrError.status });
389
473
  }
390
474
  const userId = userIdOrError;
391
- const email = options.includeEmail !== false ? await getUserEmailFromRequest(request) : null;
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
- }
414
- const deduplicator = getSharedDeduplicator(options.deduplication);
415
- const response = await deduplicator.deduplicate(userId, async () => {
416
- try {
417
- const ensuredCustomerRef = await solvaPay.ensureCustomer(userId, userId, {
418
- email: email || void 0,
419
- name: name || void 0
475
+ const response = await deduplicator.deduplicate(
476
+ userId,
477
+ async () => {
478
+ return await (0, import_server21.checkPurchaseCore)(request, {
479
+ solvaPay: options.solvaPay,
480
+ includeEmail: options.includeEmail,
481
+ includeName: options.includeName
420
482
  });
421
- const customer = await solvaPay.getCustomer({ customerRef: ensuredCustomerRef });
422
- const filteredPurchases = (customer.purchases || []).filter(
423
- (p) => p.status === "active"
424
- );
425
- const result = {
426
- customerRef: customer.customerRef || userId,
427
- email: customer.email,
428
- name: customer.name,
429
- purchases: filteredPurchases
430
- };
431
- return result;
432
- } catch (error) {
433
- console.error("[checkPurchase] Error fetching customer:", error);
434
- return {
435
- customerRef: userId,
436
- purchases: []
437
- };
438
483
  }
439
- });
484
+ );
485
+ if ((0, import_server21.isErrorResult)(response)) {
486
+ return import_server20.NextResponse.json(
487
+ { error: response.error, details: response.details },
488
+ { status: response.status }
489
+ );
490
+ }
440
491
  return response;
441
492
  } catch (error) {
442
493
  console.error("Check purchase failed:", error);
443
- if (error instanceof import_core.SolvaPayError) {
444
- return import_server16.NextResponse.json({ error: error.message }, { status: 500 });
445
- }
446
494
  const errorMessage = error instanceof Error ? error.message : "Unknown error";
447
- return import_server16.NextResponse.json(
495
+ return import_server20.NextResponse.json(
448
496
  { error: "Failed to check purchase", details: errorMessage },
449
497
  { status: 500 }
450
498
  );
@@ -452,6 +500,7 @@ async function checkPurchase(request, options = {}) {
452
500
  }
453
501
  // Annotate the CommonJS export names for ESM import in node:
454
502
  0 && (module.exports = {
503
+ activatePlan,
455
504
  cancelRenewal,
456
505
  checkPurchase,
457
506
  clearAllPurchaseCache,
@@ -461,9 +510,13 @@ async function checkPurchase(request, options = {}) {
461
510
  createCustomerSession,
462
511
  createPaymentIntent,
463
512
  createSupabaseAuthMiddleware,
513
+ createTopupPaymentIntent,
464
514
  getAuthenticatedUser,
515
+ getCustomerBalance,
465
516
  getPurchaseCacheStats,
466
517
  listPlans,
467
518
  processPaymentIntent,
468
- syncCustomer
519
+ reactivateRenewal,
520
+ syncCustomer,
521
+ trackUsage
469
522
  });
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { NextResponse } from 'next/server';
2
2
  import * as _solvapay_server from '@solvapay/server';
3
- import { AuthenticatedUser, SolvaPay } from '@solvapay/server';
3
+ import { AuthenticatedUser, SolvaPay, CustomerBalanceResult, ActivatePlanResult, listPlansCore } from '@solvapay/server';
4
4
  export { AuthMiddlewareOptions, SupabaseAuthMiddlewareOptions, createAuthMiddleware, createSupabaseAuthMiddleware } from './middleware.cjs';
5
5
  import '@solvapay/auth';
6
6
 
@@ -40,7 +40,7 @@ interface PurchaseCheckResult {
40
40
  purchases: Array<{
41
41
  reference: string;
42
42
  productName?: string;
43
- productReference?: string;
43
+ productRef?: string;
44
44
  status?: string;
45
45
  startDate?: string;
46
46
  planSnapshot?: {
@@ -200,6 +200,16 @@ declare function syncCustomer(request: globalThis.Request, options?: {
200
200
  includeEmail?: boolean;
201
201
  includeName?: boolean;
202
202
  }): Promise<string | NextResponse>;
203
+ /**
204
+ * Get customer credits - Next.js wrapper
205
+ *
206
+ * @param request - Next.js request object
207
+ * @param options - Configuration options
208
+ * @returns Customer credits result or NextResponse error
209
+ */
210
+ declare function getCustomerBalance(request: globalThis.Request, options?: {
211
+ solvaPay?: SolvaPay;
212
+ }): Promise<CustomerBalanceResult | NextResponse>;
203
213
 
204
214
  declare function createPaymentIntent(request: globalThis.Request, body: {
205
215
  planRef: string;
@@ -209,7 +219,22 @@ declare function createPaymentIntent(request: globalThis.Request, body: {
209
219
  includeEmail?: boolean;
210
220
  includeName?: boolean;
211
221
  }): Promise<{
212
- id: string;
222
+ processorPaymentId: string;
223
+ clientSecret: string;
224
+ publishableKey: string;
225
+ accountId?: string;
226
+ customerRef: string;
227
+ } | NextResponse>;
228
+ declare function createTopupPaymentIntent(request: globalThis.Request, body: {
229
+ amount: number;
230
+ currency: string;
231
+ description?: string;
232
+ }, options?: {
233
+ solvaPay?: SolvaPay;
234
+ includeEmail?: boolean;
235
+ includeName?: boolean;
236
+ }): Promise<{
237
+ processorPaymentId: string;
213
238
  clientSecret: string;
214
239
  publishableKey: string;
215
240
  accountId?: string;
@@ -249,8 +274,17 @@ declare function createCustomerSession(request: globalThis.Request, options?: {
249
274
  customerUrl: string;
250
275
  } | NextResponse>;
251
276
 
277
+ declare function activatePlan(request: globalThis.Request, body: {
278
+ productRef: string;
279
+ planRef: string;
280
+ }, options?: {
281
+ solvaPay?: SolvaPay;
282
+ includeEmail?: boolean;
283
+ includeName?: boolean;
284
+ }): Promise<ActivatePlanResult | NextResponse>;
285
+
252
286
  /**
253
- * Next.js Purchase Cancellation Helpers
287
+ * Next.js Purchase Cancellation & Reactivation Helpers
254
288
  */
255
289
  /**
256
290
  * Cancel purchase - Next.js wrapper
@@ -266,14 +300,39 @@ declare function cancelRenewal(request: globalThis.Request, body: {
266
300
  }, options?: {
267
301
  solvaPay?: SolvaPay;
268
302
  }): Promise<Record<string, unknown> | NextResponse>;
303
+ /**
304
+ * Reactivate purchase - Next.js wrapper
305
+ *
306
+ * Undoes a pending cancellation, restoring auto-renewal.
307
+ *
308
+ * @param request - Next.js request object
309
+ * @param body - Reactivation parameters
310
+ * @param options - Configuration options
311
+ * @returns Reactivated purchase response or NextResponse error
312
+ */
313
+ declare function reactivateRenewal(request: globalThis.Request, body: {
314
+ purchaseRef: string;
315
+ }, options?: {
316
+ solvaPay?: SolvaPay;
317
+ }): Promise<Record<string, unknown> | NextResponse>;
269
318
 
319
+ type ListPlansSuccess = Exclude<Awaited<ReturnType<typeof listPlansCore>>, {
320
+ error: string;
321
+ }>;
270
322
  /**
271
323
  * Next.js Plans Helper
272
324
  */
273
- declare function listPlans(request: globalThis.Request): Promise<{
274
- plans: Array<Record<string, unknown>>;
275
- productRef: string;
276
- } | NextResponse>;
325
+ declare function listPlans(request: globalThis.Request): Promise<ListPlansSuccess | NextResponse>;
326
+
327
+ declare function trackUsage(request: globalThis.Request, body: {
328
+ actionType?: 'transaction' | 'api_call' | 'hour' | 'email' | 'storage' | 'custom';
329
+ units?: number;
330
+ productRef?: string;
331
+ description?: string;
332
+ metadata?: Record<string, unknown>;
333
+ }, options?: {
334
+ solvaPay?: SolvaPay;
335
+ }): Promise<NextResponse>;
277
336
 
278
337
  /**
279
338
  * SolvaPay Next.js SDK
@@ -321,41 +380,9 @@ interface CheckPurchaseOptions {
321
380
  * - Fast path optimization using cached customer references from client
322
381
  * - Automatic customer creation if needed
323
382
  *
324
- * The function:
325
- * 1. Extracts user ID from request (via requireUserId from @solvapay/auth)
326
- * 2. Gets user email and name from Supabase JWT token (if available)
327
- * 3. Validates cached customer reference (if provided via header)
328
- * 4. Ensures customer exists in SolvaPay backend
329
- * 5. Returns customer purchase information
330
- *
331
- * @param request - Next.js request object (NextRequest extends Request)
332
- * @param options - Configuration options
333
- * @param options.deduplication - Request deduplication options (see {@link RequestDeduplicationOptions})
334
- * @param options.solvaPay - Optional SolvaPay instance (creates new one if not provided)
335
- * @param options.includeEmail - Whether to include email in response (default: true)
336
- * @param options.includeName - Whether to include name in response (default: true)
337
- * @returns Purchase check result with customer data and purchases, or NextResponse error
338
- *
339
- * @example
340
- * ```typescript
341
- * import { NextRequest, NextResponse } from 'next/server';
342
- * import { checkPurchase } from '@solvapay/next';
343
- *
344
- * export async function GET(request: NextRequest) {
345
- * const result = await checkPurchase(request);
346
- *
347
- * if (result instanceof NextResponse) {
348
- * return result; // Error response
349
- * }
350
- *
351
- * return NextResponse.json(result);
352
- * }
353
- * ```
354
- *
355
- * @see {@link clearPurchaseCache} for cache management
356
- * @see {@link getPurchaseCacheStats} for cache monitoring
357
- * @since 1.0.0
383
+ * Delegates to `checkPurchaseCore` from `@solvapay/server` for the actual logic,
384
+ * wrapping with Next.js-specific deduplication and response formatting.
358
385
  */
359
386
  declare function checkPurchase(request: Request, options?: CheckPurchaseOptions): Promise<PurchaseCheckResult | NextResponse>;
360
387
 
361
- export { type CheckPurchaseOptions, type PurchaseCheckResult, type RequestDeduplicationOptions, cancelRenewal, checkPurchase, clearAllPurchaseCache, clearPurchaseCache, createCheckoutSession, createCustomerSession, createPaymentIntent, getAuthenticatedUser, getPurchaseCacheStats, listPlans, processPaymentIntent, syncCustomer };
388
+ export { type CheckPurchaseOptions, type PurchaseCheckResult, type RequestDeduplicationOptions, activatePlan, cancelRenewal, checkPurchase, clearAllPurchaseCache, clearPurchaseCache, createCheckoutSession, createCustomerSession, createPaymentIntent, createTopupPaymentIntent, getAuthenticatedUser, getCustomerBalance, getPurchaseCacheStats, listPlans, processPaymentIntent, reactivateRenewal, syncCustomer, trackUsage };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { NextResponse } from 'next/server';
2
2
  import * as _solvapay_server from '@solvapay/server';
3
- import { AuthenticatedUser, SolvaPay } from '@solvapay/server';
3
+ import { AuthenticatedUser, SolvaPay, CustomerBalanceResult, ActivatePlanResult, listPlansCore } from '@solvapay/server';
4
4
  export { AuthMiddlewareOptions, SupabaseAuthMiddlewareOptions, createAuthMiddleware, createSupabaseAuthMiddleware } from './middleware.js';
5
5
  import '@solvapay/auth';
6
6
 
@@ -40,7 +40,7 @@ interface PurchaseCheckResult {
40
40
  purchases: Array<{
41
41
  reference: string;
42
42
  productName?: string;
43
- productReference?: string;
43
+ productRef?: string;
44
44
  status?: string;
45
45
  startDate?: string;
46
46
  planSnapshot?: {
@@ -200,6 +200,16 @@ declare function syncCustomer(request: globalThis.Request, options?: {
200
200
  includeEmail?: boolean;
201
201
  includeName?: boolean;
202
202
  }): Promise<string | NextResponse>;
203
+ /**
204
+ * Get customer credits - Next.js wrapper
205
+ *
206
+ * @param request - Next.js request object
207
+ * @param options - Configuration options
208
+ * @returns Customer credits result or NextResponse error
209
+ */
210
+ declare function getCustomerBalance(request: globalThis.Request, options?: {
211
+ solvaPay?: SolvaPay;
212
+ }): Promise<CustomerBalanceResult | NextResponse>;
203
213
 
204
214
  declare function createPaymentIntent(request: globalThis.Request, body: {
205
215
  planRef: string;
@@ -209,7 +219,22 @@ declare function createPaymentIntent(request: globalThis.Request, body: {
209
219
  includeEmail?: boolean;
210
220
  includeName?: boolean;
211
221
  }): Promise<{
212
- id: string;
222
+ processorPaymentId: string;
223
+ clientSecret: string;
224
+ publishableKey: string;
225
+ accountId?: string;
226
+ customerRef: string;
227
+ } | NextResponse>;
228
+ declare function createTopupPaymentIntent(request: globalThis.Request, body: {
229
+ amount: number;
230
+ currency: string;
231
+ description?: string;
232
+ }, options?: {
233
+ solvaPay?: SolvaPay;
234
+ includeEmail?: boolean;
235
+ includeName?: boolean;
236
+ }): Promise<{
237
+ processorPaymentId: string;
213
238
  clientSecret: string;
214
239
  publishableKey: string;
215
240
  accountId?: string;
@@ -249,8 +274,17 @@ declare function createCustomerSession(request: globalThis.Request, options?: {
249
274
  customerUrl: string;
250
275
  } | NextResponse>;
251
276
 
277
+ declare function activatePlan(request: globalThis.Request, body: {
278
+ productRef: string;
279
+ planRef: string;
280
+ }, options?: {
281
+ solvaPay?: SolvaPay;
282
+ includeEmail?: boolean;
283
+ includeName?: boolean;
284
+ }): Promise<ActivatePlanResult | NextResponse>;
285
+
252
286
  /**
253
- * Next.js Purchase Cancellation Helpers
287
+ * Next.js Purchase Cancellation & Reactivation Helpers
254
288
  */
255
289
  /**
256
290
  * Cancel purchase - Next.js wrapper
@@ -266,14 +300,39 @@ declare function cancelRenewal(request: globalThis.Request, body: {
266
300
  }, options?: {
267
301
  solvaPay?: SolvaPay;
268
302
  }): Promise<Record<string, unknown> | NextResponse>;
303
+ /**
304
+ * Reactivate purchase - Next.js wrapper
305
+ *
306
+ * Undoes a pending cancellation, restoring auto-renewal.
307
+ *
308
+ * @param request - Next.js request object
309
+ * @param body - Reactivation parameters
310
+ * @param options - Configuration options
311
+ * @returns Reactivated purchase response or NextResponse error
312
+ */
313
+ declare function reactivateRenewal(request: globalThis.Request, body: {
314
+ purchaseRef: string;
315
+ }, options?: {
316
+ solvaPay?: SolvaPay;
317
+ }): Promise<Record<string, unknown> | NextResponse>;
269
318
 
319
+ type ListPlansSuccess = Exclude<Awaited<ReturnType<typeof listPlansCore>>, {
320
+ error: string;
321
+ }>;
270
322
  /**
271
323
  * Next.js Plans Helper
272
324
  */
273
- declare function listPlans(request: globalThis.Request): Promise<{
274
- plans: Array<Record<string, unknown>>;
275
- productRef: string;
276
- } | NextResponse>;
325
+ declare function listPlans(request: globalThis.Request): Promise<ListPlansSuccess | NextResponse>;
326
+
327
+ declare function trackUsage(request: globalThis.Request, body: {
328
+ actionType?: 'transaction' | 'api_call' | 'hour' | 'email' | 'storage' | 'custom';
329
+ units?: number;
330
+ productRef?: string;
331
+ description?: string;
332
+ metadata?: Record<string, unknown>;
333
+ }, options?: {
334
+ solvaPay?: SolvaPay;
335
+ }): Promise<NextResponse>;
277
336
 
278
337
  /**
279
338
  * SolvaPay Next.js SDK
@@ -321,41 +380,9 @@ interface CheckPurchaseOptions {
321
380
  * - Fast path optimization using cached customer references from client
322
381
  * - Automatic customer creation if needed
323
382
  *
324
- * The function:
325
- * 1. Extracts user ID from request (via requireUserId from @solvapay/auth)
326
- * 2. Gets user email and name from Supabase JWT token (if available)
327
- * 3. Validates cached customer reference (if provided via header)
328
- * 4. Ensures customer exists in SolvaPay backend
329
- * 5. Returns customer purchase information
330
- *
331
- * @param request - Next.js request object (NextRequest extends Request)
332
- * @param options - Configuration options
333
- * @param options.deduplication - Request deduplication options (see {@link RequestDeduplicationOptions})
334
- * @param options.solvaPay - Optional SolvaPay instance (creates new one if not provided)
335
- * @param options.includeEmail - Whether to include email in response (default: true)
336
- * @param options.includeName - Whether to include name in response (default: true)
337
- * @returns Purchase check result with customer data and purchases, or NextResponse error
338
- *
339
- * @example
340
- * ```typescript
341
- * import { NextRequest, NextResponse } from 'next/server';
342
- * import { checkPurchase } from '@solvapay/next';
343
- *
344
- * export async function GET(request: NextRequest) {
345
- * const result = await checkPurchase(request);
346
- *
347
- * if (result instanceof NextResponse) {
348
- * return result; // Error response
349
- * }
350
- *
351
- * return NextResponse.json(result);
352
- * }
353
- * ```
354
- *
355
- * @see {@link clearPurchaseCache} for cache management
356
- * @see {@link getPurchaseCacheStats} for cache monitoring
357
- * @since 1.0.0
383
+ * Delegates to `checkPurchaseCore` from `@solvapay/server` for the actual logic,
384
+ * wrapping with Next.js-specific deduplication and response formatting.
358
385
  */
359
386
  declare function checkPurchase(request: Request, options?: CheckPurchaseOptions): Promise<PurchaseCheckResult | NextResponse>;
360
387
 
361
- export { type CheckPurchaseOptions, type PurchaseCheckResult, type RequestDeduplicationOptions, cancelRenewal, checkPurchase, clearAllPurchaseCache, clearPurchaseCache, createCheckoutSession, createCustomerSession, createPaymentIntent, getAuthenticatedUser, getPurchaseCacheStats, listPlans, processPaymentIntent, syncCustomer };
388
+ export { type CheckPurchaseOptions, type PurchaseCheckResult, type RequestDeduplicationOptions, activatePlan, cancelRenewal, checkPurchase, clearAllPurchaseCache, clearPurchaseCache, createCheckoutSession, createCustomerSession, createPaymentIntent, createTopupPaymentIntent, getAuthenticatedUser, getCustomerBalance, getPurchaseCacheStats, listPlans, processPaymentIntent, reactivateRenewal, syncCustomer, trackUsage };
package/dist/index.js CHANGED
@@ -4,9 +4,8 @@ import {
4
4
  } from "./chunk-F7TBIH6W.js";
5
5
 
6
6
  // src/index.ts
7
- import { NextResponse as NextResponse7 } from "next/server";
8
- import { createSolvaPay } from "@solvapay/server";
9
- import { SolvaPayError } from "@solvapay/core";
7
+ import { NextResponse as NextResponse9 } from "next/server";
8
+ import { checkPurchaseCore, isErrorResult as isErrorResult9 } from "@solvapay/server";
10
9
 
11
10
  // src/cache.ts
12
11
  function createRequestDeduplicator(options = {}) {
@@ -157,7 +156,7 @@ async function getAuthenticatedUser(request, options = {}) {
157
156
 
158
157
  // src/helpers/customer.ts
159
158
  import { NextResponse as NextResponse2 } from "next/server";
160
- import { syncCustomerCore, isErrorResult as isErrorResult2 } from "@solvapay/server";
159
+ import { syncCustomerCore, getCustomerBalanceCore, isErrorResult as isErrorResult2 } from "@solvapay/server";
161
160
  async function syncCustomer(request, options = {}) {
162
161
  const result = await syncCustomerCore(request, options);
163
162
  if (isErrorResult2(result)) {
@@ -168,11 +167,22 @@ async function syncCustomer(request, options = {}) {
168
167
  }
169
168
  return result;
170
169
  }
170
+ async function getCustomerBalance(request, options = {}) {
171
+ const result = await getCustomerBalanceCore(request, options);
172
+ if (isErrorResult2(result)) {
173
+ return NextResponse2.json(
174
+ { error: result.error, details: result.details },
175
+ { status: result.status }
176
+ );
177
+ }
178
+ return result;
179
+ }
171
180
 
172
181
  // src/helpers/payment.ts
173
182
  import { NextResponse as NextResponse3 } from "next/server";
174
183
  import {
175
184
  createPaymentIntentCore,
185
+ createTopupPaymentIntentCore,
176
186
  processPaymentIntentCore,
177
187
  isErrorResult as isErrorResult3
178
188
  } from "@solvapay/server";
@@ -194,6 +204,23 @@ async function createPaymentIntent(request, body, options = {}) {
194
204
  }
195
205
  return result;
196
206
  }
207
+ async function createTopupPaymentIntent(request, body, options = {}) {
208
+ const result = await createTopupPaymentIntentCore(request, body, options);
209
+ if (isErrorResult3(result)) {
210
+ return NextResponse3.json(
211
+ { error: result.error, details: result.details },
212
+ { status: result.status }
213
+ );
214
+ }
215
+ try {
216
+ const userResult = await getAuthenticatedUserCore2(request);
217
+ if (!isErrorResult3(userResult)) {
218
+ clearPurchaseCache(userResult.userId);
219
+ }
220
+ } catch {
221
+ }
222
+ return result;
223
+ }
197
224
  async function processPaymentIntent(request, body, options = {}) {
198
225
  const result = await processPaymentIntentCore(request, body, options);
199
226
  if (isErrorResult3(result)) {
@@ -240,12 +267,12 @@ async function createCustomerSession(request, options = {}) {
240
267
  return result;
241
268
  }
242
269
 
243
- // src/helpers/renewal.ts
270
+ // src/helpers/activation.ts
244
271
  import { NextResponse as NextResponse5 } from "next/server";
245
- import { cancelPurchaseCore, isErrorResult as isErrorResult5 } from "@solvapay/server";
272
+ import { activatePlanCore, isErrorResult as isErrorResult5 } from "@solvapay/server";
246
273
  import { getAuthenticatedUserCore as getAuthenticatedUserCore3 } from "@solvapay/server";
247
- async function cancelRenewal(request, body, options = {}) {
248
- const result = await cancelPurchaseCore(request, body, options);
274
+ async function activatePlan(request, body, options = {}) {
275
+ const result = await activatePlanCore(request, body, options);
249
276
  if (isErrorResult5(result)) {
250
277
  return NextResponse5.json(
251
278
  { error: result.error, details: result.details },
@@ -262,94 +289,117 @@ async function cancelRenewal(request, body, options = {}) {
262
289
  return result;
263
290
  }
264
291
 
265
- // src/helpers/plans.ts
292
+ // src/helpers/renewal.ts
266
293
  import { NextResponse as NextResponse6 } from "next/server";
267
- import { listPlansCore, isErrorResult as isErrorResult6 } from "@solvapay/server";
268
- async function listPlans(request) {
269
- const result = await listPlansCore(request);
294
+ import {
295
+ cancelPurchaseCore,
296
+ reactivatePurchaseCore,
297
+ isErrorResult as isErrorResult6,
298
+ getAuthenticatedUserCore as getAuthenticatedUserCore4
299
+ } from "@solvapay/server";
300
+ async function cancelRenewal(request, body, options = {}) {
301
+ const result = await cancelPurchaseCore(request, body, options);
302
+ if (isErrorResult6(result)) {
303
+ return NextResponse6.json(
304
+ { error: result.error, details: result.details },
305
+ { status: result.status }
306
+ );
307
+ }
308
+ try {
309
+ const userResult = await getAuthenticatedUserCore4(request);
310
+ if (!isErrorResult6(userResult)) {
311
+ clearPurchaseCache(userResult.userId);
312
+ }
313
+ } catch {
314
+ }
315
+ return result;
316
+ }
317
+ async function reactivateRenewal(request, body, options = {}) {
318
+ const result = await reactivatePurchaseCore(request, body, options);
270
319
  if (isErrorResult6(result)) {
271
320
  return NextResponse6.json(
272
321
  { error: result.error, details: result.details },
273
322
  { status: result.status }
274
323
  );
275
324
  }
325
+ try {
326
+ const userResult = await getAuthenticatedUserCore4(request);
327
+ if (!isErrorResult6(userResult)) {
328
+ clearPurchaseCache(userResult.userId);
329
+ }
330
+ } catch {
331
+ }
332
+ return result;
333
+ }
334
+
335
+ // src/helpers/plans.ts
336
+ import { NextResponse as NextResponse7 } from "next/server";
337
+ import { listPlansCore, isErrorResult as isErrorResult7 } from "@solvapay/server";
338
+ async function listPlans(request) {
339
+ const result = await listPlansCore(request);
340
+ if (isErrorResult7(result)) {
341
+ return NextResponse7.json(
342
+ { error: result.error, details: result.details },
343
+ { status: result.status }
344
+ );
345
+ }
276
346
  return result;
277
347
  }
278
348
 
349
+ // src/helpers/usage.ts
350
+ import { NextResponse as NextResponse8 } from "next/server";
351
+ import { trackUsageCore, isErrorResult as isErrorResult8 } from "@solvapay/server";
352
+ async function trackUsage(request, body, options = {}) {
353
+ const result = await trackUsageCore(request, body, options);
354
+ if (isErrorResult8(result)) {
355
+ return NextResponse8.json(
356
+ { error: result.error, details: result.details },
357
+ { status: result.status }
358
+ );
359
+ }
360
+ return NextResponse8.json(result);
361
+ }
362
+
279
363
  // src/index.ts
280
364
  async function checkPurchase(request, options = {}) {
365
+ const deduplicator = getSharedDeduplicator(options.deduplication);
281
366
  try {
282
- const { requireUserId, getUserEmailFromRequest, getUserNameFromRequest } = await import("@solvapay/auth");
367
+ const { requireUserId } = await import("@solvapay/auth");
283
368
  const userIdOrError = requireUserId(request);
284
369
  if (userIdOrError instanceof Response) {
285
370
  const clonedResponse = userIdOrError.clone();
286
371
  const body = await clonedResponse.json().catch(() => ({ error: "Unauthorized" }));
287
- return NextResponse7.json(body, { status: userIdOrError.status });
372
+ return NextResponse9.json(body, { status: userIdOrError.status });
288
373
  }
289
374
  const userId = userIdOrError;
290
- const email = options.includeEmail !== false ? await getUserEmailFromRequest(request) : null;
291
- const name = options.includeName !== false ? await getUserNameFromRequest(request) : null;
292
- const cachedCustomerRef = request.headers.get("x-solvapay-customer-ref");
293
- const solvaPay = options.solvaPay || createSolvaPay();
294
- if (cachedCustomerRef) {
295
- try {
296
- const customer = await solvaPay.getCustomer({ customerRef: cachedCustomerRef });
297
- if (customer && customer.customerRef) {
298
- if (customer.externalRef && customer.externalRef === userId) {
299
- const filteredPurchases = (customer.purchases || []).filter(
300
- (p) => p.status === "active"
301
- );
302
- return {
303
- customerRef: customer.customerRef,
304
- email: customer.email,
305
- name: customer.name,
306
- purchases: filteredPurchases
307
- };
308
- }
309
- }
310
- } catch {
311
- }
312
- }
313
- const deduplicator = getSharedDeduplicator(options.deduplication);
314
- const response = await deduplicator.deduplicate(userId, async () => {
315
- try {
316
- const ensuredCustomerRef = await solvaPay.ensureCustomer(userId, userId, {
317
- email: email || void 0,
318
- name: name || void 0
375
+ const response = await deduplicator.deduplicate(
376
+ userId,
377
+ async () => {
378
+ return await checkPurchaseCore(request, {
379
+ solvaPay: options.solvaPay,
380
+ includeEmail: options.includeEmail,
381
+ includeName: options.includeName
319
382
  });
320
- const customer = await solvaPay.getCustomer({ customerRef: ensuredCustomerRef });
321
- const filteredPurchases = (customer.purchases || []).filter(
322
- (p) => p.status === "active"
323
- );
324
- const result = {
325
- customerRef: customer.customerRef || userId,
326
- email: customer.email,
327
- name: customer.name,
328
- purchases: filteredPurchases
329
- };
330
- return result;
331
- } catch (error) {
332
- console.error("[checkPurchase] Error fetching customer:", error);
333
- return {
334
- customerRef: userId,
335
- purchases: []
336
- };
337
383
  }
338
- });
384
+ );
385
+ if (isErrorResult9(response)) {
386
+ return NextResponse9.json(
387
+ { error: response.error, details: response.details },
388
+ { status: response.status }
389
+ );
390
+ }
339
391
  return response;
340
392
  } catch (error) {
341
393
  console.error("Check purchase failed:", error);
342
- if (error instanceof SolvaPayError) {
343
- return NextResponse7.json({ error: error.message }, { status: 500 });
344
- }
345
394
  const errorMessage = error instanceof Error ? error.message : "Unknown error";
346
- return NextResponse7.json(
395
+ return NextResponse9.json(
347
396
  { error: "Failed to check purchase", details: errorMessage },
348
397
  { status: 500 }
349
398
  );
350
399
  }
351
400
  }
352
401
  export {
402
+ activatePlan,
353
403
  cancelRenewal,
354
404
  checkPurchase,
355
405
  clearAllPurchaseCache,
@@ -359,9 +409,13 @@ export {
359
409
  createCustomerSession,
360
410
  createPaymentIntent,
361
411
  createSupabaseAuthMiddleware,
412
+ createTopupPaymentIntent,
362
413
  getAuthenticatedUser,
414
+ getCustomerBalance,
363
415
  getPurchaseCacheStats,
364
416
  listPlans,
365
417
  processPaymentIntent,
366
- syncCustomer
418
+ reactivateRenewal,
419
+ syncCustomer,
420
+ trackUsage
367
421
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solvapay/next",
3
- "version": "1.0.6",
3
+ "version": "1.0.9-preview.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
@@ -34,9 +34,9 @@
34
34
  },
35
35
  "sideEffects": false,
36
36
  "dependencies": {
37
- "@solvapay/auth": "1.0.6",
38
- "@solvapay/core": "1.0.6",
39
- "@solvapay/server": "1.0.6"
37
+ "@solvapay/core": "1.0.9-preview.1",
38
+ "@solvapay/server": "1.0.9-preview.1",
39
+ "@solvapay/auth": "1.0.9-preview.1"
40
40
  },
41
41
  "peerDependencies": {
42
42
  "next": ">=13.0.0"