@tarout/cli 0.2.1 → 0.2.2
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/dist/{api-SHKZO2SZ.js → api-735LN7BA.js} +2 -2
- package/dist/{billing-ENTHZKID.js → billing-WOKNOS4N.js} +4 -4
- package/dist/{chunk-XSJKHLNL.js → chunk-5XBVQICT.js} +113 -14
- package/dist/{chunk-FKX4CRPL.js → chunk-7YS2WBLB.js} +1 -1
- package/dist/chunk-CJMIX35A.js +127 -0
- package/dist/{chunk-FS74WWHV.js → chunk-KL3JNPAY.js} +7 -2
- package/dist/index.js +1220 -303
- package/dist/{prompts-WNFR34TG.js → prompts-QQ2FZKQT.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-J3H7LTFT.js +0 -68
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
pollCheckoutUntilTerminal,
|
|
3
3
|
registerBillingCommands
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-5XBVQICT.js";
|
|
5
|
+
import "./chunk-7YS2WBLB.js";
|
|
6
|
+
import "./chunk-CJMIX35A.js";
|
|
7
|
+
import "./chunk-KL3JNPAY.js";
|
|
8
8
|
export {
|
|
9
9
|
pollCheckoutUntilTerminal,
|
|
10
10
|
registerBillingCommands
|
|
@@ -3,11 +3,11 @@ import {
|
|
|
3
3
|
getApiClient,
|
|
4
4
|
handleError,
|
|
5
5
|
isLoggedIn
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-7YS2WBLB.js";
|
|
7
7
|
import {
|
|
8
8
|
confirm,
|
|
9
9
|
select
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-CJMIX35A.js";
|
|
11
11
|
import {
|
|
12
12
|
ExitCode,
|
|
13
13
|
box,
|
|
@@ -20,9 +20,10 @@ import {
|
|
|
20
20
|
outputJsonLine,
|
|
21
21
|
shouldSkipConfirmation,
|
|
22
22
|
table
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-KL3JNPAY.js";
|
|
24
24
|
|
|
25
25
|
// src/commands/billing.ts
|
|
26
|
+
import { InvalidArgumentError } from "commander";
|
|
26
27
|
import open from "open";
|
|
27
28
|
|
|
28
29
|
// src/utils/spinner.ts
|
|
@@ -153,10 +154,22 @@ function registerBillingCommands(program) {
|
|
|
153
154
|
handleError(err);
|
|
154
155
|
}
|
|
155
156
|
});
|
|
156
|
-
billing.command("upgrade").argument("[plan]", "Plan key to switch to").description("Upgrade or change subscription plan").option(
|
|
157
|
+
billing.command("upgrade").argument("[plan]", "Plan key to switch to (alias: --plan)").description("Upgrade or change subscription plan").option(
|
|
158
|
+
"--plan <key>",
|
|
159
|
+
"Plan key (alias for the positional argument; useful for agent invocations)"
|
|
160
|
+
).option(
|
|
157
161
|
"-q, --quantity <n>",
|
|
158
162
|
"Plan quantity (for multi-slot plans)",
|
|
159
163
|
Number.parseInt
|
|
164
|
+
).option(
|
|
165
|
+
"--billing-period <period>",
|
|
166
|
+
"Billing period: monthly or yearly (yearly = 10\xD7 monthly, 2 months free)",
|
|
167
|
+
parseBillingPeriod
|
|
168
|
+
).option(
|
|
169
|
+
"--addon <key[:qty]>",
|
|
170
|
+
"Bundled addon to purchase with the plan change (repeatable, e.g. --addon db.standard:2)",
|
|
171
|
+
collectAddon,
|
|
172
|
+
[]
|
|
160
173
|
).option(
|
|
161
174
|
"-w, --wait",
|
|
162
175
|
"After hosted-checkout opens, poll status until the payment is confirmed"
|
|
@@ -172,7 +185,9 @@ function registerBillingCommands(program) {
|
|
|
172
185
|
try {
|
|
173
186
|
if (!isLoggedIn()) throw new AuthError();
|
|
174
187
|
const client = getApiClient();
|
|
175
|
-
let targetPlan = planKey;
|
|
188
|
+
let targetPlan = planKey || options.plan;
|
|
189
|
+
const billingPeriod = options.billingPeriod;
|
|
190
|
+
const addons = Array.isArray(options.addon) && options.addon.length > 0 ? options.addon : void 0;
|
|
176
191
|
if (!targetPlan) {
|
|
177
192
|
const _spinner = startSpinner("Fetching plans...");
|
|
178
193
|
const catalog = await client.subscription.getCatalog.query();
|
|
@@ -187,15 +202,30 @@ function registerBillingCommands(program) {
|
|
|
187
202
|
plans.map((p) => ({
|
|
188
203
|
name: `${p.planKey || p.key || p.name} ${p.priceHalalas ? `(${(p.priceHalalas / 100).toFixed(2)} SAR/mo)` : "(Free)"}`,
|
|
189
204
|
value: p.planKey || p.key || p.name
|
|
190
|
-
}))
|
|
205
|
+
})),
|
|
206
|
+
{
|
|
207
|
+
field: "plan",
|
|
208
|
+
flag: "--plan",
|
|
209
|
+
context: {
|
|
210
|
+
available: plans.map((p) => ({
|
|
211
|
+
key: p.planKey || p.key || p.name,
|
|
212
|
+
priceHalalas: p.priceHalalas ?? 0
|
|
213
|
+
}))
|
|
214
|
+
}
|
|
215
|
+
}
|
|
191
216
|
);
|
|
192
217
|
}
|
|
218
|
+
if (!targetPlan) {
|
|
219
|
+
throw new Error("No plan selected");
|
|
220
|
+
}
|
|
193
221
|
const _previewSpinner = startSpinner("Calculating change...");
|
|
194
222
|
let preview;
|
|
195
223
|
try {
|
|
196
224
|
preview = await client.subscription.previewPlanChange.query({
|
|
197
225
|
planKey: targetPlan,
|
|
198
|
-
planQuantity: options.quantity
|
|
226
|
+
planQuantity: options.quantity,
|
|
227
|
+
billingPeriod,
|
|
228
|
+
addons
|
|
199
229
|
});
|
|
200
230
|
succeedSpinner();
|
|
201
231
|
} catch {
|
|
@@ -206,6 +236,12 @@ function registerBillingCommands(program) {
|
|
|
206
236
|
log("");
|
|
207
237
|
log(`Plan: ${colors.cyan(targetPlan)}`);
|
|
208
238
|
if (options.quantity) log(`Quantity: ${options.quantity}`);
|
|
239
|
+
if (billingPeriod) log(`Billing period: ${billingPeriod}`);
|
|
240
|
+
if (addons && addons.length > 0) {
|
|
241
|
+
log(
|
|
242
|
+
`Addons: ${addons.map((a) => `${a.addonKey}\xD7${a.quantity}`).join(", ")}`
|
|
243
|
+
);
|
|
244
|
+
}
|
|
209
245
|
if (preview?.amountDue !== void 0) {
|
|
210
246
|
log(
|
|
211
247
|
`Amount due now: ${colors.bold(`${(preview.amountDue / 100).toFixed(2)} SAR`)}`
|
|
@@ -214,7 +250,18 @@ function registerBillingCommands(program) {
|
|
|
214
250
|
log("");
|
|
215
251
|
const confirmed = await confirm(
|
|
216
252
|
`Switch to plan "${targetPlan}"?`,
|
|
217
|
-
false
|
|
253
|
+
false,
|
|
254
|
+
{
|
|
255
|
+
field: "confirm_upgrade",
|
|
256
|
+
flag: "--yes",
|
|
257
|
+
context: {
|
|
258
|
+
plan: targetPlan,
|
|
259
|
+
quantity: options.quantity,
|
|
260
|
+
billingPeriod,
|
|
261
|
+
addons,
|
|
262
|
+
amountDueHalalas: preview?.amountDue
|
|
263
|
+
}
|
|
264
|
+
}
|
|
218
265
|
);
|
|
219
266
|
if (!confirmed) {
|
|
220
267
|
log("Cancelled.");
|
|
@@ -224,7 +271,9 @@ function registerBillingCommands(program) {
|
|
|
224
271
|
const _changeSpinner = startSpinner("Changing plan...");
|
|
225
272
|
const result = await client.subscription.changePlan.mutate({
|
|
226
273
|
planKey: targetPlan,
|
|
227
|
-
planQuantity: options.quantity
|
|
274
|
+
planQuantity: options.quantity,
|
|
275
|
+
billingPeriod,
|
|
276
|
+
addons
|
|
228
277
|
});
|
|
229
278
|
succeedSpinner("Plan changed!");
|
|
230
279
|
if (result?.applied) {
|
|
@@ -369,6 +418,14 @@ function registerBillingCommands(program) {
|
|
|
369
418
|
try {
|
|
370
419
|
if (!isLoggedIn()) throw new AuthError();
|
|
371
420
|
const client = getApiClient();
|
|
421
|
+
if (isJsonMode()) {
|
|
422
|
+
outputJsonLine({
|
|
423
|
+
type: "event",
|
|
424
|
+
event: "checkout_polling_started",
|
|
425
|
+
orderId,
|
|
426
|
+
timeoutSeconds: options.timeout
|
|
427
|
+
});
|
|
428
|
+
}
|
|
372
429
|
const final = await pollCheckoutUntilTerminal(client, orderId, {
|
|
373
430
|
timeoutMs: options.timeout * 1e3,
|
|
374
431
|
intervalMs: 4e3
|
|
@@ -414,7 +471,8 @@ function registerBillingCommands(program) {
|
|
|
414
471
|
log("");
|
|
415
472
|
const confirmed = await confirm(
|
|
416
473
|
"Are you sure you want to cancel your subscription?",
|
|
417
|
-
false
|
|
474
|
+
false,
|
|
475
|
+
{ field: "confirm_cancel", flag: "--yes" }
|
|
418
476
|
);
|
|
419
477
|
if (!confirmed) {
|
|
420
478
|
log("Cancelled.");
|
|
@@ -472,7 +530,12 @@ function registerBillingCommands(program) {
|
|
|
472
530
|
log("");
|
|
473
531
|
const confirmed = await confirm(
|
|
474
532
|
`Add addon "${addonKey}" \xD7 ${quantity}?`,
|
|
475
|
-
false
|
|
533
|
+
false,
|
|
534
|
+
{
|
|
535
|
+
field: "confirm_addon_add",
|
|
536
|
+
flag: "--yes",
|
|
537
|
+
context: { addonKey, quantity }
|
|
538
|
+
}
|
|
476
539
|
);
|
|
477
540
|
if (!confirmed) {
|
|
478
541
|
log("Cancelled.");
|
|
@@ -503,7 +566,15 @@ function registerBillingCommands(program) {
|
|
|
503
566
|
try {
|
|
504
567
|
if (!isLoggedIn()) throw new AuthError();
|
|
505
568
|
if (!shouldSkipConfirmation()) {
|
|
506
|
-
const confirmed = await confirm(
|
|
569
|
+
const confirmed = await confirm(
|
|
570
|
+
`Remove addon "${addonKey}"?`,
|
|
571
|
+
false,
|
|
572
|
+
{
|
|
573
|
+
field: "confirm_addon_remove",
|
|
574
|
+
flag: "--yes",
|
|
575
|
+
context: { addonKey }
|
|
576
|
+
}
|
|
577
|
+
);
|
|
507
578
|
if (!confirmed) {
|
|
508
579
|
log("Cancelled.");
|
|
509
580
|
return;
|
|
@@ -584,7 +655,11 @@ function registerBillingCommands(program) {
|
|
|
584
655
|
if (!shouldSkipConfirmation()) {
|
|
585
656
|
log(`
|
|
586
657
|
Purchase ${quantity}\xD7 ${colors.cyan(addonKey)}?`);
|
|
587
|
-
const confirmed = await confirm("Proceed?", false
|
|
658
|
+
const confirmed = await confirm("Proceed?", false, {
|
|
659
|
+
field: "confirm_addon_buy",
|
|
660
|
+
flag: "--yes",
|
|
661
|
+
context: { addonKey, quantity }
|
|
662
|
+
});
|
|
588
663
|
if (!confirmed) {
|
|
589
664
|
log("Cancelled.");
|
|
590
665
|
return;
|
|
@@ -614,7 +689,8 @@ Payment required: ${colors.cyan(result.paymentUrl)}
|
|
|
614
689
|
if (!shouldSkipConfirmation()) {
|
|
615
690
|
const confirmed = await confirm(
|
|
616
691
|
"Cancel the pending plan change?",
|
|
617
|
-
false
|
|
692
|
+
false,
|
|
693
|
+
{ field: "confirm_pending_cancel", flag: "--yes" }
|
|
618
694
|
);
|
|
619
695
|
if (!confirmed) {
|
|
620
696
|
log("Cancelled.");
|
|
@@ -867,6 +943,29 @@ async function pollCheckoutUntilTerminal(client, orderId, opts) {
|
|
|
867
943
|
failureReason: r.failureReason
|
|
868
944
|
};
|
|
869
945
|
}
|
|
946
|
+
function collectAddon(value, previous) {
|
|
947
|
+
const [rawKey, rawQty] = value.split(":");
|
|
948
|
+
const addonKey = (rawKey || "").trim();
|
|
949
|
+
if (!addonKey) {
|
|
950
|
+
throw new InvalidArgumentError(
|
|
951
|
+
`Invalid --addon value "${value}". Expected key[:qty] (e.g. db.standard:2).`
|
|
952
|
+
);
|
|
953
|
+
}
|
|
954
|
+
const quantity = rawQty === void 0 ? 1 : Number.parseInt(rawQty, 10);
|
|
955
|
+
if (!Number.isFinite(quantity) || quantity <= 0) {
|
|
956
|
+
throw new InvalidArgumentError(
|
|
957
|
+
`Invalid --addon quantity in "${value}". Expected a positive integer.`
|
|
958
|
+
);
|
|
959
|
+
}
|
|
960
|
+
return [...previous, { addonKey, quantity }];
|
|
961
|
+
}
|
|
962
|
+
function parseBillingPeriod(raw) {
|
|
963
|
+
const v = raw.toLowerCase();
|
|
964
|
+
if (v === "monthly" || v === "yearly") return v;
|
|
965
|
+
throw new InvalidArgumentError(
|
|
966
|
+
`Invalid --billing-period "${raw}". Expected "monthly" or "yearly".`
|
|
967
|
+
);
|
|
968
|
+
}
|
|
870
969
|
function formatSubStatus(status) {
|
|
871
970
|
const map = {
|
|
872
971
|
active: colors.success("active"),
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ExitCode,
|
|
3
|
+
exit,
|
|
4
|
+
isJsonMode,
|
|
5
|
+
isNonInteractiveMode,
|
|
6
|
+
outputNeedsInput
|
|
7
|
+
} from "./chunk-KL3JNPAY.js";
|
|
8
|
+
|
|
9
|
+
// src/utils/prompts.ts
|
|
10
|
+
import inquirer from "inquirer";
|
|
11
|
+
function emitNeedsInputAndExit(descriptor, rest) {
|
|
12
|
+
outputNeedsInput({ ...descriptor, ...rest });
|
|
13
|
+
exit(ExitCode.NEEDS_INPUT);
|
|
14
|
+
}
|
|
15
|
+
function shouldEmitNeedsInput() {
|
|
16
|
+
return isJsonMode() || isNonInteractiveMode();
|
|
17
|
+
}
|
|
18
|
+
function emitUnannotatedPromptError(kind, question) {
|
|
19
|
+
outputNeedsInput({
|
|
20
|
+
field: "unannotated_prompt",
|
|
21
|
+
kind,
|
|
22
|
+
question,
|
|
23
|
+
flag: "--yes",
|
|
24
|
+
context: {
|
|
25
|
+
hint: "This prompt site does not yet expose a CLI flag. Re-invoke with --yes (for confirms) or provide the value as a positional/flag argument, or file an issue to ask for explicit flag support for this command."
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
exit(ExitCode.NEEDS_INPUT);
|
|
29
|
+
}
|
|
30
|
+
async function confirm(message, defaultValue = false, descriptor) {
|
|
31
|
+
if (descriptor && shouldEmitNeedsInput()) {
|
|
32
|
+
emitNeedsInputAndExit(descriptor, {
|
|
33
|
+
kind: "confirm",
|
|
34
|
+
question: message,
|
|
35
|
+
default: defaultValue
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
if (!descriptor && shouldEmitNeedsInput()) {
|
|
39
|
+
emitUnannotatedPromptError("confirm", message);
|
|
40
|
+
}
|
|
41
|
+
const { confirmed } = await inquirer.prompt([
|
|
42
|
+
{
|
|
43
|
+
type: "confirm",
|
|
44
|
+
name: "confirmed",
|
|
45
|
+
message,
|
|
46
|
+
default: defaultValue
|
|
47
|
+
}
|
|
48
|
+
]);
|
|
49
|
+
return confirmed;
|
|
50
|
+
}
|
|
51
|
+
async function input(message, defaultValue, descriptor) {
|
|
52
|
+
if (descriptor && shouldEmitNeedsInput()) {
|
|
53
|
+
emitNeedsInputAndExit(descriptor, {
|
|
54
|
+
kind: "input",
|
|
55
|
+
question: message,
|
|
56
|
+
default: defaultValue
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
if (!descriptor && shouldEmitNeedsInput()) {
|
|
60
|
+
emitUnannotatedPromptError("input", message);
|
|
61
|
+
}
|
|
62
|
+
const { value } = await inquirer.prompt([
|
|
63
|
+
{
|
|
64
|
+
type: "input",
|
|
65
|
+
name: "value",
|
|
66
|
+
message,
|
|
67
|
+
default: defaultValue
|
|
68
|
+
}
|
|
69
|
+
]);
|
|
70
|
+
return value;
|
|
71
|
+
}
|
|
72
|
+
async function select(message, choices, descriptor) {
|
|
73
|
+
if (descriptor && shouldEmitNeedsInput()) {
|
|
74
|
+
emitNeedsInputAndExit(descriptor, {
|
|
75
|
+
kind: "select",
|
|
76
|
+
question: message,
|
|
77
|
+
choices: choices.map((c) => ({ label: c.name, value: c.value }))
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
if (!descriptor && shouldEmitNeedsInput()) {
|
|
81
|
+
emitUnannotatedPromptError("select", message);
|
|
82
|
+
}
|
|
83
|
+
const { value } = await inquirer.prompt([
|
|
84
|
+
{
|
|
85
|
+
type: "list",
|
|
86
|
+
name: "value",
|
|
87
|
+
message,
|
|
88
|
+
choices
|
|
89
|
+
}
|
|
90
|
+
]);
|
|
91
|
+
return value;
|
|
92
|
+
}
|
|
93
|
+
async function password(message, descriptor) {
|
|
94
|
+
if (descriptor && shouldEmitNeedsInput()) {
|
|
95
|
+
emitNeedsInputAndExit(
|
|
96
|
+
{ ...descriptor, sensitive: true },
|
|
97
|
+
{ kind: "password", question: message }
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
if (!descriptor && shouldEmitNeedsInput()) {
|
|
101
|
+
emitUnannotatedPromptError("password", message);
|
|
102
|
+
}
|
|
103
|
+
const { value } = await inquirer.prompt([
|
|
104
|
+
{
|
|
105
|
+
type: "password",
|
|
106
|
+
name: "value",
|
|
107
|
+
message,
|
|
108
|
+
mask: "*"
|
|
109
|
+
}
|
|
110
|
+
]);
|
|
111
|
+
return value;
|
|
112
|
+
}
|
|
113
|
+
async function promptOrEmit(req, fallback) {
|
|
114
|
+
if (shouldEmitNeedsInput()) {
|
|
115
|
+
outputNeedsInput(req);
|
|
116
|
+
exit(ExitCode.NEEDS_INPUT);
|
|
117
|
+
}
|
|
118
|
+
return fallback();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export {
|
|
122
|
+
confirm,
|
|
123
|
+
input,
|
|
124
|
+
select,
|
|
125
|
+
password,
|
|
126
|
+
promptOrEmit
|
|
127
|
+
};
|
|
@@ -43,7 +43,7 @@ function jsonError(code, message, suggestions, details) {
|
|
|
43
43
|
};
|
|
44
44
|
}
|
|
45
45
|
function outputJson(response) {
|
|
46
|
-
console.log(JSON.stringify(response
|
|
46
|
+
console.log(JSON.stringify(response));
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
// src/lib/output.ts
|
|
@@ -52,7 +52,8 @@ var globalOptions = {
|
|
|
52
52
|
quiet: false,
|
|
53
53
|
verbose: false,
|
|
54
54
|
noColor: false,
|
|
55
|
-
yes: false
|
|
55
|
+
yes: false,
|
|
56
|
+
nonInteractive: false
|
|
56
57
|
};
|
|
57
58
|
function setGlobalOptions(options) {
|
|
58
59
|
globalOptions = { ...globalOptions, ...options };
|
|
@@ -63,6 +64,9 @@ function isJsonMode() {
|
|
|
63
64
|
function shouldSkipConfirmation() {
|
|
64
65
|
return globalOptions.yes;
|
|
65
66
|
}
|
|
67
|
+
function isNonInteractiveMode() {
|
|
68
|
+
return globalOptions.nonInteractive;
|
|
69
|
+
}
|
|
66
70
|
function c(colorFn, str) {
|
|
67
71
|
return globalOptions.noColor ? str : colorFn(str);
|
|
68
72
|
}
|
|
@@ -183,6 +187,7 @@ export {
|
|
|
183
187
|
setGlobalOptions,
|
|
184
188
|
isJsonMode,
|
|
185
189
|
shouldSkipConfirmation,
|
|
190
|
+
isNonInteractiveMode,
|
|
186
191
|
colors,
|
|
187
192
|
getStatusBadge,
|
|
188
193
|
log,
|