@farthershore/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.
Files changed (44) hide show
  1. package/README.md +83 -0
  2. package/dist/auth.d.ts +1 -0
  3. package/dist/auth.js +18 -0
  4. package/dist/auth.js.map +1 -0
  5. package/dist/client.d.ts +74 -0
  6. package/dist/client.js +71 -0
  7. package/dist/client.js.map +1 -0
  8. package/dist/commands/billing.d.ts +3 -0
  9. package/dist/commands/billing.js +32 -0
  10. package/dist/commands/billing.js.map +1 -0
  11. package/dist/commands/init.d.ts +3 -0
  12. package/dist/commands/init.js +42 -0
  13. package/dist/commands/init.js.map +1 -0
  14. package/dist/commands/login.d.ts +2 -0
  15. package/dist/commands/login.js +82 -0
  16. package/dist/commands/login.js.map +1 -0
  17. package/dist/commands/plans.d.ts +3 -0
  18. package/dist/commands/plans.js +205 -0
  19. package/dist/commands/plans.js.map +1 -0
  20. package/dist/commands/products.d.ts +3 -0
  21. package/dist/commands/products.js +77 -0
  22. package/dist/commands/products.js.map +1 -0
  23. package/dist/commands/team.d.ts +3 -0
  24. package/dist/commands/team.js +47 -0
  25. package/dist/commands/team.js.map +1 -0
  26. package/dist/commands/tokens.d.ts +3 -0
  27. package/dist/commands/tokens.js +31 -0
  28. package/dist/commands/tokens.js.map +1 -0
  29. package/dist/commands/usage.d.ts +3 -0
  30. package/dist/commands/usage.js +24 -0
  31. package/dist/commands/usage.js.map +1 -0
  32. package/dist/config.d.ts +9 -0
  33. package/dist/config.js +74 -0
  34. package/dist/config.js.map +1 -0
  35. package/dist/index.d.ts +2 -0
  36. package/dist/index.js +58 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/output.d.ts +11 -0
  39. package/dist/output.js +48 -0
  40. package/dist/output.js.map +1 -0
  41. package/dist/types.d.ts +86 -0
  42. package/dist/types.js +10 -0
  43. package/dist/types.js.map +1 -0
  44. package/package.json +53 -0
@@ -0,0 +1,205 @@
1
+ import * as readline from "node:readline/promises";
2
+ import { writeConfigFile, readConfigFile, getConfigPath } from "../config.js";
3
+ import * as output from "../output.js";
4
+ export function registerPlanCommands(program, getClient) {
5
+ const plans = program.command("plans").description("Manage product plans");
6
+ plans
7
+ .command("list")
8
+ .description("List plans for a product")
9
+ .requiredOption("--product <id>", "Product ID")
10
+ .action(async (opts) => {
11
+ const client = getClient();
12
+ const product = await client.getProduct(opts.product);
13
+ if (!product.plans?.length) {
14
+ output.info("No plans found.");
15
+ return;
16
+ }
17
+ console.log(output.table(["Name", "Key", "Type", "Price", "Active"], product.plans.map((p) => [
18
+ p.name,
19
+ p.key,
20
+ p.type,
21
+ p.monthlyPriceCents > 0
22
+ ? output.formatPrice(p.monthlyPriceCents) + "/mo"
23
+ : "free",
24
+ p.isActive ? "✓" : "✗",
25
+ ])));
26
+ });
27
+ // --- Config-as-code commands ---
28
+ plans
29
+ .command("pull")
30
+ .description("Pull plan config from server to local YAML file")
31
+ .requiredOption("--product <id>", "Product ID or slug")
32
+ .action(async (opts) => {
33
+ const client = getClient();
34
+ const yamlStr = await client.exportPlanConfig(opts.product);
35
+ // Derive slug for local storage
36
+ const product = await client.getProduct(opts.product);
37
+ const slug = product.runtimeHostname?.split(".")[0] ??
38
+ product.name.toLowerCase().replace(/\s+/g, "-");
39
+ const path = writeConfigFile(slug, yamlStr);
40
+ output.success(`Pulled ${product.plans?.length ?? 0} plans from "${product.name}"`);
41
+ console.log(` Written to ${path}`);
42
+ });
43
+ plans
44
+ .command("push")
45
+ .description("Validate, diff, and apply local plan config")
46
+ .requiredOption("--product <id>", "Product ID or slug")
47
+ .option("--yes", "Skip confirmation prompt (CI mode)")
48
+ .option("--force", "Override config hash check")
49
+ .action(async (opts) => {
50
+ const client = getClient();
51
+ // Load local config
52
+ const product = await client.getProduct(opts.product);
53
+ const slug = product.runtimeHostname?.split(".")[0] ??
54
+ product.name.toLowerCase().replace(/\s+/g, "-");
55
+ const yamlStr = readConfigFile(slug);
56
+ if (!yamlStr) {
57
+ output.error(`No local config found. Run \`farthershore plans pull --product ${opts.product}\` first.`);
58
+ process.exit(1);
59
+ }
60
+ // Extract configHash
61
+ const hashMatch = yamlStr.match(/configHash:\s*['"]?([a-f0-9]+)['"]?/);
62
+ const configHash = hashMatch?.[1];
63
+ // Step 1: Validate + diff
64
+ output.info("Validating...");
65
+ const diff = await client.applyPlanConfig(opts.product, yamlStr, {
66
+ configHash,
67
+ force: opts.force,
68
+ validateOnly: true,
69
+ });
70
+ if (!diff.valid) {
71
+ output.error("Validation failed:\n");
72
+ for (const err of diff.errors) {
73
+ console.error(` ${err.line != null ? `Line ${err.line}: ` : ""}${err.message}`);
74
+ }
75
+ process.exit(1);
76
+ }
77
+ if (diff.changes.length === 0) {
78
+ output.success("No changes detected.");
79
+ return;
80
+ }
81
+ // Step 2: Show diff
82
+ const creates = diff.changes.filter((c) => c.action === "create").length;
83
+ const updates = diff.changes.filter((c) => c.action === "update").length;
84
+ const deactivates = diff.changes.filter((c) => c.action === "deactivate").length;
85
+ console.log(`\n Plan: ${creates ? `${creates} to add` : ""}${creates && updates ? ", " : ""}${updates ? `${updates} to change` : ""}${(creates || updates) && deactivates ? ", " : ""}${deactivates ? `${deactivates} to deactivate` : ""}\n`);
86
+ for (const change of diff.changes) {
87
+ const symbol = change.action === "create"
88
+ ? "+"
89
+ : change.action === "update"
90
+ ? "~"
91
+ : "-";
92
+ console.log(` ${symbol} ${change.name} (${change.key}): ${change.details}`);
93
+ }
94
+ for (const w of diff.warnings) {
95
+ output.warn(` ${w.message}`);
96
+ }
97
+ // Step 3: Confirm
98
+ if (!opts.yes) {
99
+ const rl = readline.createInterface({
100
+ input: process.stdin,
101
+ output: process.stdout,
102
+ });
103
+ const answer = await rl.question("\n Apply these changes? (yes/no): ");
104
+ rl.close();
105
+ if (answer.trim().toLowerCase() !== "yes") {
106
+ console.log(" Cancelled.");
107
+ return;
108
+ }
109
+ }
110
+ // Step 4: Apply
111
+ output.info("\n Applying...");
112
+ const result = await client.applyPlanConfig(opts.product, yamlStr, {
113
+ configHash,
114
+ force: opts.force,
115
+ });
116
+ if (!result.applied) {
117
+ output.error("Apply failed:");
118
+ for (const err of result.errors) {
119
+ console.error(` ${err.message}`);
120
+ }
121
+ process.exit(1);
122
+ }
123
+ for (const r of result.results ?? []) {
124
+ const symbol = r.action === "create" ? "+" : r.action === "update" ? "~" : "-";
125
+ console.log(` ${symbol} ${r.action} ${r.key} (${r.id})`);
126
+ }
127
+ output.success(`${result.results?.length ?? 0} changes applied.`);
128
+ });
129
+ plans
130
+ .command("diff")
131
+ .description("Show what would change without applying")
132
+ .requiredOption("--product <id>", "Product ID or slug")
133
+ .action(async (opts) => {
134
+ const client = getClient();
135
+ const product = await client.getProduct(opts.product);
136
+ const slug = product.runtimeHostname?.split(".")[0] ??
137
+ product.name.toLowerCase().replace(/\s+/g, "-");
138
+ const yamlStr = readConfigFile(slug);
139
+ if (!yamlStr) {
140
+ output.error(`No local config found. Run \`farthershore plans pull --product ${opts.product}\` first.`);
141
+ process.exit(1);
142
+ }
143
+ const hashMatch = yamlStr.match(/configHash:\s*['"]?([a-f0-9]+)['"]?/);
144
+ const diff = await client.applyPlanConfig(opts.product, yamlStr, {
145
+ configHash: hashMatch?.[1],
146
+ validateOnly: true,
147
+ });
148
+ if (!diff.valid) {
149
+ output.error("Validation errors:");
150
+ for (const err of diff.errors)
151
+ console.error(` ${err.message}`);
152
+ process.exit(1);
153
+ }
154
+ if (diff.changes.length === 0) {
155
+ output.success("No changes. Local config matches remote.");
156
+ return;
157
+ }
158
+ for (const change of diff.changes) {
159
+ const symbol = change.action === "create"
160
+ ? "+"
161
+ : change.action === "update"
162
+ ? "~"
163
+ : "-";
164
+ console.log(` ${symbol} ${change.name} (${change.key}): ${change.details}`);
165
+ }
166
+ output.info("\n No changes applied. Run `farthershore plans push` to apply.");
167
+ });
168
+ plans
169
+ .command("validate")
170
+ .description("Validate local config file (offline)")
171
+ .action(() => {
172
+ // TODO: Offline YAML schema validation
173
+ output.info("Offline validation not yet implemented. Use `farthershore plans diff` for server-side validation.");
174
+ });
175
+ plans
176
+ .command("status")
177
+ .description("Check if local config matches remote")
178
+ .requiredOption("--product <id>", "Product ID or slug")
179
+ .action(async (opts) => {
180
+ const client = getClient();
181
+ const product = await client.getProduct(opts.product);
182
+ const slug = product.runtimeHostname?.split(".")[0] ??
183
+ product.name.toLowerCase().replace(/\s+/g, "-");
184
+ const localYaml = readConfigFile(slug);
185
+ const localPath = getConfigPath(slug);
186
+ if (!localYaml) {
187
+ output.info(`No local config at ${localPath}`);
188
+ output.info(`Run \`farthershore plans pull --product ${opts.product}\` to fetch.`);
189
+ return;
190
+ }
191
+ const localHash = localYaml.match(/configHash:\s*['"]?([a-f0-9]+)['"]?/)?.[1];
192
+ const remoteYaml = await client.exportPlanConfig(opts.product);
193
+ const remoteHash = remoteYaml.match(/configHash:\s*['"]?([a-f0-9]+)['"]?/)?.[1];
194
+ console.log(` Local: ${localPath}`);
195
+ console.log(` Hash: ${localHash?.slice(0, 16) ?? "none"}...`);
196
+ console.log(` Remote: ${remoteHash?.slice(0, 16) ?? "none"}...`);
197
+ if (localHash === remoteHash) {
198
+ output.success("Up to date.");
199
+ }
200
+ else {
201
+ output.warn("Remote has changed. Run `farthershore plans pull` to get latest.");
202
+ }
203
+ });
204
+ }
205
+ //# sourceMappingURL=plans.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plans.js","sourceRoot":"","sources":["../../src/commands/plans.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ import type { ApiClient } from "../client.js";
3
+ export declare function registerProductCommands(program: Command, getClient: () => ApiClient): void;
@@ -0,0 +1,77 @@
1
+ import * as output from "../output.js";
2
+ export function registerProductCommands(program, getClient) {
3
+ const products = program
4
+ .command("products")
5
+ .description("Manage API products");
6
+ products
7
+ .command("list")
8
+ .alias("ls")
9
+ .description("List products in your organization")
10
+ .action(async () => {
11
+ const client = getClient();
12
+ const items = await client.listProducts();
13
+ if (items.length === 0) {
14
+ output.info("No products found. Create one with `farthershore products create`.");
15
+ return;
16
+ }
17
+ console.log(output.table(["Name", "Status", "Plans", "Created"], items.map((p) => [
18
+ p.name,
19
+ p.status,
20
+ String(p.plans?.length ?? 0),
21
+ output.formatDate(p.createdAt),
22
+ ])));
23
+ });
24
+ products
25
+ .command("get <id>")
26
+ .description("Show product details")
27
+ .action(async (id) => {
28
+ const client = getClient();
29
+ const product = await client.getProduct(id);
30
+ output.heading(product.name);
31
+ console.log(` ID: ${product.id}`);
32
+ console.log(` Status: ${product.status}`);
33
+ console.log(` Base URL: ${product.baseUrl}`);
34
+ console.log(` Gateway: ${product.runtimeHostname ?? "—"}`);
35
+ console.log(` Portal: ${product.portalHostname ?? "—"}`);
36
+ console.log(` Plans: ${product.plans?.length ?? 0}`);
37
+ if (product.plans?.length) {
38
+ for (const plan of product.plans) {
39
+ console.log(` • ${plan.name} (${plan.type}) ${plan.monthlyPriceCents > 0 ? output.formatPrice(plan.monthlyPriceCents) + "/mo" : "free"}`);
40
+ }
41
+ }
42
+ });
43
+ products
44
+ .command("create <name>")
45
+ .description("Create a new draft product")
46
+ .requiredOption("--base-url <url>", "Backend API base URL")
47
+ .option("--description <desc>", "Product description")
48
+ .action(async (name, opts) => {
49
+ const client = getClient();
50
+ const product = await client.createProduct({
51
+ name,
52
+ baseUrl: opts.baseUrl,
53
+ description: opts.description,
54
+ });
55
+ output.success(`Created product "${product.name}" (${product.id})`);
56
+ console.log(` Status: ${product.status}`);
57
+ console.log(` Gateway: ${product.runtimeHostname ?? "—"}`);
58
+ });
59
+ products
60
+ .command("publish <id>")
61
+ .description("Publish a draft product")
62
+ .action(async (id) => {
63
+ const client = getClient();
64
+ const product = await client.publishProduct(id);
65
+ output.success(`Published "${product.name}"`);
66
+ console.log(` Gateway: ${product.runtimeHostname}`);
67
+ });
68
+ products
69
+ .command("delete <id>")
70
+ .description("Delete a product")
71
+ .action(async (id) => {
72
+ const client = getClient();
73
+ await client.deleteProduct(id);
74
+ output.success(`Deleted product ${id}`);
75
+ });
76
+ }
77
+ //# sourceMappingURL=products.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"products.js","sourceRoot":"","sources":["../../src/commands/products.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ import type { ApiClient } from "../client.js";
3
+ export declare function registerTeamCommands(program: Command, getClient: () => ApiClient): void;
@@ -0,0 +1,47 @@
1
+ import { loadCredentials } from "../config.js";
2
+ import * as output from "../output.js";
3
+ export function registerTeamCommands(program, getClient) {
4
+ const team = program.command("team").description("Manage organization team");
5
+ team
6
+ .command("list")
7
+ .alias("ls")
8
+ .description("List organization members")
9
+ .action(async () => {
10
+ const client = getClient();
11
+ const creds = loadCredentials();
12
+ if (!creds?.orgId) {
13
+ output.error("No active organization. Run `farthershore login` first.");
14
+ process.exit(1);
15
+ }
16
+ const members = await client.listMembers(creds.orgId);
17
+ console.log(output.table(["User ID", "Role"], members.map((m) => [m.userId, m.role])));
18
+ });
19
+ team
20
+ .command("invite <email>")
21
+ .description("Invite a member to the organization")
22
+ .option("--role <role>", "Role: owner, admin, or member", "member")
23
+ .action(async (email, opts) => {
24
+ const client = getClient();
25
+ const creds = loadCredentials();
26
+ if (!creds?.orgId) {
27
+ output.error("No active organization. Run `farthershore login` first.");
28
+ process.exit(1);
29
+ }
30
+ await client.inviteMember(creds.orgId, email, opts.role);
31
+ output.success(`Invited ${email} as ${opts.role}.`);
32
+ });
33
+ team
34
+ .command("remove <userId>")
35
+ .description("Remove a member from the organization")
36
+ .action(async (userId) => {
37
+ const client = getClient();
38
+ const creds = loadCredentials();
39
+ if (!creds?.orgId) {
40
+ output.error("No active organization. Run `farthershore login` first.");
41
+ process.exit(1);
42
+ }
43
+ await client.removeMember(creds.orgId, userId);
44
+ output.success(`Removed member ${userId}.`);
45
+ });
46
+ }
47
+ //# sourceMappingURL=team.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team.js","sourceRoot":"","sources":["../../src/commands/team.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,MAAM,MAAM,cAAc,CAAC;AAEvC,MAAM,UAAU,oBAAoB,CAClC,OAAgB,EAChB,SAA0B;IAE1B,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,0BAA0B,CAAC,CAAC;IAE7E,IAAI;SACD,OAAO,CAAC,MAAM,CAAC;SACf,KAAK,CAAC,IAAI,CAAC;SACX,WAAW,CAAC,2BAA2B,CAAC;SACxC,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;QAChC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC;YAClB,MAAM,CAAC,KAAK,CAAC,yDAAyD,CAAC,CAAC;YACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACtD,OAAO,CAAC,GAAG,CACT,MAAM,CAAC,KAAK,CACV,CAAC,SAAS,EAAE,MAAM,CAAC,EACnB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CACvC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEL,IAAI;SACD,OAAO,CAAC,gBAAgB,CAAC;SACzB,WAAW,CAAC,qCAAqC,CAAC;SAClD,MAAM,CAAC,eAAe,EAAE,+BAA+B,EAAE,QAAQ,CAAC;SAClE,MAAM,CAAC,KAAK,EAAE,KAAa,EAAE,IAAsB,EAAE,EAAE;QACtD,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;QAChC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC;YAClB,MAAM,CAAC,KAAK,CAAC,yDAAyD,CAAC,CAAC;YACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACzD,MAAM,CAAC,OAAO,CAAC,WAAW,KAAK,OAAO,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEL,IAAI;SACD,OAAO,CAAC,iBAAiB,CAAC;SAC1B,WAAW,CAAC,uCAAuC,CAAC;SACpD,MAAM,CAAC,KAAK,EAAE,MAAc,EAAE,EAAE;QAC/B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;QAChC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC;YAClB,MAAM,CAAC,KAAK,CAAC,yDAAyD,CAAC,CAAC;YACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC/C,MAAM,CAAC,OAAO,CAAC,kBAAkB,MAAM,GAAG,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ import type { ApiClient } from "../client.js";
3
+ export declare function registerTokenCommands(program: Command, getClient: () => ApiClient): void;
@@ -0,0 +1,31 @@
1
+ import * as output from "../output.js";
2
+ export function registerTokenCommands(program, getClient) {
3
+ const tokens = program.command("tokens").description("Manage API tokens");
4
+ tokens
5
+ .command("list")
6
+ .alias("ls")
7
+ .description("List maker tokens")
8
+ .action(async () => {
9
+ const client = getClient();
10
+ const items = await client.listTokens();
11
+ if (items.length === 0) {
12
+ output.info("No tokens found.");
13
+ return;
14
+ }
15
+ console.log(output.table(["Label", "Last 4", "Scope", "Created"], items.map((t) => [
16
+ t.label,
17
+ `...${t.lastFour}`,
18
+ t.productId ? `product:${t.productId.slice(0, 8)}` : "org-wide",
19
+ output.formatDate(t.createdAt),
20
+ ])));
21
+ });
22
+ tokens
23
+ .command("revoke <id>")
24
+ .description("Revoke a token")
25
+ .action(async (id) => {
26
+ const client = getClient();
27
+ await client.revokeToken(id);
28
+ output.success(`Token ${id} revoked.`);
29
+ });
30
+ }
31
+ //# sourceMappingURL=tokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/commands/tokens.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,MAAM,cAAc,CAAC;AAEvC,MAAM,UAAU,qBAAqB,CACnC,OAAgB,EAChB,SAA0B;IAE1B,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,mBAAmB,CAAC,CAAC;IAE1E,MAAM;SACH,OAAO,CAAC,MAAM,CAAC;SACf,KAAK,CAAC,IAAI,CAAC;SACX,WAAW,CAAC,mBAAmB,CAAC;SAChC,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC;QACxC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;YAChC,OAAO;QACT,CAAC;QACD,OAAO,CAAC,GAAG,CACT,MAAM,CAAC,KAAK,CACV,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,CAAC,EACvC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YACf,CAAC,CAAC,KAAK;YACP,MAAM,CAAC,CAAC,QAAQ,EAAE;YAClB,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU;YAC/D,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;SAC/B,CAAC,CACH,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEL,MAAM;SACH,OAAO,CAAC,aAAa,CAAC;SACtB,WAAW,CAAC,gBAAgB,CAAC;SAC7B,MAAM,CAAC,KAAK,EAAE,EAAU,EAAE,EAAE;QAC3B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QAC7B,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ import type { ApiClient } from "../client.js";
3
+ export declare function registerUsageCommands(program: Command, getClient: () => ApiClient): void;
@@ -0,0 +1,24 @@
1
+ import * as output from "../output.js";
2
+ export function registerUsageCommands(program, getClient) {
3
+ program
4
+ .command("usage")
5
+ .description("Show usage analytics for a product")
6
+ .requiredOption("--product <id>", "Product ID")
7
+ .option("--live", "Poll for live updates every 5 seconds")
8
+ .action(async (opts) => {
9
+ const client = getClient();
10
+ async function showUsage() {
11
+ const data = await client.getUsage(opts.product);
12
+ if (opts.live)
13
+ console.clear();
14
+ output.heading("Usage Summary");
15
+ console.log(output.json(data));
16
+ }
17
+ await showUsage();
18
+ if (opts.live) {
19
+ output.info("Polling every 5s. Press Ctrl+C to stop.");
20
+ setInterval(showUsage, 5000);
21
+ }
22
+ });
23
+ }
24
+ //# sourceMappingURL=usage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.js","sourceRoot":"","sources":["../../src/commands/usage.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,MAAM,cAAc,CAAC;AAEvC,MAAM,UAAU,qBAAqB,CACnC,OAAgB,EAChB,SAA0B;IAE1B,OAAO;SACJ,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,oCAAoC,CAAC;SACjD,cAAc,CAAC,gBAAgB,EAAE,YAAY,CAAC;SAC9C,MAAM,CAAC,QAAQ,EAAE,uCAAuC,CAAC;SACzD,MAAM,CAAC,KAAK,EAAE,IAAyC,EAAE,EAAE;QAC1D,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAE3B,KAAK,UAAU,SAAS;YACtB,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACjD,IAAI,IAAI,CAAC,IAAI;gBAAE,OAAO,CAAC,KAAK,EAAE,CAAC;YAC/B,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;YAChC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACjC,CAAC;QAED,MAAM,SAAS,EAAE,CAAC;QAElB,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,MAAM,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;YACvD,WAAW,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { CliConfig, Credentials } from "./types.js";
2
+ export declare function loadConfig(): CliConfig;
3
+ export declare function saveConfig(config: Partial<CliConfig>): void;
4
+ export declare function loadCredentials(): Credentials | null;
5
+ export declare function saveCredentials(creds: Credentials): void;
6
+ export declare function clearCredentials(): void;
7
+ export declare function getConfigPath(productSlug: string): string;
8
+ export declare function writeConfigFile(productSlug: string, content: string): string;
9
+ export declare function readConfigFile(productSlug: string): string | null;
package/dist/config.js ADDED
@@ -0,0 +1,74 @@
1
+ // ~/.farthershore/ config management
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { join } from "node:path";
5
+ const CONFIG_DIR = join(homedir(), ".farthershore");
6
+ const CONFIG_FILE = join(CONFIG_DIR, "config.json");
7
+ const CREDENTIALS_FILE = join(CONFIG_DIR, "credentials.json");
8
+ const CONFIGS_DIR = join(CONFIG_DIR, "configs");
9
+ function ensureDir(dir) {
10
+ if (!existsSync(dir))
11
+ mkdirSync(dir, { recursive: true });
12
+ }
13
+ // --- Config ---
14
+ const DEFAULT_CONFIG = {
15
+ apiUrl: "https://api.farthershore.com",
16
+ defaultFormat: "table",
17
+ };
18
+ export function loadConfig() {
19
+ ensureDir(CONFIG_DIR);
20
+ if (!existsSync(CONFIG_FILE))
21
+ return DEFAULT_CONFIG;
22
+ try {
23
+ return {
24
+ ...DEFAULT_CONFIG,
25
+ ...JSON.parse(readFileSync(CONFIG_FILE, "utf-8")),
26
+ };
27
+ }
28
+ catch {
29
+ return DEFAULT_CONFIG;
30
+ }
31
+ }
32
+ export function saveConfig(config) {
33
+ ensureDir(CONFIG_DIR);
34
+ const current = loadConfig();
35
+ writeFileSync(CONFIG_FILE, JSON.stringify({ ...current, ...config }, null, 2) + "\n");
36
+ }
37
+ // --- Credentials ---
38
+ export function loadCredentials() {
39
+ if (!existsSync(CREDENTIALS_FILE))
40
+ return null;
41
+ try {
42
+ return JSON.parse(readFileSync(CREDENTIALS_FILE, "utf-8"));
43
+ }
44
+ catch {
45
+ return null;
46
+ }
47
+ }
48
+ export function saveCredentials(creds) {
49
+ ensureDir(CONFIG_DIR);
50
+ writeFileSync(CREDENTIALS_FILE, JSON.stringify(creds, null, 2) + "\n");
51
+ }
52
+ export function clearCredentials() {
53
+ if (existsSync(CREDENTIALS_FILE)) {
54
+ writeFileSync(CREDENTIALS_FILE, "{}");
55
+ }
56
+ }
57
+ // --- Plan configs ---
58
+ export function getConfigPath(productSlug) {
59
+ const dir = join(CONFIGS_DIR, productSlug);
60
+ ensureDir(dir);
61
+ return join(dir, "plans.yaml");
62
+ }
63
+ export function writeConfigFile(productSlug, content) {
64
+ const path = getConfigPath(productSlug);
65
+ writeFileSync(path, content);
66
+ return path;
67
+ }
68
+ export function readConfigFile(productSlug) {
69
+ const path = getConfigPath(productSlug);
70
+ if (!existsSync(path))
71
+ return null;
72
+ return readFileSync(path, "utf-8");
73
+ }
74
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import { createClient } from "./client.js";
4
+ import { resolveToken } from "./auth.js";
5
+ import { loadConfig } from "./config.js";
6
+ import { registerLoginCommands } from "./commands/login.js";
7
+ import { registerProductCommands } from "./commands/products.js";
8
+ import { registerPlanCommands } from "./commands/plans.js";
9
+ import { registerTokenCommands } from "./commands/tokens.js";
10
+ import { registerTeamCommands } from "./commands/team.js";
11
+ import { registerBillingCommands } from "./commands/billing.js";
12
+ import { registerUsageCommands } from "./commands/usage.js";
13
+ import { registerInitCommand } from "./commands/init.js";
14
+ import { CliError } from "./types.js";
15
+ const program = new Command();
16
+ program
17
+ .name("farthershore")
18
+ .description("FartherShore CLI — manage API products, plans, and billing")
19
+ .version("0.1.0")
20
+ .option("--token <token>", "Override auth token")
21
+ .option("--api-url <url>", "Override API base URL")
22
+ .option("--format <format>", "Output format: table, json, yaml");
23
+ // Lazy client — created on first use with resolved auth
24
+ function getClient() {
25
+ const config = loadConfig();
26
+ const globalOpts = program.opts();
27
+ const token = resolveToken(globalOpts.token);
28
+ const apiUrl = globalOpts.apiUrl ?? process.env.FARTHERSHORE_API_URL ?? config.apiUrl;
29
+ return createClient({ apiUrl, token });
30
+ }
31
+ // Register all command groups
32
+ registerLoginCommands(program);
33
+ registerProductCommands(program, getClient);
34
+ registerPlanCommands(program, getClient);
35
+ registerTokenCommands(program, getClient);
36
+ registerTeamCommands(program, getClient);
37
+ registerBillingCommands(program, getClient);
38
+ registerUsageCommands(program, getClient);
39
+ registerInitCommand(program, getClient);
40
+ // Global error handler
41
+ program.exitOverride();
42
+ async function main() {
43
+ try {
44
+ await program.parseAsync(process.argv);
45
+ }
46
+ catch (err) {
47
+ if (err instanceof CliError) {
48
+ process.stderr.write(`Error: ${err.message}\n`);
49
+ process.exitCode = 1;
50
+ }
51
+ else if (err instanceof Error && err.message !== "(outputHelp)") {
52
+ process.stderr.write(`Error: ${err.message}\n`);
53
+ process.exitCode = 1;
54
+ }
55
+ }
56
+ }
57
+ main();
58
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export declare function table(headers: string[], rows: string[][]): string;
2
+ export declare function json(data: unknown): string;
3
+ export declare function success(msg: string): void;
4
+ export declare function error(msg: string): void;
5
+ export declare function warn(msg: string): void;
6
+ export declare function info(msg: string): void;
7
+ export declare function heading(msg: string): void;
8
+ export declare function formatPrice(cents: number): string;
9
+ export declare function formatDate(iso: string): string;
10
+ export declare function isTTY(): boolean;
11
+ export declare function outputFormat(flagFormat: string | undefined): "table" | "json" | "yaml";