diff --git a/packages/cli/README.md b/packages/cli/README.md index 0d9f79b..dc5e382 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -8,7 +8,7 @@ CLI-native affiliate tracking. Connect Stripe, track commissions, manage partner # Create your affiliate program npx affitor init -# Connect Stripe in the Affitor dashboard: program Settings, Connect Stripe +# Connect Stripe in the Affitor dashboard: Program settings → Payments, Connect Stripe # Check program health npx affitor status @@ -25,7 +25,7 @@ npx affitor test sale |---|---| | `affitor init` | Create a new affiliate program. Interactive prompts or `--no-interactive` with flags. | | `affitor onboard` | Wire Affitor into an existing app end-to-end: detect → install browser tracking → inject the Stripe sale call → verify. | -| `affitor setup stripe` | Points you to the dashboard, where Stripe is connected (program Settings, Connect Stripe). Exits 1. | +| `affitor setup stripe` | Points you to the dashboard, where Stripe is connected (Program settings → Payments, Connect Stripe). Exits 1. | | `affitor setup dns` | Set up DNS CNAME tracking (coming soon). | | `affitor status` | Show program health: DNS, Stripe connection, recent events. | | `affitor test [type]` | Send a test event (`click`, `lead`, or `sale`). | @@ -93,7 +93,7 @@ Running `npx affitor init` creates: ## Stripe -Stripe is connected from the Affitor dashboard (program Settings, Connect Stripe), not from the CLI. Affitor's own webhook then records sales and renewals; add Affitor metadata to your checkout so sales are attributed reliably. +Stripe is connected from the Affitor dashboard (Program settings → Payments, Connect Stripe), not from the CLI. Affitor's own webhook then records sales and renewals; add Affitor metadata to your checkout so sales are attributed reliably. ## Requirements diff --git a/packages/cli/src/commands/init.ts b/packages/cli/src/commands/init.ts index 496f786..ab7eb5d 100644 --- a/packages/cli/src/commands/init.ts +++ b/packages/cli/src/commands/init.ts @@ -77,7 +77,7 @@ export async function runInit( "Affitor already configured in this directory.\n" + " Use `npx affitor status` to check your program.\n" + " `init` creates a new program: it does not restore this one and does not replace its API key.\n" + - " For a new key, ask a workspace owner of this program to open Affitor → Settings → API Key " + + " For a new key, ask a workspace owner of this program to open Affitor → Program settings → Developers → API keys " + "and click Regenerate, then replace the key this project uses.", ); if (flags.json) { diff --git a/packages/cli/src/commands/setup-stripe.ts b/packages/cli/src/commands/setup-stripe.ts index eaeb5e9..f99b940 100644 --- a/packages/cli/src/commands/setup-stripe.ts +++ b/packages/cli/src/commands/setup-stripe.ts @@ -11,7 +11,7 @@ import type { CLIFlags } from "../types.js"; * 410 Gone (W37-1690), and the webhook it created pointed at a URL the CMS does not serve. */ export const STRIPE_SETUP_MOVED = - "Stripe is connected from the Affitor dashboard, not the CLI: open the program, go to Settings, and use Connect Stripe."; + "Stripe is connected from the Affitor dashboard, not the CLI: open Affitor → Program settings → Payments and click Connect Stripe."; export function registerSetupCommand(program: Command) { const setup = program @@ -80,6 +80,6 @@ function runSetupDns(flags: CLIFlags) { "", ]); - logger.info(` Get started: connect Stripe from the Affitor dashboard (program Settings, Connect Stripe).`); + logger.info(` Get started: connect Stripe from the Affitor dashboard (Program settings → Payments, Connect Stripe).`); logger.newline(); } diff --git a/packages/cli/src/commands/status.ts b/packages/cli/src/commands/status.ts index 40b9e7e..96e83c4 100644 --- a/packages/cli/src/commands/status.ts +++ b/packages/cli/src/commands/status.ts @@ -87,7 +87,7 @@ export async function runStatus(flags: CLIFlags) { logger.step(`DNS: Add CNAME t.${domain} → track.affitor.com`); } if (!status.stripe_connected) { - logger.step("Stripe: Connect it in the Affitor dashboard (program Settings, Connect Stripe)"); + logger.step("Stripe: Connect it in the Affitor dashboard (Program settings → Payments, Connect Stripe)"); } } catch (err) { if (err instanceof APIError) { @@ -102,7 +102,7 @@ export async function runStatus(flags: CLIFlags) { // only AFFITOR_API_KEY would leave the refused key on the wire. logger.error( "API key expired or invalid.\n" + - ` Ask a workspace owner of ${config ? `program ${config.program_id}` : "the program"} to open Affitor → Settings → API Key and click Regenerate.\n` + + ` Ask a workspace owner of ${config ? `program ${config.program_id}` : "the program"} to open Affitor → Program settings → Developers → API keys and click Regenerate.\n` + ` Then replace the key in ${apiKeySourceLabel(flags)} with the new one.`, ); } else { diff --git a/packages/cli/src/lib/config.ts b/packages/cli/src/lib/config.ts index 7370737..2a5a420 100644 --- a/packages/cli/src/lib/config.ts +++ b/packages/cli/src/lib/config.ts @@ -291,7 +291,7 @@ export function writeEnvExample( AFFITOR_API_KEY=${apiKey} AFFITOR_PROGRAM_ID=${config.program_id} -# STRIPE_CONNECTED_ACCOUNT_ID= (connect Stripe in the Affitor dashboard: program Settings, Connect Stripe) +# STRIPE_CONNECTED_ACCOUNT_ID= (connect Stripe in the Affitor dashboard: Program settings → Payments, Connect Stripe) `; writeFileSync(join(dir, ".env.example"), content); } @@ -367,7 +367,7 @@ curl -X POST ${config.api_url}/api/v1/track/lead \\ ### 3. Sale/Revenue Tracking -**Option A: Stripe (recommended)**: connect Stripe in the Affitor dashboard (program Settings, Connect Stripe). Affitor's webhook records sales; add Affitor metadata to your checkout so sales are attributed reliably. +**Option A: Stripe (recommended)**: connect Stripe in the Affitor dashboard (Program settings → Payments, Connect Stripe). Affitor's webhook records sales; add Affitor metadata to your checkout so sales are attributed reliably. **Option B: Sale API (any payment provider)** diff --git a/packages/cli/tests/api-client.test.ts b/packages/cli/tests/api-client.test.ts index e2cab82..57f04e8 100644 --- a/packages/cli/tests/api-client.test.ts +++ b/packages/cli/tests/api-client.test.ts @@ -66,7 +66,7 @@ describe("AffitorAPI error parsing", () => { const ROTATION_WARNING = { code: "api_key_rotation_required", message: "This API key must be replaced by 2026-10-03.", - hint: "Create a new key in Affitor → Settings → API Key, then update AFFITOR_API_KEY on your server.", + hint: "In Affitor → Program settings → Developers → API keys, click Regenerate to get a new key, then update AFFITOR_API_KEY on your server.", rotate_by: "2026-10-03T00:00:00Z", docs_url: "https://affitor.com/docs/api-reference/errors#api_key_rotation_required", }; @@ -80,7 +80,7 @@ const ROTATION_ERROR = { error: { code: "api_key_rotation_required", message: "This API key was retired on 2026-10-03.", - hint: "Create a new key in Affitor → Settings → API Key.", + hint: "In Affitor → Program settings → Developers → API keys, click Regenerate to get a new key.", docs_url: "https://affitor.com/docs/api-reference/errors#api_key_rotation_required", }, }; @@ -225,7 +225,7 @@ describe("AffitorAPI key-rotation signal", () => { } catch (e) { expect(e).toBeInstanceOf(APIError); expect((e as APIError).message).toContain(ROTATION_ERROR.error.message); - expect((e as APIError).message).toContain("Create a new key in Affitor"); + expect((e as APIError).message).toContain("click Regenerate to get a new key"); } }); }); diff --git a/packages/cli/tests/exit-codes.test.ts b/packages/cli/tests/exit-codes.test.ts index 5327bb9..dbce11b 100644 --- a/packages/cli/tests/exit-codes.test.ts +++ b/packages/cli/tests/exit-codes.test.ts @@ -39,7 +39,7 @@ const ROTATION_401 = { error: { code: "api_key_rotation_required", message: "This API key was retired on 2026-10-03.", - hint: "Create a new key in Affitor → Settings → API Key.", + hint: "In Affitor → Program settings → Developers → API keys, click Regenerate to get a new key.", }, }; diff --git a/packages/cli/tests/init-already-configured.test.ts b/packages/cli/tests/init-already-configured.test.ts index 6181858..4d21c77 100644 --- a/packages/cli/tests/init-already-configured.test.ts +++ b/packages/cli/tests/init-already-configured.test.ts @@ -11,7 +11,7 @@ import type { CLIFlags } from "../src/types"; * Product rule: `init` creates a new program. It does not restore the program this directory * already points at, and it does not replace that program's API key. The message has to say * both, and name what does produce a new key: a workspace owner of the program regenerating - * it in Settings → API Key. + * it in Program settings → Developers → API keys. */ const flags: CLIFlags = { @@ -75,7 +75,7 @@ describe("affitor init in a directory that is already configured", () => { expect(out).toContain("does not restore this one"); expect(out).toContain("does not replace its API key"); expect(out).toContain("workspace owner of this program"); - expect(out).toContain("Affitor → Settings → API Key"); + expect(out).toContain("Affitor → Program settings → Developers → API keys"); expect(out).toContain("Regenerate"); expect(out).not.toContain("to reinitialize"); }); diff --git a/packages/cli/tests/onboard-rotation.test.ts b/packages/cli/tests/onboard-rotation.test.ts index 8d44229..2774e92 100644 --- a/packages/cli/tests/onboard-rotation.test.ts +++ b/packages/cli/tests/onboard-rotation.test.ts @@ -18,7 +18,7 @@ const ROTATION_401 = { error: { code: "api_key_rotation_required", message: "This API key was retired on 2026-10-03.", - hint: "Create a new key in Affitor → Settings → API Key.", + hint: "In Affitor → Program settings → Developers → API keys, click Regenerate to get a new key.", }, }; diff --git a/packages/cli/tests/setup-stripe.test.ts b/packages/cli/tests/setup-stripe.test.ts index 39d34c7..0aad209 100644 --- a/packages/cli/tests/setup-stripe.test.ts +++ b/packages/cli/tests/setup-stripe.test.ts @@ -37,6 +37,10 @@ describe("affitor setup stripe", () => { expect(fetch).not.toHaveBeenCalled(); }); + it("names the dashboard page as it is today (nav v2)", () => { + expect(STRIPE_SETUP_MOVED).toContain("Affitor → Program settings → Payments and click Connect Stripe"); + }); + it("old flags are accepted and still get the directions", async () => { await run(["setup", "stripe", "--stripe-secret-key", "sk_test_x", "--stripe-client-id", "ca_x"]); expect(process.exitCode).toBe(1); diff --git a/packages/cli/tests/status-invalid-key.test.ts b/packages/cli/tests/status-invalid-key.test.ts index b81bd75..326781b 100644 --- a/packages/cli/tests/status-invalid-key.test.ts +++ b/packages/cli/tests/status-invalid-key.test.ts @@ -108,7 +108,7 @@ describe("affitor status: what a refused key is told to do", () => { const out = await statusStderr({ ...baseFlags, apiKey: "aff_test_key" }); expect(out).toContain(`workspace owner of program ${PROGRAM_ID}`); - expect(out).toContain("Affitor → Settings → API Key"); + expect(out).toContain("Affitor → Program settings → Developers → API keys"); expect(out).toContain("Regenerate"); expect(out).not.toContain("affitor init"); }); @@ -139,7 +139,7 @@ describe("affitor status: what a refused key is told to do", () => { // the API said. Written out here rather than imported: this is the CMS 401 text. const fromApi = "Invalid API key. To get a working key for the program you already have, ask a workspace " + - "owner of that program to open Affitor → Settings → API Key and click Regenerate, then " + + "owner of that program to open Affitor → Program settings → Developers → API keys and click Regenerate, then " + "replace the key you are sending with the new one."; respond401({ data: null, error: { status: 401, message: fromApi } }); @@ -202,14 +202,14 @@ describe("affitor status: what a refused key is told to do", () => { error: { code: "api_key_rotation_required", message: "This API key was retired on 2026-10-03.", - hint: "Create a new key in Affitor → Settings → API Key.", + hint: "In Affitor → Program settings → Developers → API keys, click Regenerate to get a new key.", }, }); const out = await statusStderr({ ...baseFlags, apiKey: "aff_test_key" }); expect(out).toContain("This API key was retired on 2026-10-03."); - expect(out).toContain("Create a new key in Affitor → Settings → API Key."); + expect(out).toContain("In Affitor → Program settings → Developers → API keys, click Regenerate to get a new key."); expect(out).not.toContain("affitor init"); }); });