@deiondz/better-auth-razorpay 2.0.12 → 2.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -219,6 +219,7 @@ interface RazorpayPluginOptions {
219
219
  razorpayKeySecret?: string // Optional: Razorpay API key secret; required when razorpayClient is not provided; when set, enables POST /razorpay/verify-payment
220
220
  razorpayWebhookSecret?: string // Optional: Webhook secret for signature verification
221
221
  createCustomerOnSignUp?: boolean // Optional: Create Razorpay customer on user sign-up (default: false)
222
+ trialOnSignUp?: { days: number; planName?: string } // Optional: When set with createCustomerOnSignUp, creates an app-level trial subscription at sign-up. Omit for no sign-up trial.
222
223
  onCustomerCreate?: (args) => Promise<void>
223
224
  getCustomerCreateParams?: (args) => Promise<{ params?: Record<string, unknown> }>
224
225
  subscription?: SubscriptionOptions // Optional: { enabled, plans, callbacks, authorizeReference, ... }
@@ -227,6 +228,17 @@ interface RazorpayPluginOptions {
227
228
  }
228
229
  ```
229
230
 
231
+ ### Optional: Trial on sign-up
232
+
233
+ When you want new users to get a **free trial** without adding a payment method first (e.g. 14 days, then they must subscribe):
234
+
235
+ - Set **both** `createCustomerOnSignUp: true` and `trialOnSignUp: { days: 14, planName: 'Trial' }` (or any `days` and display `planName`).
236
+ - On sign-up, the plugin creates a Razorpay customer and **one local subscription** with `status: 'trialing'`, `trialStart` / `trialEnd`, and no `razorpaySubscriptionId` (no Razorpay subscription until they subscribe).
237
+ - **Subscription list** returns this record; your app can show "Free trial — ends &lt;trialEnd&gt;" and gate features when `trialEnd < now`.
238
+ - The user can **subscribe anytime** via create-or-update (choose a plan, get checkout URL); the same record is updated to a paid subscription (plan, `razorpaySubscriptionId`, status from Razorpay).
239
+
240
+ **Configurable:** Omit `trialOnSignUp` for products that do not want sign-up trials (e.g. checkout-first or plan-based trial only). If `trialOnSignUp` is not set, behavior is unchanged.
241
+
230
242
  ### Callback functions
231
243
 
232
244
  The plugin supports the same callback hooks as the [community plugin](https://github.com/iamjasonkendrick/better-auth-razorpay). You can use them for emails, analytics, external systems, or custom logic.
@@ -254,6 +266,7 @@ razorpayPlugin({
254
266
  razorpayWebhookSecret: process.env.RAZORPAY_WEBHOOK_SECRET,
255
267
  razorpayKeySecret: process.env.RAZORPAY_KEY_SECRET, // optional: enables verify-payment endpoint
256
268
  createCustomerOnSignUp: true,
269
+ trialOnSignUp: { days: 14, planName: 'Trial' }, // optional: app-level trial at sign-up
257
270
  onCustomerCreate: async ({ user, razorpayCustomer }) => {
258
271
  console.log(`Razorpay customer created for user ${user.id}: ${razorpayCustomer.id}`)
259
272
  },
@@ -1,10 +1,10 @@
1
- import { S as SubscriptionRecord } from '../types-VZW_XCzQ.js';
1
+ import { S as SubscriptionRecord } from '../types-BC0odu_S.js';
2
2
  import * as _tanstack_react_query from '@tanstack/react-query';
3
3
  import { UseMutationOptions, UseQueryOptions } from '@tanstack/react-query';
4
4
  import * as react from 'react';
5
5
  import { ReactNode } from 'react';
6
- import { c as RazorpayAuthClient, d as CancelSubscriptionResponse, a as CancelSubscriptionInput, e as CreateOrUpdateSubscriptionResponse, C as CreateOrUpdateSubscriptionInput, P as PlanSummary, f as RestoreSubscriptionResponse, b as RestoreSubscriptionInput, g as ListSubscriptionsResponse, h as VerifyPaymentResponse, V as VerifyPaymentInput, L as ListSubscriptionsInput } from '../types-BGWv0IJy.js';
7
- export { G as GetPlansResponse, i as RazorpayApiError, R as RazorpayApiResult, j as RazorpayClientActions } from '../types-BGWv0IJy.js';
6
+ import { c as RazorpayAuthClient, d as CancelSubscriptionResponse, a as CancelSubscriptionInput, e as CreateOrUpdateSubscriptionResponse, C as CreateOrUpdateSubscriptionInput, P as PlanSummary, f as RestoreSubscriptionResponse, b as RestoreSubscriptionInput, g as ListSubscriptionsResponse, h as VerifyPaymentResponse, V as VerifyPaymentInput, L as ListSubscriptionsInput } from '../types-B91GdcpF.js';
7
+ export { G as GetPlansResponse, i as RazorpayApiError, R as RazorpayApiResult, j as RazorpayClientActions } from '../types-B91GdcpF.js';
8
8
  import 'razorpay';
9
9
 
10
10
  /**
package/dist/client.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { S as SubscriptionRecord } from './types-VZW_XCzQ.js';
1
+ import { S as SubscriptionRecord } from './types-BC0odu_S.js';
2
2
  import { razorpayPlugin } from './index.js';
3
- import { R as RazorpayApiResult, P as PlanSummary, L as ListSubscriptionsInput, C as CreateOrUpdateSubscriptionInput, a as CancelSubscriptionInput, b as RestoreSubscriptionInput, V as VerifyPaymentInput } from './types-BGWv0IJy.js';
3
+ import { R as RazorpayApiResult, P as PlanSummary, L as ListSubscriptionsInput, C as CreateOrUpdateSubscriptionInput, a as CancelSubscriptionInput, b as RestoreSubscriptionInput, V as VerifyPaymentInput } from './types-B91GdcpF.js';
4
4
  import 'razorpay';
5
5
  import 'better-auth';
6
6
 
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { BetterAuthPlugin } from 'better-auth';
2
- import { R as RazorpayPluginOptions } from './types-VZW_XCzQ.js';
3
- export { O as OnWebhookEventCallback, a as RazorpayApiResponse, b as RazorpayErrorResponse, c as RazorpayPlan, d as RazorpaySubscription, e as RazorpaySuccessResponse, f as RazorpayUserRecord, g as RazorpayWebhookContext, h as RazorpayWebhookEvent, i as RazorpayWebhookPayload, S as SubscriptionRecord, j as SubscriptionStatus } from './types-VZW_XCzQ.js';
2
+ import { R as RazorpayPluginOptions } from './types-BC0odu_S.js';
3
+ export { O as OnWebhookEventCallback, a as RazorpayApiResponse, b as RazorpayErrorResponse, c as RazorpayPlan, d as RazorpaySubscription, e as RazorpaySuccessResponse, f as RazorpayUserRecord, g as RazorpayWebhookContext, h as RazorpayWebhookEvent, i as RazorpayWebhookPayload, S as SubscriptionRecord, j as SubscriptionStatus } from './types-BC0odu_S.js';
4
4
  import 'razorpay';
5
5
 
6
6
  interface WebhookResult {
@@ -23,6 +23,7 @@ interface WebhookResult {
23
23
  * @param options.razorpayKeySecret - Razorpay API key secret (required when razorpayClient is not provided; when set, also enables POST /razorpay/verify-payment)
24
24
  * @param options.razorpayWebhookSecret - Webhook secret for signature verification
25
25
  * @param options.createCustomerOnSignUp - Create Razorpay customer when user signs up (default: false)
26
+ * @param options.trialOnSignUp - Optional. When set with createCustomerOnSignUp, creates an app-level trial subscription at sign-up. { days, planName? }. Omit for no sign-up trial.
26
27
  * @param options.onCustomerCreate - Callback after customer is created
27
28
  * @param options.getCustomerCreateParams - Custom params when creating customer
28
29
  * @param options.subscription - Subscription config (enabled, plans, callbacks, authorizeReference)
package/dist/index.js CHANGED
@@ -4334,8 +4334,15 @@ var createOrUpdateSubscription = (razorpay, options) => createAuthEndpoint2(
4334
4334
  "created",
4335
4335
  "halted"
4336
4336
  ];
4337
- const hasActiveSubscription = (existingSubs ?? []).filter((s) => activeStatuses.includes(s.status)).length > 0;
4338
- if (hasActiveSubscription) {
4337
+ const subs = existingSubs ?? [];
4338
+ const activePaidSubs = subs.filter(
4339
+ (s) => activeStatuses.includes(s.status) && s.razorpaySubscriptionId
4340
+ );
4341
+ const appTrialSubs = subs.filter(
4342
+ (s) => s.status === "trialing" && !s.razorpaySubscriptionId
4343
+ );
4344
+ const appTrialSub = appTrialSubs.length === 1 ? appTrialSubs[0] : null;
4345
+ if (activePaidSubs.length > 0) {
4339
4346
  return {
4340
4347
  success: false,
4341
4348
  error: {
@@ -4354,7 +4361,7 @@ var createOrUpdateSubscription = (razorpay, options) => createAuthEndpoint2(
4354
4361
  };
4355
4362
  if (subOpts.getSubscriptionCreateParams) {
4356
4363
  const tempSub = {
4357
- id: "",
4364
+ id: appTrialSub?.id ?? "",
4358
4365
  plan: plan.name,
4359
4366
  referenceId: userId,
4360
4367
  status: "created",
@@ -4379,17 +4386,64 @@ var createOrUpdateSubscription = (razorpay, options) => createAuthEndpoint2(
4379
4386
  const rpSubscription = await razorpay.subscriptions.create(
4380
4387
  subscriptionPayload
4381
4388
  );
4389
+ const periodStart = rpSubscription.current_start ? new Date(rpSubscription.current_start * 1e3) : null;
4390
+ const periodEnd = rpSubscription.current_end ? new Date(rpSubscription.current_end * 1e3) : null;
4391
+ const newStatus = toLocalStatus(rpSubscription.status);
4392
+ if (appTrialSub) {
4393
+ await ctx.context.adapter.update({
4394
+ model: "subscription",
4395
+ where: [{ field: "id", value: appTrialSub.id }],
4396
+ update: {
4397
+ data: {
4398
+ plan: plan.name,
4399
+ razorpaySubscriptionId: rpSubscription.id,
4400
+ status: newStatus,
4401
+ trialEnd: now,
4402
+ periodStart,
4403
+ periodEnd,
4404
+ seats: body.seats,
4405
+ updatedAt: now
4406
+ }
4407
+ }
4408
+ });
4409
+ if (subOpts.onSubscriptionCreated) {
4410
+ const updatedRecord = {
4411
+ ...appTrialSub,
4412
+ plan: plan.name,
4413
+ razorpaySubscriptionId: rpSubscription.id,
4414
+ status: newStatus,
4415
+ trialEnd: now,
4416
+ periodStart,
4417
+ periodEnd,
4418
+ seats: body.seats,
4419
+ updatedAt: now
4420
+ };
4421
+ await subOpts.onSubscriptionCreated({
4422
+ razorpaySubscription: rpSubscription,
4423
+ subscription: updatedRecord,
4424
+ plan
4425
+ });
4426
+ }
4427
+ const data2 = {
4428
+ subscriptionId: appTrialSub.id,
4429
+ razorpaySubscriptionId: rpSubscription.id
4430
+ };
4431
+ if (!body.embed) {
4432
+ data2.checkoutUrl = body.disableRedirect ? rpSubscription.short_url : body.successUrl ? `${rpSubscription.short_url}?redirect=${encodeURIComponent(body.successUrl)}` : rpSubscription.short_url;
4433
+ }
4434
+ return { success: true, data: data2 };
4435
+ }
4382
4436
  const subscriptionRecord = {
4383
4437
  id: localId,
4384
4438
  plan: plan.name,
4385
4439
  referenceId: userId,
4386
4440
  razorpayCustomerId: user.razorpayCustomerId ?? null,
4387
4441
  razorpaySubscriptionId: rpSubscription.id,
4388
- status: toLocalStatus(rpSubscription.status),
4442
+ status: newStatus,
4389
4443
  trialStart: null,
4390
4444
  trialEnd: null,
4391
- periodStart: rpSubscription.current_start ? new Date(rpSubscription.current_start * 1e3) : null,
4392
- periodEnd: rpSubscription.current_end ? new Date(rpSubscription.current_end * 1e3) : null,
4445
+ periodStart,
4446
+ periodEnd,
4393
4447
  cancelAtPeriodEnd: false,
4394
4448
  seats: body.seats,
4395
4449
  groupId: null,
@@ -4855,6 +4909,7 @@ var razorpayPlugin = (options) => {
4855
4909
  razorpayKeySecret,
4856
4910
  razorpayWebhookSecret,
4857
4911
  createCustomerOnSignUp = false,
4912
+ trialOnSignUp,
4858
4913
  onCustomerCreate,
4859
4914
  getCustomerCreateParams,
4860
4915
  subscription: subOpts,
@@ -4951,6 +5006,34 @@ var razorpayPlugin = (options) => {
4951
5006
  razorpayCustomer: { id: customer.id, ...customer }
4952
5007
  });
4953
5008
  }
5009
+ if (trialOnSignUp && typeof trialOnSignUp.days === "number" && trialOnSignUp.days > 0 && adapter.create) {
5010
+ const now = /* @__PURE__ */ new Date();
5011
+ const trialEnd = new Date(now.getTime() + trialOnSignUp.days * 24 * 60 * 60 * 1e3);
5012
+ const planName = trialOnSignUp.planName ?? "Trial";
5013
+ const localId = `sub_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
5014
+ const subscriptionRecord = {
5015
+ id: localId,
5016
+ plan: planName,
5017
+ referenceId: user.id,
5018
+ razorpayCustomerId: customer.id,
5019
+ razorpaySubscriptionId: null,
5020
+ status: "trialing",
5021
+ trialStart: now,
5022
+ trialEnd,
5023
+ periodStart: null,
5024
+ periodEnd: null,
5025
+ cancelAtPeriodEnd: false,
5026
+ seats: 1,
5027
+ groupId: null,
5028
+ createdAt: now,
5029
+ updatedAt: now
5030
+ };
5031
+ await adapter.create({
5032
+ model: "subscription",
5033
+ data: subscriptionRecord,
5034
+ forceAllowId: true
5035
+ });
5036
+ }
4954
5037
  } catch (err) {
4955
5038
  console.error("[better-auth-razorpay] Create customer on sign-up failed:", err);
4956
5039
  }