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
package/index.ts
ADDED
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import DodoPayments from 'dodopayments';
|
|
4
|
+
import { input, select } from '@inquirer/prompts';
|
|
5
|
+
import open from 'open';
|
|
6
|
+
import { CurrencyToSymbolMap } from './utils/currency-to-symbol-map';
|
|
7
|
+
import fs from 'node:fs';
|
|
8
|
+
|
|
9
|
+
// The below is used to check if the error is a Dodo Payments error or not in the API Request
|
|
10
|
+
type DodoPaymentsAPIError = {
|
|
11
|
+
error: {
|
|
12
|
+
code: 'NOT_FOUND';
|
|
13
|
+
message: string;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function isDodoPaymentsAPIError(e: unknown): e is DodoPaymentsAPIError {
|
|
18
|
+
return (
|
|
19
|
+
typeof e === "object" &&
|
|
20
|
+
e !== null &&
|
|
21
|
+
"error" in e &&
|
|
22
|
+
typeof (e as any).error?.code === "string"
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Function to add hyperlinked text
|
|
27
|
+
const link = (text: string, url: string) =>
|
|
28
|
+
`\u001b]8;;${url}\u001b\\${text}\u001b]8;;\u001b\\`;
|
|
29
|
+
|
|
30
|
+
// For help commands
|
|
31
|
+
const usage: {
|
|
32
|
+
[key: string]: {
|
|
33
|
+
command: string,
|
|
34
|
+
description: string
|
|
35
|
+
}[]
|
|
36
|
+
} = {
|
|
37
|
+
products: [
|
|
38
|
+
{ command: 'list', description: 'List your products' },
|
|
39
|
+
{ command: 'create', description: 'Create a new product' },
|
|
40
|
+
{ command: 'info', description: 'Get info about a product' }
|
|
41
|
+
],
|
|
42
|
+
payments: [
|
|
43
|
+
{ command: 'list', description: 'List your payments' },
|
|
44
|
+
{ command: 'info', description: 'Information about a payment' },
|
|
45
|
+
],
|
|
46
|
+
customers: [
|
|
47
|
+
{ command: 'list', description: 'List your customers' },
|
|
48
|
+
{ command: 'create', description: 'Create a customer' },
|
|
49
|
+
{ command: 'update', description: 'Update a customer' },
|
|
50
|
+
],
|
|
51
|
+
discounts: [
|
|
52
|
+
{ command: 'list', description: 'List your discounts' },
|
|
53
|
+
{ command: 'create', description: 'Create a discount' },
|
|
54
|
+
{ command: 'delete', description: 'Remove a discount' },
|
|
55
|
+
],
|
|
56
|
+
wh: [
|
|
57
|
+
{ command: '', description: 'Send a webhook event' },
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
const args = process.argv;
|
|
63
|
+
const category = args[2];
|
|
64
|
+
const subCommand = args[3];
|
|
65
|
+
const homedir = os.homedir();
|
|
66
|
+
|
|
67
|
+
// Added this to the top so that it can bypass all further auth that happens for the login route
|
|
68
|
+
if (category === 'login') {
|
|
69
|
+
open('https://app.dodopayments.com/developer/api-keys');
|
|
70
|
+
const API_KEY = await input({ message: 'Enter your Dodo Payments API Key:', required: true });
|
|
71
|
+
const MODE = await select({
|
|
72
|
+
choices: [{ name: "Test Mode", value: 'test_mode' }, { name: "Live Mode", value: 'live_mode' }],
|
|
73
|
+
message: 'Choose the environment:'
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Initialize the Dodo Payment client to test the API key
|
|
77
|
+
const newDodoClient = new DodoPayments({
|
|
78
|
+
bearerToken: API_KEY,
|
|
79
|
+
environment: (MODE as 'test_mode' | 'live_mode') // as 'test_mode' | 'live_mode' used to bypass ts error
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
console.log("Verifying Dodo Payments API Key");
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
// Make this request just to confirm whether API key is correct or not
|
|
86
|
+
await newDodoClient.products.list({ page_size: 1 });
|
|
87
|
+
console.log('Successfully verified your Dodo Payments API Key!');
|
|
88
|
+
} catch (err) {
|
|
89
|
+
console.log("Something went wrong while authenticating:", err);
|
|
90
|
+
process.exit(1);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
console.log("Storing / Updating existing configuration...")
|
|
95
|
+
let existingConfig;
|
|
96
|
+
try {
|
|
97
|
+
existingConfig = Object.create(JSON.parse(fs.readFileSync(path.join(homedir, '.dodopayments', 'api-key'), 'utf-8')));
|
|
98
|
+
} catch {
|
|
99
|
+
existingConfig = {};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
existingConfig[MODE] = API_KEY;
|
|
103
|
+
fs.writeFileSync(path.join(homedir, '.dodopayments', 'api-key'), JSON.stringify(existingConfig));
|
|
104
|
+
|
|
105
|
+
// Mode will always be either test_mode or live_mode
|
|
106
|
+
existingConfig[MODE] = API_KEY;
|
|
107
|
+
console.log("Setup complete successfully!");
|
|
108
|
+
process.exit(0);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Webhook is managed completely by another file
|
|
112
|
+
if (category === 'wh') {
|
|
113
|
+
await import('./dodo-webhooks/index.ts');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Normal functions which require the API key to be present start from here
|
|
117
|
+
// Authentication part
|
|
118
|
+
// Read the API key config
|
|
119
|
+
if (!fs.existsSync(path.join(homedir, '.dodopayments', 'api-key'))) {
|
|
120
|
+
console.log('Please login using `dodo login` command first!');
|
|
121
|
+
process.exit(0);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Parse the API key config
|
|
125
|
+
let existingAPIKeyConfigParsed;
|
|
126
|
+
try {
|
|
127
|
+
existingAPIKeyConfigParsed = JSON.parse(fs.readFileSync(path.join(homedir, '.dodopayments', 'api-key'), 'utf-8'));
|
|
128
|
+
} catch {
|
|
129
|
+
// Delete API config if something fails with parsing
|
|
130
|
+
fs.rmSync(path.join(homedir, '.dodopayments', 'api-key'), { force: true });
|
|
131
|
+
console.log("Failed to decode API Key configuration. Your config has been reset. Please log in again using `dodo login`");
|
|
132
|
+
process.exit(0);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
// Final variables
|
|
137
|
+
let API_KEY;
|
|
138
|
+
let MODE;
|
|
139
|
+
|
|
140
|
+
// Retrive the keys of the parsed API key config to auto determine the environment if possible.
|
|
141
|
+
const existingAPIKeyConfigParsedKeys = Object.keys(existingAPIKeyConfigParsed);
|
|
142
|
+
|
|
143
|
+
// If there is only one mode auth mehtod then
|
|
144
|
+
if (existingAPIKeyConfigParsedKeys.length === 1) {
|
|
145
|
+
MODE = existingAPIKeyConfigParsedKeys[0]
|
|
146
|
+
API_KEY = existingAPIKeyConfigParsed[MODE!];
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
// If there are multiple modes (i.e. both test mode & live mode) then prompt the user to select one environment to continue
|
|
150
|
+
MODE = await select({
|
|
151
|
+
choices: [{ name: "Test Mode", value: 'test_mode' }, { name: "Live Mode", value: 'live_mode' }],
|
|
152
|
+
message: 'Choose the environment:'
|
|
153
|
+
});
|
|
154
|
+
API_KEY = existingAPIKeyConfigParsed[MODE];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Initialize the Dodo Payments SDK to be used from now on
|
|
158
|
+
const DodoClient = new DodoPayments({
|
|
159
|
+
bearerToken: API_KEY,
|
|
160
|
+
environment: (MODE as 'test_mode' | 'live_mode') // as 'test_mode' | 'live_mode' used to bypass ts error
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// Continuation of other functions that require api key
|
|
164
|
+
if (category === 'products') {
|
|
165
|
+
if (subCommand === 'list') {
|
|
166
|
+
const page = await input({
|
|
167
|
+
message: 'Enter page:',
|
|
168
|
+
default: "1",
|
|
169
|
+
validate: (e => e.trim() !== '')
|
|
170
|
+
});
|
|
171
|
+
console.table((await DodoClient.products.list({ page_number: parseInt(page) - 1, page_size: 100 })).items, ['name', 'product_id', 'updated_at', 'price']);
|
|
172
|
+
} else if (subCommand === 'create') {
|
|
173
|
+
open('https://app.dodopayments.com/products/create');
|
|
174
|
+
} else if (subCommand === 'info') {
|
|
175
|
+
try {
|
|
176
|
+
const product_id = await input({
|
|
177
|
+
message: "Enter product ID:",
|
|
178
|
+
validate: (e => e.startsWith('pdt_') || 'Please enter a valid product ID!')
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
const info = await DodoClient.products.retrieve(product_id);
|
|
182
|
+
console.table({
|
|
183
|
+
product_id: info.product_id,
|
|
184
|
+
name: info.name,
|
|
185
|
+
description: info.description,
|
|
186
|
+
created_at: info.created_at,
|
|
187
|
+
...info.is_recurring ? {
|
|
188
|
+
price: `${CurrencyToSymbolMap[info.price.currency] || (info.price.currency + ' ')}${(info.price.price * 0.01).toFixed(2)}/${info.price.payment_frequency_interval}`,
|
|
189
|
+
} : {
|
|
190
|
+
price: `${CurrencyToSymbolMap[info.price.currency] || (info.price.currency + ' ')}${(info.price.price * 0.01).toFixed(2)} (One Time)`,
|
|
191
|
+
},
|
|
192
|
+
tax_category: info.tax_category,
|
|
193
|
+
edit_url: link('CTRL + Click to open', `https://app.dodopayments.com/products/edit?id=${info.product_id}`)
|
|
194
|
+
});
|
|
195
|
+
} catch (e) {
|
|
196
|
+
if (isDodoPaymentsAPIError(e) && e.error.code === "NOT_FOUND") {
|
|
197
|
+
console.log("Incorrect product ID!");
|
|
198
|
+
} else {
|
|
199
|
+
console.error(e);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
} else {
|
|
203
|
+
usage.products!.forEach(e => {
|
|
204
|
+
console.log(`dodo products ${e.command} - ${e.description}`)
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
} else if (category === 'payments') {
|
|
208
|
+
if (subCommand === 'list') {
|
|
209
|
+
const page = await input({
|
|
210
|
+
message: 'Enter page:',
|
|
211
|
+
default: "1",
|
|
212
|
+
validate: (e => e.trim() !== '')
|
|
213
|
+
});
|
|
214
|
+
const payments = (await DodoClient.payments.list({ page_number: parseInt(page) - 1, page_size: 100 })).items;
|
|
215
|
+
const paymentsTable = payments.map(payment => {
|
|
216
|
+
return {
|
|
217
|
+
'payment id': payment.payment_id,
|
|
218
|
+
'created at': new Date(payment.created_at).toLocaleString(),
|
|
219
|
+
'subscription id': payment.subscription_id,
|
|
220
|
+
'total amount': `${CurrencyToSymbolMap[payment.currency] || (payment.currency + ' ')}${(payment.total_amount * 0.01).toFixed(2)}`,
|
|
221
|
+
status: payment.status,
|
|
222
|
+
'more info': link('CTRL + Click to open', `https://app.dodopayments.com/transactions/payments/${payment.payment_id}`)
|
|
223
|
+
};
|
|
224
|
+
});
|
|
225
|
+
console.table(paymentsTable);
|
|
226
|
+
} else if (subCommand === 'info') {
|
|
227
|
+
try {
|
|
228
|
+
const payment_id = 'pay_0NWiGvZPWxeWeNWISbfat';
|
|
229
|
+
const payment_info = await DodoClient.payments.retrieve(payment_id);
|
|
230
|
+
console.log(payment_info);
|
|
231
|
+
const payment_table = {
|
|
232
|
+
'payment id': payment_info.payment_id,
|
|
233
|
+
status: payment_info.status,
|
|
234
|
+
'total amount': `${CurrencyToSymbolMap[payment_info.currency] || payment_info.currency + ' '}${(payment_info.total_amount * 0.01).toFixed(2)}`,
|
|
235
|
+
'payment method': payment_info.payment_method,
|
|
236
|
+
createdAt: new Date(payment_info.created_at).toLocaleString(),
|
|
237
|
+
customer: payment_info.customer.customer_id,
|
|
238
|
+
'customer email': payment_info.customer.email,
|
|
239
|
+
...payment_info.subscription_id && {
|
|
240
|
+
'subscription id': payment_info.subscription_id
|
|
241
|
+
},
|
|
242
|
+
'billing address street': `${payment_info.billing.street}`,
|
|
243
|
+
'billing address state': `${payment_info.billing.state}`,
|
|
244
|
+
'billing address city': `${payment_info.billing.city}`,
|
|
245
|
+
'billing address country': `${payment_info.billing.country}`,
|
|
246
|
+
'billing address zipcode': `${payment_info.billing.zipcode}`,
|
|
247
|
+
'more info': link('Ctrl + Click to open', `https://app.dodopayments.com/transactions/payments/${payment_info.payment_id}`)
|
|
248
|
+
}
|
|
249
|
+
console.table(payment_table);
|
|
250
|
+
} catch (e) {
|
|
251
|
+
if (isDodoPaymentsAPIError(e) && e.error.code === 'NOT_FOUND') {
|
|
252
|
+
console.log("Incorrect payment ID!")
|
|
253
|
+
} else {
|
|
254
|
+
console.error(e);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
} else {
|
|
258
|
+
usage.payments!.forEach(e => {
|
|
259
|
+
console.log(`dodo payments ${e.command} - ${e.description}`)
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
} else if (category === 'customers') {
|
|
263
|
+
if (subCommand === 'list') {
|
|
264
|
+
const page = await input({
|
|
265
|
+
message: 'Enter page:',
|
|
266
|
+
default: "1",
|
|
267
|
+
validate: (e => e.trim() !== '')
|
|
268
|
+
});
|
|
269
|
+
console.table((await DodoClient.customers.list({ page_number: parseInt(page) - 1, page_size: 100 })).items, ['customer_id', 'name', 'email', 'phone_number']);
|
|
270
|
+
} else if (subCommand === 'create') {
|
|
271
|
+
const name = await input({
|
|
272
|
+
message: "Enter Name: ",
|
|
273
|
+
validate: (e => e.trim() !== '')
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
const email = await input({
|
|
277
|
+
message: "Enter Email: ",
|
|
278
|
+
validate: (e => e.trim() !== '')
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
const phone = await input({
|
|
282
|
+
message: "Enter Phone Number: ",
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
const creation = await DodoClient.customers.create({
|
|
286
|
+
name,
|
|
287
|
+
email,
|
|
288
|
+
phone_number: phone.trim() !== '' ? phone : null
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
console.log('Customer Successfully Created!');
|
|
292
|
+
console.table([creation], ['customer_id', 'name', 'email', 'phone_number']);
|
|
293
|
+
} else if (subCommand === 'update') {
|
|
294
|
+
const customer_id = await input({
|
|
295
|
+
message: "Enter customer ID:",
|
|
296
|
+
validate: (e => e.startsWith('cus_') || 'Please enter a valid customer ID!')
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
try {
|
|
300
|
+
const existingInfo = await DodoClient.customers.retrieve(customer_id);
|
|
301
|
+
const name = await input({
|
|
302
|
+
message: "Enter customer name:",
|
|
303
|
+
default: existingInfo.name
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
const phone = await input({
|
|
307
|
+
message: "Enter customer phone:",
|
|
308
|
+
default: existingInfo.phone_number?.toString()
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
const updated = await DodoClient.customers.update(customer_id, {
|
|
312
|
+
name: name,
|
|
313
|
+
phone_number: phone.trim() !== '' ? phone : null
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
console.table([updated], ['customer_id', 'name', 'email', 'phone_number']);
|
|
317
|
+
} catch (e) {
|
|
318
|
+
if (isDodoPaymentsAPIError(e) && e.error.code === "NOT_FOUND") {
|
|
319
|
+
console.log("Incorrect customer ID!");
|
|
320
|
+
} else {
|
|
321
|
+
console.error(e);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
} else {
|
|
325
|
+
usage.products!.forEach(e => {
|
|
326
|
+
console.log(`dodo customers ${e.command} - ${e.description}`)
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
} else if (category === 'discounts') {
|
|
330
|
+
if (subCommand === 'list') {
|
|
331
|
+
const page = await input({
|
|
332
|
+
message: 'Enter page:',
|
|
333
|
+
default: "1",
|
|
334
|
+
validate: (e => e.trim() !== '')
|
|
335
|
+
});
|
|
336
|
+
const discounts = await DodoClient.discounts.list({ page_number: parseInt(page) - 1, page_size: 100 });
|
|
337
|
+
const discountsTable = discounts.items.map(e => (
|
|
338
|
+
{
|
|
339
|
+
name: e.name,
|
|
340
|
+
code: e.code,
|
|
341
|
+
'discount id': e.discount_id,
|
|
342
|
+
'created at': new Date(e.created_at).toLocaleString(),
|
|
343
|
+
...e.type === 'percentage' ? {
|
|
344
|
+
amount: `${(e.amount * 0.01).toFixed(2)}%`
|
|
345
|
+
} : {
|
|
346
|
+
// I just added this in case of a breaking change in the future
|
|
347
|
+
amount: e.amount
|
|
348
|
+
},
|
|
349
|
+
'more info': link('Ctrl + Click for more info', `https://app.dodopayments.com/sales/discounts/edit?id=${e.discount_id}`)
|
|
350
|
+
}
|
|
351
|
+
));
|
|
352
|
+
|
|
353
|
+
console.table(discountsTable);
|
|
354
|
+
} else if (subCommand === 'create') {
|
|
355
|
+
const name = await input({
|
|
356
|
+
message: "Enter discount name:",
|
|
357
|
+
validate: (e => e.trim() !== '')
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
const percentage = await input({
|
|
361
|
+
message: "Enter discount percentage:",
|
|
362
|
+
// Make sure user enters valid value
|
|
363
|
+
validate: (e => {
|
|
364
|
+
const parsed = parseFloat(e);
|
|
365
|
+
if (!Number.isNaN(parsed) && parsed > 0 && parsed <= 100) {
|
|
366
|
+
return true;
|
|
367
|
+
} else {
|
|
368
|
+
return false;
|
|
369
|
+
}
|
|
370
|
+
})
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
const code = await input({
|
|
374
|
+
message: "Enter discount code (Optional):"
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
const cycles = await input({
|
|
378
|
+
message: "Enter discount cycles (Optional):"
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
const newDiscount = await DodoClient.discounts.create({
|
|
382
|
+
name,
|
|
383
|
+
code: code.trim() !== '' ? code : null,
|
|
384
|
+
amount: parseFloat(percentage) * 100,
|
|
385
|
+
type: 'percentage',
|
|
386
|
+
// If the subscription cycles is provided
|
|
387
|
+
...cycles.trim() !== '' && {
|
|
388
|
+
subscription_cycles: parseInt(cycles)
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
console.log('Discount created successfully!');
|
|
393
|
+
console.table({
|
|
394
|
+
name: newDiscount.name,
|
|
395
|
+
code: newDiscount.code,
|
|
396
|
+
'discount id': newDiscount.discount_id,
|
|
397
|
+
...cycles.trim() !== '' && {
|
|
398
|
+
'subscription cycles': newDiscount.subscription_cycles
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
} else if (subCommand === 'delete') {
|
|
402
|
+
await DodoClient.discounts.delete(await input({
|
|
403
|
+
message: "Enter discount ID to be deleted:",
|
|
404
|
+
validate: (e => e.startsWith('dsc_'))
|
|
405
|
+
}));
|
|
406
|
+
|
|
407
|
+
console.log("Successfully deleted discount!");
|
|
408
|
+
} else {
|
|
409
|
+
usage.discounts!.forEach(e => {
|
|
410
|
+
console.log(`dodo discounts ${e.command} - ${e.description}`)
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
} else if (category === 'licences') {
|
|
414
|
+
if (subCommand === 'list') {
|
|
415
|
+
const page = await input({
|
|
416
|
+
message: 'Enter page:',
|
|
417
|
+
default: "1",
|
|
418
|
+
validate: (e => e.trim() !== '')
|
|
419
|
+
});
|
|
420
|
+
const licences = await DodoClient.licenseKeys.list({ page_number: parseInt(page) - 1, page_size: 100 });
|
|
421
|
+
console.log(licences.items);
|
|
422
|
+
} else {
|
|
423
|
+
usage.licences!.forEach(e => {
|
|
424
|
+
console.log(`dodo licences ${e.command} - ${e.description}`)
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
} else {
|
|
428
|
+
// List all available methods
|
|
429
|
+
// todo: Add more comments to make it clear what's being done
|
|
430
|
+
Object.keys(usage).forEach(e => {
|
|
431
|
+
console.log(`Category: ${e}`);
|
|
432
|
+
(usage as any)[e].forEach((y: { command: string, description: string }) => {
|
|
433
|
+
console.log(`dodo ${e} ${y.command} - ${y.description}`)
|
|
434
|
+
});
|
|
435
|
+
// Blank space as a separator
|
|
436
|
+
console.log("");
|
|
437
|
+
});
|
|
438
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dodopayments-cli",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "A CLI for Dodo Payments",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"dodopayments",
|
|
7
|
+
"cli"
|
|
8
|
+
],
|
|
9
|
+
"homepage": "https://github.com/dodopayments/dodopayments-cli#readme",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/dodopayments/dodopayments-cli/issues"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/dodopayments/dodopayments-cli.git"
|
|
16
|
+
},
|
|
17
|
+
"license": "ISC",
|
|
18
|
+
"author": "Dodo Payments",
|
|
19
|
+
"type": "module",
|
|
20
|
+
"main": "index.ts",
|
|
21
|
+
"bin": {
|
|
22
|
+
"dodo": "dist/index.js",
|
|
23
|
+
"dodopayments": "dist/index.js"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "bun build ./index.ts --minify --target node --outfile ./dist/index.js",
|
|
27
|
+
"build-native": "bun run build-binaries.ts"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"dodopayments": "^2.17.1",
|
|
31
|
+
"inquirer": "^13.2.1",
|
|
32
|
+
"open": "^11.0.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/bun": "latest"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"typescript": "^5.9.3"
|
|
39
|
+
},
|
|
40
|
+
"module": "index.ts"
|
|
41
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
// Environment setup & latest features
|
|
4
|
+
"lib": ["ESNext"],
|
|
5
|
+
"target": "ESNext",
|
|
6
|
+
"module": "Preserve",
|
|
7
|
+
"moduleDetection": "force",
|
|
8
|
+
"jsx": "react-jsx",
|
|
9
|
+
"allowJs": true,
|
|
10
|
+
|
|
11
|
+
// Bundler mode
|
|
12
|
+
"moduleResolution": "bundler",
|
|
13
|
+
"allowImportingTsExtensions": true,
|
|
14
|
+
"verbatimModuleSyntax": true,
|
|
15
|
+
"noEmit": true,
|
|
16
|
+
|
|
17
|
+
// Best practices
|
|
18
|
+
"strict": true,
|
|
19
|
+
"skipLibCheck": true,
|
|
20
|
+
"noFallthroughCasesInSwitch": true,
|
|
21
|
+
"noUncheckedIndexedAccess": true,
|
|
22
|
+
"noImplicitOverride": true,
|
|
23
|
+
|
|
24
|
+
// Some stricter flags (disabled by default)
|
|
25
|
+
"noUnusedLocals": false,
|
|
26
|
+
"noUnusedParameters": false,
|
|
27
|
+
"noPropertyAccessFromIndexSignature": false
|
|
28
|
+
}
|
|
29
|
+
}
|