dodopayments-cli 2.0.0

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.
@@ -0,0 +1,44 @@
1
+ import { type baseArgs } from "../types/baseArgs"
2
+
3
+ const genBaseRefundData = ({
4
+ business_id = 'bus_test'
5
+ }: baseArgs) => {
6
+ return {
7
+ "business_id": business_id,
8
+ "data": {
9
+ "amount": 400,
10
+ "business_id": business_id,
11
+ "created_at": new Date().toISOString(),
12
+ "currency": "USD",
13
+ "customer": {
14
+ "customer_id": "cus_test",
15
+ "email": "test@acme.com",
16
+ "name": "Test user",
17
+ "phone_number": null
18
+ },
19
+ "is_partial": false,
20
+ "payload_type": "Refund",
21
+ "payment_id": "pay_test",
22
+ "reason": "Testing success refund",
23
+ "refund_id": "ref_test",
24
+ "status": "succeeded"
25
+ },
26
+ "timestamp": new Date().toISOString(),
27
+ }
28
+ }
29
+
30
+ const genRefundSuccess = (args: baseArgs) => {
31
+ return {
32
+ ...genBaseRefundData(args),
33
+ "type": "refund.succeeded"
34
+ }
35
+ }
36
+
37
+ const genRefundFailed = (args: baseArgs) => {
38
+ return {
39
+ ...genBaseRefundData(args),
40
+ "type": "refund.failed"
41
+ }
42
+ }
43
+
44
+ export { genRefundSuccess, genRefundFailed }
@@ -0,0 +1,153 @@
1
+ import { type baseArgs } from '../types/baseArgs';
2
+
3
+ // For subscription data
4
+ const genBaseSubscriptionData = ({
5
+ business_id = 'bus_test',
6
+ product_id = 'pdt_test',
7
+ subscription_id = 'sub_test',
8
+ qty = 1,
9
+ metadata
10
+ }: baseArgs) => {
11
+ return {
12
+ "business_id": business_id,
13
+ "data": {
14
+ "addons": [],
15
+ "billing": {
16
+ "city": "New York",
17
+ "country": "US",
18
+ "state": "New York",
19
+ "street": "11th Main",
20
+ "zipcode": "12345"
21
+ },
22
+ "cancel_at_next_billing_date": false,
23
+ "cancelled_at": null,
24
+ "created_at": new Date().toISOString(),
25
+ "currency": "USD",
26
+ "customer": {
27
+ "customer_id": "cus_123456",
28
+ "email": "test@acme.com",
29
+ "name": "Test user",
30
+ "phone_number": null
31
+ },
32
+ "discount_cycles_remaining": null,
33
+ "discount_id": null,
34
+ "expires_at": null,
35
+ "metadata": metadata,
36
+ "meters": [],
37
+ "next_billing_date": new Date(new Date().setMonth(new Date().getMonth() + 1)),
38
+ "on_demand": false,
39
+ "payload_type": "Subscription",
40
+ "payment_frequency_count": 1,
41
+ "payment_frequency_interval": "Month",
42
+ "previous_billing_date": new Date().toISOString(),
43
+ "product_id": product_id,
44
+ "quantity": qty,
45
+ "recurring_pre_tax_amount": 400,
46
+ "status": "active",
47
+ "subscription_id": subscription_id,
48
+ "subscription_period_count": 10,
49
+ "subscription_period_interval": "Year",
50
+ "tax_inclusive": false,
51
+ "trial_period_days": 0
52
+ },
53
+ "timestamp": new Date().toISOString()
54
+ }
55
+ }
56
+
57
+ const genSubscriptionActive = (args: baseArgs) => {
58
+ return {
59
+ ...genBaseSubscriptionData(args),
60
+ "type": "subscription.active"
61
+ };
62
+ }
63
+
64
+ const genSubscriptionUpdated = (args: baseArgs) => {
65
+ const base = genBaseSubscriptionData(args);
66
+ return {
67
+ ...base,
68
+ "type": "subscription.updated",
69
+ data: {
70
+ ...base.data,
71
+ status: "active"
72
+ }
73
+ };
74
+ }
75
+
76
+ const genSubscriptionOnHold = (args: baseArgs) => {
77
+ const base = genBaseSubscriptionData(args);
78
+ return {
79
+ ...base,
80
+ "type": "subscription.on_hold",
81
+ data: {
82
+ ...base.data,
83
+ status: "on_hold"
84
+ }
85
+ };
86
+ }
87
+
88
+ const genSubscriptionRenewed = (args: baseArgs) => {
89
+ return {
90
+ ...genBaseSubscriptionData(args),
91
+ "type": "subscription.renewed"
92
+ };
93
+ }
94
+
95
+ const genSubscriptionPlanChanged = (args: baseArgs) => {
96
+ const base = genBaseSubscriptionData(args);
97
+ return {
98
+ ...base,
99
+ "type": "subscription.plan_changed",
100
+ data: {
101
+ ...base.data,
102
+ status: "active"
103
+ }
104
+ };
105
+ }
106
+
107
+ const genSubscriptionCancelled = (args: baseArgs) => {
108
+ const base = genBaseSubscriptionData(args);
109
+ return {
110
+ ...base,
111
+ "type": "subscription.cancelled",
112
+ data: {
113
+ ...base.data,
114
+ cancel_at_next_billing_date: true,
115
+ status: 'cancelled'
116
+ }
117
+ };
118
+ }
119
+
120
+ const genSubscriptionFailed = (args: baseArgs) => {
121
+ const base = genBaseSubscriptionData(args);
122
+ return {
123
+ ...base,
124
+ "type": "subscription.failed",
125
+ data: {
126
+ ...base.data,
127
+ status: "failed"
128
+ }
129
+ };
130
+ }
131
+
132
+ const genSubscriptionExpired = (args: baseArgs) => {
133
+ const base = genBaseSubscriptionData(args);
134
+ return {
135
+ ...base,
136
+ "type": "subscription.expired",
137
+ data: {
138
+ ...base.data,
139
+ status: "expired"
140
+ }
141
+ };
142
+ }
143
+
144
+ export {
145
+ genSubscriptionActive,
146
+ genSubscriptionUpdated,
147
+ genSubscriptionOnHold,
148
+ genSubscriptionRenewed,
149
+ genSubscriptionPlanChanged,
150
+ genSubscriptionCancelled,
151
+ genSubscriptionFailed,
152
+ genSubscriptionExpired
153
+ };
@@ -0,0 +1,24 @@
1
+ export const supportedEvents: string[] = [
2
+ "subscription.active",
3
+ "subscription.updated",
4
+ "subscription.on_hold",
5
+ "subscription.renewed",
6
+ "subscription.plan_changed",
7
+ "subscription.cancelled",
8
+ "subscription.failed",
9
+ "subscription.expired",
10
+ "payment.success",
11
+ "payment.failed",
12
+ "payment.processing",
13
+ "payment.cancelled",
14
+ "licence.created",
15
+ "refund.success",
16
+ "refund.failed",
17
+ "dispute.opened",
18
+ "dispute.expired",
19
+ "dispute.accepted",
20
+ "dispute.cancelled",
21
+ "dispute.challenged",
22
+ "dispute.won",
23
+ "dispute.lost"
24
+ ];
@@ -0,0 +1,207 @@
1
+ import { input, password as passwordPrompt, select } from '@inquirer/prompts';
2
+ import { supportedEvents } from './functions/supported-events';
3
+
4
+ // Subscription Events
5
+ import {
6
+ genSubscriptionActive,
7
+ genSubscriptionUpdated,
8
+ genSubscriptionOnHold,
9
+ genSubscriptionRenewed,
10
+ genSubscriptionPlanChanged,
11
+ genSubscriptionCancelled,
12
+ genSubscriptionFailed,
13
+ genSubscriptionExpired
14
+ } from './functions/generate-subscription-data';
15
+
16
+ // Payment events
17
+ import {
18
+ genPaymentSuccess,
19
+ genPaymentFailed,
20
+ genPaymentProcessing,
21
+ genPaymentCancelled
22
+ } from './functions/generate-payment-data';
23
+
24
+ // Refund events
25
+ import {
26
+ genRefundSuccess,
27
+ genRefundFailed
28
+ } from './functions/generate-refund-data';
29
+
30
+ // Dispute events
31
+ import {
32
+ genDisputeOpened,
33
+ genDisputeExpired,
34
+ genDisputeAccepted,
35
+ genDisputeCancelled,
36
+ genDisputeChallenged,
37
+ genDisputeWon,
38
+ genDisputeLost
39
+ } from './functions/generate-dispute-data';
40
+
41
+ // Licence events
42
+ import {
43
+ genLicenceCreated
44
+ } from './functions/generate-licence-data';
45
+
46
+ const endpoint = await input({
47
+ message: 'What is your endpoint?',
48
+ validate: (input) => {
49
+ if (!input.startsWith('http')) {
50
+ return 'Please enter a valid URL starting with http or https';
51
+ }
52
+ return true;
53
+ }
54
+ });
55
+
56
+ // const webhook_secret = await passwordPrompt({
57
+ // message: 'What is your Dodo Payments webhook secret? (Optional)',
58
+ // mask: true
59
+ // });
60
+
61
+ const business_id = await input({
62
+ message: 'What is your Dodo Payments business ID? (Optional)',
63
+ default: 'bus_test'
64
+ });
65
+
66
+ const product_id = await input({
67
+ message: 'What is your product ID? (Optional)',
68
+ default: 'pdt_test'
69
+ });
70
+
71
+ const metadata = await input({
72
+ message: 'What is your metadata? (JSON stringified, Optional)',
73
+ default: '{}'
74
+ });
75
+
76
+ while (true) {
77
+ const event = await select({
78
+ message: 'Select an event to send:',
79
+ choices: [...supportedEvents, 'exit'].map(e => ({ value: e, name: e })),
80
+ loop: false,
81
+ });
82
+
83
+ if (event === 'exit') {
84
+ console.log('Exiting...');
85
+ process.exit();
86
+ }
87
+
88
+ let data;
89
+ const metadataParsed: { [key: string]: string } = JSON.parse(metadata);
90
+
91
+ // Parameters based on subscription event
92
+ if (event.startsWith('subscription.')) {
93
+ const params = {
94
+ business_id,
95
+ product_id,
96
+ metadata: metadataParsed
97
+ };
98
+
99
+ if (event === 'subscription.active') {
100
+ data = genSubscriptionActive(params);
101
+ } else if (event === 'subscription.updated') {
102
+ data = genSubscriptionUpdated(params);
103
+ } else if (event === 'subscription.on_hold') {
104
+ data = genSubscriptionOnHold(params);
105
+ } else if (event === 'subscription.renewed') {
106
+ data = genSubscriptionRenewed(params);
107
+ } else if (event === 'subscription.plan_changed') {
108
+ data = genSubscriptionPlanChanged(params);
109
+ } else if (event === 'subscription.cancelled') {
110
+ data = genSubscriptionCancelled(params);
111
+ } else if (event === 'subscription.failed') {
112
+ data = genSubscriptionFailed(params);
113
+ } else if (event === 'subscription.expired') {
114
+ data = genSubscriptionExpired(params);
115
+ }
116
+ }
117
+
118
+ // Parameters based on payment event
119
+ if (event.startsWith('payment.')) {
120
+ const params = {
121
+ business_id,
122
+ product_id,
123
+ metadata: metadataParsed
124
+ };
125
+
126
+ if (event === 'payment.success') {
127
+ data = genPaymentSuccess(params);
128
+ } else if (event === 'payment.failed') {
129
+ data = genPaymentFailed(params);
130
+ } else if (event === 'payment.processing') {
131
+ data = genPaymentProcessing(params);
132
+ } else if (event === 'payment.cancelled') {
133
+ data = genPaymentCancelled(params);
134
+ }
135
+ }
136
+
137
+ // Parameters based on refund event
138
+ if (event.startsWith('refund.')) {
139
+ const params = {
140
+ business_id
141
+ };
142
+
143
+ if (event === 'refund.success') {
144
+ data = genRefundSuccess(params);
145
+ } else if (event === 'refund.failed') {
146
+ data = genRefundFailed(params);
147
+ }
148
+ }
149
+
150
+ // Parameters based on dispute event
151
+ if (event.startsWith('dispute.')) {
152
+ const params = {
153
+ business_id
154
+ };
155
+
156
+ if (event === 'dispute.opened') {
157
+ data = genDisputeOpened(params);
158
+ } else if (event === 'dispute.expired') {
159
+ data = genDisputeExpired(params);
160
+ } else if (event === 'dispute.accepted') {
161
+ data = genDisputeAccepted(params);
162
+ } else if (event === 'dispute.cancelled') {
163
+ data = genDisputeCancelled(params);
164
+ } else if (event === 'dispute.challenged') {
165
+ data = genDisputeChallenged(params);
166
+ } else if (event === 'dispute.won') {
167
+ data = genDisputeWon(params);
168
+ } else if (event === 'dispute.lost') {
169
+ data = genDisputeLost(params);
170
+ }
171
+ }
172
+
173
+ // Parameters based on licence event
174
+ if (event.startsWith('licence.')) {
175
+ const params = {
176
+ business_id,
177
+ product_id
178
+ };
179
+
180
+ if (event === 'licence.created') {
181
+ data = genLicenceCreated(params);
182
+ }
183
+ }
184
+
185
+ // const timestamp = new Date();
186
+ // const webhookId = crypto.randomUUID();
187
+ // const webhookInstance = new Webhook(webhook_secret);
188
+ // const payloadString = JSON.stringify(data);
189
+ // const signature = webhookInstance.sign(webhookId, timestamp, payloadString);
190
+
191
+ await fetch(endpoint, {
192
+ method: 'POST',
193
+ headers: {
194
+ 'Content-Type': 'application/json',
195
+ // "webhook-id": webhookId,
196
+ // "webhook-timestamp": Math.floor(timestamp.getTime() / 1000).toString(),
197
+ // "webhook-signature": signature,
198
+ },
199
+ body: JSON.stringify(data)
200
+ }).then(async res => {
201
+ console.log(`✅ Webhook Event Sent!\nReceived Response Code: ${res.status}\nReceived Response Body: ${await res.text()}`);
202
+ console.log();
203
+ }).catch(error => {
204
+ console.error('❌ Webhook Event Failed:', error);
205
+ console.log();
206
+ });
207
+ }
@@ -0,0 +1,9 @@
1
+ export type baseArgs = {
2
+ business_id?: string,
3
+ subscription_id?: string,
4
+ product_id?: string,
5
+ qty?: number,
6
+ metadata?: {
7
+ [key: string]: string
8
+ }
9
+ }