@solvapay/next 1.0.6 → 1.0.8-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,21 @@ __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,
46
+ getMerchant: () => getMerchant,
47
+ getProduct: () => getProduct,
43
48
  getPurchaseCacheStats: () => getPurchaseCacheStats,
44
49
  listPlans: () => listPlans,
45
50
  processPaymentIntent: () => processPaymentIntent,
46
- syncCustomer: () => syncCustomer
51
+ reactivateRenewal: () => reactivateRenewal,
52
+ syncCustomer: () => syncCustomer,
53
+ trackUsage: () => trackUsage
47
54
  });
48
55
  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");
56
+ var import_server24 = require("next/server");
57
+ var import_server25 = require("@solvapay/server");
52
58
 
53
59
  // src/cache.ts
54
60
  function createRequestDeduplicator(options = {}) {
@@ -207,6 +213,16 @@ async function syncCustomer(request, options = {}) {
207
213
  }
208
214
  return result;
209
215
  }
216
+ async function getCustomerBalance(request, options = {}) {
217
+ const result = await (0, import_server4.getCustomerBalanceCore)(request, options);
218
+ if ((0, import_server4.isErrorResult)(result)) {
219
+ return import_server3.NextResponse.json(
220
+ { error: result.error, details: result.details },
221
+ { status: result.status }
222
+ );
223
+ }
224
+ return result;
225
+ }
210
226
 
211
227
  // src/helpers/payment.ts
212
228
  var import_server5 = require("next/server");
@@ -229,6 +245,23 @@ async function createPaymentIntent(request, body, options = {}) {
229
245
  }
230
246
  return result;
231
247
  }
248
+ async function createTopupPaymentIntent(request, body, options = {}) {
249
+ const result = await (0, import_server6.createTopupPaymentIntentCore)(request, body, options);
250
+ if ((0, import_server6.isErrorResult)(result)) {
251
+ return import_server5.NextResponse.json(
252
+ { error: result.error, details: result.details },
253
+ { status: result.status }
254
+ );
255
+ }
256
+ try {
257
+ const userResult = await (0, import_server7.getAuthenticatedUserCore)(request);
258
+ if (!(0, import_server6.isErrorResult)(userResult)) {
259
+ clearPurchaseCache(userResult.userId);
260
+ }
261
+ } catch {
262
+ }
263
+ return result;
264
+ }
232
265
  async function processPaymentIntent(request, body, options = {}) {
233
266
  const result = await (0, import_server6.processPaymentIntentCore)(request, body, options);
234
267
  if ((0, import_server6.isErrorResult)(result)) {
@@ -271,12 +304,12 @@ async function createCustomerSession(request, options = {}) {
271
304
  return result;
272
305
  }
273
306
 
274
- // src/helpers/renewal.ts
307
+ // src/helpers/activation.ts
275
308
  var import_server10 = require("next/server");
276
309
  var import_server11 = require("@solvapay/server");
277
310
  var import_server12 = require("@solvapay/server");
278
- async function cancelRenewal(request, body, options = {}) {
279
- const result = await (0, import_server11.cancelPurchaseCore)(request, body, options);
311
+ async function activatePlan(request, body, options = {}) {
312
+ const result = await (0, import_server11.activatePlanCore)(request, body, options);
280
313
  if ((0, import_server11.isErrorResult)(result)) {
281
314
  return import_server10.NextResponse.json(
282
315
  { error: result.error, details: result.details },
@@ -293,29 +326,109 @@ async function cancelRenewal(request, body, options = {}) {
293
326
  return result;
294
327
  }
295
328
 
296
- // src/helpers/plans.ts
329
+ // src/helpers/renewal.ts
297
330
  var import_server13 = require("next/server");
298
331
  var import_server14 = require("@solvapay/server");
299
- async function listPlans(request) {
300
- const result = await (0, import_server14.listPlansCore)(request);
332
+ async function cancelRenewal(request, body, options = {}) {
333
+ const result = await (0, import_server14.cancelPurchaseCore)(request, body, options);
301
334
  if ((0, import_server14.isErrorResult)(result)) {
302
335
  return import_server13.NextResponse.json(
303
336
  { error: result.error, details: result.details },
304
337
  { status: result.status }
305
338
  );
306
339
  }
340
+ try {
341
+ const userResult = await (0, import_server14.getAuthenticatedUserCore)(request);
342
+ if (!(0, import_server14.isErrorResult)(userResult)) {
343
+ clearPurchaseCache(userResult.userId);
344
+ }
345
+ } catch {
346
+ }
347
+ return result;
348
+ }
349
+ async function reactivateRenewal(request, body, options = {}) {
350
+ const result = await (0, import_server14.reactivatePurchaseCore)(request, body, options);
351
+ if ((0, import_server14.isErrorResult)(result)) {
352
+ return import_server13.NextResponse.json(
353
+ { error: result.error, details: result.details },
354
+ { status: result.status }
355
+ );
356
+ }
357
+ try {
358
+ const userResult = await (0, import_server14.getAuthenticatedUserCore)(request);
359
+ if (!(0, import_server14.isErrorResult)(userResult)) {
360
+ clearPurchaseCache(userResult.userId);
361
+ }
362
+ } catch {
363
+ }
307
364
  return result;
308
365
  }
309
366
 
310
- // src/helpers/middleware.ts
367
+ // src/helpers/plans.ts
311
368
  var import_server15 = require("next/server");
369
+ var import_server16 = require("@solvapay/server");
370
+ async function listPlans(request, options = {}) {
371
+ const result = await (0, import_server16.listPlansCore)(request, options);
372
+ if ((0, import_server16.isErrorResult)(result)) {
373
+ return import_server15.NextResponse.json(
374
+ { error: result.error, details: result.details },
375
+ { status: result.status }
376
+ );
377
+ }
378
+ return result;
379
+ }
380
+
381
+ // src/helpers/merchant.ts
382
+ var import_server17 = require("next/server");
383
+ var import_server18 = require("@solvapay/server");
384
+ async function getMerchant(request, options = {}) {
385
+ const result = await (0, import_server18.getMerchantCore)(request, options);
386
+ if ((0, import_server18.isErrorResult)(result)) {
387
+ return import_server17.NextResponse.json(
388
+ { error: result.error, details: result.details },
389
+ { status: result.status }
390
+ );
391
+ }
392
+ return result;
393
+ }
394
+
395
+ // src/helpers/product.ts
396
+ var import_server19 = require("next/server");
397
+ var import_server20 = require("@solvapay/server");
398
+ async function getProduct(request, options = {}) {
399
+ const result = await (0, import_server20.getProductCore)(request, options);
400
+ if ((0, import_server20.isErrorResult)(result)) {
401
+ return import_server19.NextResponse.json(
402
+ { error: result.error, details: result.details },
403
+ { status: result.status }
404
+ );
405
+ }
406
+ return result;
407
+ }
408
+
409
+ // src/helpers/usage.ts
410
+ var import_server21 = require("next/server");
411
+ var import_server22 = require("@solvapay/server");
412
+ async function trackUsage(request, body, options = {}) {
413
+ const result = await (0, import_server22.trackUsageCore)(request, body, options);
414
+ if ((0, import_server22.isErrorResult)(result)) {
415
+ return import_server21.NextResponse.json(
416
+ { error: result.error, details: result.details },
417
+ { status: result.status }
418
+ );
419
+ }
420
+ return import_server21.NextResponse.json(result);
421
+ }
422
+
423
+ // src/helpers/middleware.ts
424
+ var import_server23 = require("next/server");
312
425
  function createAuthMiddleware(options) {
313
426
  const { adapter, publicRoutes = [], userIdHeader = "x-user-id" } = options;
314
427
  return async function middleware(request) {
315
428
  const req = request;
316
429
  const { pathname } = req.nextUrl;
317
430
  if (!pathname.startsWith("/api")) {
318
- return import_server15.NextResponse.next();
431
+ return import_server23.NextResponse.next();
319
432
  }
320
433
  const isPublicRoute = publicRoutes.some((route) => pathname.startsWith(route));
321
434
  const userId = await adapter.getUserIdFromRequest(req);
@@ -324,21 +437,21 @@ function createAuthMiddleware(options) {
324
437
  if (userId) {
325
438
  requestHeaders2.set(userIdHeader, userId);
326
439
  }
327
- return import_server15.NextResponse.next({
440
+ return import_server23.NextResponse.next({
328
441
  request: {
329
442
  headers: requestHeaders2
330
443
  }
331
444
  });
332
445
  }
333
446
  if (!userId) {
334
- return import_server15.NextResponse.json(
447
+ return import_server23.NextResponse.json(
335
448
  { error: "Unauthorized", details: "Valid authentication required" },
336
449
  { status: 401 }
337
450
  );
338
451
  }
339
452
  const requestHeaders = new Headers(req.headers);
340
453
  requestHeaders.set(userIdHeader, userId);
341
- return import_server15.NextResponse.next({
454
+ return import_server23.NextResponse.next({
342
455
  request: {
343
456
  headers: requestHeaders
344
457
  }
@@ -379,72 +492,37 @@ function createSupabaseAuthMiddleware(options = {}) {
379
492
 
380
493
  // src/index.ts
381
494
  async function checkPurchase(request, options = {}) {
495
+ const deduplicator = getSharedDeduplicator(options.deduplication);
382
496
  try {
383
- const { requireUserId, getUserEmailFromRequest, getUserNameFromRequest } = await import("@solvapay/auth");
497
+ const { requireUserId } = await import("@solvapay/auth");
384
498
  const userIdOrError = requireUserId(request);
385
499
  if (userIdOrError instanceof Response) {
386
500
  const clonedResponse = userIdOrError.clone();
387
501
  const body = await clonedResponse.json().catch(() => ({ error: "Unauthorized" }));
388
- return import_server16.NextResponse.json(body, { status: userIdOrError.status });
502
+ return import_server24.NextResponse.json(body, { status: userIdOrError.status });
389
503
  }
390
504
  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
505
+ const response = await deduplicator.deduplicate(
506
+ userId,
507
+ async () => {
508
+ return await (0, import_server25.checkPurchaseCore)(request, {
509
+ solvaPay: options.solvaPay,
510
+ includeEmail: options.includeEmail,
511
+ includeName: options.includeName
420
512
  });
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
513
  }
439
- });
514
+ );
515
+ if ((0, import_server25.isErrorResult)(response)) {
516
+ return import_server24.NextResponse.json(
517
+ { error: response.error, details: response.details },
518
+ { status: response.status }
519
+ );
520
+ }
440
521
  return response;
441
522
  } catch (error) {
442
523
  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
524
  const errorMessage = error instanceof Error ? error.message : "Unknown error";
447
- return import_server16.NextResponse.json(
525
+ return import_server24.NextResponse.json(
448
526
  { error: "Failed to check purchase", details: errorMessage },
449
527
  { status: 500 }
450
528
  );
@@ -452,6 +530,7 @@ async function checkPurchase(request, options = {}) {
452
530
  }
453
531
  // Annotate the CommonJS export names for ESM import in node:
454
532
  0 && (module.exports = {
533
+ activatePlan,
455
534
  cancelRenewal,
456
535
  checkPurchase,
457
536
  clearAllPurchaseCache,
@@ -461,9 +540,15 @@ async function checkPurchase(request, options = {}) {
461
540
  createCustomerSession,
462
541
  createPaymentIntent,
463
542
  createSupabaseAuthMiddleware,
543
+ createTopupPaymentIntent,
464
544
  getAuthenticatedUser,
545
+ getCustomerBalance,
546
+ getMerchant,
547
+ getProduct,
465
548
  getPurchaseCacheStats,
466
549
  listPlans,
467
550
  processPaymentIntent,
468
- syncCustomer
551
+ reactivateRenewal,
552
+ syncCustomer,
553
+ trackUsage
469
554
  });
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, getMerchantCore, getProductCore } 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,75 @@ 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, options?: {
326
+ solvaPay?: SolvaPay;
327
+ }): Promise<ListPlansSuccess | NextResponse>;
328
+
329
+ type GetMerchantSuccess = Exclude<Awaited<ReturnType<typeof getMerchantCore>>, {
330
+ error: string;
331
+ }>;
332
+ /**
333
+ * Next.js route wrapper for GET /api/merchant.
334
+ *
335
+ * @example
336
+ * ```ts
337
+ * // app/api/merchant/route.ts
338
+ * import { getMerchant } from '@solvapay/next/helpers'
339
+ * export const GET = (request: Request) => getMerchant(request)
340
+ * ```
341
+ */
342
+ declare function getMerchant(request: globalThis.Request, options?: {
343
+ solvaPay?: SolvaPay;
344
+ }): Promise<GetMerchantSuccess | NextResponse>;
345
+
346
+ type GetProductSuccess = Exclude<Awaited<ReturnType<typeof getProductCore>>, {
347
+ error: string;
348
+ }>;
349
+ /**
350
+ * Next.js route wrapper for GET /api/get-product?productRef=...
351
+ *
352
+ * @example
353
+ * ```ts
354
+ * // app/api/get-product/route.ts
355
+ * import { getProduct } from '@solvapay/next/helpers'
356
+ * export const GET = (request: Request) => getProduct(request)
357
+ * ```
358
+ */
359
+ declare function getProduct(request: globalThis.Request, options?: {
360
+ solvaPay?: SolvaPay;
361
+ }): Promise<GetProductSuccess | NextResponse>;
362
+
363
+ declare function trackUsage(request: globalThis.Request, body: {
364
+ actionType?: 'transaction' | 'api_call' | 'hour' | 'email' | 'storage' | 'custom';
365
+ units?: number;
366
+ productRef?: string;
367
+ description?: string;
368
+ metadata?: Record<string, unknown>;
369
+ }, options?: {
370
+ solvaPay?: SolvaPay;
371
+ }): Promise<NextResponse>;
277
372
 
278
373
  /**
279
374
  * SolvaPay Next.js SDK
@@ -321,41 +416,9 @@ interface CheckPurchaseOptions {
321
416
  * - Fast path optimization using cached customer references from client
322
417
  * - Automatic customer creation if needed
323
418
  *
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
419
+ * Delegates to `checkPurchaseCore` from `@solvapay/server` for the actual logic,
420
+ * wrapping with Next.js-specific deduplication and response formatting.
358
421
  */
359
422
  declare function checkPurchase(request: Request, options?: CheckPurchaseOptions): Promise<PurchaseCheckResult | NextResponse>;
360
423
 
361
- export { type CheckPurchaseOptions, type PurchaseCheckResult, type RequestDeduplicationOptions, cancelRenewal, checkPurchase, clearAllPurchaseCache, clearPurchaseCache, createCheckoutSession, createCustomerSession, createPaymentIntent, getAuthenticatedUser, getPurchaseCacheStats, listPlans, processPaymentIntent, syncCustomer };
424
+ export { type CheckPurchaseOptions, type PurchaseCheckResult, type RequestDeduplicationOptions, activatePlan, cancelRenewal, checkPurchase, clearAllPurchaseCache, clearPurchaseCache, createCheckoutSession, createCustomerSession, createPaymentIntent, createTopupPaymentIntent, getAuthenticatedUser, getCustomerBalance, getMerchant, getProduct, 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, getMerchantCore, getProductCore } 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,75 @@ 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, options?: {
326
+ solvaPay?: SolvaPay;
327
+ }): Promise<ListPlansSuccess | NextResponse>;
328
+
329
+ type GetMerchantSuccess = Exclude<Awaited<ReturnType<typeof getMerchantCore>>, {
330
+ error: string;
331
+ }>;
332
+ /**
333
+ * Next.js route wrapper for GET /api/merchant.
334
+ *
335
+ * @example
336
+ * ```ts
337
+ * // app/api/merchant/route.ts
338
+ * import { getMerchant } from '@solvapay/next/helpers'
339
+ * export const GET = (request: Request) => getMerchant(request)
340
+ * ```
341
+ */
342
+ declare function getMerchant(request: globalThis.Request, options?: {
343
+ solvaPay?: SolvaPay;
344
+ }): Promise<GetMerchantSuccess | NextResponse>;
345
+
346
+ type GetProductSuccess = Exclude<Awaited<ReturnType<typeof getProductCore>>, {
347
+ error: string;
348
+ }>;
349
+ /**
350
+ * Next.js route wrapper for GET /api/get-product?productRef=...
351
+ *
352
+ * @example
353
+ * ```ts
354
+ * // app/api/get-product/route.ts
355
+ * import { getProduct } from '@solvapay/next/helpers'
356
+ * export const GET = (request: Request) => getProduct(request)
357
+ * ```
358
+ */
359
+ declare function getProduct(request: globalThis.Request, options?: {
360
+ solvaPay?: SolvaPay;
361
+ }): Promise<GetProductSuccess | NextResponse>;
362
+
363
+ declare function trackUsage(request: globalThis.Request, body: {
364
+ actionType?: 'transaction' | 'api_call' | 'hour' | 'email' | 'storage' | 'custom';
365
+ units?: number;
366
+ productRef?: string;
367
+ description?: string;
368
+ metadata?: Record<string, unknown>;
369
+ }, options?: {
370
+ solvaPay?: SolvaPay;
371
+ }): Promise<NextResponse>;
277
372
 
278
373
  /**
279
374
  * SolvaPay Next.js SDK
@@ -321,41 +416,9 @@ interface CheckPurchaseOptions {
321
416
  * - Fast path optimization using cached customer references from client
322
417
  * - Automatic customer creation if needed
323
418
  *
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
419
+ * Delegates to `checkPurchaseCore` from `@solvapay/server` for the actual logic,
420
+ * wrapping with Next.js-specific deduplication and response formatting.
358
421
  */
359
422
  declare function checkPurchase(request: Request, options?: CheckPurchaseOptions): Promise<PurchaseCheckResult | NextResponse>;
360
423
 
361
- export { type CheckPurchaseOptions, type PurchaseCheckResult, type RequestDeduplicationOptions, cancelRenewal, checkPurchase, clearAllPurchaseCache, clearPurchaseCache, createCheckoutSession, createCustomerSession, createPaymentIntent, getAuthenticatedUser, getPurchaseCacheStats, listPlans, processPaymentIntent, syncCustomer };
424
+ export { type CheckPurchaseOptions, type PurchaseCheckResult, type RequestDeduplicationOptions, activatePlan, cancelRenewal, checkPurchase, clearAllPurchaseCache, clearPurchaseCache, createCheckoutSession, createCustomerSession, createPaymentIntent, createTopupPaymentIntent, getAuthenticatedUser, getCustomerBalance, getMerchant, getProduct, 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 NextResponse11 } from "next/server";
8
+ import { checkPurchaseCore, isErrorResult as isErrorResult11 } 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,145 @@ 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, options = {}) {
339
+ const result = await listPlansCore(request, options);
340
+ if (isErrorResult7(result)) {
341
+ return NextResponse7.json(
342
+ { error: result.error, details: result.details },
343
+ { status: result.status }
344
+ );
345
+ }
346
+ return result;
347
+ }
348
+
349
+ // src/helpers/merchant.ts
350
+ import { NextResponse as NextResponse8 } from "next/server";
351
+ import { getMerchantCore, isErrorResult as isErrorResult8 } from "@solvapay/server";
352
+ async function getMerchant(request, options = {}) {
353
+ const result = await getMerchantCore(request, options);
354
+ if (isErrorResult8(result)) {
355
+ return NextResponse8.json(
356
+ { error: result.error, details: result.details },
357
+ { status: result.status }
358
+ );
359
+ }
276
360
  return result;
277
361
  }
278
362
 
363
+ // src/helpers/product.ts
364
+ import { NextResponse as NextResponse9 } from "next/server";
365
+ import { getProductCore, isErrorResult as isErrorResult9 } from "@solvapay/server";
366
+ async function getProduct(request, options = {}) {
367
+ const result = await getProductCore(request, options);
368
+ if (isErrorResult9(result)) {
369
+ return NextResponse9.json(
370
+ { error: result.error, details: result.details },
371
+ { status: result.status }
372
+ );
373
+ }
374
+ return result;
375
+ }
376
+
377
+ // src/helpers/usage.ts
378
+ import { NextResponse as NextResponse10 } from "next/server";
379
+ import { trackUsageCore, isErrorResult as isErrorResult10 } from "@solvapay/server";
380
+ async function trackUsage(request, body, options = {}) {
381
+ const result = await trackUsageCore(request, body, options);
382
+ if (isErrorResult10(result)) {
383
+ return NextResponse10.json(
384
+ { error: result.error, details: result.details },
385
+ { status: result.status }
386
+ );
387
+ }
388
+ return NextResponse10.json(result);
389
+ }
390
+
279
391
  // src/index.ts
280
392
  async function checkPurchase(request, options = {}) {
393
+ const deduplicator = getSharedDeduplicator(options.deduplication);
281
394
  try {
282
- const { requireUserId, getUserEmailFromRequest, getUserNameFromRequest } = await import("@solvapay/auth");
395
+ const { requireUserId } = await import("@solvapay/auth");
283
396
  const userIdOrError = requireUserId(request);
284
397
  if (userIdOrError instanceof Response) {
285
398
  const clonedResponse = userIdOrError.clone();
286
399
  const body = await clonedResponse.json().catch(() => ({ error: "Unauthorized" }));
287
- return NextResponse7.json(body, { status: userIdOrError.status });
400
+ return NextResponse11.json(body, { status: userIdOrError.status });
288
401
  }
289
402
  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
403
+ const response = await deduplicator.deduplicate(
404
+ userId,
405
+ async () => {
406
+ return await checkPurchaseCore(request, {
407
+ solvaPay: options.solvaPay,
408
+ includeEmail: options.includeEmail,
409
+ includeName: options.includeName
319
410
  });
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
411
  }
338
- });
412
+ );
413
+ if (isErrorResult11(response)) {
414
+ return NextResponse11.json(
415
+ { error: response.error, details: response.details },
416
+ { status: response.status }
417
+ );
418
+ }
339
419
  return response;
340
420
  } catch (error) {
341
421
  console.error("Check purchase failed:", error);
342
- if (error instanceof SolvaPayError) {
343
- return NextResponse7.json({ error: error.message }, { status: 500 });
344
- }
345
422
  const errorMessage = error instanceof Error ? error.message : "Unknown error";
346
- return NextResponse7.json(
423
+ return NextResponse11.json(
347
424
  { error: "Failed to check purchase", details: errorMessage },
348
425
  { status: 500 }
349
426
  );
350
427
  }
351
428
  }
352
429
  export {
430
+ activatePlan,
353
431
  cancelRenewal,
354
432
  checkPurchase,
355
433
  clearAllPurchaseCache,
@@ -359,9 +437,15 @@ export {
359
437
  createCustomerSession,
360
438
  createPaymentIntent,
361
439
  createSupabaseAuthMiddleware,
440
+ createTopupPaymentIntent,
362
441
  getAuthenticatedUser,
442
+ getCustomerBalance,
443
+ getMerchant,
444
+ getProduct,
363
445
  getPurchaseCacheStats,
364
446
  listPlans,
365
447
  processPaymentIntent,
366
- syncCustomer
448
+ reactivateRenewal,
449
+ syncCustomer,
450
+ trackUsage
367
451
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solvapay/next",
3
- "version": "1.0.6",
3
+ "version": "1.0.8-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/auth": "1.0.8-preview.1",
38
+ "@solvapay/server": "1.0.8-preview.1",
39
+ "@solvapay/core": "1.0.8-preview.1"
40
40
  },
41
41
  "peerDependencies": {
42
42
  "next": ">=13.0.0"