faces-cli 1.6.6 → 1.6.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.
@@ -1,5 +1,5 @@
1
- import { BaseCommand } from '../../base.js';
2
- export default class BillingCheckout extends BaseCommand {
1
+ import { BaseCommand } from '../../../base.js';
2
+ export default class BillingSubscriptionActivate extends BaseCommand {
3
3
  static description: string;
4
4
  static flags: {
5
5
  plan: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
@@ -0,0 +1,75 @@
1
+ import { Flags } from '@oclif/core';
2
+ import { BaseCommand } from '../../../base.js';
3
+ import { FacesAPIError } from '../../../client.js';
4
+ export default class BillingSubscriptionActivate extends BaseCommand {
5
+ static description = 'Activate or reactivate a subscription plan';
6
+ static flags = {
7
+ ...BaseCommand.baseFlags,
8
+ plan: Flags.string({
9
+ description: 'Plan to activate',
10
+ options: ['connect'],
11
+ default: 'connect',
12
+ }),
13
+ };
14
+ async run() {
15
+ const { flags } = await this.parse(BillingSubscriptionActivate);
16
+ const client = this.makeClient(flags);
17
+ const json = this.jsonEnabled();
18
+ // Fetch current state
19
+ let sub;
20
+ try {
21
+ sub = await client.get('/v1/billing/subscription');
22
+ }
23
+ catch (err) {
24
+ if (err instanceof FacesAPIError)
25
+ this.error(`Error (${err.statusCode}): ${err.message}`);
26
+ throw err;
27
+ }
28
+ const plan = sub.plan;
29
+ const cancelAtPeriodEnd = sub.cancel_at_period_end;
30
+ // Already active Connect, not pending cancel
31
+ if (plan === 'connect' && !cancelAtPeriodEnd) {
32
+ if (!json)
33
+ this.log('Already on the Connect plan.');
34
+ return { status: 'already_active', plan: 'connect' };
35
+ }
36
+ // Pending cancel — reactivate instead of creating a new checkout
37
+ if (plan === 'connect' && cancelAtPeriodEnd) {
38
+ let data;
39
+ try {
40
+ data = await client.post('/v1/billing/subscription/reactivate');
41
+ }
42
+ catch (err) {
43
+ if (err instanceof FacesAPIError)
44
+ this.error(`Error (${err.statusCode}): ${err.message}`);
45
+ throw err;
46
+ }
47
+ const result = data;
48
+ if (!json) {
49
+ this.log(`Reactivated. Connect plan continues — next renewal: ${result.current_period_end ?? 'unknown'}.`);
50
+ }
51
+ return { status: 'reactivated', ...result };
52
+ }
53
+ // Free plan — create checkout
54
+ let data;
55
+ try {
56
+ data = await client.post(`/v1/billing/checkout?plan=${flags.plan}&source=cli`);
57
+ }
58
+ catch (err) {
59
+ if (err instanceof FacesAPIError)
60
+ this.error(`Error (${err.statusCode}): ${err.message}`);
61
+ throw err;
62
+ }
63
+ const result = data;
64
+ const url = result.checkout_url;
65
+ if (!json) {
66
+ this.log('Subscription Connect — $17/month');
67
+ this.log('');
68
+ this.log('Complete payment at this link:');
69
+ this.log(` ${url}`);
70
+ this.log('');
71
+ this.log('After payment, verify with: faces billing:subscription');
72
+ }
73
+ return { status: 'checkout_created', checkout_url: url };
74
+ }
75
+ }
@@ -0,0 +1,12 @@
1
+ import { BaseCommand } from '../../../base.js';
2
+ export default class BillingSubscriptionCancel extends BaseCommand {
3
+ static description: string;
4
+ static flags: {
5
+ yes: import("@oclif/core/interfaces").BooleanFlag<boolean>;
6
+ 'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
+ token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
+ 'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
+ };
10
+ run(): Promise<unknown>;
11
+ private confirm;
12
+ }
@@ -0,0 +1,68 @@
1
+ import { Flags } from '@oclif/core';
2
+ import { createInterface } from 'node:readline';
3
+ import { BaseCommand } from '../../../base.js';
4
+ import { FacesAPIError } from '../../../client.js';
5
+ export default class BillingSubscriptionCancel extends BaseCommand {
6
+ static description = 'Cancel your subscription (keeps access until period end)';
7
+ static flags = {
8
+ ...BaseCommand.baseFlags,
9
+ yes: Flags.boolean({ description: 'Skip confirmation', default: false }),
10
+ };
11
+ async run() {
12
+ const { flags } = await this.parse(BillingSubscriptionCancel);
13
+ const client = this.makeClient(flags);
14
+ const json = this.jsonEnabled();
15
+ // Fetch current state
16
+ let sub;
17
+ try {
18
+ sub = await client.get('/v1/billing/subscription');
19
+ }
20
+ catch (err) {
21
+ if (err instanceof FacesAPIError)
22
+ this.error(`Error (${err.statusCode}): ${err.message}`);
23
+ throw err;
24
+ }
25
+ const plan = sub.plan;
26
+ if (plan === 'free') {
27
+ if (!json)
28
+ this.log('No active subscription to cancel (currently on pay-per-token plan).');
29
+ return { status: 'no_subscription' };
30
+ }
31
+ if (sub.cancel_at_period_end) {
32
+ if (!json)
33
+ this.log(`Already canceled. Connect access ends ${sub.current_period_end ?? 'at period end'}.`);
34
+ return { status: 'already_canceled', current_period_end: sub.current_period_end };
35
+ }
36
+ // Confirm
37
+ if (!flags.yes) {
38
+ const periodEnd = sub.current_period_end ?? 'period end';
39
+ const confirmed = await this.confirm(`Cancel Connect plan? You'll keep access until ${periodEnd}.`);
40
+ if (!confirmed)
41
+ this.error('Aborted.');
42
+ }
43
+ let data;
44
+ try {
45
+ data = await client.post('/v1/billing/subscription/cancel');
46
+ }
47
+ catch (err) {
48
+ if (err instanceof FacesAPIError)
49
+ this.error(`Error (${err.statusCode}): ${err.message}`);
50
+ throw err;
51
+ }
52
+ const result = data;
53
+ if (!json) {
54
+ this.log(`Canceled. Connect access continues until ${result.current_period_end ?? 'period end'}.`);
55
+ this.log('To reactivate before then: faces billing:subscription:activate');
56
+ }
57
+ return { status: 'canceled', ...result };
58
+ }
59
+ confirm(message) {
60
+ return new Promise((resolve) => {
61
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
62
+ rl.question(`${message} [y/N] `, (answer) => {
63
+ rl.close();
64
+ resolve(answer.toLowerCase() === 'y');
65
+ });
66
+ });
67
+ }
68
+ }
@@ -0,0 +1,10 @@
1
+ import { BaseCommand } from '../../../base.js';
2
+ export default class BillingSubscription extends BaseCommand {
3
+ static description: string;
4
+ static flags: {
5
+ 'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
6
+ token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
+ 'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
+ };
9
+ run(): Promise<unknown>;
10
+ }
@@ -0,0 +1,24 @@
1
+ import { BaseCommand } from '../../../base.js';
2
+ import { FacesAPIError } from '../../../client.js';
3
+ export default class BillingSubscription extends BaseCommand {
4
+ static description = 'Show current plan, face count, and renewal date';
5
+ static flags = {
6
+ ...BaseCommand.baseFlags,
7
+ };
8
+ async run() {
9
+ const { flags } = await this.parse(BillingSubscription);
10
+ const client = this.makeClient(flags);
11
+ let data;
12
+ try {
13
+ data = await client.get('/v1/billing/subscription');
14
+ }
15
+ catch (err) {
16
+ if (err instanceof FacesAPIError)
17
+ this.error(`Error (${err.statusCode}): ${err.message}`);
18
+ throw err;
19
+ }
20
+ if (!this.jsonEnabled())
21
+ this.printHuman(data);
22
+ return data;
23
+ }
24
+ }