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.
- package/.github/ISSUE_TEMPLATE/bug_report.yml +125 -0
- package/.github/ISSUE_TEMPLATE/config.yml +11 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +88 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +69 -0
- package/.github/workflows/publish.yml +63 -0
- package/CODE_OF_CONDUCT.md +133 -0
- package/CONTRIBUTING.md +200 -0
- package/LICENSE +21 -0
- package/README.md +185 -0
- package/SECURITY.md +98 -0
- package/build-binaries.ts +22 -0
- package/dist/index.js +28 -0
- package/dodo-webhooks/functions/generate-dispute-data.ts +123 -0
- package/dodo-webhooks/functions/generate-licence-data.ts +39 -0
- package/dodo-webhooks/functions/generate-payment-data.ts +101 -0
- package/dodo-webhooks/functions/generate-refund-data.ts +44 -0
- package/dodo-webhooks/functions/generate-subscription-data.ts +153 -0
- package/dodo-webhooks/functions/supported-events.ts +24 -0
- package/dodo-webhooks/index.ts +207 -0
- package/dodo-webhooks/types/baseArgs.ts +9 -0
- package/index.ts +438 -0
- package/package.json +41 -0
- package/tsconfig.json +29 -0
- package/utils/currency-to-symbol-map.ts +8 -0
|
@@ -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
|
+
}
|