affitor 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 +91 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +33 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +194 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/setup-stripe.d.ts +3 -0
- package/dist/commands/setup-stripe.d.ts.map +1 -0
- package/dist/commands/setup-stripe.js +188 -0
- package/dist/commands/setup-stripe.js.map +1 -0
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +95 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/test.d.ts +3 -0
- package/dist/commands/test.d.ts.map +1 -0
- package/dist/commands/test.js +89 -0
- package/dist/commands/test.js.map +1 -0
- package/dist/lib/api-client.d.ts +37 -0
- package/dist/lib/api-client.d.ts.map +1 -0
- package/dist/lib/api-client.js +92 -0
- package/dist/lib/api-client.js.map +1 -0
- package/dist/lib/config.d.ts +12 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +110 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/flags.d.ts +7 -0
- package/dist/lib/flags.d.ts.map +1 -0
- package/dist/lib/flags.js +20 -0
- package/dist/lib/flags.js.map +1 -0
- package/dist/lib/logger.d.ts +24 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +78 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/prompts.d.ts +9 -0
- package/dist/lib/prompts.d.ts.map +1 -0
- package/dist/lib/prompts.js +79 -0
- package/dist/lib/prompts.js.map +1 -0
- package/dist/lib/stripe-oauth.d.ts +15 -0
- package/dist/lib/stripe-oauth.d.ts.map +1 -0
- package/dist/lib/stripe-oauth.js +168 -0
- package/dist/lib/stripe-oauth.js.map +1 -0
- package/dist/types.d.ts +84 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +17 -0
- package/dist/types.js.map +1 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# affitor
|
|
2
|
+
|
|
3
|
+
CLI-native affiliate tracking. Connect Stripe, track commissions, manage partners -- all from your terminal.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Create your affiliate program
|
|
9
|
+
npx affitor init
|
|
10
|
+
|
|
11
|
+
# Connect Stripe for automatic payment tracking
|
|
12
|
+
npx affitor setup stripe
|
|
13
|
+
|
|
14
|
+
# Check program health
|
|
15
|
+
npx affitor status
|
|
16
|
+
|
|
17
|
+
# Send test events
|
|
18
|
+
npx affitor test click
|
|
19
|
+
npx affitor test lead
|
|
20
|
+
npx affitor test sale
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Commands
|
|
24
|
+
|
|
25
|
+
| Command | Description |
|
|
26
|
+
|---|---|
|
|
27
|
+
| `affitor init` | Create a new affiliate program. Interactive prompts or `--no-interactive` with flags. |
|
|
28
|
+
| `affitor setup stripe` | Connect Stripe via OAuth. Auto-configures webhooks for payment tracking. |
|
|
29
|
+
| `affitor setup dns` | Set up DNS CNAME tracking (coming soon). |
|
|
30
|
+
| `affitor status` | Show program health: DNS, Stripe connection, recent events. |
|
|
31
|
+
| `affitor test [type]` | Send a test event (`click`, `lead`, or `sale`). |
|
|
32
|
+
|
|
33
|
+
## Global Flags
|
|
34
|
+
|
|
35
|
+
| Flag | Description |
|
|
36
|
+
|---|---|
|
|
37
|
+
| `--json` | Output as JSON (for AI agents and scripts) |
|
|
38
|
+
| `--no-interactive` | Skip all prompts, fail on missing values |
|
|
39
|
+
| `--auto-confirm` | Auto-yes to confirmation prompts |
|
|
40
|
+
| `--quiet` | Suppress non-essential output |
|
|
41
|
+
| `--api-key <key>` | Override API key from config |
|
|
42
|
+
| `--api-url <url>` | Override API URL |
|
|
43
|
+
| `--verbose` | Debug output |
|
|
44
|
+
|
|
45
|
+
## Non-Interactive Mode (for AI Agents)
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npx affitor init \
|
|
49
|
+
--name "My SaaS" \
|
|
50
|
+
--domain "example.com" \
|
|
51
|
+
--commission-type recurring_percent \
|
|
52
|
+
--commission-rate 20 \
|
|
53
|
+
--duration-months 12 \
|
|
54
|
+
--cookie-duration 90 \
|
|
55
|
+
--no-interactive \
|
|
56
|
+
--json
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## What Gets Created
|
|
60
|
+
|
|
61
|
+
Running `npx affitor init` creates:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
.affitor/
|
|
65
|
+
config.json -- program configuration
|
|
66
|
+
.env.example -- environment variables template
|
|
67
|
+
skills.md -- AI agent instructions
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Stripe Auto-Connect
|
|
71
|
+
|
|
72
|
+
`npx affitor setup stripe` automates the entire Stripe integration:
|
|
73
|
+
|
|
74
|
+
1. Opens Stripe Connect OAuth in your browser
|
|
75
|
+
2. Creates webhook endpoint on your Stripe account
|
|
76
|
+
3. Configures event listeners for:
|
|
77
|
+
- `customer.created` -- lead tracking
|
|
78
|
+
- `checkout.session.completed` -- sale tracking
|
|
79
|
+
- `invoice.paid` -- recurring commissions
|
|
80
|
+
- `invoice.payment_failed` -- failed payment alerts
|
|
81
|
+
- `charge.refunded` -- automatic commission clawback
|
|
82
|
+
- `customer.subscription.deleted` -- churn tracking
|
|
83
|
+
|
|
84
|
+
## Requirements
|
|
85
|
+
|
|
86
|
+
- Node.js >= 18
|
|
87
|
+
- Stripe account (for `setup stripe`)
|
|
88
|
+
|
|
89
|
+
## License
|
|
90
|
+
|
|
91
|
+
MIT
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { setLoggerOptions } from "./lib/logger.js";
|
|
4
|
+
import { registerInitCommand } from "./commands/init.js";
|
|
5
|
+
import { registerSetupCommand } from "./commands/setup-stripe.js";
|
|
6
|
+
import { registerStatusCommand } from "./commands/status.js";
|
|
7
|
+
import { registerTestCommand } from "./commands/test.js";
|
|
8
|
+
const program = new Command();
|
|
9
|
+
program
|
|
10
|
+
.name("affitor")
|
|
11
|
+
.description("CLI-native affiliate tracking. Connect Stripe, track commissions, manage partners.")
|
|
12
|
+
.version("0.1.0")
|
|
13
|
+
.option("--json", "Output as JSON (for agent parsing)", false)
|
|
14
|
+
.option("--no-interactive", "Skip all prompts, fail on missing values")
|
|
15
|
+
.option("--auto-confirm", "Auto-yes to all confirmation prompts", false)
|
|
16
|
+
.option("--quiet", "Suppress non-essential output", false)
|
|
17
|
+
.option("--api-key <key>", "Override API key from config")
|
|
18
|
+
.option("--api-url <url>", "Override API URL (default: api.affitor.com)")
|
|
19
|
+
.option("--verbose", "Debug-level output", false)
|
|
20
|
+
.hook("preAction", () => {
|
|
21
|
+
const opts = program.opts();
|
|
22
|
+
setLoggerOptions({
|
|
23
|
+
json: opts.json,
|
|
24
|
+
quiet: opts.quiet,
|
|
25
|
+
verbose: opts.verbose,
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
registerInitCommand(program);
|
|
29
|
+
registerSetupCommand(program);
|
|
30
|
+
registerStatusCommand(program);
|
|
31
|
+
registerTestCommand(program);
|
|
32
|
+
program.parse();
|
|
33
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEzD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,SAAS,CAAC;KACf,WAAW,CACV,oFAAoF,CACrF;KACA,OAAO,CAAC,OAAO,CAAC;KAChB,MAAM,CAAC,QAAQ,EAAE,oCAAoC,EAAE,KAAK,CAAC;KAC7D,MAAM,CAAC,kBAAkB,EAAE,0CAA0C,CAAC;KACtE,MAAM,CAAC,gBAAgB,EAAE,sCAAsC,EAAE,KAAK,CAAC;KACvE,MAAM,CAAC,SAAS,EAAE,+BAA+B,EAAE,KAAK,CAAC;KACzD,MAAM,CAAC,iBAAiB,EAAE,8BAA8B,CAAC;KACzD,MAAM,CAAC,iBAAiB,EAAE,6CAA6C,CAAC;KACxE,MAAM,CAAC,WAAW,EAAE,oBAAoB,EAAE,KAAK,CAAC;KAChD,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE;IACtB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAC5B,gBAAgB,CAAC;QACf,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,OAAO,EAAE,IAAI,CAAC,OAAO;KACtB,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEL,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAC7B,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAC9B,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAC/B,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAE7B,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuBzC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,QAgBnD"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import * as logger from "../lib/logger.js";
|
|
2
|
+
import { AffitorAPI, APIError, NetworkError } from "../lib/api-client.js";
|
|
3
|
+
import { configExists, writeConfig, writeEnvExample, writeSkillsFile, appendToGitignore, } from "../lib/config.js";
|
|
4
|
+
import { promptProgramName, promptDomain, promptCommissionType, promptCommissionRate, promptDurationMonths, promptCookieDuration, confirmAction, } from "../lib/prompts.js";
|
|
5
|
+
import { DEFAULT_API_URL } from "../types.js";
|
|
6
|
+
import { getFlags } from "../lib/flags.js";
|
|
7
|
+
export function registerInitCommand(program) {
|
|
8
|
+
program
|
|
9
|
+
.command("init")
|
|
10
|
+
.description("Initialize a new Affitor affiliate program")
|
|
11
|
+
.option("--name <name>", "Program name")
|
|
12
|
+
.option("--domain <domain>", "Root domain (e.g., example.com)")
|
|
13
|
+
.option("--commission-type <type>", "Commission type: percent, fixed, recurring_percent, recurring_fixed")
|
|
14
|
+
.option("--commission-rate <rate>", "Commission rate (% or $)", parseFloat)
|
|
15
|
+
.option("--cookie-duration <days>", "Cookie duration in days", parseInt)
|
|
16
|
+
.option("--duration-months <months>", "Commission duration in months (for recurring)", parseInt)
|
|
17
|
+
.action(async (opts, cmd) => {
|
|
18
|
+
await runInit(opts, getFlags(cmd));
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
async function runInit(opts, flags) {
|
|
22
|
+
if (configExists()) {
|
|
23
|
+
logger.error("Affitor already configured in this directory.\n" +
|
|
24
|
+
" Use `npx affitor status` to check your program.\n" +
|
|
25
|
+
" Delete `.affitor/` to reinitialize.");
|
|
26
|
+
if (flags.json) {
|
|
27
|
+
logger.json({ error: "already_configured" });
|
|
28
|
+
}
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
const interactive = !flags.noInteractive;
|
|
32
|
+
let name = opts.name;
|
|
33
|
+
let domain = opts.domain;
|
|
34
|
+
let commissionType = opts.commissionType;
|
|
35
|
+
let commissionRate = opts.commissionRate;
|
|
36
|
+
let cookieDuration = opts.cookieDuration;
|
|
37
|
+
let durationMonths = opts.durationMonths;
|
|
38
|
+
if (interactive) {
|
|
39
|
+
logger.box([
|
|
40
|
+
"",
|
|
41
|
+
" Welcome to Affitor",
|
|
42
|
+
" CLI-native affiliate tracking",
|
|
43
|
+
"",
|
|
44
|
+
]);
|
|
45
|
+
name ??= await promptProgramName();
|
|
46
|
+
domain ??= await promptDomain();
|
|
47
|
+
commissionType ??= await promptCommissionType();
|
|
48
|
+
commissionRate ??= await promptCommissionRate(commissionType);
|
|
49
|
+
if (commissionType.startsWith("recurring")) {
|
|
50
|
+
durationMonths ??= await promptDurationMonths();
|
|
51
|
+
}
|
|
52
|
+
cookieDuration ??= await promptCookieDuration();
|
|
53
|
+
}
|
|
54
|
+
if (!name || !domain || !commissionType || commissionRate === undefined) {
|
|
55
|
+
logger.error("Missing required options. In non-interactive mode, provide:\n" +
|
|
56
|
+
" --name <name> --domain <domain> --commission-type <type> --commission-rate <rate>");
|
|
57
|
+
if (flags.json) {
|
|
58
|
+
logger.json({ error: "missing_options" });
|
|
59
|
+
}
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
// Clean domain
|
|
63
|
+
domain = domain
|
|
64
|
+
.trim()
|
|
65
|
+
.toLowerCase()
|
|
66
|
+
.replace(/^https?:\/\//, "")
|
|
67
|
+
.replace(/\/$/, "");
|
|
68
|
+
cookieDuration ??= 90;
|
|
69
|
+
if (interactive && !flags.autoConfirm) {
|
|
70
|
+
logger.newline();
|
|
71
|
+
logger.info(` Program: ${name}`);
|
|
72
|
+
logger.info(` Domain: ${domain}`);
|
|
73
|
+
logger.info(` Commission: ${formatCommission(commissionType, commissionRate, durationMonths)}`);
|
|
74
|
+
logger.info(` Cookie: ${cookieDuration} days`);
|
|
75
|
+
logger.newline();
|
|
76
|
+
const confirmed = await confirmAction("Create this program?");
|
|
77
|
+
if (!confirmed) {
|
|
78
|
+
logger.info("Cancelled.");
|
|
79
|
+
process.exit(0);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const apiUrl = flags.apiUrl ?? DEFAULT_API_URL;
|
|
83
|
+
const api = new AffitorAPI({ apiUrl });
|
|
84
|
+
logger.step("Creating program...");
|
|
85
|
+
let response;
|
|
86
|
+
try {
|
|
87
|
+
response = await api.initProgram({
|
|
88
|
+
name,
|
|
89
|
+
domain,
|
|
90
|
+
commission_type: commissionType,
|
|
91
|
+
commission_rate: commissionRate,
|
|
92
|
+
cookie_duration: cookieDuration,
|
|
93
|
+
duration_months: durationMonths,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
if (err instanceof APIError) {
|
|
98
|
+
logger.error(`API error: ${err.message}`);
|
|
99
|
+
if (flags.json)
|
|
100
|
+
logger.json({ error: err.message, status: err.status });
|
|
101
|
+
}
|
|
102
|
+
else if (err instanceof NetworkError) {
|
|
103
|
+
logger.error(err.message);
|
|
104
|
+
if (flags.json)
|
|
105
|
+
logger.json({ error: "network_error" });
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
logger.error(`Unexpected error: ${err.message}`);
|
|
109
|
+
if (flags.json)
|
|
110
|
+
logger.json({ error: "unexpected_error" });
|
|
111
|
+
}
|
|
112
|
+
process.exit(1);
|
|
113
|
+
}
|
|
114
|
+
logger.success("Program created");
|
|
115
|
+
const config = {
|
|
116
|
+
version: 1,
|
|
117
|
+
program_id: response.program_id,
|
|
118
|
+
domain,
|
|
119
|
+
tracking_subdomain: `t.${domain}`,
|
|
120
|
+
commission: {
|
|
121
|
+
type: commissionType,
|
|
122
|
+
rate: commissionRate,
|
|
123
|
+
duration_months: durationMonths,
|
|
124
|
+
},
|
|
125
|
+
cookie: {
|
|
126
|
+
name: "_aff",
|
|
127
|
+
duration_days: cookieDuration,
|
|
128
|
+
},
|
|
129
|
+
ref_param: "aff",
|
|
130
|
+
stripe_connected: false,
|
|
131
|
+
api_key: response.api_key,
|
|
132
|
+
api_url: apiUrl,
|
|
133
|
+
created_at: new Date().toISOString(),
|
|
134
|
+
};
|
|
135
|
+
writeConfig(config);
|
|
136
|
+
logger.success("Config written to .affitor/config.json");
|
|
137
|
+
writeEnvExample(config);
|
|
138
|
+
logger.success("Env template written to .affitor/.env.example");
|
|
139
|
+
writeSkillsFile(config, name);
|
|
140
|
+
logger.success("Agent skills written to .affitor/skills.md");
|
|
141
|
+
appendToGitignore();
|
|
142
|
+
if (flags.json) {
|
|
143
|
+
logger.json({
|
|
144
|
+
program_id: response.program_id,
|
|
145
|
+
api_key: response.api_key,
|
|
146
|
+
domain,
|
|
147
|
+
tracking_subdomain: `t.${domain}`,
|
|
148
|
+
status: "created",
|
|
149
|
+
next_steps: [
|
|
150
|
+
`Add CNAME record: t.${domain} → track.affitor.com`,
|
|
151
|
+
"Run: npx affitor setup dns",
|
|
152
|
+
"Run: npx affitor setup stripe",
|
|
153
|
+
],
|
|
154
|
+
});
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
logger.box([
|
|
158
|
+
" Program created!",
|
|
159
|
+
"",
|
|
160
|
+
` Program ID: ${response.program_id}`,
|
|
161
|
+
` API Key: ${response.api_key}`,
|
|
162
|
+
` Domain: ${domain}`,
|
|
163
|
+
` Commission: ${formatCommission(commissionType, commissionRate, durationMonths)}`,
|
|
164
|
+
]);
|
|
165
|
+
logger.info("Next steps:");
|
|
166
|
+
logger.newline();
|
|
167
|
+
logger.info(" 1. Add DNS record (required):");
|
|
168
|
+
logger.info(` CNAME t.${domain} → track.affitor.com`);
|
|
169
|
+
logger.newline();
|
|
170
|
+
logger.info(" 2. Verify DNS:");
|
|
171
|
+
logger.info(" $ npx affitor setup dns");
|
|
172
|
+
logger.newline();
|
|
173
|
+
logger.info(" 3. Connect Stripe (recommended):");
|
|
174
|
+
logger.info(" $ npx affitor setup stripe");
|
|
175
|
+
logger.newline();
|
|
176
|
+
logger.info(" 4. Test tracking:");
|
|
177
|
+
logger.info(" $ npx affitor test click");
|
|
178
|
+
logger.newline();
|
|
179
|
+
logger.info("Files created:");
|
|
180
|
+
logger.info(" .affitor/config.json — program configuration");
|
|
181
|
+
logger.info(" .affitor/skills.md — agent instructions");
|
|
182
|
+
logger.info(" .affitor/.env.example — environment variables template");
|
|
183
|
+
}
|
|
184
|
+
function formatCommission(type, rate, durationMonths) {
|
|
185
|
+
const isPercent = type.includes("percent");
|
|
186
|
+
const value = isPercent ? `${rate}%` : `$${rate}`;
|
|
187
|
+
const isRecurring = type.startsWith("recurring");
|
|
188
|
+
if (isRecurring) {
|
|
189
|
+
const duration = durationMonths === 0 ? "lifetime" : `${durationMonths} months`;
|
|
190
|
+
return `${value} recurring (${duration})`;
|
|
191
|
+
}
|
|
192
|
+
return `${value} per sale`;
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-stripe.d.ts","sourceRoot":"","sources":["../../src/commands/setup-stripe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQzC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,QAoBpD"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import * as logger from "../lib/logger.js";
|
|
2
|
+
import { readConfig, updateConfig, writeEnvExample, ConfigNotFoundError } from "../lib/config.js";
|
|
3
|
+
import { runStripeOAuth, StripeOAuthError } from "../lib/stripe-oauth.js";
|
|
4
|
+
import { AffitorAPI, APIError, NetworkError } from "../lib/api-client.js";
|
|
5
|
+
import { getFlags } from "../lib/flags.js";
|
|
6
|
+
export function registerSetupCommand(program) {
|
|
7
|
+
const setup = program
|
|
8
|
+
.command("setup")
|
|
9
|
+
.description("Set up integrations (stripe, dns)");
|
|
10
|
+
setup
|
|
11
|
+
.command("stripe")
|
|
12
|
+
.description("Connect Stripe for automatic payment tracking")
|
|
13
|
+
.option("--stripe-client-id <id>", "Stripe Connect client ID override")
|
|
14
|
+
.option("--stripe-secret-key <key>", "Stripe secret key (for webhook creation)")
|
|
15
|
+
.action(async (opts, cmd) => {
|
|
16
|
+
await runSetupStripe(opts, getFlags(cmd));
|
|
17
|
+
});
|
|
18
|
+
setup
|
|
19
|
+
.command("dns")
|
|
20
|
+
.description("Set up DNS CNAME tracking (coming soon)")
|
|
21
|
+
.action(async (_opts, cmd) => {
|
|
22
|
+
runSetupDns(getFlags(cmd));
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
async function runSetupStripe(opts, flags) {
|
|
26
|
+
let config;
|
|
27
|
+
try {
|
|
28
|
+
config = readConfig();
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
if (err instanceof ConfigNotFoundError) {
|
|
32
|
+
logger.error(err.message);
|
|
33
|
+
if (flags.json)
|
|
34
|
+
logger.json({ error: "no_config" });
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
throw err;
|
|
38
|
+
}
|
|
39
|
+
if (config.stripe_connected) {
|
|
40
|
+
logger.warn("Stripe is already connected.");
|
|
41
|
+
logger.info(` Account: ${config.stripe_account_id}`);
|
|
42
|
+
logger.info(" To reconnect, disconnect first via the dashboard.");
|
|
43
|
+
if (flags.json) {
|
|
44
|
+
logger.json({
|
|
45
|
+
status: "already_connected",
|
|
46
|
+
stripe_account_id: config.stripe_account_id,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
process.exit(0);
|
|
50
|
+
}
|
|
51
|
+
const clientId = opts.stripeClientId ??
|
|
52
|
+
process.env.STRIPE_CONNECT_CLIENT_ID ??
|
|
53
|
+
process.env.AFFITOR_STRIPE_CLIENT_ID;
|
|
54
|
+
if (!clientId) {
|
|
55
|
+
logger.error("Stripe Connect client ID not configured.\n" +
|
|
56
|
+
" Set STRIPE_CONNECT_CLIENT_ID or AFFITOR_STRIPE_CLIENT_ID environment variable,\n" +
|
|
57
|
+
" or pass --stripe-client-id <id>.");
|
|
58
|
+
if (flags.json)
|
|
59
|
+
logger.json({ error: "missing_stripe_client_id" });
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
const stripeSecretKey = opts.stripeSecretKey ??
|
|
63
|
+
process.env.STRIPE_SECRET_KEY ??
|
|
64
|
+
process.env.AFFITOR_STRIPE_SECRET_KEY;
|
|
65
|
+
if (!stripeSecretKey) {
|
|
66
|
+
logger.error("Stripe secret key not configured.\n" +
|
|
67
|
+
" Set STRIPE_SECRET_KEY or AFFITOR_STRIPE_SECRET_KEY environment variable,\n" +
|
|
68
|
+
" or pass --stripe-secret-key <key>.");
|
|
69
|
+
if (flags.json)
|
|
70
|
+
logger.json({ error: "missing_stripe_secret_key" });
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
const apiUrl = flags.apiUrl ?? config.api_url;
|
|
74
|
+
const webhookUrl = `${apiUrl}/webhooks/stripe/${config.program_id}`;
|
|
75
|
+
try {
|
|
76
|
+
const result = await runStripeOAuth({
|
|
77
|
+
clientId,
|
|
78
|
+
programId: config.program_id,
|
|
79
|
+
webhookUrl,
|
|
80
|
+
stripeSecretKey,
|
|
81
|
+
});
|
|
82
|
+
// Save to Affitor API
|
|
83
|
+
const api = new AffitorAPI({
|
|
84
|
+
apiUrl: apiUrl,
|
|
85
|
+
apiKey: flags.apiKey ?? config.api_key,
|
|
86
|
+
});
|
|
87
|
+
logger.step("Saving connection...");
|
|
88
|
+
const saveResult = await api.saveStripeConnection({
|
|
89
|
+
program_id: config.program_id,
|
|
90
|
+
stripe_user_id: result.stripe_user_id,
|
|
91
|
+
webhook_endpoint_id: result.webhook_endpoint_id,
|
|
92
|
+
webhook_secret: result.webhook_secret,
|
|
93
|
+
});
|
|
94
|
+
// Update local config
|
|
95
|
+
const updated = updateConfig({
|
|
96
|
+
stripe_connected: true,
|
|
97
|
+
stripe_account_id: result.stripe_user_id,
|
|
98
|
+
});
|
|
99
|
+
writeEnvExample(updated);
|
|
100
|
+
if (flags.json) {
|
|
101
|
+
logger.json({
|
|
102
|
+
status: "connected",
|
|
103
|
+
stripe_account_id: result.stripe_user_id,
|
|
104
|
+
webhook_endpoint_id: result.webhook_endpoint_id,
|
|
105
|
+
charges_enabled: saveResult.charges_enabled,
|
|
106
|
+
payouts_enabled: saveResult.payouts_enabled,
|
|
107
|
+
});
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
logger.box([
|
|
111
|
+
" Stripe connected!",
|
|
112
|
+
"",
|
|
113
|
+
` Account: ${result.stripe_user_id}`,
|
|
114
|
+
` Charges: ${saveResult.charges_enabled ? "✓ Enabled" : "⚠ Pending verification"}`,
|
|
115
|
+
` Payouts: ${saveResult.payouts_enabled ? "✓ Enabled" : "⚠ Pending verification"}`,
|
|
116
|
+
"",
|
|
117
|
+
" Webhooks auto-configured:",
|
|
118
|
+
" ✓ customer.created → lead tracking",
|
|
119
|
+
" ✓ checkout.session.completed → sale tracking",
|
|
120
|
+
" ✓ invoice.paid → recurring commission",
|
|
121
|
+
" ✓ charge.refunded → auto clawback",
|
|
122
|
+
]);
|
|
123
|
+
logger.info("Test it:");
|
|
124
|
+
logger.info(" $ npx affitor test sale");
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
if (err instanceof StripeOAuthError) {
|
|
128
|
+
logger.error(err.message);
|
|
129
|
+
if (flags.json)
|
|
130
|
+
logger.json({ error: "stripe_oauth_error", message: err.message });
|
|
131
|
+
}
|
|
132
|
+
else if (err instanceof APIError) {
|
|
133
|
+
logger.error(`API error: ${err.message}`);
|
|
134
|
+
if (flags.json)
|
|
135
|
+
logger.json({ error: "api_error", message: err.message });
|
|
136
|
+
}
|
|
137
|
+
else if (err instanceof NetworkError) {
|
|
138
|
+
logger.error(err.message);
|
|
139
|
+
if (flags.json)
|
|
140
|
+
logger.json({ error: "network_error" });
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
logger.error(`Unexpected error: ${err.message}`);
|
|
144
|
+
if (flags.json)
|
|
145
|
+
logger.json({ error: "unexpected_error", message: err.message });
|
|
146
|
+
}
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
function runSetupDns(flags) {
|
|
151
|
+
let config;
|
|
152
|
+
try {
|
|
153
|
+
config = readConfig();
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
if (err instanceof ConfigNotFoundError) {
|
|
157
|
+
logger.error(err.message);
|
|
158
|
+
if (flags.json)
|
|
159
|
+
logger.json({ error: "no_config" });
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
162
|
+
throw err;
|
|
163
|
+
}
|
|
164
|
+
if (flags.json) {
|
|
165
|
+
logger.json({
|
|
166
|
+
status: "not_implemented",
|
|
167
|
+
message: "DNS tracking setup coming soon. Use Stripe tracking for now.",
|
|
168
|
+
cname: {
|
|
169
|
+
type: "CNAME",
|
|
170
|
+
name: `t.${config.domain}`,
|
|
171
|
+
target: "track.affitor.com",
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
logger.info("DNS tracking setup is coming soon.");
|
|
177
|
+
logger.newline();
|
|
178
|
+
logger.info("When available, add this DNS record:");
|
|
179
|
+
logger.newline();
|
|
180
|
+
logger.info(` Type: CNAME`);
|
|
181
|
+
logger.info(` Name: t.${config.domain}`);
|
|
182
|
+
logger.info(` Target: track.affitor.com`);
|
|
183
|
+
logger.info(` TTL: Auto (or 300)`);
|
|
184
|
+
logger.newline();
|
|
185
|
+
logger.info("For now, use Stripe tracking:");
|
|
186
|
+
logger.info(" $ npx affitor setup stripe");
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=setup-stripe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-stripe.js","sourceRoot":"","sources":["../../src/commands/setup-stripe.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOzC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,QAOrD"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import * as logger from "../lib/logger.js";
|
|
2
|
+
import { readConfig, ConfigNotFoundError } from "../lib/config.js";
|
|
3
|
+
import { AffitorAPI, APIError, NetworkError } from "../lib/api-client.js";
|
|
4
|
+
import { getFlags } from "../lib/flags.js";
|
|
5
|
+
export function registerStatusCommand(program) {
|
|
6
|
+
program
|
|
7
|
+
.command("status")
|
|
8
|
+
.description("Show program health: DNS, Stripe, recent events")
|
|
9
|
+
.action(async (_opts, cmd) => {
|
|
10
|
+
await runStatus(getFlags(cmd));
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
async function runStatus(flags) {
|
|
14
|
+
let config;
|
|
15
|
+
try {
|
|
16
|
+
config = readConfig();
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
if (err instanceof ConfigNotFoundError) {
|
|
20
|
+
logger.error(err.message);
|
|
21
|
+
if (flags.json)
|
|
22
|
+
logger.json({ error: "no_config" });
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
throw err;
|
|
26
|
+
}
|
|
27
|
+
const api = new AffitorAPI({
|
|
28
|
+
apiUrl: flags.apiUrl ?? config.api_url,
|
|
29
|
+
apiKey: flags.apiKey ?? config.api_key,
|
|
30
|
+
});
|
|
31
|
+
try {
|
|
32
|
+
const status = await api.getStatus(config.program_id);
|
|
33
|
+
if (flags.json) {
|
|
34
|
+
logger.json(status);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
logger.box([
|
|
38
|
+
` ${status.name}`,
|
|
39
|
+
` ${config.domain}`,
|
|
40
|
+
"",
|
|
41
|
+
` Program ID: ${status.program_id}`,
|
|
42
|
+
]);
|
|
43
|
+
// DNS status
|
|
44
|
+
if (status.dns_verified) {
|
|
45
|
+
logger.success(`DNS: verified (t.${config.domain})`);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
logger.warn(`DNS: not configured`);
|
|
49
|
+
logger.step(`Add CNAME: t.${config.domain} → track.affitor.com`);
|
|
50
|
+
}
|
|
51
|
+
// Stripe status
|
|
52
|
+
if (status.stripe_connected) {
|
|
53
|
+
logger.success(`Stripe: connected${status.stripe_charges_enabled ? "" : " (pending verification)"}`);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
logger.warn("Stripe: not connected");
|
|
57
|
+
logger.step("Run: npx affitor setup stripe");
|
|
58
|
+
}
|
|
59
|
+
logger.newline();
|
|
60
|
+
// Events (last 24h)
|
|
61
|
+
logger.info(" Events (last 24h):");
|
|
62
|
+
logger.info(` Clicks: ${status.recent_events.clicks_24h}`);
|
|
63
|
+
logger.info(` Leads: ${status.recent_events.leads_24h}`);
|
|
64
|
+
logger.info(` Sales: ${status.recent_events.sales_24h}`);
|
|
65
|
+
logger.newline();
|
|
66
|
+
// Partners & commissions
|
|
67
|
+
logger.info(` Active partners: ${status.active_partners}`);
|
|
68
|
+
logger.info(` Pending commissions: ${status.pending_commissions}`);
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
if (err instanceof APIError) {
|
|
72
|
+
if (err.status === 401) {
|
|
73
|
+
logger.error("API key expired or invalid.\n" +
|
|
74
|
+
" Run `npx affitor init` to get a new API key.");
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
logger.error(`API error: ${err.message}`);
|
|
78
|
+
}
|
|
79
|
+
if (flags.json)
|
|
80
|
+
logger.json({ error: err.message, status: err.status });
|
|
81
|
+
}
|
|
82
|
+
else if (err instanceof NetworkError) {
|
|
83
|
+
logger.error(err.message);
|
|
84
|
+
if (flags.json)
|
|
85
|
+
logger.json({ error: "network_error" });
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
logger.error(`Unexpected error: ${err.message}`);
|
|
89
|
+
if (flags.json)
|
|
90
|
+
logger.json({ error: "unexpected_error" });
|
|
91
|
+
}
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=status.js.map
|