@deiondz/better-auth-razorpay 2.0.5 → 2.0.7

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/client/types.ts DELETED
@@ -1,154 +0,0 @@
1
- /**
2
- * Client-side types for Razorpay plugin hooks and API responses.
3
- */
4
-
5
- import type { SubscriptionRecord } from '../lib/types'
6
-
7
- /** Plan summary returned by GET /razorpay/get-plans (client-safe shape). */
8
- export interface PlanSummary {
9
- name: string
10
- monthlyPlanId: string
11
- annualPlanId?: string
12
- limits?: Record<string, number>
13
- freeTrial?: { days: number }
14
- }
15
-
16
- /** Response shape for get-plans (success). */
17
- export interface GetPlansResponse {
18
- success: true
19
- data: PlanSummary[]
20
- }
21
-
22
- /** Response shape for subscription/list (success). */
23
- export interface ListSubscriptionsResponse {
24
- success: true
25
- data: SubscriptionRecord[]
26
- }
27
-
28
- /** Response shape for create-or-update (success). */
29
- export interface CreateOrUpdateSubscriptionResponse {
30
- success: true
31
- data: {
32
- checkoutUrl: string
33
- subscriptionId: string
34
- razorpaySubscriptionId: string
35
- }
36
- }
37
-
38
- /** Response shape for cancel (success). */
39
- export interface CancelSubscriptionResponse {
40
- success: true
41
- data: {
42
- id: string
43
- status: string
44
- plan_id: string
45
- current_end?: number
46
- ended_at?: number | null
47
- }
48
- }
49
-
50
- /** Response shape for restore (success). */
51
- export interface RestoreSubscriptionResponse {
52
- success: true
53
- data: { id: string; status: string }
54
- }
55
-
56
- /** Error shape from plugin API. */
57
- export interface RazorpayApiError {
58
- success: false
59
- error: { code: string; description: string; [key: string]: unknown }
60
- }
61
-
62
- /** Any plugin API response (success or error). */
63
- export type RazorpayApiResult<T = unknown> =
64
- | { success: true; data: T }
65
- | RazorpayApiError
66
-
67
- /** Razorpay API actions from the client plugin (authClient.razorpay). Use these so requests hit the correct paths. */
68
- export interface RazorpayClientActions {
69
- getPlans: (fetchOptions?: { query?: Record<string, string> }) => Promise<RazorpayApiResult<PlanSummary[]>>
70
- listSubscriptions: (
71
- input?: ListSubscriptionsInput,
72
- fetchOptions?: { query?: Record<string, string> }
73
- ) => Promise<RazorpayApiResult<ListSubscriptionsResponse['data']>>
74
- createOrUpdateSubscription: (
75
- input: CreateOrUpdateSubscriptionInput,
76
- fetchOptions?: { body?: Record<string, unknown> }
77
- ) => Promise<RazorpayApiResult<CreateOrUpdateSubscriptionResponse['data']>>
78
- cancelSubscription: (
79
- input: CancelSubscriptionInput,
80
- fetchOptions?: { body?: Record<string, unknown> }
81
- ) => Promise<RazorpayApiResult<CancelSubscriptionResponse['data']>>
82
- restoreSubscription: (
83
- input: RestoreSubscriptionInput,
84
- fetchOptions?: { body?: Record<string, unknown> }
85
- ) => Promise<RazorpayApiResult<RestoreSubscriptionResponse['data']>>
86
- verifyPayment: (
87
- input: VerifyPaymentInput,
88
- fetchOptions?: { body?: Record<string, unknown> }
89
- ) => Promise<RazorpayApiResult<VerifyPaymentResponse['data']>>
90
- }
91
-
92
- /**
93
- * Minimal auth client interface for Razorpay hooks.
94
- * Primary: razorpay is set when razorpayClientPlugin() is used in createAuthClient({ plugins: [...] }); prefer it so requests hit the correct paths.
95
- * Fallback: api is optional for custom clients that implement path-based api.get/api.post.
96
- */
97
- export interface RazorpayAuthClient {
98
- /** Set when razorpayClientPlugin() is used in createAuthClient({ plugins: [razorpayClientPlugin()] }). Prefer these methods over api.get/post. */
99
- razorpay?: RazorpayClientActions
100
- /** Optional; for custom clients that implement path-based api.get/post. */
101
- api?: {
102
- get: (
103
- path: string,
104
- options?: { query?: Record<string, string> }
105
- ) => Promise<RazorpayApiResult<unknown>>
106
- post: (
107
- path: string,
108
- options?: { body?: Record<string, unknown> }
109
- ) => Promise<RazorpayApiResult<unknown>>
110
- }
111
- }
112
-
113
- /** Input for create-or-update subscription. */
114
- export interface CreateOrUpdateSubscriptionInput {
115
- plan: string
116
- annual?: boolean
117
- seats?: number
118
- subscriptionId?: string
119
- successUrl?: string
120
- disableRedirect?: boolean
121
- }
122
-
123
- /** Input for cancel subscription. */
124
- export interface CancelSubscriptionInput {
125
- subscriptionId: string
126
- immediately?: boolean
127
- }
128
-
129
- /** Input for restore subscription. */
130
- export interface RestoreSubscriptionInput {
131
- subscriptionId: string
132
- }
133
-
134
- /** Input for list subscriptions (query). */
135
- export interface ListSubscriptionsInput {
136
- referenceId?: string
137
- }
138
-
139
- /** Input for verify-payment (Razorpay checkout success callback payload). */
140
- export interface VerifyPaymentInput {
141
- razorpay_payment_id: string
142
- razorpay_subscription_id: string
143
- razorpay_signature: string
144
- }
145
-
146
- /** Response shape for verify-payment (success). */
147
- export interface VerifyPaymentResponse {
148
- success: true
149
- data: {
150
- message: string
151
- payment_id: string
152
- subscription_id: string
153
- }
154
- }
package/client.ts DELETED
@@ -1,105 +0,0 @@
1
- import type { BetterAuthClientPlugin } from 'better-auth/client'
2
- import type { razorpayPlugin } from './index'
3
- import type {
4
- PlanSummary,
5
- CreateOrUpdateSubscriptionInput,
6
- CancelSubscriptionInput,
7
- RestoreSubscriptionInput,
8
- ListSubscriptionsInput,
9
- VerifyPaymentInput,
10
- ListSubscriptionsResponse,
11
- CreateOrUpdateSubscriptionResponse,
12
- CancelSubscriptionResponse,
13
- RestoreSubscriptionResponse,
14
- VerifyPaymentResponse,
15
- RazorpayApiResult,
16
- } from './client/types'
17
-
18
- type FetchFn = (
19
- path: string,
20
- options?: {
21
- method?: string
22
- body?: Record<string, unknown>
23
- query?: Record<string, string>
24
- }
25
- ) => Promise<RazorpayApiResult<unknown>>
26
-
27
- const PATHS = {
28
- getPlans: '/razorpay/get-plans',
29
- listSubscriptions: '/razorpay/subscription/list',
30
- createOrUpdateSubscription: '/razorpay/subscription/create-or-update',
31
- cancelSubscription: '/razorpay/subscription/cancel',
32
- restoreSubscription: '/razorpay/subscription/restore',
33
- verifyPayment: '/razorpay/verify-payment',
34
- } as const
35
-
36
- /**
37
- * Razorpay client plugin for Better Auth.
38
- * Exposes authClient.razorpay.* so requests use the correct paths and avoid 404s from api.get/post.
39
- * Add to createAuthClient: plugins: [razorpayClientPlugin()]
40
- */
41
- export const razorpayClientPlugin = () =>
42
- ({
43
- id: 'razorpay-plugin',
44
- $InferServerPlugin: {} as ReturnType<typeof razorpayPlugin>,
45
- getActions: ($fetch: FetchFn) => ({
46
- razorpay: {
47
- getPlans: (fetchOptions?: Parameters<FetchFn>[1]) =>
48
- $fetch(PATHS.getPlans, { method: 'GET', ...fetchOptions }) as Promise<
49
- RazorpayApiResult<PlanSummary[]>
50
- >,
51
-
52
- listSubscriptions: (
53
- input?: ListSubscriptionsInput,
54
- fetchOptions?: Parameters<FetchFn>[1]
55
- ) =>
56
- $fetch(PATHS.listSubscriptions, {
57
- method: 'GET',
58
- query: input?.referenceId ? { referenceId: input.referenceId } : undefined,
59
- ...fetchOptions,
60
- }) as Promise<RazorpayApiResult<ListSubscriptionsResponse['data']>>,
61
-
62
- createOrUpdateSubscription: (
63
- input: CreateOrUpdateSubscriptionInput,
64
- fetchOptions?: Parameters<FetchFn>[1]
65
- ) =>
66
- $fetch(PATHS.createOrUpdateSubscription, {
67
- method: 'POST',
68
- body: input as unknown as Record<string, unknown>,
69
- ...fetchOptions,
70
- }) as Promise<
71
- RazorpayApiResult<CreateOrUpdateSubscriptionResponse['data']>
72
- >,
73
-
74
- cancelSubscription: (
75
- input: CancelSubscriptionInput,
76
- fetchOptions?: Parameters<FetchFn>[1]
77
- ) =>
78
- $fetch(PATHS.cancelSubscription, {
79
- method: 'POST',
80
- body: input as unknown as Record<string, unknown>,
81
- ...fetchOptions,
82
- }) as Promise<RazorpayApiResult<CancelSubscriptionResponse['data']>>,
83
-
84
- restoreSubscription: (
85
- input: RestoreSubscriptionInput,
86
- fetchOptions?: Parameters<FetchFn>[1]
87
- ) =>
88
- $fetch(PATHS.restoreSubscription, {
89
- method: 'POST',
90
- body: input as unknown as Record<string, unknown>,
91
- ...fetchOptions,
92
- }) as Promise<RazorpayApiResult<RestoreSubscriptionResponse['data']>>,
93
-
94
- verifyPayment: (
95
- input: VerifyPaymentInput,
96
- fetchOptions?: Parameters<FetchFn>[1]
97
- ) =>
98
- $fetch(PATHS.verifyPayment, {
99
- method: 'POST',
100
- body: input as unknown as Record<string, unknown>,
101
- ...fetchOptions,
102
- }) as Promise<RazorpayApiResult<VerifyPaymentResponse['data']>>,
103
- },
104
- }),
105
- }) satisfies BetterAuthClientPlugin
package/index.ts DELETED
@@ -1,162 +0,0 @@
1
- import type { BetterAuthPlugin } from 'better-auth'
2
- import {
3
- cancelSubscription,
4
- createOrUpdateSubscription,
5
- getPlans,
6
- listSubscriptions,
7
- restoreSubscription,
8
- verifyPayment,
9
- webhook,
10
- } from './api'
11
- import type { RazorpayPluginOptions, RazorpayUserRecord } from './lib'
12
-
13
- /**
14
- * Razorpay plugin for Better Auth.
15
- *
16
- * Aligns with the subscription flow from the community plugin:
17
- * - Subscription: create-or-update (checkout URL), cancel, restore, list
18
- * - Customer: optional creation on sign-up, callbacks and params
19
- * - Webhooks: subscription events (activated, cancelled, expired, etc.) with optional callbacks
20
- * - Plans: named plans with monthly/annual IDs, limits, free trial
21
- *
22
- * @param options - Plugin configuration
23
- * @param options.razorpayClient - Initialized Razorpay instance (key_id, key_secret)
24
- * @param options.razorpayWebhookSecret - Webhook secret for signature verification
25
- * @param options.razorpayKeySecret - API key secret for payment signature verification (optional; when set, enables POST /razorpay/verify-payment)
26
- * @param options.createCustomerOnSignUp - Create Razorpay customer when user signs up (default: false)
27
- * @param options.onCustomerCreate - Callback after customer is created
28
- * @param options.getCustomerCreateParams - Custom params when creating customer
29
- * @param options.subscription - Subscription config (enabled, plans, callbacks, authorizeReference)
30
- * @param options.onEvent - Global callback for all webhook events
31
- */
32
- export const razorpayPlugin = (options: RazorpayPluginOptions) => {
33
- const {
34
- razorpayClient,
35
- razorpayWebhookSecret,
36
- razorpayKeySecret,
37
- createCustomerOnSignUp = false,
38
- onCustomerCreate,
39
- getCustomerCreateParams,
40
- subscription: subOpts,
41
- onEvent,
42
- } = options
43
-
44
- if (!razorpayClient) {
45
- throw new Error('Razorpay plugin: razorpayClient is required')
46
- }
47
-
48
- const razorpay = razorpayClient as import('razorpay')
49
-
50
- const plugin = {
51
- id: 'razorpay-plugin',
52
-
53
- schema: {
54
- user: {
55
- fields: {
56
- razorpayCustomerId: { type: 'string', required: false },
57
- },
58
- },
59
- subscription: {
60
- fields: {
61
- id: { type: 'string', required: true },
62
- plan: { type: 'string', required: true },
63
- referenceId: { type: 'string', required: true },
64
- razorpayCustomerId: { type: 'string', required: false },
65
- razorpaySubscriptionId: { type: 'string', required: false },
66
- status: { type: 'string', required: true },
67
- trialStart: { type: 'date', required: false },
68
- trialEnd: { type: 'date', required: false },
69
- periodStart: { type: 'date', required: false },
70
- periodEnd: { type: 'date', required: false },
71
- cancelAtPeriodEnd: { type: 'boolean', required: false },
72
- seats: { type: 'number', required: false },
73
- groupId: { type: 'string', required: false },
74
- createdAt: { type: 'date', required: true },
75
- updatedAt: { type: 'date', required: true },
76
- },
77
- },
78
- },
79
-
80
- endpoints: {
81
- 'subscription/create-or-update': createOrUpdateSubscription(razorpay, {
82
- subscription: subOpts,
83
- createCustomerOnSignUp,
84
- }),
85
- 'subscription/cancel': cancelSubscription(razorpay),
86
- 'subscription/restore': restoreSubscription(razorpay),
87
- 'subscription/list': listSubscriptions({ subscription: subOpts }),
88
- 'get-plans': getPlans({ subscription: subOpts }),
89
- ...(razorpayKeySecret
90
- ? { 'verify-payment': verifyPayment(razorpayKeySecret) }
91
- : {}),
92
- webhook: webhook(razorpayWebhookSecret, options.onWebhookEvent ?? undefined, {
93
- subscription: subOpts,
94
- onEvent,
95
- }),
96
- },
97
-
98
- databaseHooks: createCustomerOnSignUp
99
- ? {
100
- user: {
101
- create: {
102
- after: async (
103
- user: RazorpayUserRecord & { id: string },
104
- ctx: { context?: { adapter?: { update: (p: unknown) => Promise<unknown> } }; adapter?: { update: (p: unknown) => Promise<unknown> }; session?: unknown }
105
- ) => {
106
- const adapter = ctx.context?.adapter ?? (ctx as { adapter?: { update: (p: unknown) => Promise<unknown> } }).adapter
107
- if (!adapter?.update) return
108
- try {
109
- const params: { name?: string; email?: string; contact?: string; [key: string]: unknown } = {
110
- name: user.name ?? user.email ?? 'Customer',
111
- email: user.email ?? undefined,
112
- }
113
- if (getCustomerCreateParams) {
114
- const extra = await getCustomerCreateParams({
115
- user: user as RazorpayUserRecord,
116
- session: ctx.session,
117
- })
118
- if (extra?.params && typeof extra.params === 'object') {
119
- Object.assign(params, extra.params)
120
- }
121
- }
122
- const customer = await razorpay.customers.create(params)
123
- await adapter.update({
124
- model: 'user',
125
- where: [{ field: 'id', value: user.id }],
126
- update: { data: { razorpayCustomerId: customer.id } },
127
- })
128
- if (onCustomerCreate) {
129
- await onCustomerCreate({
130
- user: user as RazorpayUserRecord,
131
- razorpayCustomer: { id: customer.id, ...(customer as unknown as Record<string, unknown>) },
132
- })
133
- }
134
- } catch (err) {
135
- console.error('[better-auth-razorpay] Create customer on sign-up failed:', err)
136
- }
137
- },
138
- },
139
- },
140
- }
141
- : undefined,
142
- }
143
-
144
- return plugin as BetterAuthPlugin
145
- }
146
-
147
- export type {
148
- OnWebhookEventCallback,
149
- RazorpayApiResponse,
150
- RazorpayErrorResponse,
151
- RazorpayPlan,
152
- RazorpayPluginOptions,
153
- RazorpaySubscription,
154
- RazorpaySuccessResponse,
155
- RazorpayUserRecord,
156
- RazorpayWebhookContext,
157
- RazorpayWebhookEvent,
158
- RazorpayWebhookPayload,
159
- SubscriptionRecord,
160
- SubscriptionStatus,
161
- } from './lib'
162
- export type { WebhookResult } from './api/webhook'
@@ -1,99 +0,0 @@
1
- import { z } from 'zod'
2
-
3
- /**
4
- * Helper function to handle Razorpay-related errors and reduce complexity.
5
- * Handles various error types including validation, network, timeout, and Razorpay API errors.
6
- */
7
- function handleRazorpayError(error: unknown): {
8
- success: false
9
- error: { code: string; description: string }
10
- } {
11
- // Handle Zod validation errors
12
- if (error instanceof z.ZodError) {
13
- return {
14
- success: false,
15
- error: {
16
- code: 'INVALID_REQUEST',
17
- description: error.issues[0]?.message || 'Validation failed',
18
- },
19
- }
20
- }
21
-
22
- // Handle network errors (fetch/axios network failures)
23
- if (error && typeof error === 'object') {
24
- // Check for network error indicators
25
- const errorObj = error as Record<string, unknown>
26
- if (
27
- 'code' in errorObj &&
28
- (errorObj.code === 'ECONNREFUSED' ||
29
- errorObj.code === 'ENOTFOUND' ||
30
- errorObj.code === 'ETIMEDOUT' ||
31
- errorObj.code === 'ECONNRESET')
32
- ) {
33
- return {
34
- success: false,
35
- error: {
36
- code: 'NETWORK_ERROR',
37
- description: 'Network connection failed. Please check your internet connection and try again.',
38
- },
39
- }
40
- }
41
-
42
- // Handle timeout errors
43
- if (
44
- 'name' in errorObj &&
45
- (errorObj.name === 'TimeoutError' ||
46
- errorObj.name === 'AbortError' ||
47
- (typeof errorObj.message === 'string' &&
48
- errorObj.message.toLowerCase().includes('timeout')))
49
- ) {
50
- return {
51
- success: false,
52
- error: {
53
- code: 'TIMEOUT_ERROR',
54
- description: 'Request timed out. Please try again.',
55
- },
56
- }
57
- }
58
-
59
- // Handle Razorpay error format: { error: { code: string, description: string } }
60
- if ('error' in errorObj) {
61
- const razorpayError = errorObj as {
62
- error?: { code?: string; description?: string; field?: string }
63
- }
64
- return {
65
- success: false,
66
- error: {
67
- code: razorpayError.error?.code || 'RAZORPAY_ERROR',
68
- description:
69
- razorpayError.error?.description ||
70
- razorpayError.error?.field
71
- ? `Razorpay error: ${razorpayError.error.field}`
72
- : 'Razorpay request failed',
73
- },
74
- }
75
- }
76
-
77
- // Handle standard error objects with message
78
- if ('message' in errorObj && typeof errorObj.message === 'string') {
79
- return {
80
- success: false,
81
- error: {
82
- code: 'UNKNOWN_ERROR',
83
- description: errorObj.message,
84
- },
85
- }
86
- }
87
- }
88
-
89
- // Fallback for unknown error types
90
- return {
91
- success: false,
92
- error: {
93
- code: 'UNKNOWN_ERROR',
94
- description: 'An unexpected error occurred. Please try again or contact support.',
95
- },
96
- }
97
- }
98
-
99
- export { handleRazorpayError }
package/lib/index.ts DELETED
@@ -1,28 +0,0 @@
1
- export { handleRazorpayError } from './error-handler'
2
- export {
3
- cancelSubscriptionSchema,
4
- createOrUpdateSubscriptionSchema,
5
- listSubscriptionsSchema,
6
- restoreSubscriptionSchema,
7
- subscribeSchema,
8
- verifyPaymentSchema,
9
- } from './schemas'
10
- export type { CreateOrUpdateSubscriptionInput } from './schemas'
11
- export type {
12
- OnWebhookEventCallback,
13
- PlanFreeTrial,
14
- PlanLimits,
15
- RazorpayApiResponse,
16
- RazorpayErrorResponse,
17
- RazorpayPlan,
18
- RazorpayPluginOptions,
19
- RazorpaySubscription,
20
- RazorpaySuccessResponse,
21
- RazorpayUserRecord,
22
- RazorpayWebhookContext,
23
- RazorpayWebhookEvent,
24
- RazorpayWebhookPayload,
25
- SubscriptionOptions,
26
- SubscriptionRecord,
27
- SubscriptionStatus,
28
- } from './types'
package/lib/schemas.ts DELETED
@@ -1,34 +0,0 @@
1
- import { z } from 'zod'
2
-
3
- export const createOrUpdateSubscriptionSchema = z.object({
4
- plan: z.string().min(1, 'Plan name is required'),
5
- annual: z.boolean().optional().default(false),
6
- seats: z.number().int().min(1).optional().default(1),
7
- subscriptionId: z.string().optional(),
8
- successUrl: z.string().url().optional(),
9
- disableRedirect: z.boolean().optional().default(false),
10
- })
11
-
12
- export const cancelSubscriptionSchema = z.object({
13
- subscriptionId: z.string().min(1, 'Subscription ID (local) is required'),
14
- immediately: z.boolean().optional().default(false),
15
- })
16
-
17
- export const restoreSubscriptionSchema = z.object({
18
- subscriptionId: z.string().min(1, 'Subscription ID (local) is required'),
19
- })
20
-
21
- export const listSubscriptionsSchema = z.object({
22
- referenceId: z.string().optional(),
23
- })
24
-
25
- export const verifyPaymentSchema = z.object({
26
- razorpay_payment_id: z.string().min(1, 'Payment ID is required'),
27
- razorpay_subscription_id: z.string().min(1, 'Subscription ID is required'),
28
- razorpay_signature: z.string().min(1, 'Signature is required'),
29
- })
30
-
31
- export {
32
- createOrUpdateSubscriptionSchema as subscribeSchema,
33
- }
34
- export type CreateOrUpdateSubscriptionInput = z.infer<typeof createOrUpdateSubscriptionSchema>