@timbrix/cli 0.1.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/README.md +319 -0
- package/bin/run.js +5 -0
- package/dist/commands/api-keys/create.d.ts +12 -0
- package/dist/commands/api-keys/create.d.ts.map +1 -0
- package/dist/commands/api-keys/create.js +65 -0
- package/dist/commands/api-keys/delete.d.ts +14 -0
- package/dist/commands/api-keys/delete.d.ts.map +1 -0
- package/dist/commands/api-keys/delete.js +55 -0
- package/dist/commands/api-keys/get.d.ts +13 -0
- package/dist/commands/api-keys/get.d.ts.map +1 -0
- package/dist/commands/api-keys/get.js +46 -0
- package/dist/commands/api-keys/list.d.ts +10 -0
- package/dist/commands/api-keys/list.d.ts.map +1 -0
- package/dist/commands/api-keys/list.js +61 -0
- package/dist/commands/login.d.ts +11 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +67 -0
- package/dist/commands/logout.d.ts +7 -0
- package/dist/commands/logout.d.ts.map +1 -0
- package/dist/commands/logout.js +19 -0
- package/dist/commands/oauth-apps/create.d.ts +12 -0
- package/dist/commands/oauth-apps/create.d.ts.map +1 -0
- package/dist/commands/oauth-apps/create.js +96 -0
- package/dist/commands/oauth-apps/delete.d.ts +13 -0
- package/dist/commands/oauth-apps/delete.d.ts.map +1 -0
- package/dist/commands/oauth-apps/delete.js +49 -0
- package/dist/commands/oauth-apps/get.d.ts +10 -0
- package/dist/commands/oauth-apps/get.d.ts.map +1 -0
- package/dist/commands/oauth-apps/get.js +41 -0
- package/dist/commands/oauth-apps/list.d.ts +10 -0
- package/dist/commands/oauth-apps/list.d.ts.map +1 -0
- package/dist/commands/oauth-apps/list.js +55 -0
- package/dist/commands/organizations/create.d.ts +11 -0
- package/dist/commands/organizations/create.d.ts.map +1 -0
- package/dist/commands/organizations/create.js +69 -0
- package/dist/commands/organizations/delete.d.ts +13 -0
- package/dist/commands/organizations/delete.d.ts.map +1 -0
- package/dist/commands/organizations/delete.js +50 -0
- package/dist/commands/organizations/get.d.ts +10 -0
- package/dist/commands/organizations/get.d.ts.map +1 -0
- package/dist/commands/organizations/get.js +46 -0
- package/dist/commands/organizations/list.d.ts +7 -0
- package/dist/commands/organizations/list.d.ts.map +1 -0
- package/dist/commands/organizations/list.js +40 -0
- package/dist/commands/products/create.d.ts +17 -0
- package/dist/commands/products/create.d.ts.map +1 -0
- package/dist/commands/products/create.js +112 -0
- package/dist/commands/products/delete.d.ts +12 -0
- package/dist/commands/products/delete.d.ts.map +1 -0
- package/dist/commands/products/delete.js +52 -0
- package/dist/commands/products/get.d.ts +11 -0
- package/dist/commands/products/get.d.ts.map +1 -0
- package/dist/commands/products/get.js +54 -0
- package/dist/commands/products/list.d.ts +13 -0
- package/dist/commands/products/list.d.ts.map +1 -0
- package/dist/commands/products/list.js +75 -0
- package/dist/commands/products/update.d.ts +18 -0
- package/dist/commands/products/update.d.ts.map +1 -0
- package/dist/commands/products/update.js +86 -0
- package/dist/commands/update.d.ts +16 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +91 -0
- package/dist/commands/webhooks/create.d.ts +11 -0
- package/dist/commands/webhooks/create.d.ts.map +1 -0
- package/dist/commands/webhooks/create.js +120 -0
- package/dist/commands/webhooks/delete.d.ts +14 -0
- package/dist/commands/webhooks/delete.d.ts.map +1 -0
- package/dist/commands/webhooks/delete.js +55 -0
- package/dist/commands/webhooks/get.d.ts +13 -0
- package/dist/commands/webhooks/get.d.ts.map +1 -0
- package/dist/commands/webhooks/get.js +45 -0
- package/dist/commands/webhooks/list.d.ts +10 -0
- package/dist/commands/webhooks/list.d.ts.map +1 -0
- package/dist/commands/webhooks/list.js +49 -0
- package/dist/config/auth.d.ts +31 -0
- package/dist/config/auth.d.ts.map +1 -0
- package/dist/config/auth.js +57 -0
- package/dist/help.d.ts +16 -0
- package/dist/help.d.ts.map +1 -0
- package/dist/help.js +22 -0
- package/dist/hooks/init/update-check.d.ts +8 -0
- package/dist/hooks/init/update-check.d.ts.map +1 -0
- package/dist/hooks/init/update-check.js +9 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/utils/client.d.ts +6 -0
- package/dist/utils/client.d.ts.map +1 -0
- package/dist/utils/client.js +18 -0
- package/dist/utils/error.d.ts +6 -0
- package/dist/utils/error.d.ts.map +1 -0
- package/dist/utils/error.js +15 -0
- package/dist/utils/logo.d.ts +14 -0
- package/dist/utils/logo.d.ts.map +1 -0
- package/dist/utils/logo.js +27 -0
- package/dist/utils/table.d.ts +6 -0
- package/dist/utils/table.d.ts.map +1 -0
- package/dist/utils/table.js +30 -0
- package/dist/utils/update-notifier.d.ts +13 -0
- package/dist/utils/update-notifier.d.ts.map +1 -0
- package/dist/utils/update-notifier.js +19 -0
- package/oclif.manifest.json +1054 -0
- package/package.json +71 -0
- package/theme.json +27 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Command } from "@oclif/core";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import ora from "ora";
|
|
4
|
+
import { createClient } from "../../utils/client.js";
|
|
5
|
+
import { getErrorMessage } from "../../utils/error.js";
|
|
6
|
+
import { createTable } from "../../utils/table.js";
|
|
7
|
+
export default class OrganizationsList extends Command {
|
|
8
|
+
static description = "List all organizations";
|
|
9
|
+
static examples = ["<%= config.bin %> <%= command.id %>"];
|
|
10
|
+
async run() {
|
|
11
|
+
const client = createClient();
|
|
12
|
+
const spinner = ora("Fetching organizations...").start();
|
|
13
|
+
try {
|
|
14
|
+
const user = await client.users.me();
|
|
15
|
+
const organizations = await client.users.getOrganizations(user.id);
|
|
16
|
+
spinner.stop();
|
|
17
|
+
if (organizations.length === 0) {
|
|
18
|
+
this.log(chalk.yellow("No organizations found"));
|
|
19
|
+
this.log(chalk.gray("\nCreate your first organization with: timbrix organizations create"));
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const table = createTable(["ID", "Name", "Slug", "Ready", "Created"]);
|
|
23
|
+
organizations.forEach((org) => {
|
|
24
|
+
table.push([
|
|
25
|
+
org.id.substring(0, 8) + "...",
|
|
26
|
+
org.legal.name || chalk.gray("—"),
|
|
27
|
+
org.slug,
|
|
28
|
+
org.is_production_ready ? chalk.green("Yes") : chalk.yellow("No"),
|
|
29
|
+
new Date(org.created_at).toLocaleDateString(),
|
|
30
|
+
]);
|
|
31
|
+
});
|
|
32
|
+
this.log(table.toString());
|
|
33
|
+
this.log(chalk.gray(`\nTotal: ${organizations.length} organization(s)`));
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
spinner.fail(chalk.red("Failed to fetch organizations"));
|
|
37
|
+
this.error(getErrorMessage(error));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Command } from "@oclif/core";
|
|
2
|
+
export default class ProductsCreate extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
org: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
"product-key": import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
price: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
sku: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
"unit-key": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
"unit-name": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
"tax-included": import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
14
|
+
};
|
|
15
|
+
run(): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=create.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/commands/products/create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAS,MAAM,aAAa,CAAA;AAO5C,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,OAAO;IACjD,OAAgB,WAAW,SAAoC;IAE/D,OAAgB,QAAQ,WAGvB;IAED,OAAgB,KAAK;;;;;;;;;MAiCpB;IAEY,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAwFlC"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { Command, Flags } from "@oclif/core";
|
|
2
|
+
import { input, confirm, number } from "@inquirer/prompts";
|
|
3
|
+
import { createClient } from "../../utils/client.js";
|
|
4
|
+
import { getErrorMessage } from "../../utils/error.js";
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
import ora from "ora";
|
|
7
|
+
export default class ProductsCreate extends Command {
|
|
8
|
+
static description = "Create a new product or service";
|
|
9
|
+
static examples = [
|
|
10
|
+
"<%= config.bin %> <%= command.id %> --org acme-corp-id",
|
|
11
|
+
"<%= config.bin %> <%= command.id %> --org acme-corp-id --description Ukelele --product-key 60131324 --price 345.60",
|
|
12
|
+
];
|
|
13
|
+
static flags = {
|
|
14
|
+
org: Flags.string({
|
|
15
|
+
char: "o",
|
|
16
|
+
description: "Organization ID",
|
|
17
|
+
required: true,
|
|
18
|
+
}),
|
|
19
|
+
description: Flags.string({
|
|
20
|
+
char: "d",
|
|
21
|
+
description: "Product or service description",
|
|
22
|
+
}),
|
|
23
|
+
"product-key": Flags.integer({
|
|
24
|
+
char: "k",
|
|
25
|
+
description: "SAT product/service key (clave SAT)",
|
|
26
|
+
}),
|
|
27
|
+
price: Flags.string({
|
|
28
|
+
char: "p",
|
|
29
|
+
description: "Unit price",
|
|
30
|
+
}),
|
|
31
|
+
sku: Flags.string({
|
|
32
|
+
char: "s",
|
|
33
|
+
description: "Internal SKU",
|
|
34
|
+
}),
|
|
35
|
+
"unit-key": Flags.string({
|
|
36
|
+
description: "SAT unit key (default: H87)",
|
|
37
|
+
}),
|
|
38
|
+
"unit-name": Flags.string({
|
|
39
|
+
description: "Unit name (default: Elemento)",
|
|
40
|
+
}),
|
|
41
|
+
"tax-included": Flags.boolean({
|
|
42
|
+
description: "Whether price includes taxes",
|
|
43
|
+
default: false,
|
|
44
|
+
allowNo: true,
|
|
45
|
+
}),
|
|
46
|
+
};
|
|
47
|
+
async run() {
|
|
48
|
+
const { flags } = await this.parse(ProductsCreate);
|
|
49
|
+
const client = createClient();
|
|
50
|
+
try {
|
|
51
|
+
const description = flags.description ||
|
|
52
|
+
(await input({
|
|
53
|
+
message: "Product description:",
|
|
54
|
+
validate: (v) => v.trim().length > 0 || "Description is required",
|
|
55
|
+
}));
|
|
56
|
+
const productKey = flags["product-key"] ||
|
|
57
|
+
(await number({
|
|
58
|
+
message: "SAT product key (clave de producto SAT):",
|
|
59
|
+
validate: (v) => (v !== undefined && v > 0) || "Must be a positive integer",
|
|
60
|
+
}));
|
|
61
|
+
const priceRaw = flags.price ||
|
|
62
|
+
(await input({
|
|
63
|
+
message: "Unit price:",
|
|
64
|
+
validate: (v) => (!isNaN(parseFloat(v)) && parseFloat(v) > 0) ||
|
|
65
|
+
"Must be a positive number",
|
|
66
|
+
}));
|
|
67
|
+
const taxIncluded = await confirm({
|
|
68
|
+
message: "Are taxes already included in the price?",
|
|
69
|
+
default: flags["tax-included"],
|
|
70
|
+
});
|
|
71
|
+
const sku = flags.sku ||
|
|
72
|
+
(await input({
|
|
73
|
+
message: "Internal SKU (leave empty to skip):",
|
|
74
|
+
})) ||
|
|
75
|
+
undefined;
|
|
76
|
+
const unitKey = flags["unit-key"] ||
|
|
77
|
+
(await input({
|
|
78
|
+
message: "SAT unit key:",
|
|
79
|
+
default: "H87",
|
|
80
|
+
}));
|
|
81
|
+
const unitName = flags["unit-name"] ||
|
|
82
|
+
(await input({
|
|
83
|
+
message: "Unit name:",
|
|
84
|
+
default: "Elemento",
|
|
85
|
+
}));
|
|
86
|
+
const spinner = ora("Creating product...").start();
|
|
87
|
+
const product = await client.products.create(flags.org, {
|
|
88
|
+
description,
|
|
89
|
+
productKey: productKey,
|
|
90
|
+
price: parseFloat(priceRaw),
|
|
91
|
+
taxIncluded,
|
|
92
|
+
sku: sku || undefined,
|
|
93
|
+
unitKey,
|
|
94
|
+
unitName,
|
|
95
|
+
taxes: [{ type: "IVA", rate: 0.16 }],
|
|
96
|
+
});
|
|
97
|
+
spinner.succeed(chalk.green("✓ Product created successfully!"));
|
|
98
|
+
this.log(chalk.gray("\nProduct Details:"));
|
|
99
|
+
this.log(` ${chalk.bold("ID:")} ${product.id}`);
|
|
100
|
+
this.log(` ${chalk.bold("Description:")} ${product.description}`);
|
|
101
|
+
this.log(` ${chalk.bold("Product Key:")} ${product.productKey}`);
|
|
102
|
+
this.log(` ${chalk.bold("Price:")} $${product.price.toFixed(2)}`);
|
|
103
|
+
this.log(` ${chalk.bold("Tax Included:")} ${product.taxIncluded ? "Yes" : "No"}`);
|
|
104
|
+
this.log(` ${chalk.bold("Unit:")} ${product.unitKey} (${product.unitName})`);
|
|
105
|
+
if (product.sku)
|
|
106
|
+
this.log(` ${chalk.bold("SKU:")} ${product.sku}`);
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
this.error(chalk.red(`Failed to create product: ${getErrorMessage(error)}`));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Command } from "@oclif/core";
|
|
2
|
+
export default class ProductsDelete extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
org: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
id: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
9
|
+
};
|
|
10
|
+
run(): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=delete.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../../src/commands/products/delete.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAS,MAAM,aAAa,CAAA;AAO5C,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,OAAO;IACjD,OAAgB,WAAW,SAAgC;IAE3D,OAAgB,QAAQ,WAGvB;IAED,OAAgB,KAAK;;;;MAepB;IAEY,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CA0BlC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Command, Flags } from "@oclif/core";
|
|
2
|
+
import { confirm } from "@inquirer/prompts";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import ora from "ora";
|
|
5
|
+
import { createClient } from "../../utils/client.js";
|
|
6
|
+
import { getErrorMessage } from "../../utils/error.js";
|
|
7
|
+
export default class ProductsDelete extends Command {
|
|
8
|
+
static description = "Delete a product or service";
|
|
9
|
+
static examples = [
|
|
10
|
+
"<%= config.bin %> <%= command.id %> --org acme-corp-id --id product-uuid",
|
|
11
|
+
"<%= config.bin %> <%= command.id %> --org acme-corp-id --id product-uuid --force",
|
|
12
|
+
];
|
|
13
|
+
static flags = {
|
|
14
|
+
org: Flags.string({
|
|
15
|
+
char: "o",
|
|
16
|
+
description: "Organization ID",
|
|
17
|
+
required: true,
|
|
18
|
+
}),
|
|
19
|
+
id: Flags.string({
|
|
20
|
+
description: "Product ID",
|
|
21
|
+
required: true,
|
|
22
|
+
}),
|
|
23
|
+
force: Flags.boolean({
|
|
24
|
+
char: "f",
|
|
25
|
+
description: "Skip confirmation prompt",
|
|
26
|
+
default: false,
|
|
27
|
+
}),
|
|
28
|
+
};
|
|
29
|
+
async run() {
|
|
30
|
+
const { flags } = await this.parse(ProductsDelete);
|
|
31
|
+
const client = createClient();
|
|
32
|
+
if (!flags.force) {
|
|
33
|
+
const ok = await confirm({
|
|
34
|
+
message: `Delete product ${flags.id}? This action cannot be undone.`,
|
|
35
|
+
default: false,
|
|
36
|
+
});
|
|
37
|
+
if (!ok) {
|
|
38
|
+
this.log(chalk.gray("Deletion cancelled"));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const spinner = ora("Deleting product...").start();
|
|
43
|
+
try {
|
|
44
|
+
await client.products.delete(flags.org, flags.id);
|
|
45
|
+
spinner.succeed(chalk.green("✓ Product deleted successfully!"));
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
spinner.fail(chalk.red("Failed to delete product"));
|
|
49
|
+
this.error(getErrorMessage(error));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Command } from "@oclif/core";
|
|
2
|
+
export default class ProductsGet extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
org: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
id: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
};
|
|
9
|
+
run(): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=get.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get.d.ts","sourceRoot":"","sources":["../../../src/commands/products/get.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAS,MAAM,aAAa,CAAA;AAO5C,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,OAAO;IAC9C,OAAgB,WAAW,SAAwB;IAEnD,OAAgB,QAAQ,WAEvB;IAED,OAAgB,KAAK;;;MAUpB;IAEY,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CA6ClC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Command, Flags } from "@oclif/core";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import ora from "ora";
|
|
4
|
+
import { createClient } from "../../utils/client.js";
|
|
5
|
+
import { getErrorMessage } from "../../utils/error.js";
|
|
6
|
+
export default class ProductsGet extends Command {
|
|
7
|
+
static description = "Get a product by ID";
|
|
8
|
+
static examples = [
|
|
9
|
+
"<%= config.bin %> <%= command.id %> --org acme-corp-id --id product-uuid",
|
|
10
|
+
];
|
|
11
|
+
static flags = {
|
|
12
|
+
org: Flags.string({
|
|
13
|
+
char: "o",
|
|
14
|
+
description: "Organization ID",
|
|
15
|
+
required: true,
|
|
16
|
+
}),
|
|
17
|
+
id: Flags.string({
|
|
18
|
+
description: "Product ID",
|
|
19
|
+
required: true,
|
|
20
|
+
}),
|
|
21
|
+
};
|
|
22
|
+
async run() {
|
|
23
|
+
const { flags } = await this.parse(ProductsGet);
|
|
24
|
+
const client = createClient();
|
|
25
|
+
const spinner = ora("Fetching product...").start();
|
|
26
|
+
try {
|
|
27
|
+
const product = await client.products.get(flags.org, flags.id);
|
|
28
|
+
spinner.stop();
|
|
29
|
+
this.log(chalk.bold("\nProduct Details:"));
|
|
30
|
+
this.log(` ${chalk.bold("ID:")} ${product.id}`);
|
|
31
|
+
this.log(` ${chalk.bold("Description:")} ${product.description}`);
|
|
32
|
+
this.log(` ${chalk.bold("Product Key:")} ${product.productKey}`);
|
|
33
|
+
this.log(` ${chalk.bold("Price:")} $${product.price.toFixed(2)}`);
|
|
34
|
+
this.log(` ${chalk.bold("Tax Included:")} ${product.taxIncluded ? "Yes" : "No"}`);
|
|
35
|
+
this.log(` ${chalk.bold("Taxability:")} ${product.taxability}`);
|
|
36
|
+
this.log(` ${chalk.bold("Unit:")} ${product.unitKey} (${product.unitName})`);
|
|
37
|
+
if (product.sku)
|
|
38
|
+
this.log(` ${chalk.bold("SKU:")} ${product.sku}`);
|
|
39
|
+
this.log(` ${chalk.bold("Livemode:")} ${product.livemode ? "Yes" : "No"}`);
|
|
40
|
+
if (product.taxes.length > 0) {
|
|
41
|
+
this.log(chalk.bold("\n Taxes:"));
|
|
42
|
+
product.taxes.forEach((tax) => {
|
|
43
|
+
this.log(` - ${tax.type}: ${(tax.rate * 100).toFixed(0)}%`);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
this.log(`\n ${chalk.bold("Created:")} ${new Date(product.createdAt).toLocaleString()}`);
|
|
47
|
+
this.log(` ${chalk.bold("Updated:")} ${new Date(product.updatedAt).toLocaleString()}`);
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
spinner.fail(chalk.red("Failed to fetch product"));
|
|
51
|
+
this.error(getErrorMessage(error));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Command } from "@oclif/core";
|
|
2
|
+
export default class ProductsList extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
org: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
sku: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
"product-key": import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
};
|
|
11
|
+
run(): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/commands/products/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAS,MAAM,aAAa,CAAA;AAQ5C,MAAM,CAAC,OAAO,OAAO,YAAa,SAAQ,OAAO;IAC/C,OAAgB,WAAW,SAAmD;IAE9E,OAAgB,QAAQ,WAIvB;IAED,OAAgB,KAAK;;;;;MAkBpB;IAEY,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAmDlC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Command, Flags } from "@oclif/core";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import ora from "ora";
|
|
4
|
+
import { createClient } from "../../utils/client.js";
|
|
5
|
+
import { getErrorMessage } from "../../utils/error.js";
|
|
6
|
+
import { createTable, truncate } from "../../utils/table.js";
|
|
7
|
+
export default class ProductsList extends Command {
|
|
8
|
+
static description = "List all products/services for an organization";
|
|
9
|
+
static examples = [
|
|
10
|
+
"<%= config.bin %> <%= command.id %> --org acme-corp-id",
|
|
11
|
+
"<%= config.bin %> <%= command.id %> --org acme-corp-id --description Ukelele",
|
|
12
|
+
"<%= config.bin %> <%= command.id %> --org acme-corp-id --sku UKL",
|
|
13
|
+
];
|
|
14
|
+
static flags = {
|
|
15
|
+
org: Flags.string({
|
|
16
|
+
char: "o",
|
|
17
|
+
description: "Organization ID",
|
|
18
|
+
required: true,
|
|
19
|
+
}),
|
|
20
|
+
description: Flags.string({
|
|
21
|
+
char: "d",
|
|
22
|
+
description: "Filter by description (partial match)",
|
|
23
|
+
}),
|
|
24
|
+
sku: Flags.string({
|
|
25
|
+
char: "s",
|
|
26
|
+
description: "Filter by SKU (partial match)",
|
|
27
|
+
}),
|
|
28
|
+
"product-key": Flags.integer({
|
|
29
|
+
char: "k",
|
|
30
|
+
description: "Filter by SAT product key (exact match)",
|
|
31
|
+
}),
|
|
32
|
+
};
|
|
33
|
+
async run() {
|
|
34
|
+
const { flags } = await this.parse(ProductsList);
|
|
35
|
+
const client = createClient();
|
|
36
|
+
const spinner = ora("Fetching products...").start();
|
|
37
|
+
try {
|
|
38
|
+
const products = await client.products.list(flags.org, {
|
|
39
|
+
description: flags.description,
|
|
40
|
+
sku: flags.sku,
|
|
41
|
+
productKey: flags["product-key"],
|
|
42
|
+
});
|
|
43
|
+
spinner.stop();
|
|
44
|
+
if (products.length === 0) {
|
|
45
|
+
this.log(chalk.yellow("No products found"));
|
|
46
|
+
this.log(chalk.gray(`\nCreate a product with: timbrix products create --org ${flags.org}`));
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const table = createTable([
|
|
50
|
+
"ID",
|
|
51
|
+
"Description",
|
|
52
|
+
"Product Key",
|
|
53
|
+
"Price",
|
|
54
|
+
"SKU",
|
|
55
|
+
"Created",
|
|
56
|
+
]);
|
|
57
|
+
products.forEach((product) => {
|
|
58
|
+
table.push([
|
|
59
|
+
product.id.substring(0, 8) + "...",
|
|
60
|
+
truncate(product.description, 30),
|
|
61
|
+
String(product.productKey),
|
|
62
|
+
`$${product.price.toFixed(2)}`,
|
|
63
|
+
product.sku ?? "-",
|
|
64
|
+
new Date(product.createdAt).toLocaleDateString(),
|
|
65
|
+
]);
|
|
66
|
+
});
|
|
67
|
+
this.log(table.toString());
|
|
68
|
+
this.log(chalk.gray(`\nTotal: ${products.length} product(s)`));
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
spinner.fail(chalk.red("Failed to fetch products"));
|
|
72
|
+
this.error(getErrorMessage(error));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Command } from "@oclif/core";
|
|
2
|
+
export default class ProductsUpdate extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
org: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
id: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
"product-key": import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
price: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
sku: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
"unit-key": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
"unit-name": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
"tax-included": import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
15
|
+
};
|
|
16
|
+
run(): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=update.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../src/commands/products/update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAS,MAAM,aAAa,CAAA;AAM5C,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,OAAO;IACjD,OAAgB,WAAW,SAAgC;IAE3D,OAAgB,QAAQ,WAGvB;IAED,OAAgB,KAAK;;;;;;;;;;MAoCpB;IAEY,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAsClC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { Command, Flags } from "@oclif/core";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import ora from "ora";
|
|
4
|
+
import { createClient } from "../../utils/client.js";
|
|
5
|
+
import { getErrorMessage } from "../../utils/error.js";
|
|
6
|
+
export default class ProductsUpdate extends Command {
|
|
7
|
+
static description = "Update a product or service";
|
|
8
|
+
static examples = [
|
|
9
|
+
"<%= config.bin %> <%= command.id %> --org acme-corp-id --id product-uuid --price 400",
|
|
10
|
+
"<%= config.bin %> <%= command.id %> --org acme-corp-id --id product-uuid --description 'Ukelele Pro'",
|
|
11
|
+
];
|
|
12
|
+
static flags = {
|
|
13
|
+
org: Flags.string({
|
|
14
|
+
char: "o",
|
|
15
|
+
description: "Organization ID",
|
|
16
|
+
required: true,
|
|
17
|
+
}),
|
|
18
|
+
id: Flags.string({
|
|
19
|
+
description: "Product ID",
|
|
20
|
+
required: true,
|
|
21
|
+
}),
|
|
22
|
+
description: Flags.string({
|
|
23
|
+
char: "d",
|
|
24
|
+
description: "Product or service description",
|
|
25
|
+
}),
|
|
26
|
+
"product-key": Flags.integer({
|
|
27
|
+
char: "k",
|
|
28
|
+
description: "SAT product/service key",
|
|
29
|
+
}),
|
|
30
|
+
price: Flags.string({
|
|
31
|
+
char: "p",
|
|
32
|
+
description: "Unit price",
|
|
33
|
+
}),
|
|
34
|
+
sku: Flags.string({
|
|
35
|
+
char: "s",
|
|
36
|
+
description: "Internal SKU",
|
|
37
|
+
}),
|
|
38
|
+
"unit-key": Flags.string({
|
|
39
|
+
description: "SAT unit key",
|
|
40
|
+
}),
|
|
41
|
+
"unit-name": Flags.string({
|
|
42
|
+
description: "Unit name",
|
|
43
|
+
}),
|
|
44
|
+
"tax-included": Flags.boolean({
|
|
45
|
+
description: "Whether price includes taxes",
|
|
46
|
+
allowNo: true,
|
|
47
|
+
}),
|
|
48
|
+
};
|
|
49
|
+
async run() {
|
|
50
|
+
const { flags } = await this.parse(ProductsUpdate);
|
|
51
|
+
const client = createClient();
|
|
52
|
+
const updates = {};
|
|
53
|
+
if (flags.description !== undefined)
|
|
54
|
+
updates.description = flags.description;
|
|
55
|
+
if (flags["product-key"] !== undefined)
|
|
56
|
+
updates.productKey = flags["product-key"];
|
|
57
|
+
if (flags.price !== undefined)
|
|
58
|
+
updates.price = parseFloat(flags.price);
|
|
59
|
+
if (flags.sku !== undefined)
|
|
60
|
+
updates.sku = flags.sku;
|
|
61
|
+
if (flags["unit-key"] !== undefined)
|
|
62
|
+
updates.unitKey = flags["unit-key"];
|
|
63
|
+
if (flags["unit-name"] !== undefined)
|
|
64
|
+
updates.unitName = flags["unit-name"];
|
|
65
|
+
if (flags["tax-included"] !== undefined)
|
|
66
|
+
updates.taxIncluded = flags["tax-included"];
|
|
67
|
+
if (Object.keys(updates).length === 0) {
|
|
68
|
+
this.error("No update fields provided. Use --description, --price, --sku, etc.");
|
|
69
|
+
}
|
|
70
|
+
const spinner = ora("Updating product...").start();
|
|
71
|
+
try {
|
|
72
|
+
const product = await client.products.update(flags.org, flags.id, updates);
|
|
73
|
+
spinner.succeed(chalk.green("✓ Product updated successfully!"));
|
|
74
|
+
this.log(chalk.gray("\nUpdated Product:"));
|
|
75
|
+
this.log(` ${chalk.bold("ID:")} ${product.id}`);
|
|
76
|
+
this.log(` ${chalk.bold("Description:")} ${product.description}`);
|
|
77
|
+
this.log(` ${chalk.bold("Price:")} $${product.price.toFixed(2)}`);
|
|
78
|
+
if (product.sku)
|
|
79
|
+
this.log(` ${chalk.bold("SKU:")} ${product.sku}`);
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
spinner.fail(chalk.red("Failed to update product"));
|
|
83
|
+
this.error(getErrorMessage(error));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Command } from "@oclif/core";
|
|
2
|
+
export default class Update extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {};
|
|
6
|
+
run(): Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* Detect which package manager is being used
|
|
9
|
+
*/
|
|
10
|
+
private detectPackageManager;
|
|
11
|
+
/**
|
|
12
|
+
* Get the appropriate update command for the package manager
|
|
13
|
+
*/
|
|
14
|
+
private getUpdateCommand;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=update.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAmBrC,MAAM,CAAC,OAAO,OAAO,MAAO,SAAQ,OAAO;IACzC,OAAgB,WAAW,SAA6C;IAExE,OAAgB,QAAQ,WAGvB;IAED,OAAgB,KAAK,KAAK;IAEb,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAuDjC;;OAEG;YACW,oBAAoB;IAiBlC;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAazB"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { Command } from "@oclif/core";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { exec } from "node:child_process";
|
|
4
|
+
import { readFileSync } from "node:fs";
|
|
5
|
+
import { dirname, join } from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { promisify } from "node:util";
|
|
8
|
+
import ora from "ora";
|
|
9
|
+
import updateNotifier from "update-notifier";
|
|
10
|
+
import { getErrorMessage } from "../utils/error.js";
|
|
11
|
+
const execAsync = promisify(exec);
|
|
12
|
+
// Get package.json path
|
|
13
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
14
|
+
const __dirname = dirname(__filename);
|
|
15
|
+
const packageJsonPath = join(__dirname, "../../package.json");
|
|
16
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
17
|
+
export default class Update extends Command {
|
|
18
|
+
static description = "Update Timbrix CLI to the latest version";
|
|
19
|
+
static examples = [
|
|
20
|
+
"<%= config.bin %> <%= command.id %>",
|
|
21
|
+
"<%= config.bin %> <%= command.id %> --check",
|
|
22
|
+
];
|
|
23
|
+
static flags = {};
|
|
24
|
+
async run() {
|
|
25
|
+
// Check for updates
|
|
26
|
+
const notifier = updateNotifier({
|
|
27
|
+
pkg: packageJson,
|
|
28
|
+
updateCheckInterval: 0, // Always check
|
|
29
|
+
});
|
|
30
|
+
if (!notifier.update) {
|
|
31
|
+
this.log(chalk.green(`✓ You are already using the latest version (${packageJson.version})`));
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const { current, latest } = notifier.update;
|
|
35
|
+
this.log(chalk.cyan("\nUpdate available:"));
|
|
36
|
+
this.log(chalk.dim(` Current: ${current}`));
|
|
37
|
+
this.log(chalk.green(` Latest: ${latest}\n`));
|
|
38
|
+
// Determine which package manager is being used
|
|
39
|
+
const packageManager = await this.detectPackageManager();
|
|
40
|
+
const spinner = ora(`Updating ${packageJson.name} to version ${latest}...`).start();
|
|
41
|
+
try {
|
|
42
|
+
// Update the package
|
|
43
|
+
const updateCommand = this.getUpdateCommand(packageManager);
|
|
44
|
+
await execAsync(updateCommand);
|
|
45
|
+
spinner.succeed(chalk.green(`✓ Successfully updated to version ${latest}!`));
|
|
46
|
+
this.log(chalk.dim(`\nRun ${chalk.bold(packageJson.bin.timbrix + " --version")} to verify the installation.`));
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
spinner.fail(chalk.red("✗ Update failed"));
|
|
50
|
+
this.error(chalk.red(`Failed to update: ${getErrorMessage(error)}\n\n` +
|
|
51
|
+
`Please try manually:\n` +
|
|
52
|
+
` ${this.getUpdateCommand(packageManager)}`));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Detect which package manager is being used
|
|
57
|
+
*/
|
|
58
|
+
async detectPackageManager() {
|
|
59
|
+
try {
|
|
60
|
+
// Check if pnpm is available
|
|
61
|
+
await execAsync("pnpm --version");
|
|
62
|
+
return "pnpm";
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
try {
|
|
66
|
+
// Check if yarn is available
|
|
67
|
+
await execAsync("yarn --version");
|
|
68
|
+
return "yarn";
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// Default to npm
|
|
72
|
+
return "npm";
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Get the appropriate update command for the package manager
|
|
78
|
+
*/
|
|
79
|
+
getUpdateCommand(packageManager) {
|
|
80
|
+
const packageName = packageJson.name;
|
|
81
|
+
switch (packageManager) {
|
|
82
|
+
case "pnpm":
|
|
83
|
+
return `pnpm add -g ${packageName}@latest`;
|
|
84
|
+
case "yarn":
|
|
85
|
+
return `yarn global add ${packageName}@latest`;
|
|
86
|
+
case "npm":
|
|
87
|
+
default:
|
|
88
|
+
return `npm install -g ${packageName}@latest`;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Command } from "@oclif/core";
|
|
2
|
+
export default class WebhooksCreate extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
org: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
url: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
};
|
|
9
|
+
run(): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=create.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/commands/webhooks/create.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAS,MAAM,aAAa,CAAA;AA0D5C,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,OAAO;IACjD,OAAgB,WAAW,SAAyB;IAEpD,OAAgB,QAAQ,WAGvB;IAED,OAAgB,KAAK;;;MAUpB;IAEY,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CA2DlC"}
|