@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.
- package/README.md +83 -0
- package/dist/auth.d.ts +1 -0
- package/dist/auth.js +18 -0
- package/dist/auth.js.map +1 -0
- package/dist/client.d.ts +74 -0
- package/dist/client.js +71 -0
- package/dist/client.js.map +1 -0
- package/dist/commands/billing.d.ts +3 -0
- package/dist/commands/billing.js +32 -0
- package/dist/commands/billing.js.map +1 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.js +42 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +82 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/plans.d.ts +3 -0
- package/dist/commands/plans.js +205 -0
- package/dist/commands/plans.js.map +1 -0
- package/dist/commands/products.d.ts +3 -0
- package/dist/commands/products.js +77 -0
- package/dist/commands/products.js.map +1 -0
- package/dist/commands/team.d.ts +3 -0
- package/dist/commands/team.js +47 -0
- package/dist/commands/team.js.map +1 -0
- package/dist/commands/tokens.d.ts +3 -0
- package/dist/commands/tokens.js +31 -0
- package/dist/commands/tokens.js.map +1 -0
- package/dist/commands/usage.d.ts +3 -0
- package/dist/commands/usage.js +24 -0
- package/dist/commands/usage.js.map +1 -0
- package/dist/config.d.ts +9 -0
- package/dist/config.js +74 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +58 -0
- package/dist/index.js.map +1 -0
- package/dist/output.d.ts +11 -0
- package/dist/output.js +48 -0
- package/dist/output.js.map +1 -0
- package/dist/types.d.ts +86 -0
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# @farthershore/cli
|
|
2
|
+
|
|
3
|
+
FartherShore CLI — manage API products, plans, and billing from the terminal.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @farthershore/cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Authentication
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Option 1: Interactive login
|
|
15
|
+
farthershore login
|
|
16
|
+
|
|
17
|
+
# Option 2: Environment variable (CI/CD)
|
|
18
|
+
export FARTHERSHORE_TOKEN=mk_xxx.yyy
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# List your products
|
|
25
|
+
farthershore products list
|
|
26
|
+
|
|
27
|
+
# Create a product
|
|
28
|
+
farthershore products create "Weather API" --base-url https://api.weather.com
|
|
29
|
+
|
|
30
|
+
# Pull plan config
|
|
31
|
+
farthershore plans pull --product <product-id>
|
|
32
|
+
|
|
33
|
+
# Edit plans.yaml, then push
|
|
34
|
+
farthershore plans push --product <product-id>
|
|
35
|
+
|
|
36
|
+
# Check Stripe status
|
|
37
|
+
farthershore billing status
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Commands
|
|
41
|
+
|
|
42
|
+
| Command | Description |
|
|
43
|
+
|---------|-------------|
|
|
44
|
+
| `farthershore login` | Authenticate with FartherShore |
|
|
45
|
+
| `farthershore whoami` | Show current auth context |
|
|
46
|
+
| `farthershore products list` | List products |
|
|
47
|
+
| `farthershore products create` | Create a draft product |
|
|
48
|
+
| `farthershore products publish` | Publish a product |
|
|
49
|
+
| `farthershore plans pull` | Export plan config to YAML |
|
|
50
|
+
| `farthershore plans push` | Validate, diff, and apply config |
|
|
51
|
+
| `farthershore plans diff` | Preview changes without applying |
|
|
52
|
+
| `farthershore tokens list` | List API tokens |
|
|
53
|
+
| `farthershore team invite` | Invite a team member |
|
|
54
|
+
| `farthershore billing connect` | Connect Stripe |
|
|
55
|
+
| `farthershore usage` | View usage analytics |
|
|
56
|
+
|
|
57
|
+
## Plan Config as Code
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# Pull current config
|
|
61
|
+
farthershore plans pull --product weather-api
|
|
62
|
+
|
|
63
|
+
# Edit the YAML
|
|
64
|
+
vim ~/.farthershore/configs/weather-api/plans.yaml
|
|
65
|
+
|
|
66
|
+
# See what would change
|
|
67
|
+
farthershore plans diff --product weather-api
|
|
68
|
+
|
|
69
|
+
# Apply changes
|
|
70
|
+
farthershore plans push --product weather-api
|
|
71
|
+
|
|
72
|
+
# CI mode (no confirmation)
|
|
73
|
+
farthershore plans push --product weather-api --yes
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Global Flags
|
|
77
|
+
|
|
78
|
+
| Flag | Description |
|
|
79
|
+
|------|-------------|
|
|
80
|
+
| `--token <token>` | Override auth token |
|
|
81
|
+
| `--api-url <url>` | Override API base URL |
|
|
82
|
+
| `--format json\|table` | Output format |
|
|
83
|
+
| `--yes` | Skip confirmation prompts |
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function resolveToken(overrideToken?: string): string;
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Token resolution: env var → credentials file → error
|
|
2
|
+
import { loadCredentials } from "./config.js";
|
|
3
|
+
import { CliError } from "./types.js";
|
|
4
|
+
export function resolveToken(overrideToken) {
|
|
5
|
+
// 1. Explicit override (--token flag)
|
|
6
|
+
if (overrideToken)
|
|
7
|
+
return overrideToken;
|
|
8
|
+
// 2. Environment variable
|
|
9
|
+
const envToken = process.env.FARTHERSHORE_TOKEN;
|
|
10
|
+
if (envToken)
|
|
11
|
+
return envToken;
|
|
12
|
+
// 3. Stored credentials (from `farthershore login`)
|
|
13
|
+
const creds = loadCredentials();
|
|
14
|
+
if (creds?.token)
|
|
15
|
+
return creds.token;
|
|
16
|
+
throw new CliError("Not authenticated. Run `farthershore login` or set FARTHERSHORE_TOKEN environment variable.");
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,uDAAuD;AAEvD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,MAAM,UAAU,YAAY,CAAC,aAAsB;IACjD,sCAAsC;IACtC,IAAI,aAAa;QAAE,OAAO,aAAa,CAAC;IAExC,0BAA0B;IAC1B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAChD,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,oDAAoD;IACpD,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;IAChC,IAAI,KAAK,EAAE,KAAK;QAAE,OAAO,KAAK,CAAC,KAAK,CAAC;IAErC,MAAM,IAAI,QAAQ,CAChB,6FAA6F,CAC9F,CAAC;AACJ,CAAC"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { Product, Plan, ApplyResponse, MakerToken, OrgMember, InitProductResponse } from "./types.js";
|
|
2
|
+
export declare function createClient(opts: {
|
|
3
|
+
apiUrl: string;
|
|
4
|
+
token: string;
|
|
5
|
+
}): {
|
|
6
|
+
bootstrap: () => Promise<{
|
|
7
|
+
user: {
|
|
8
|
+
id: string;
|
|
9
|
+
clerkUserId: string;
|
|
10
|
+
};
|
|
11
|
+
activeOrganization: {
|
|
12
|
+
id: string;
|
|
13
|
+
name?: string;
|
|
14
|
+
slug?: string;
|
|
15
|
+
};
|
|
16
|
+
memberships: Array<{
|
|
17
|
+
organization: {
|
|
18
|
+
id: string;
|
|
19
|
+
name?: string;
|
|
20
|
+
slug?: string;
|
|
21
|
+
};
|
|
22
|
+
role: string;
|
|
23
|
+
}>;
|
|
24
|
+
}>;
|
|
25
|
+
validateToken: () => Promise<{
|
|
26
|
+
valid: boolean;
|
|
27
|
+
type: string;
|
|
28
|
+
orgId: string;
|
|
29
|
+
productId: string | null;
|
|
30
|
+
permissions: string[];
|
|
31
|
+
}>;
|
|
32
|
+
listProducts: () => Promise<Product[]>;
|
|
33
|
+
getProduct: (id: string) => Promise<Product>;
|
|
34
|
+
createProduct: (data: {
|
|
35
|
+
name: string;
|
|
36
|
+
baseUrl: string;
|
|
37
|
+
description?: string;
|
|
38
|
+
}) => Promise<Product>;
|
|
39
|
+
updateProduct: (id: string, data: Record<string, unknown>) => Promise<Product>;
|
|
40
|
+
deleteProduct: (id: string) => Promise<void>;
|
|
41
|
+
publishProduct: (id: string) => Promise<Product>;
|
|
42
|
+
initProduct: (data: {
|
|
43
|
+
name: string;
|
|
44
|
+
baseUrl?: string;
|
|
45
|
+
description?: string;
|
|
46
|
+
displayName?: string;
|
|
47
|
+
billingStrategy?: string;
|
|
48
|
+
}) => Promise<InitProductResponse>;
|
|
49
|
+
listPlans: (productId: string) => Promise<Plan[]>;
|
|
50
|
+
createPlan: (productId: string, data: Record<string, unknown>) => Promise<Plan>;
|
|
51
|
+
updatePlan: (productId: string, planId: string, data: Record<string, unknown>) => Promise<Plan>;
|
|
52
|
+
deletePlan: (productId: string, planId: string) => Promise<void>;
|
|
53
|
+
exportPlanConfig: (productId: string) => Promise<string>;
|
|
54
|
+
applyPlanConfig: (productId: string, config: string, opts?: {
|
|
55
|
+
configHash?: string;
|
|
56
|
+
force?: boolean;
|
|
57
|
+
validateOnly?: boolean;
|
|
58
|
+
}) => Promise<ApplyResponse>;
|
|
59
|
+
listTokens: () => Promise<MakerToken[]>;
|
|
60
|
+
revokeToken: (id: string) => Promise<void>;
|
|
61
|
+
listMembers: (orgId: string) => Promise<OrgMember[]>;
|
|
62
|
+
inviteMember: (orgId: string, email: string, role: string) => Promise<unknown>;
|
|
63
|
+
removeMember: (orgId: string, userId: string) => Promise<void>;
|
|
64
|
+
getStripeStatus: () => Promise<{
|
|
65
|
+
connected: boolean;
|
|
66
|
+
chargesEnabled?: boolean;
|
|
67
|
+
accountId?: string;
|
|
68
|
+
}>;
|
|
69
|
+
startStripeOnboard: () => Promise<{
|
|
70
|
+
url: string;
|
|
71
|
+
}>;
|
|
72
|
+
getUsage: (productId: string) => Promise<Record<string, unknown>>;
|
|
73
|
+
};
|
|
74
|
+
export type ApiClient = ReturnType<typeof createClient>;
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// Typed API client for the FartherShore platform
|
|
2
|
+
import { CliError } from "./types.js";
|
|
3
|
+
export function createClient(opts) {
|
|
4
|
+
async function request(method, path, body) {
|
|
5
|
+
const res = await fetch(`${opts.apiUrl}${path}`, {
|
|
6
|
+
method,
|
|
7
|
+
headers: {
|
|
8
|
+
Authorization: `Bearer ${opts.token}`,
|
|
9
|
+
"Content-Type": "application/json",
|
|
10
|
+
},
|
|
11
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
12
|
+
});
|
|
13
|
+
if (!res.ok) {
|
|
14
|
+
const err = await res.json().catch(() => ({ error: res.statusText }));
|
|
15
|
+
throw new CliError(err.error ?? `API error: ${res.status}`, res.status);
|
|
16
|
+
}
|
|
17
|
+
if (res.status === 204)
|
|
18
|
+
return undefined;
|
|
19
|
+
return res.json();
|
|
20
|
+
}
|
|
21
|
+
async function rawText(method, path) {
|
|
22
|
+
const res = await fetch(`${opts.apiUrl}${path}`, {
|
|
23
|
+
method,
|
|
24
|
+
headers: { Authorization: `Bearer ${opts.token}` },
|
|
25
|
+
});
|
|
26
|
+
if (!res.ok) {
|
|
27
|
+
throw new CliError(`API error: ${res.status}`, res.status);
|
|
28
|
+
}
|
|
29
|
+
return res.text();
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
// --- Auth ---
|
|
33
|
+
bootstrap: () => request("POST", "/builder/context/bootstrap"),
|
|
34
|
+
validateToken: () => request("POST", "/auth/validate-token"),
|
|
35
|
+
// --- Products ---
|
|
36
|
+
listProducts: () => request("GET", "/products"),
|
|
37
|
+
getProduct: (id) => request("GET", `/products/${id}`),
|
|
38
|
+
createProduct: (data) => request("POST", "/products", data),
|
|
39
|
+
updateProduct: (id, data) => request("PATCH", `/products/${id}`, data),
|
|
40
|
+
deleteProduct: (id) => request("DELETE", `/products/${id}`),
|
|
41
|
+
publishProduct: (id) => request("POST", `/products/${id}/publish`),
|
|
42
|
+
initProduct: (data) => request("POST", "/products/init", data),
|
|
43
|
+
// --- Plans ---
|
|
44
|
+
listPlans: (productId) => request("GET", `/products/${productId}/plans`),
|
|
45
|
+
createPlan: (productId, data) => request("POST", `/products/${productId}/plans`, data),
|
|
46
|
+
updatePlan: (productId, planId, data) => request("PATCH", `/products/${productId}/plans/${planId}`, data),
|
|
47
|
+
deletePlan: (productId, planId) => request("DELETE", `/products/${productId}/plans/${planId}`),
|
|
48
|
+
// --- Plan config (declarative) ---
|
|
49
|
+
exportPlanConfig: (productId) => rawText("GET", `/products/${productId}/plans/export`),
|
|
50
|
+
applyPlanConfig: (productId, config, opts) => {
|
|
51
|
+
const params = opts?.validateOnly ? "?validate_only=true" : "";
|
|
52
|
+
return request("POST", `/products/${productId}/plans/apply${params}`, { config, configHash: opts?.configHash, force: opts?.force });
|
|
53
|
+
},
|
|
54
|
+
// --- Tokens ---
|
|
55
|
+
listTokens: () => request("GET", "/maker-tokens"),
|
|
56
|
+
revokeToken: (id) => request("DELETE", `/maker-tokens/${id}`),
|
|
57
|
+
// --- Team ---
|
|
58
|
+
listMembers: (orgId) => request("GET", `/builder/organizations/${orgId}/members`),
|
|
59
|
+
inviteMember: (orgId, email, role) => request("POST", `/builder/organizations/${orgId}/invitations`, {
|
|
60
|
+
email,
|
|
61
|
+
role,
|
|
62
|
+
}),
|
|
63
|
+
removeMember: (orgId, userId) => request("DELETE", `/builder/organizations/${orgId}/members/${userId}`),
|
|
64
|
+
// --- Billing ---
|
|
65
|
+
getStripeStatus: () => request("GET", "/builder/stripe/status"),
|
|
66
|
+
startStripeOnboard: () => request("POST", "/builder/stripe/onboard"),
|
|
67
|
+
// --- Usage ---
|
|
68
|
+
getUsage: (productId) => request("GET", `/products/${productId}/usage`),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as output from "../output.js";
|
|
2
|
+
export function registerBillingCommands(program, getClient) {
|
|
3
|
+
const billing = program
|
|
4
|
+
.command("billing")
|
|
5
|
+
.description("Stripe billing integration");
|
|
6
|
+
billing
|
|
7
|
+
.command("status")
|
|
8
|
+
.description("Show Stripe connection status")
|
|
9
|
+
.action(async () => {
|
|
10
|
+
const client = getClient();
|
|
11
|
+
const status = await client.getStripeStatus();
|
|
12
|
+
if (status.connected) {
|
|
13
|
+
output.success("Stripe connected");
|
|
14
|
+
console.log(` Account: ${status.accountId}`);
|
|
15
|
+
console.log(` Charges enabled: ${status.chargesEnabled ? "✓" : "✗"}`);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
output.warn("Stripe not connected.");
|
|
19
|
+
output.info("Run `farthershore billing connect` to start onboarding.");
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
billing
|
|
23
|
+
.command("connect")
|
|
24
|
+
.description("Start Stripe Connect onboarding (opens browser)")
|
|
25
|
+
.action(async () => {
|
|
26
|
+
const client = getClient();
|
|
27
|
+
const result = await client.startStripeOnboard();
|
|
28
|
+
output.success("Stripe onboarding started.");
|
|
29
|
+
console.log(`\n Open this URL in your browser:\n ${result.url}\n`);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=billing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"billing.js","sourceRoot":"","sources":["../../src/commands/billing.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,MAAM,cAAc,CAAC;AAEvC,MAAM,UAAU,uBAAuB,CACrC,OAAgB,EAChB,SAA0B;IAE1B,MAAM,OAAO,GAAG,OAAO;SACpB,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,4BAA4B,CAAC,CAAC;IAE7C,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,+BAA+B,CAAC;SAC5C,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,eAAe,EAAE,CAAC;QAC9C,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACrB,MAAM,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;YACnC,OAAO,CAAC,GAAG,CAAC,sBAAsB,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;YACtD,OAAO,CAAC,GAAG,CAAC,sBAAsB,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;QACzE,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;YACrC,MAAM,CAAC,IAAI,CAAC,yDAAyD,CAAC,CAAC;QACzE,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,iDAAiD,CAAC;SAC9D,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,kBAAkB,EAAE,CAAC;QACjD,MAAM,CAAC,OAAO,CAAC,4BAA4B,CAAC,CAAC;QAC7C,OAAO,CAAC,GAAG,CAAC,yCAAyC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import * as output from "../output.js";
|
|
2
|
+
export function registerInitCommand(program, getClient) {
|
|
3
|
+
program
|
|
4
|
+
.command("init <name>")
|
|
5
|
+
.description("Create a new product with a GitHub repo for agent-first configuration")
|
|
6
|
+
.option("--base-url <url>", "Backend API base URL")
|
|
7
|
+
.option("--description <desc>", "Product description")
|
|
8
|
+
.option("--display-name <name>", "Display name")
|
|
9
|
+
.option("--billing <strategy>", "Billing strategy: subscription|usage_based|hybrid", "subscription")
|
|
10
|
+
.action(async (name, opts) => {
|
|
11
|
+
const client = getClient();
|
|
12
|
+
const result = await client.initProduct({
|
|
13
|
+
name,
|
|
14
|
+
baseUrl: opts.baseUrl,
|
|
15
|
+
description: opts.description,
|
|
16
|
+
displayName: opts.displayName,
|
|
17
|
+
billingStrategy: opts.billing,
|
|
18
|
+
});
|
|
19
|
+
const format = output.outputFormat(program.opts().format);
|
|
20
|
+
if (format === "json") {
|
|
21
|
+
console.log(output.json(result));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
output.success(`Created product "${result.product.name}" (DRAFT)`);
|
|
25
|
+
console.log();
|
|
26
|
+
if (result.repo) {
|
|
27
|
+
console.log(` Repository: ${result.repo.htmlUrl}`);
|
|
28
|
+
console.log(` Clone: git clone ${result.repo.cloneUrl}`);
|
|
29
|
+
console.log();
|
|
30
|
+
}
|
|
31
|
+
console.log(" Next steps:");
|
|
32
|
+
console.log(" 1. Clone the repository");
|
|
33
|
+
console.log(" 2. Read AGENTS.md for the full configuration reference");
|
|
34
|
+
console.log(" 3. Edit product.yaml — add your base URL, plans, and meters");
|
|
35
|
+
console.log(" 4. Push to main — a valid config goes live automatically");
|
|
36
|
+
console.log();
|
|
37
|
+
if (result.agent.agentsMdUrl) {
|
|
38
|
+
console.log(` Docs: ${result.agent.agentsMdUrl}`);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,MAAM,cAAc,CAAC;AAEvC,MAAM,UAAU,mBAAmB,CACjC,OAAgB,EAChB,SAA0B;IAE1B,OAAO;SACJ,OAAO,CAAC,aAAa,CAAC;SACtB,WAAW,CACV,uEAAuE,CACxE;SACA,MAAM,CAAC,kBAAkB,EAAE,sBAAsB,CAAC;SAClD,MAAM,CAAC,sBAAsB,EAAE,qBAAqB,CAAC;SACrD,MAAM,CAAC,uBAAuB,EAAE,cAAc,CAAC;SAC/C,MAAM,CACL,sBAAsB,EACtB,mDAAmD,EACnD,cAAc,CACf;SACA,MAAM,CACL,KAAK,EACH,IAAY,EACZ,IAKC,EACD,EAAE;QACF,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC;YACtC,IAAI;YACJ,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,eAAe,EAAE,IAAI,CAAC,OAAO;SAC9B,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC;QAE1D,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;YACjC,OAAO;QACT,CAAC;QAED,MAAM,CAAC,OAAO,CAAC,oBAAoB,MAAM,CAAC,OAAO,CAAC,IAAI,WAAW,CAAC,CAAC;QACnE,OAAO,CAAC,GAAG,EAAE,CAAC;QAEd,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YAChB,OAAO,CAAC,GAAG,CAAC,kBAAkB,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;YACrD,OAAO,CAAC,GAAG,CAAC,4BAA4B,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;YAChE,OAAO,CAAC,GAAG,EAAE,CAAC;QAChB,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;QAC3C,OAAO,CAAC,GAAG,CACT,4DAA4D,CAC7D,CAAC;QACF,OAAO,CAAC,GAAG,CACT,iEAAiE,CAClE,CAAC;QACF,OAAO,CAAC,GAAG,CACT,8DAA8D,CAC/D,CAAC;QACF,OAAO,CAAC,GAAG,EAAE,CAAC;QAEd,IAAI,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;YAC7B,OAAO,CAAC,GAAG,CAAC,WAAW,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;QACrD,CAAC;IACH,CAAC,CACF,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import * as readline from "node:readline/promises";
|
|
2
|
+
import { createClient } from "../client.js";
|
|
3
|
+
import { loadConfig, saveCredentials, clearCredentials, loadCredentials, } from "../config.js";
|
|
4
|
+
import { resolveToken } from "../auth.js";
|
|
5
|
+
import * as output from "../output.js";
|
|
6
|
+
export function registerLoginCommands(program) {
|
|
7
|
+
program
|
|
8
|
+
.command("login")
|
|
9
|
+
.description("Authenticate with FartherShore")
|
|
10
|
+
.action(async () => {
|
|
11
|
+
const config = loadConfig();
|
|
12
|
+
console.log("Authenticate with FartherShore\n");
|
|
13
|
+
console.log("1. Create a token at https://farthershore.com/settings/tokens");
|
|
14
|
+
console.log("2. Paste it below:\n");
|
|
15
|
+
const rl = readline.createInterface({
|
|
16
|
+
input: process.stdin,
|
|
17
|
+
output: process.stdout,
|
|
18
|
+
});
|
|
19
|
+
const token = await rl.question("Token: ");
|
|
20
|
+
rl.close();
|
|
21
|
+
if (!token.trim()) {
|
|
22
|
+
output.error("No token provided.");
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
const client = createClient({
|
|
27
|
+
apiUrl: config.apiUrl,
|
|
28
|
+
token: token.trim(),
|
|
29
|
+
});
|
|
30
|
+
const ctx = await client.bootstrap();
|
|
31
|
+
saveCredentials({
|
|
32
|
+
token: token.trim(),
|
|
33
|
+
orgId: ctx.activeOrganization.id,
|
|
34
|
+
userId: ctx.user.id,
|
|
35
|
+
});
|
|
36
|
+
output.success(`Authenticated as user ${ctx.user.id}`);
|
|
37
|
+
console.log(` Organization: ${ctx.activeOrganization.name ?? ctx.activeOrganization.slug ?? ctx.activeOrganization.id}`);
|
|
38
|
+
output.info("Credentials saved to ~/.farthershore/credentials.json");
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
output.error(err instanceof Error ? err.message : "Authentication failed");
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
program
|
|
46
|
+
.command("logout")
|
|
47
|
+
.description("Clear stored credentials")
|
|
48
|
+
.action(() => {
|
|
49
|
+
clearCredentials();
|
|
50
|
+
output.success("Credentials cleared.");
|
|
51
|
+
});
|
|
52
|
+
program
|
|
53
|
+
.command("whoami")
|
|
54
|
+
.description("Show current auth context")
|
|
55
|
+
.action(async () => {
|
|
56
|
+
const config = loadConfig();
|
|
57
|
+
try {
|
|
58
|
+
const token = resolveToken();
|
|
59
|
+
const client = createClient({ apiUrl: config.apiUrl, token });
|
|
60
|
+
const ctx = await client.bootstrap();
|
|
61
|
+
output.heading("Current Context");
|
|
62
|
+
console.log(` User: ${ctx.user.id}`);
|
|
63
|
+
console.log(` Organization: ${ctx.activeOrganization.name ?? ctx.activeOrganization.id}`);
|
|
64
|
+
console.log(` Memberships: ${ctx.memberships.length} org(s)`);
|
|
65
|
+
const creds = loadCredentials();
|
|
66
|
+
if (creds?.token?.startsWith("mk_")) {
|
|
67
|
+
output.info(" Auth: Maker Token");
|
|
68
|
+
}
|
|
69
|
+
else if (process.env.FARTHERSHORE_TOKEN) {
|
|
70
|
+
output.info(" Auth: Environment variable");
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
output.info(" Auth: Stored credentials");
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
output.error(err instanceof Error ? err.message : "Not authenticated");
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
|