@affonso/cli 0.1.4 → 0.2.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 (3) hide show
  1. package/README.md +43 -10
  2. package/dist/index.js +809 -306
  3. package/package.json +5 -3
package/dist/index.js CHANGED
@@ -26,13 +26,62 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
26
  // src/cli.ts
27
27
  var import_commander = require("commander");
28
28
 
29
+ // package.json
30
+ var package_default = {
31
+ name: "@affonso/cli",
32
+ version: "0.2.0",
33
+ description: "Command line interface for the Affonso affiliate marketing platform",
34
+ bin: {
35
+ affonso: "dist/index.js"
36
+ },
37
+ files: [
38
+ "dist"
39
+ ],
40
+ scripts: {
41
+ build: "tsup",
42
+ prepack: "npm run build -- --silent",
43
+ dev: "tsup --watch",
44
+ test: "vitest run",
45
+ "test:package": "npm run build && node scripts/smoke-package.mjs",
46
+ "test:watch": "vitest",
47
+ lint: "biome check src/",
48
+ "lint:fix": "biome check --write src/",
49
+ typecheck: "tsc --noEmit"
50
+ },
51
+ engines: {
52
+ node: ">=18"
53
+ },
54
+ dependencies: {
55
+ "@affonso/sdk": "^1.0.2",
56
+ commander: "^12.0.0",
57
+ open: "^10.0.0"
58
+ },
59
+ devDependencies: {
60
+ "@biomejs/biome": "^1.9.0",
61
+ "@types/node": "^20.0.0",
62
+ tsup: "^8.0.0",
63
+ typescript: "^5.7.0",
64
+ vitest: "^2.0.0"
65
+ },
66
+ keywords: [
67
+ "affonso",
68
+ "affiliate",
69
+ "cli"
70
+ ],
71
+ license: "MIT"
72
+ };
73
+
29
74
  // src/lib/client.ts
30
75
  var import_sdk = require("@affonso/sdk");
31
76
 
77
+ // src/auth/oauth.ts
78
+ var import_node_crypto = __toESM(require("crypto"));
79
+ var import_node_http = __toESM(require("http"));
80
+
32
81
  // src/auth/storage.ts
33
82
  var import_node_fs = __toESM(require("fs"));
34
- var import_node_path = __toESM(require("path"));
35
83
  var import_node_os = __toESM(require("os"));
84
+ var import_node_path = __toESM(require("path"));
36
85
  var CONFIG_DIR = import_node_path.default.join(import_node_os.default.homedir(), ".config", "affonso");
37
86
  var AUTH_FILE = import_node_path.default.join(CONFIG_DIR, "auth.json");
38
87
  var CONFIG_FILE = import_node_path.default.join(CONFIG_DIR, "config.json");
@@ -85,38 +134,7 @@ function saveConfig(config) {
85
134
  });
86
135
  }
87
136
 
88
- // src/auth/resolve.ts
89
- function resolveAuth(flagApiKey) {
90
- if (flagApiKey) {
91
- return { apiKey: flagApiKey, source: "flag" };
92
- }
93
- const envKey = process.env.AFFONSO_API_KEY;
94
- if (envKey) {
95
- return { apiKey: envKey, source: "env" };
96
- }
97
- const config = loadConfig();
98
- if (config.api_key) {
99
- return { apiKey: config.api_key, source: "config" };
100
- }
101
- const auth = loadAuth();
102
- if (auth?.access_token) {
103
- if (auth.expires_at && Date.now() > auth.expires_at) {
104
- return null;
105
- }
106
- return { apiKey: auth.access_token, source: "oauth" };
107
- }
108
- return null;
109
- }
110
- function resolveBaseUrl(flagBaseUrl) {
111
- if (flagBaseUrl) return flagBaseUrl;
112
- const config = loadConfig();
113
- if (config.base_url) return config.base_url;
114
- return "https://api.affonso.io/v1";
115
- }
116
-
117
137
  // src/auth/oauth.ts
118
- var import_node_crypto = __toESM(require("crypto"));
119
- var import_node_http = __toESM(require("http"));
120
138
  var CLIENT_ID = "d4e5f6a7-b8c9-4d0e-a1f2-b3c4d5e6f7a8";
121
139
  var SCOPES = "read write";
122
140
  var LOGIN_TIMEOUT_MS = 5 * 60 * 1e3;
@@ -139,7 +157,7 @@ async function login(baseUrl) {
139
157
  const { verifier, challenge } = generatePKCE();
140
158
  return new Promise((resolve, reject) => {
141
159
  const server = import_node_http.default.createServer(async (req, res) => {
142
- const url = new URL(req.url ?? "/", `http://localhost`);
160
+ const url = new URL(req.url ?? "/", "http://localhost");
143
161
  if (url.pathname !== "/callback") {
144
162
  res.writeHead(404);
145
163
  res.end("Not found");
@@ -267,6 +285,35 @@ function errorPage(message) {
267
285
  </body></html>`;
268
286
  }
269
287
 
288
+ // src/auth/resolve.ts
289
+ function resolveAuth(flagApiKey) {
290
+ if (flagApiKey) {
291
+ return { apiKey: flagApiKey, source: "flag" };
292
+ }
293
+ const envKey = process.env.AFFONSO_API_KEY;
294
+ if (envKey) {
295
+ return { apiKey: envKey, source: "env" };
296
+ }
297
+ const config = loadConfig();
298
+ if (config.api_key) {
299
+ return { apiKey: config.api_key, source: "config" };
300
+ }
301
+ const auth = loadAuth();
302
+ if (auth?.access_token) {
303
+ if (auth.expires_at && Date.now() > auth.expires_at) {
304
+ return null;
305
+ }
306
+ return { apiKey: auth.access_token, source: "oauth" };
307
+ }
308
+ return null;
309
+ }
310
+ function resolveBaseUrl(flagBaseUrl) {
311
+ if (flagBaseUrl) return flagBaseUrl;
312
+ const config = loadConfig();
313
+ if (config.base_url) return config.base_url;
314
+ return "https://api.affonso.io/v1";
315
+ }
316
+
270
317
  // src/lib/client.ts
271
318
  async function getClient(opts2) {
272
319
  const baseUrl = resolveBaseUrl(opts2.baseUrl);
@@ -278,7 +325,9 @@ async function getClient(opts2) {
278
325
  if (refreshed) {
279
326
  auth = resolveAuth(opts2.apiKey);
280
327
  } else {
281
- console.error("Error: Session expired and token refresh failed. Run `affonso login` to re-authenticate.");
328
+ console.error(
329
+ "Error: Session expired and token refresh failed. Run `affonso login` to re-authenticate."
330
+ );
282
331
  process.exit(1);
283
332
  }
284
333
  }
@@ -287,7 +336,17 @@ async function getClient(opts2) {
287
336
  console.error("Error: Authentication required. Run `affonso login` or set AFFONSO_API_KEY.");
288
337
  process.exit(1);
289
338
  }
290
- return new import_sdk.Affonso(auth.apiKey, { baseUrl });
339
+ return new import_sdk.Affonso(auth.apiKey, {
340
+ baseUrl,
341
+ signingSecret: process.env.AFFONSO_SIGNING_SECRET,
342
+ sourceSigningSecrets: {
343
+ ...process.env.AFFONSO_CUSTOM_SOURCE_SIGNING_SECRET ? { custom: process.env.AFFONSO_CUSTOM_SOURCE_SIGNING_SECRET } : {},
344
+ ...process.env.AFFONSO_SEGMENT_SIGNING_SECRET ? {
345
+ segment: process.env.AFFONSO_SEGMENT_SIGNING_SECRET,
346
+ segment_webhook: process.env.AFFONSO_SEGMENT_SIGNING_SECRET
347
+ } : {}
348
+ }
349
+ });
291
350
  }
292
351
 
293
352
  // src/lib/errors.ts
@@ -334,7 +393,13 @@ function handleError(err, json) {
334
393
  }
335
394
  if (err instanceof Error) {
336
395
  if (json) {
337
- console.error(JSON.stringify({ success: false, error: { code: "CLI_ERROR", message: err.message } }, null, 2));
396
+ console.error(
397
+ JSON.stringify(
398
+ { success: false, error: { code: "CLI_ERROR", message: err.message } },
399
+ null,
400
+ 2
401
+ )
402
+ );
338
403
  } else {
339
404
  console.error(`Error: ${err.message}`);
340
405
  }
@@ -355,6 +420,35 @@ function opts(cmd) {
355
420
  return merged;
356
421
  }
357
422
 
423
+ // src/lib/parse.ts
424
+ var import_node_fs2 = require("fs");
425
+ function readJsonInput(value) {
426
+ if (!value.startsWith("@")) return value;
427
+ const path2 = value.slice(1);
428
+ if (!path2) throw new Error("JSON file path must follow @.");
429
+ return (0, import_node_fs2.readFileSync)(path2, "utf8");
430
+ }
431
+ function parseJson(value, optionName) {
432
+ try {
433
+ return JSON.parse(readJsonInput(value));
434
+ } catch (error) {
435
+ const detail = error instanceof Error ? error.message : String(error);
436
+ throw new Error(`Invalid JSON for ${optionName}: ${detail}`);
437
+ }
438
+ }
439
+ function parseJsonObject(value, optionName) {
440
+ if (value === void 0) return void 0;
441
+ const parsed = parseJson(value, optionName);
442
+ if (parsed === null || Array.isArray(parsed) || typeof parsed !== "object") {
443
+ throw new Error(`${optionName} must contain a JSON object.`);
444
+ }
445
+ return parsed;
446
+ }
447
+ function commaSeparated(value) {
448
+ if (value === void 0) return void 0;
449
+ return value.split(",").map((item) => item.trim()).filter(Boolean);
450
+ }
451
+
358
452
  // src/output/json.ts
359
453
  function formatJson(data) {
360
454
  return JSON.stringify(data, null, 2);
@@ -388,9 +482,11 @@ function formatTable(data, columns) {
388
482
  return truncated.padEnd(widths[col]);
389
483
  }).join(" ")
390
484
  );
391
- return [header, dim("\u2500".repeat(header.replace(/\x1b\[[0-9;]*m/g, "").length)), ...rows].join(
392
- "\n"
485
+ const tableWidth = cols.reduce(
486
+ (total, col) => total + widths[col],
487
+ Math.max(0, cols.length - 1) * 2
393
488
  );
489
+ return [header, dim("\u2500".repeat(tableWidth)), ...rows].join("\n");
394
490
  }
395
491
  function formatValue(val) {
396
492
  if (val === null || val === void 0) return "\u2014";
@@ -422,10 +518,8 @@ function output(result, opts2, columns) {
422
518
  console.log(formatTable(result.data, columns));
423
519
  if (result.pagination) {
424
520
  const p = result.pagination;
425
- console.log(
426
- `
427
- Page ${p.page}/${p.total_pages} (${p.total} total)`
428
- );
521
+ console.log(`
522
+ Page ${p.page}/${p.total_pages} (${p.total} total)`);
429
523
  }
430
524
  return;
431
525
  }
@@ -453,7 +547,7 @@ function outputSuccess(message, opts2) {
453
547
  // src/commands/affiliates.ts
454
548
  function registerAffiliateCommands(program2) {
455
549
  const affiliates = program2.command("affiliates").description("Manage affiliates");
456
- affiliates.command("list").description("List affiliates").option("--limit <n>", "Items per page", "50").option("--page <n>", "Page number", "1").option("--status <status>", "Filter by status (pending, approved, rejected)").option("--search <query>", "Search by name or email").option("--group-id <id>", "Filter by group ID").option("--program-id <id>", "Filter by program ID").option("--expand <fields>", "Expand fields (comma-separated)").option("--sort <field:dir>", "Sort (e.g. createdAt:desc)").option("--date-from <date>", "Filter from date").option("--date-to <date>", "Filter to date").action(async function() {
550
+ affiliates.command("list").description("List affiliates").option("--limit <n>", "Items per page", "50").option("--page <n>", "Page number", "1").option("--status <status>", "Filter by status (pending, approved, rejected)").option("--search <query>", "Search by name or email").option("--group-id <id>", "Filter by group ID").option("--expand <fields>", "Expand fields (comma-separated)").option("--sort <field:dir>", "Sort (e.g. createdAt:desc)").option("--date-from <date>", "Filter from date").option("--date-to <date>", "Filter to date").action(async function() {
457
551
  const o = opts(this);
458
552
  try {
459
553
  const client = await getClient(o);
@@ -463,13 +557,19 @@ function registerAffiliateCommands(program2) {
463
557
  partnership_status: o.status,
464
558
  search: o.search,
465
559
  group_id: o.groupId,
466
- program_id: o.programId,
467
560
  expand: o.expand,
468
561
  sort: o.sort,
469
562
  dateFrom: o.dateFrom,
470
563
  dateTo: o.dateTo
471
564
  });
472
- output(result, o, ["id", "name", "email", "partnership_status", "tracking_id", "created_at"]);
565
+ output(result, o, [
566
+ "id",
567
+ "name",
568
+ "email",
569
+ "partnership_status",
570
+ "tracking_id",
571
+ "created_at"
572
+ ]);
473
573
  } catch (err) {
474
574
  handleError(err, o.json);
475
575
  }
@@ -486,29 +586,33 @@ function registerAffiliateCommands(program2) {
486
586
  handleError(err, o.json);
487
587
  }
488
588
  });
489
- affiliates.command("create").description("Create an affiliate").requiredOption("--name <name>", "Affiliate name").requiredOption("--email <email>", "Affiliate email").requiredOption("--program-id <id>", "Program ID").option("--tracking-id <id>", "Custom tracking ID").option("--group-id <id>", "Group ID").option("--company-name <name>", "Company name").option("--country-code <code>", "Country code").option("--external-user-id <id>", "External user ID").action(async function() {
589
+ affiliates.command("create").description("Create an affiliate").requiredOption("--name <name>", "Affiliate name").requiredOption("--email <email>", "Affiliate email").option("--tracking-id <id>", "Custom tracking ID").option("--group-id <id>", "Group ID").option("--company-name <name>", "Company name").option("--country-code <code>", "Country code").option("--status <status>", "Partnership status (pending, approved, rejected)").option("--onboarding-completed", "Mark onboarding as completed").option("--payout-method <method>", "Payout method").option("--payout-details-json <json|@file>", "Payout details as JSON or @file").option("--external-user-id <id>", "External user ID").option("--metadata-json <json|@file>", "Metadata as JSON or @file").action(async function() {
490
590
  const o = opts(this);
491
591
  try {
492
- const client = await getClient(o);
493
- const result = await client.affiliates.create({
592
+ const params = {
494
593
  name: o.name,
495
594
  email: o.email,
496
- program_id: o.programId,
497
595
  tracking_id: o.trackingId,
498
596
  group_id: o.groupId,
499
597
  company_name: o.companyName,
500
598
  country_code: o.countryCode,
501
- external_user_id: o.externalUserId
502
- });
599
+ status: o.status,
600
+ onboarding_completed: o.onboardingCompleted || void 0,
601
+ payout_method: o.payoutMethod,
602
+ payout_details: parseJsonObject(o.payoutDetailsJson, "--payout-details-json"),
603
+ external_user_id: o.externalUserId,
604
+ metadata: parseJsonObject(o.metadataJson, "--metadata-json")
605
+ };
606
+ const client = await getClient(o);
607
+ const result = await client.affiliates.create(params);
503
608
  output(result, o);
504
609
  } catch (err) {
505
610
  handleError(err, o.json);
506
611
  }
507
612
  });
508
- affiliates.command("update <id>").description("Update an affiliate").option("--name <name>", "Affiliate name").option("--email <email>", "Affiliate email").option("--status <status>", "Status (pending, approved, rejected)").option("--group-id <id>", "Group ID").option("--company-name <name>", "Company name").option("--country-code <code>", "Country code").option("--external-user-id <id>", "External user ID").option("--onboarding-completed", "Mark onboarding as completed").action(async function(id) {
613
+ affiliates.command("update <id>").description("Update an affiliate").option("--name <name>", "Affiliate name").option("--email <email>", "Affiliate email").option("--status <status>", "Status (pending, approved, rejected)").option("--group-id <id>", "Group ID").option("--company-name <name>", "Company name").option("--country-code <code>", "Country code").option("--invoice-details-json <json|@file>", "Invoice details as JSON or @file").option("--payout-method <method>", "Payout method").option("--payout-details-json <json|@file>", "Payout details as JSON or @file").option("--external-user-id <id>", "External user ID").option("--metadata-json <json|@file>", "Metadata as JSON or @file").option("--onboarding-completed", "Mark onboarding as completed").option("--no-onboarding-completed", "Mark onboarding as incomplete").action(async function(id) {
509
614
  const o = opts(this);
510
615
  try {
511
- const client = await getClient(o);
512
616
  const params = {};
513
617
  if (o.name !== void 0) params.name = o.name;
514
618
  if (o.email !== void 0) params.email = o.email;
@@ -516,8 +620,17 @@ function registerAffiliateCommands(program2) {
516
620
  if (o.groupId !== void 0) params.group_id = o.groupId;
517
621
  if (o.companyName !== void 0) params.company_name = o.companyName;
518
622
  if (o.countryCode !== void 0) params.country_code = o.countryCode;
623
+ if (o.invoiceDetailsJson !== void 0)
624
+ params.invoice_details = parseJsonObject(o.invoiceDetailsJson, "--invoice-details-json");
625
+ if (o.payoutMethod !== void 0) params.payout_method = o.payoutMethod;
626
+ if (o.payoutDetailsJson !== void 0)
627
+ params.payout_details = parseJsonObject(o.payoutDetailsJson, "--payout-details-json");
519
628
  if (o.externalUserId !== void 0) params.external_user_id = o.externalUserId;
520
- if (o.onboardingCompleted) params.onboarding_completed = true;
629
+ if (o.metadataJson !== void 0)
630
+ params.metadata = parseJsonObject(o.metadataJson, "--metadata-json");
631
+ if (o.onboardingCompleted !== void 0)
632
+ params.onboarding_completed = o.onboardingCompleted;
633
+ const client = await getClient(o);
521
634
  const result = await client.affiliates.update(id, params);
522
635
  output(result, o);
523
636
  } catch (err) {
@@ -534,84 +647,42 @@ function registerAffiliateCommands(program2) {
534
647
  handleError(err, o.json);
535
648
  }
536
649
  });
537
- }
538
-
539
- // src/commands/referrals.ts
540
- function registerReferralCommands(program2) {
541
- const referrals = program2.command("referrals").description("Manage referrals");
542
- referrals.command("list").description("List referrals").option("--limit <n>", "Items per page", "50").option("--starting-after <id>", "Cursor: fetch items after this ID").option("--ending-before <id>", "Cursor: fetch items before this ID").option("--affiliate-id <id>", "Filter by affiliate ID").option("--status <status>", "Filter by status").option("--order <dir>", "Order (asc, desc)").option("--expand <fields>", "Expand fields").option("--created-gte <date>", "Created after date").option("--created-lte <date>", "Created before date").action(async function() {
543
- const o = opts(this);
544
- try {
545
- const client = await getClient(o);
546
- const result = await client.referrals.list({
547
- limit: Number(o.limit),
548
- starting_after: o.startingAfter,
549
- ending_before: o.endingBefore,
550
- affiliate_id: o.affiliateId,
551
- status: o.status,
552
- order: o.order,
553
- expand: o.expand,
554
- created_gte: o.createdGte,
555
- created_lte: o.createdLte
556
- });
557
- output(result, o, ["id", "affiliate_id", "email", "status", "created_at"]);
558
- } catch (err) {
559
- handleError(err, o.json);
560
- }
561
- });
562
- referrals.command("get <id>").description("Get a referral by ID").option("--expand <fields>", "Expand fields").option("--include <fields>", "Include fields").action(async function(id) {
563
- const o = opts(this);
564
- try {
565
- const client = await getClient(o);
566
- const result = await client.referrals.retrieve(id, {
567
- expand: o.expand,
568
- include: o.include
569
- });
570
- output(result, o);
571
- } catch (err) {
572
- handleError(err, o.json);
573
- }
574
- });
575
- referrals.command("create").description("Create a referral").requiredOption("--email <email>", "Referral email").requiredOption("--affiliate-id <id>", "Affiliate ID").option("--subscription-id <id>", "Subscription ID").option("--customer-id <id>", "Customer ID").option("--click-id <id>", "Click ID").option("--status <status>", "Initial status").option("--name <name>", "Referral name").action(async function() {
650
+ const onboarding = affiliates.command("onboarding-responses").description("Manage affiliate onboarding responses");
651
+ onboarding.command("get <affiliate-id>").description("Get an affiliate's onboarding responses").action(async function(affiliateId) {
576
652
  const o = opts(this);
577
653
  try {
578
654
  const client = await getClient(o);
579
- const result = await client.referrals.create({
580
- email: o.email,
581
- affiliate_id: o.affiliateId,
582
- subscription_id: o.subscriptionId,
583
- customer_id: o.customerId,
584
- click_id: o.clickId,
585
- status: o.status,
586
- name: o.name
587
- });
588
- output(result, o);
655
+ output(await client.affiliates.retrieveOnboardingResponses(affiliateId), o);
589
656
  } catch (err) {
590
657
  handleError(err, o.json);
591
658
  }
592
659
  });
593
- referrals.command("update <id>").description("Update a referral").option("--email <email>", "Referral email").option("--status <status>", "Status").option("--subscription-id <id>", "Subscription ID").option("--customer-id <id>", "Customer ID").option("--name <name>", "Referral name").action(async function(id) {
660
+ onboarding.command("submit <affiliate-id>").description("Submit an affiliate's onboarding responses").requiredOption("--responses-json <json|@file>", "Response array as JSON or @file").option("--mark-complete", "Mark onboarding as complete").action(async function(affiliateId) {
594
661
  const o = opts(this);
595
662
  try {
663
+ const responses = parseJson(
664
+ o.responsesJson,
665
+ "--responses-json"
666
+ );
667
+ if (!Array.isArray(responses))
668
+ throw new Error("--responses-json must contain a JSON array.");
596
669
  const client = await getClient(o);
597
- const params = {};
598
- if (o.email !== void 0) params.email = o.email;
599
- if (o.status !== void 0) params.status = o.status;
600
- if (o.subscriptionId !== void 0) params.subscription_id = o.subscriptionId;
601
- if (o.customerId !== void 0) params.customer_id = o.customerId;
602
- if (o.name !== void 0) params.name = o.name;
603
- const result = await client.referrals.update(id, params);
604
- output(result, o);
670
+ output(
671
+ await client.affiliates.submitOnboardingResponses(affiliateId, {
672
+ responses,
673
+ mark_complete: o.markComplete || void 0
674
+ }),
675
+ o
676
+ );
605
677
  } catch (err) {
606
678
  handleError(err, o.json);
607
679
  }
608
680
  });
609
- referrals.command("delete <id>").description("Delete a referral").action(async function(id) {
681
+ affiliates.command("portal-token <id>").description("Create a portal login token for an affiliate").action(async function(id) {
610
682
  const o = opts(this);
611
683
  try {
612
684
  const client = await getClient(o);
613
- const result = await client.referrals.del(id);
614
- outputSuccess(result.message ?? "Referral deleted.", o);
685
+ output(await client.affiliates.createPortalToken(id), o);
615
686
  } catch (err) {
616
687
  handleError(err, o.json);
617
688
  }
@@ -621,13 +692,13 @@ function registerReferralCommands(program2) {
621
692
  // src/commands/clicks.ts
622
693
  function registerClickCommands(program2) {
623
694
  const clicks = program2.command("clicks").description("Track click events");
624
- clicks.command("create").description("Record a click event").requiredOption("--program-id <id>", "Program ID").requiredOption("--tracking-id <id>", "Tracking ID").option("--referrer <url>", "Referrer URL").option("--utm-source <val>", "UTM source").option("--utm-medium <val>", "UTM medium").option("--utm-campaign <val>", "UTM campaign").option("--utm-term <val>", "UTM term").option("--utm-content <val>", "UTM content").option("--sub1 <val>", "Sub-tracking parameter 1").option("--sub2 <val>", "Sub-tracking parameter 2").option("--sub3 <val>", "Sub-tracking parameter 3").option("--sub4 <val>", "Sub-tracking parameter 4").option("--sub5 <val>", "Sub-tracking parameter 5").option("--ip <ip>", "IP address").option("--user-agent <ua>", "User agent string").action(async function() {
695
+ clicks.command("create").description("Record a click event").requiredOption("--tracking-id <id>", "Tracking ID").option("--created-at <date>", "Creation timestamp (ISO 8601)").option("--referrer <url>", "Referrer URL").option("--utm-source <val>", "UTM source").option("--utm-medium <val>", "UTM medium").option("--utm-campaign <val>", "UTM campaign").option("--utm-term <val>", "UTM term").option("--utm-content <val>", "UTM content").option("--sub1 <val>", "Sub-tracking parameter 1").option("--sub2 <val>", "Sub-tracking parameter 2").option("--sub3 <val>", "Sub-tracking parameter 3").option("--sub4 <val>", "Sub-tracking parameter 4").option("--sub5 <val>", "Sub-tracking parameter 5").option("--ip <ip>", "IP address").option("--user-agent <ua>", "User agent string").option("--gclid <id>", "Google click ID").option("--fbclid <id>", "Meta click ID").option("--msclkid <id>", "Microsoft click ID").option("--ttclid <id>", "TikTok click ID").action(async function() {
625
696
  const o = opts(this);
626
697
  try {
627
698
  const client = await getClient(o);
628
699
  const result = await client.clicks.create({
629
- programId: o.programId,
630
700
  trackingId: o.trackingId,
701
+ createdAt: o.createdAt,
631
702
  referrer: o.referrer,
632
703
  utmSource: o.utmSource,
633
704
  utmMedium: o.utmMedium,
@@ -640,7 +711,11 @@ function registerClickCommands(program2) {
640
711
  sub4: o.sub4,
641
712
  sub5: o.sub5,
642
713
  ip: o.ip,
643
- userAgent: o.userAgent
714
+ userAgent: o.userAgent,
715
+ gclid: o.gclid,
716
+ fbclid: o.fbclid,
717
+ msclkid: o.msclkid,
718
+ ttclid: o.ttclid
644
719
  });
645
720
  output(result, o);
646
721
  } catch (err) {
@@ -693,7 +768,7 @@ function registerCommissionCommands(program2) {
693
768
  handleError(err, o.json);
694
769
  }
695
770
  });
696
- commissions.command("create").description("Create a commission").requiredOption("--referral-id <id>", "Referral ID").requiredOption("--sale-amount <n>", "Sale amount").requiredOption("--sale-amount-currency <code>", "Sale currency (e.g. USD)").requiredOption("--commission-amount <n>", "Commission amount").requiredOption("--commission-currency <code>", "Commission currency").option("--is-subscription", "Mark as subscription commission").option("--status <status>", "Commission status").option("--sales-status <status>", "Sales status").option("--payment-intent-id <id>", "Payment intent ID").option("--hold-period-days <n>", "Hold period in days").action(async function() {
771
+ commissions.command("create").description("Create a commission").requiredOption("--referral-id <id>", "Referral ID").requiredOption("--sale-amount <n>", "Sale amount").option("--sale-amount-currency <code>", "Sale currency (defaults to program currency)").requiredOption("--commission-amount <n>", "Commission amount").option("--commission-currency <code>", "Commission currency").option("--is-subscription", "Mark as subscription commission").option("--status <status>", "Commission status").option("--sales-status <status>", "Sales status").option("--payment-intent-id <id>", "Payment intent ID").option("--hold-period-days <n>", "Hold period in days").option("--created-at <date>", "Creation timestamp (ISO 8601)").action(async function() {
697
772
  const o = opts(this);
698
773
  try {
699
774
  const client = await getClient(o);
@@ -707,7 +782,8 @@ function registerCommissionCommands(program2) {
707
782
  status: o.status,
708
783
  sales_status: o.salesStatus,
709
784
  payment_intent_id: o.paymentIntentId,
710
- hold_period_days: o.holdPeriodDays ? Number(o.holdPeriodDays) : void 0
785
+ hold_period_days: o.holdPeriodDays ? Number(o.holdPeriodDays) : void 0,
786
+ created_at: o.createdAt
711
787
  });
712
788
  output(result, o);
713
789
  } catch (err) {
@@ -744,10 +820,109 @@ function registerCommissionCommands(program2) {
744
820
  });
745
821
  }
746
822
 
823
+ // src/commands/config.ts
824
+ var VALID_KEYS = ["api-key", "base-url"];
825
+ var KEY_MAP = {
826
+ "api-key": "api_key",
827
+ "base-url": "base_url"
828
+ };
829
+ function registerConfigCommands(program2) {
830
+ const config = program2.command("config").description("Manage CLI configuration");
831
+ config.command("get <key>").description("Get a config value (api-key, base-url)").action(async function(key) {
832
+ const o = opts(this);
833
+ try {
834
+ if (!VALID_KEYS.includes(key)) {
835
+ console.error(`Unknown config key: ${key}. Valid keys: ${VALID_KEYS.join(", ")}`);
836
+ process.exit(1);
837
+ }
838
+ const stored = loadConfig();
839
+ const mappedKey = KEY_MAP[key];
840
+ const value = stored[mappedKey];
841
+ if (value) {
842
+ if (key === "api-key") {
843
+ const v = value;
844
+ console.log(`${v.slice(0, 10)}...${v.slice(-4)}`);
845
+ } else {
846
+ console.log(value);
847
+ }
848
+ } else {
849
+ console.log(`${key} is not set.`);
850
+ }
851
+ } catch (err) {
852
+ handleError(err, o.json);
853
+ }
854
+ });
855
+ config.command("set <key> <value>").description("Set a config value (api-key, base-url)").action(async function(key, value) {
856
+ const o = opts(this);
857
+ try {
858
+ if (!VALID_KEYS.includes(key)) {
859
+ console.error(`Unknown config key: ${key}. Valid keys: ${VALID_KEYS.join(", ")}`);
860
+ process.exit(1);
861
+ }
862
+ const mappedKey = KEY_MAP[key];
863
+ saveConfig({ [mappedKey]: value });
864
+ console.log(`${key} saved.`);
865
+ } catch (err) {
866
+ handleError(err, o.json);
867
+ }
868
+ });
869
+ }
870
+
871
+ // src/commands/conversions.ts
872
+ function registerConversionCommands(program2) {
873
+ const conversions = program2.command("conversions").description("Track and refund conversions");
874
+ conversions.command("create").description("Create a conversion (requires AFFONSO_SIGNING_SECRET)").requiredOption("--sale-amount <n>", "Sale amount").requiredOption("--external-event-id <id>", "Idempotent external event ID").option("--referral-id <id>", "Referral ID").option("--click-id <id>", "Click ID").option("--affonso-id <id>", "Affonso click ID").option("--affonso-referral <id>", "Affonso referral identifier").option("--customer-id <id>", "Customer ID").option("--external-user-id <id>", "External user ID").option("--sale-amount-currency <code>", "Sale currency").option("--product-ids <ids>", "Product IDs (comma-separated)").option("--price-ids <ids>", "Price IDs (comma-separated)").option("--interval <interval>", "Billing interval (monthly, yearly)").option("--is-subscription", "Mark as a subscription").option("--created-at <date>", "Creation timestamp (ISO 8601)").option("--status <status>", "Commission status").option("--sales-status <status>", "Sales status").option("--metadata-json <json|@file>", "Metadata as JSON or @file").action(async function() {
875
+ const o = opts(this);
876
+ try {
877
+ const params = {
878
+ referral_id: o.referralId,
879
+ click_id: o.clickId,
880
+ affonso_id: o.affonsoId,
881
+ affonso_referral: o.affonsoReferral,
882
+ customer_id: o.customerId,
883
+ external_user_id: o.externalUserId,
884
+ sale_amount: Number(o.saleAmount),
885
+ sale_amount_currency: o.saleAmountCurrency,
886
+ product_ids: commaSeparated(o.productIds),
887
+ price_ids: commaSeparated(o.priceIds),
888
+ interval: o.interval,
889
+ is_subscription: o.isSubscription || void 0,
890
+ external_event_id: o.externalEventId,
891
+ created_at: o.createdAt,
892
+ status: o.status,
893
+ sales_status: o.salesStatus,
894
+ metadata: parseJsonObject(o.metadataJson, "--metadata-json")
895
+ };
896
+ const client = await getClient(o);
897
+ output(await client.conversions.create(params), o);
898
+ } catch (err) {
899
+ handleError(err, o.json);
900
+ }
901
+ });
902
+ conversions.command("refund <id>").description("Refund a conversion (requires AFFONSO_SIGNING_SECRET)").option("--amount <n>", "Partial refund amount").option("--currency <code>", "Refund currency").option("--reason <reason>", "Refund reason").option("--external-event-id <id>", "Idempotent external event ID").option("--refunded-at <date>", "Refund timestamp (ISO 8601)").action(async function(id) {
903
+ const o = opts(this);
904
+ try {
905
+ const client = await getClient(o);
906
+ output(
907
+ await client.conversions.refund(id, {
908
+ amount: o.amount === void 0 ? void 0 : Number(o.amount),
909
+ currency: o.currency,
910
+ reason: o.reason,
911
+ external_event_id: o.externalEventId,
912
+ refunded_at: o.refundedAt
913
+ }),
914
+ o
915
+ );
916
+ } catch (err) {
917
+ handleError(err, o.json);
918
+ }
919
+ });
920
+ }
921
+
747
922
  // src/commands/coupons.ts
748
923
  function registerCouponCommands(program2) {
749
924
  const coupons = program2.command("coupons").description("Manage coupons");
750
- coupons.command("list").description("List coupons").option("--limit <n>", "Items per page", "50").option("--page <n>", "Page number", "1").option("--affiliate-id <id>", "Filter by affiliate ID").option("--program-id <id>", "Filter by program ID").option("--search <query>", "Search by code").option("--expand <fields>", "Expand fields").option("--sort <field:dir>", "Sort").action(async function() {
925
+ coupons.command("list").description("List coupons").option("--limit <n>", "Items per page", "50").option("--page <n>", "Page number", "1").option("--affiliate-id <id>", "Filter by affiliate ID").option("--search <query>", "Search by code").option("--expand <fields>", "Expand fields").option("--sort <field:dir>", "Sort").action(async function() {
751
926
  const o = opts(this);
752
927
  try {
753
928
  const client = await getClient(o);
@@ -755,12 +930,19 @@ function registerCouponCommands(program2) {
755
930
  limit: Number(o.limit),
756
931
  page: Number(o.page),
757
932
  affiliate_id: o.affiliateId,
758
- program_id: o.programId,
759
933
  search: o.search,
760
934
  expand: o.expand,
761
935
  sort: o.sort
762
936
  });
763
- output(result, o, ["id", "affiliate_id", "code", "discount_type", "discount_value", "duration", "created_at"]);
937
+ output(result, o, [
938
+ "id",
939
+ "affiliate_id",
940
+ "code",
941
+ "discount_type",
942
+ "discount_value",
943
+ "duration",
944
+ "created_at"
945
+ ]);
764
946
  } catch (err) {
765
947
  handleError(err, o.json);
766
948
  }
@@ -789,7 +971,7 @@ function registerCouponCommands(program2) {
789
971
  duration: o.duration,
790
972
  duration_in_months: o.durationInMonths ? Number(o.durationInMonths) : void 0,
791
973
  currency: o.currency,
792
- product_ids: o.productIds?.split(",")
974
+ product_ids: o.productIds?.split(",").map((id) => id.trim()).filter(Boolean)
793
975
  });
794
976
  output(result, o);
795
977
  } catch (err) {
@@ -808,31 +990,248 @@ function registerCouponCommands(program2) {
808
990
  });
809
991
  }
810
992
 
811
- // src/commands/payouts.ts
812
- function registerPayoutCommands(program2) {
813
- const payouts = program2.command("payouts").description("Manage payouts");
814
- payouts.command("list").description("List payouts").option("--limit <n>", "Items per page", "50").option("--page <n>", "Page number", "1").option("--status <status>", "Filter by status (pending, processing, completed, failed, cancelled)").option("--affiliate-id <id>", "Filter by affiliate ID").option("--sort <field:dir>", "Sort").option("--date-from <date>", "Filter from date").option("--date-to <date>", "Filter to date").action(async function() {
993
+ // src/commands/embed-tokens.ts
994
+ function registerEmbedTokenCommands(program2) {
995
+ const embedTokens = program2.command("embed-tokens").description("Generate embed tokens");
996
+ embedTokens.command("create").description("Create an embed token").requiredOption("--email <email>", "Partner email").option("--external-user-id <id>", "External user ID").option("--name <name>", "Partner name").option("--image <url>", "Partner image URL").option("--group-id <id>", "Affiliate group ID").option("--metadata-json <json|@file>", "Metadata as JSON or @file").action(async function() {
815
997
  const o = opts(this);
816
998
  try {
999
+ const metadata = parseJsonObject(o.metadataJson, "--metadata-json");
817
1000
  const client = await getClient(o);
818
- const result = await client.payouts.list({
819
- limit: Number(o.limit),
820
- page: Number(o.page),
821
- status: o.status,
822
- affiliateId: o.affiliateId,
823
- sort: o.sort,
824
- dateFrom: o.dateFrom,
825
- dateTo: o.dateTo
1001
+ const result = await client.embedTokens.create({
1002
+ partner: {
1003
+ email: o.email,
1004
+ name: o.name,
1005
+ image: o.image
1006
+ },
1007
+ groupId: o.groupId,
1008
+ externalUserId: o.externalUserId,
1009
+ metadata
826
1010
  });
827
- output(result, o, ["id", "affiliate_id", "amount", "status", "payment_method", "created_at"]);
1011
+ output(result, o);
828
1012
  } catch (err) {
829
1013
  handleError(err, o.json);
830
1014
  }
831
1015
  });
832
- payouts.command("get <id>").description("Get a payout by ID").action(async function(id) {
1016
+ }
1017
+
1018
+ // src/commands/events.ts
1019
+ function registerEventCommands(program2) {
1020
+ program2.command("events").description("Track server-side events").command("create").description("Create a server-side event (requires AFFONSO_SIGNING_SECRET)").requiredOption("--event-name <name>", "Event name").option("--event-type <type>", "Event type (conversion, lead, trial, milestone)").option("--referral-id <id>", "Referral ID").option("--click-id <id>", "Click ID").option("--affonso-id <id>", "Affonso click ID").option("--affonso-referral <id>", "Affonso referral identifier").option("--customer-id <id>", "Customer ID").option("--external-user-id <id>", "External user ID").option("--occurred-at <date>", "Event timestamp (ISO 8601)").option("--external-event-id <id>", "Idempotent external event ID").option("--sale-amount <n>", "Sale amount").option("--sale-amount-currency <code>", "Sale currency").option("--product-ids <ids>", "Product IDs (comma-separated)").option("--price-ids <ids>", "Price IDs (comma-separated)").option("--interval <interval>", "Billing interval (monthly, yearly)").option("--is-subscription", "Mark as a subscription").option("--metadata-json <json|@file>", "Metadata as JSON or @file").action(async function() {
833
1021
  const o = opts(this);
834
1022
  try {
835
- const client = await getClient(o);
1023
+ const params = {
1024
+ event_name: o.eventName,
1025
+ event_type: o.eventType,
1026
+ referral_id: o.referralId,
1027
+ click_id: o.clickId,
1028
+ affonso_id: o.affonsoId,
1029
+ affonso_referral: o.affonsoReferral,
1030
+ customer_id: o.customerId,
1031
+ external_user_id: o.externalUserId,
1032
+ occurred_at: o.occurredAt,
1033
+ external_event_id: o.externalEventId,
1034
+ sale_amount: o.saleAmount === void 0 ? void 0 : Number(o.saleAmount),
1035
+ sale_amount_currency: o.saleAmountCurrency,
1036
+ product_ids: commaSeparated(o.productIds),
1037
+ price_ids: commaSeparated(o.priceIds),
1038
+ interval: o.interval,
1039
+ is_subscription: o.isSubscription || void 0,
1040
+ metadata: parseJsonObject(o.metadataJson, "--metadata-json")
1041
+ };
1042
+ const client = await getClient(o);
1043
+ output(await client.events.create(params), o);
1044
+ } catch (err) {
1045
+ handleError(err, o.json);
1046
+ }
1047
+ });
1048
+ }
1049
+
1050
+ // src/commands/login.ts
1051
+ function registerLoginCommand(program2) {
1052
+ program2.command("login").description("Log in via browser (OAuth 2.1)").action(async function() {
1053
+ const o = opts(this);
1054
+ try {
1055
+ const existing = resolveAuth();
1056
+ if (existing?.source === "oauth") {
1057
+ console.log("Already logged in. Run `affonso logout` first to switch accounts.");
1058
+ return;
1059
+ }
1060
+ const baseUrl = resolveBaseUrl(o.baseUrl);
1061
+ await login(baseUrl);
1062
+ console.log("Successfully logged in!");
1063
+ } catch (err) {
1064
+ handleError(err, o.json);
1065
+ }
1066
+ });
1067
+ }
1068
+
1069
+ // src/commands/logout.ts
1070
+ function registerLogoutCommand(program2) {
1071
+ program2.command("logout").description("Log out and remove stored credentials").action(async function() {
1072
+ const o = opts(this);
1073
+ try {
1074
+ const auth = loadAuth();
1075
+ if (auth?.access_token) {
1076
+ const baseUrl = resolveBaseUrl(o.baseUrl);
1077
+ const issuer = baseUrl.replace(/\/v1\/?$/, "");
1078
+ try {
1079
+ await fetch(`${issuer}/oauth/revoke`, {
1080
+ method: "POST",
1081
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
1082
+ body: new URLSearchParams({
1083
+ token: auth.access_token,
1084
+ client_id: CLIENT_ID
1085
+ })
1086
+ });
1087
+ } catch {
1088
+ }
1089
+ }
1090
+ clearAuth();
1091
+ console.log("Logged out.");
1092
+ } catch (err) {
1093
+ handleError(err, o.json);
1094
+ }
1095
+ });
1096
+ }
1097
+
1098
+ // src/commands/marketplace.ts
1099
+ var import_sdk3 = require("@affonso/sdk");
1100
+ function registerMarketplaceCommands(program2) {
1101
+ const marketplace = program2.command("marketplace").description("Browse the affiliate marketplace (public, no auth required)");
1102
+ marketplace.command("list").description("List marketplace programs").option("--limit <n>", "Items per page", "50").option("--page <n>", "Page number", "1").option("--category <cat>", "Filter by category").action(async function() {
1103
+ const o = opts(this);
1104
+ try {
1105
+ const baseUrl = resolveBaseUrl(o.baseUrl);
1106
+ const client = new import_sdk3.Affonso("public", { baseUrl });
1107
+ const result = await client.marketplace.list({
1108
+ limit: Number(o.limit),
1109
+ page: Number(o.page),
1110
+ category: o.category
1111
+ });
1112
+ output(result, o, [
1113
+ "id",
1114
+ "name",
1115
+ "marketplace_joined_at",
1116
+ "access_mode",
1117
+ "currency",
1118
+ "website_url"
1119
+ ]);
1120
+ } catch (err) {
1121
+ handleError(err, o.json);
1122
+ }
1123
+ });
1124
+ marketplace.command("get <id>").description("Get a marketplace program by ID").action(async function(id) {
1125
+ const o = opts(this);
1126
+ try {
1127
+ const baseUrl = resolveBaseUrl(o.baseUrl);
1128
+ const client = new import_sdk3.Affonso("public", { baseUrl });
1129
+ const result = await client.marketplace.retrieve(id);
1130
+ output(result, o);
1131
+ } catch (err) {
1132
+ handleError(err, o.json);
1133
+ }
1134
+ });
1135
+ }
1136
+
1137
+ // src/commands/onboarding-form.ts
1138
+ function questions(value) {
1139
+ const parsed = parseJson(value, "--questions-json");
1140
+ if (!Array.isArray(parsed)) throw new Error("--questions-json must contain a JSON array.");
1141
+ return parsed;
1142
+ }
1143
+ function registerOnboardingFormCommands(program2) {
1144
+ const form = program2.command("onboarding-form").description("Manage the onboarding form");
1145
+ form.command("get").description("Get the onboarding form").action(async function() {
1146
+ const o = opts(this);
1147
+ try {
1148
+ const client = await getClient(o);
1149
+ output(await client.onboardingForm.retrieve(), o);
1150
+ } catch (err) {
1151
+ handleError(err, o.json);
1152
+ }
1153
+ });
1154
+ form.command("create").description("Create the onboarding form").requiredOption("--name <name>", "Form name").requiredOption("--questions-json <json|@file>", "Questions array as JSON or @file").option("--description <text>", "Form description").action(async function() {
1155
+ const o = opts(this);
1156
+ try {
1157
+ const parsedQuestions = questions(o.questionsJson);
1158
+ const client = await getClient(o);
1159
+ output(
1160
+ await client.onboardingForm.create({
1161
+ name: o.name,
1162
+ description: o.description,
1163
+ questions: parsedQuestions
1164
+ }),
1165
+ o
1166
+ );
1167
+ } catch (err) {
1168
+ handleError(err, o.json);
1169
+ }
1170
+ });
1171
+ form.command("update").description("Update the onboarding form").option("--name <name>", "Form name").option("--description <text>", "Form description").option("--questions-json <json|@file>", "Questions array as JSON or @file").action(async function() {
1172
+ const o = opts(this);
1173
+ try {
1174
+ const parsedQuestions = o.questionsJson === void 0 ? void 0 : questions(o.questionsJson);
1175
+ const client = await getClient(o);
1176
+ output(
1177
+ await client.onboardingForm.update({
1178
+ name: o.name,
1179
+ description: o.description,
1180
+ questions: parsedQuestions
1181
+ }),
1182
+ o
1183
+ );
1184
+ } catch (err) {
1185
+ handleError(err, o.json);
1186
+ }
1187
+ });
1188
+ form.command("delete").description("Delete the onboarding form").action(async function() {
1189
+ const o = opts(this);
1190
+ try {
1191
+ const client = await getClient(o);
1192
+ const result = await client.onboardingForm.del();
1193
+ outputSuccess(result.message ?? "Onboarding form deleted.", o);
1194
+ } catch (err) {
1195
+ handleError(err, o.json);
1196
+ }
1197
+ });
1198
+ }
1199
+
1200
+ // src/commands/payouts.ts
1201
+ function registerPayoutCommands(program2) {
1202
+ const payouts = program2.command("payouts").description("Manage payouts");
1203
+ payouts.command("list").description("List payouts").option("--limit <n>", "Items per page", "50").option("--page <n>", "Page number", "1").option(
1204
+ "--status <status>",
1205
+ "Filter by status (pending, processing, completed, failed, cancelled)"
1206
+ ).option("--affiliate-id <id>", "Filter by affiliate ID").option("--sort <field:dir>", "Sort").option("--date-from <date>", "Filter from date").option("--date-to <date>", "Filter to date").action(async function() {
1207
+ const o = opts(this);
1208
+ try {
1209
+ const client = await getClient(o);
1210
+ const result = await client.payouts.list({
1211
+ limit: Number(o.limit),
1212
+ page: Number(o.page),
1213
+ status: o.status,
1214
+ affiliateId: o.affiliateId,
1215
+ sort: o.sort,
1216
+ dateFrom: o.dateFrom,
1217
+ dateTo: o.dateTo
1218
+ });
1219
+ output(result, o, [
1220
+ "id",
1221
+ "affiliate_id",
1222
+ "amount",
1223
+ "status",
1224
+ "payment_method",
1225
+ "created_at"
1226
+ ]);
1227
+ } catch (err) {
1228
+ handleError(err, o.json);
1229
+ }
1230
+ });
1231
+ payouts.command("get <id>").description("Get a payout by ID").action(async function(id) {
1232
+ const o = opts(this);
1233
+ try {
1234
+ const client = await getClient(o);
836
1235
  const result = await client.payouts.retrieve(id);
837
1236
  output(result, o);
838
1237
  } catch (err) {
@@ -868,20 +1267,24 @@ function registerProgramCommands(program2) {
868
1267
  handleError(err, o.json);
869
1268
  }
870
1269
  });
871
- prog.command("update").description("Update program settings").option("--name <name>", "Program name").option("--tagline <text>", "Tagline").option("--category <cat>", "Category").option("--description <text>", "Description").option("--website-url <url>", "Website URL").option("--logo-url <url>", "Logo URL").option("--access-mode <mode>", "Access mode: PUBLIC, PRIVATE, or INVITE").option("--affiliate-links-enabled", "Enable affiliate links").option("--no-affiliate-links-enabled", "Disable affiliate links").action(async function() {
1270
+ prog.command("update").description("Update program settings").option("--name <name>", "Program name").option("--tagline <text>", "Tagline").option("--description <text>", "Description").option("--website-url <url>", "Website URL").option("--logo-url <url>", "Logo URL").option("--access-mode <mode>", "Access mode: PUBLIC, PRIVATE, or INVITE").option("--affiliate-links-enabled", "Enable affiliate links").option("--no-affiliate-links-enabled", "Disable affiliate links").option(
1271
+ "--customer-information-visibility <visibility>",
1272
+ "Customer data visibility (HIDDEN, NAME, EMAIL, NAME_AND_EMAIL)"
1273
+ ).action(async function() {
872
1274
  const o = opts(this);
873
1275
  try {
874
1276
  const client = await getClient(o);
875
1277
  const params = {};
876
1278
  if (o.name !== void 0) params.name = o.name;
877
1279
  if (o.tagline !== void 0) params.tagline = o.tagline;
878
- if (o.category !== void 0) params.category = o.category;
879
1280
  if (o.description !== void 0) params.description = o.description;
880
1281
  if (o.websiteUrl !== void 0) params.website_url = o.websiteUrl;
881
1282
  if (o.logoUrl !== void 0) params.logo_url = o.logoUrl;
882
1283
  if (o.accessMode !== void 0) params.access_mode = o.accessMode;
883
1284
  if (o.affiliateLinksEnabled !== void 0)
884
1285
  params.affiliate_links_enabled = o.affiliateLinksEnabled;
1286
+ if (o.customerInformationVisibility !== void 0)
1287
+ params.customer_information_visibility = o.customerInformationVisibility;
885
1288
  const result = await client.program.update(params);
886
1289
  output(result, o);
887
1290
  } catch (err) {
@@ -909,7 +1312,10 @@ function registerPaymentTerms(prog) {
909
1312
  handleError(err, o.json);
910
1313
  }
911
1314
  });
912
- pt.command("update").description("Update payment terms").option("--commission-type <type>", "Commission type (percentage, fixed)").option("--commission-rate <n>", "Commission rate").option("--commission-duration <dur>", "Duration (forever, once, first_month, custom)").option("--commission-duration-value <n>", "Custom duration value").option("--payment-threshold <n>", "Minimum payout threshold").option("--payment-frequency <freq>", "Payment frequency (monthly, biweekly, weekly)").option("--cookie-lifetime <days>", "Cookie lifetime in days").option("--auto-payout", "Enable auto payout").option("--no-auto-payout", "Disable auto payout").option("--invoice-required", "Require invoices").option("--no-invoice-required", "Don't require invoices").action(async function() {
1315
+ pt.command("update").description("Update payment terms").option("--commission-type <type>", "Commission type (PERCENTAGE, FIXED, CREDITS)").option("--commission-rate <n>", "Commission rate").option("--commission-duration <dur>", "Duration (lifetime, time_limited, payment_limited)").option("--commissions-limit <n>", "Commission duration limit").option("--commissions-hold-days <n>", "Commission hold period in days").option("--payment-threshold <n>", "Minimum payout threshold").option("--payment-frequency <freq>", "Payment frequency (weekly, monthly)").option("--payment-methods <methods>", "Payment methods (comma-separated)").option("--custom-payment-terms <text>", "Custom payment terms").option("--cookie-lifetime <days>", "Cookie lifetime in days").option("--auto-payout", "Enable auto payout").option("--no-auto-payout", "Disable auto payout").option(
1316
+ "--invoice-rule <rule>",
1317
+ "Invoice rule (NONE, OWNER_PROVIDES, AFFILIATE_PROVIDES, SELF_BILLING)"
1318
+ ).option("--invoice-prefix <prefix>", "Invoice number prefix").option("--require-tax-forms", "Require tax forms").option("--no-require-tax-forms", "Do not require tax forms").option("--owner-company-name <name>", "Owner company name").option("--owner-address-line-1 <value>", "Owner address line 1").option("--owner-address-line-2 <value>", "Owner address line 2").option("--owner-city <city>", "Owner city").option("--owner-postal-code <code>", "Owner postal code").option("--owner-country <code>", "Owner country code").option("--owner-vat-id <id>", "Owner VAT ID").option("--owner-vat-rate <n>", "Owner VAT rate").action(async function() {
913
1319
  const o = opts(this);
914
1320
  try {
915
1321
  const client = await getClient(o);
@@ -917,13 +1323,27 @@ function registerPaymentTerms(prog) {
917
1323
  if (o.commissionType !== void 0) params.commission_type = o.commissionType;
918
1324
  if (o.commissionRate !== void 0) params.commission_rate = Number(o.commissionRate);
919
1325
  if (o.commissionDuration !== void 0) params.commission_duration = o.commissionDuration;
920
- if (o.commissionDurationValue !== void 0)
921
- params.commission_duration_value = Number(o.commissionDurationValue);
1326
+ if (o.commissionsLimit !== void 0) params.commissions_limit = Number(o.commissionsLimit);
1327
+ if (o.commissionsHoldDays !== void 0)
1328
+ params.commissions_hold_days = Number(o.commissionsHoldDays);
922
1329
  if (o.paymentThreshold !== void 0) params.payment_threshold = Number(o.paymentThreshold);
923
1330
  if (o.paymentFrequency !== void 0) params.payment_frequency = o.paymentFrequency;
1331
+ if (o.paymentMethods !== void 0)
1332
+ params.payment_methods = commaSeparated(o.paymentMethods) ?? [];
1333
+ if (o.customPaymentTerms !== void 0) params.custom_payment_terms = o.customPaymentTerms;
924
1334
  if (o.cookieLifetime !== void 0) params.cookie_lifetime = Number(o.cookieLifetime);
925
1335
  if (o.autoPayout !== void 0) params.auto_payout = o.autoPayout;
926
- if (o.invoiceRequired !== void 0) params.invoice_required = o.invoiceRequired;
1336
+ if (o.invoiceRule !== void 0) params.invoice_rule = o.invoiceRule;
1337
+ if (o.invoicePrefix !== void 0) params.invoice_prefix = o.invoicePrefix;
1338
+ if (o.requireTaxForms !== void 0) params.require_tax_forms = o.requireTaxForms;
1339
+ if (o.ownerCompanyName !== void 0) params.owner_company_name = o.ownerCompanyName;
1340
+ if (o.ownerAddressLine1 !== void 0) params.owner_address_line_1 = o.ownerAddressLine1;
1341
+ if (o.ownerAddressLine2 !== void 0) params.owner_address_line_2 = o.ownerAddressLine2;
1342
+ if (o.ownerCity !== void 0) params.owner_city = o.ownerCity;
1343
+ if (o.ownerPostalCode !== void 0) params.owner_postal_code = o.ownerPostalCode;
1344
+ if (o.ownerCountry !== void 0) params.owner_country = o.ownerCountry;
1345
+ if (o.ownerVatId !== void 0) params.owner_vat_id = o.ownerVatId;
1346
+ if (o.ownerVatRate !== void 0) params.owner_vat_rate = Number(o.ownerVatRate);
927
1347
  const result = await client.program.paymentTerms.update(params);
928
1348
  output(result, o);
929
1349
  } catch (err) {
@@ -943,17 +1363,30 @@ function registerTracking(prog) {
943
1363
  handleError(err, o.json);
944
1364
  }
945
1365
  });
946
- tracking.command("update").description("Update tracking settings").option("--default-referral-parameter <param>", "Default referral parameter").option("--enabled-referral-parameters <params>", "Enabled parameters (comma-separated)").option("--track-email", "Track email").option("--no-track-email", "Don't track email").option("--track-name", "Track name").option("--no-track-name", "Don't track name").action(async function() {
1366
+ tracking.command("update").description("Update tracking settings").option("--default-referral-parameter <param>", "Default referral parameter").option("--enabled-referral-parameters <params>", "Enabled parameters (comma-separated)").option("--email-tracking-enabled", "Enable email tracking").option("--no-email-tracking-enabled", "Disable email tracking").option("--name-tracking-enabled", "Enable name tracking").option("--no-name-tracking-enabled", "Disable name tracking").option("--postbacks-enabled", "Enable postbacks").option("--no-postbacks-enabled", "Disable postbacks").option("--append-affonso-id-enabled", "Append the Affonso click ID").option("--no-append-affonso-id-enabled", "Do not append the Affonso click ID").option("--tracking-template-enabled", "Enable the tracking template").option("--no-tracking-template-enabled", "Disable the tracking template").option("--tracking-template-json <json|@file>", "Tracking template array as JSON or @file").action(async function() {
947
1367
  const o = opts(this);
948
1368
  try {
949
- const client = await getClient(o);
950
1369
  const params = {};
951
1370
  if (o.defaultReferralParameter !== void 0)
952
1371
  params.default_referral_parameter = o.defaultReferralParameter;
953
1372
  if (o.enabledReferralParameters !== void 0)
954
- params.enabled_referral_parameters = o.enabledReferralParameters.split(",");
955
- if (o.trackEmail !== void 0) params.track_email = o.trackEmail;
956
- if (o.trackName !== void 0) params.track_name = o.trackName;
1373
+ params.enabled_referral_parameters = commaSeparated(o.enabledReferralParameters) ?? [];
1374
+ if (o.emailTrackingEnabled !== void 0)
1375
+ params.email_tracking_enabled = o.emailTrackingEnabled;
1376
+ if (o.nameTrackingEnabled !== void 0)
1377
+ params.name_tracking_enabled = o.nameTrackingEnabled;
1378
+ if (o.postbacksEnabled !== void 0) params.postbacks_enabled = o.postbacksEnabled;
1379
+ if (o.appendAffonsoIdEnabled !== void 0)
1380
+ params.append_affonso_id_enabled = o.appendAffonsoIdEnabled;
1381
+ if (o.trackingTemplateEnabled !== void 0)
1382
+ params.tracking_template_enabled = o.trackingTemplateEnabled;
1383
+ if (o.trackingTemplateJson !== void 0) {
1384
+ const template = parseJson(o.trackingTemplateJson, "--tracking-template-json");
1385
+ if (!Array.isArray(template))
1386
+ throw new Error("--tracking-template-json must contain a JSON array.");
1387
+ params.tracking_template = template;
1388
+ }
1389
+ const client = await getClient(o);
957
1390
  const result = await client.program.tracking.update(params);
958
1391
  output(result, o);
959
1392
  } catch (err) {
@@ -973,7 +1406,7 @@ function registerRestrictions(prog) {
973
1406
  handleError(err, o.json);
974
1407
  }
975
1408
  });
976
- restrictions.command("update").description("Update restrictions").option("--websites", "Allow websites").option("--no-websites", "Disallow websites").option("--social-marketing", "Allow social marketing").option("--no-social-marketing", "Disallow social marketing").option("--organic-social", "Allow organic social").option("--no-organic-social", "Disallow organic social").option("--email-marketing", "Allow email marketing").option("--no-email-marketing", "Disallow email marketing").option("--paid-ads", "Allow paid ads").option("--no-paid-ads", "Disallow paid ads").option("--content-marketing", "Allow content marketing").option("--no-content-marketing", "Disallow content marketing").option("--coupon-sites", "Allow coupon sites").option("--no-coupon-sites", "Disallow coupon sites").option("--review-sites", "Allow review sites").option("--no-review-sites", "Disallow review sites").option("--incentivized-traffic", "Allow incentivized traffic").option("--no-incentivized-traffic", "Disallow incentivized traffic").option("--trademark-bidding", "Allow trademark bidding").option("--no-trademark-bidding", "Disallow trademark bidding").action(async function() {
1409
+ restrictions.command("update").description("Update restrictions").option("--websites", "Allow websites").option("--no-websites", "Disallow websites").option("--social-marketing", "Allow social marketing").option("--no-social-marketing", "Disallow social marketing").option("--organic-social", "Allow organic social").option("--no-organic-social", "Disallow organic social").option("--email-marketing", "Allow email marketing").option("--no-email-marketing", "Disallow email marketing").option("--mobile-traffic", "Allow mobile traffic").option("--no-mobile-traffic", "Disallow mobile traffic").option("--search-engine-marketing", "Allow search engine marketing").option("--no-search-engine-marketing", "Disallow search engine marketing").option("--organic-search", "Allow organic search").option("--no-organic-search", "Disallow organic search").option("--rebrokering", "Allow rebrokering").option("--no-rebrokering", "Disallow rebrokering").option("--incent", "Allow incentivized traffic").option("--no-incent", "Disallow incentivized traffic").option("--brand-bidding", "Allow brand bidding").option("--no-brand-bidding", "Disallow brand bidding").option("--additional-restrictions <text>", "Additional restriction text").action(async function() {
977
1410
  const o = opts(this);
978
1411
  try {
979
1412
  const client = await getClient(o);
@@ -983,17 +1416,19 @@ function registerRestrictions(prog) {
983
1416
  ["socialMarketing", "social_marketing"],
984
1417
  ["organicSocial", "organic_social"],
985
1418
  ["emailMarketing", "email_marketing"],
986
- ["paidAds", "paid_ads"],
987
- ["contentMarketing", "content_marketing"],
988
- ["couponSites", "coupon_sites"],
989
- ["reviewSites", "review_sites"],
990
- ["incentivizedTraffic", "incentivized_traffic"],
991
- ["trademarkBidding", "trademark_bidding"]
1419
+ ["mobileTraffic", "mobile_traffic"],
1420
+ ["searchEngineMarketing", "search_engine_marketing"],
1421
+ ["organicSearch", "organic_search"],
1422
+ ["rebrokering", "rebrokering"],
1423
+ ["incent", "incent"],
1424
+ ["brandBidding", "brand_bidding"]
992
1425
  ];
993
1426
  for (const [camel, snake] of fieldMap) {
994
1427
  const val = o[camel];
995
1428
  if (val !== void 0) params[snake] = val;
996
1429
  }
1430
+ if (o.additionalRestrictions !== void 0)
1431
+ params.additional_restrictions = o.additionalRestrictions;
997
1432
  const result = await client.program.restrictions.update(params);
998
1433
  output(result, o);
999
1434
  } catch (err) {
@@ -1013,15 +1448,36 @@ function registerFraudRules(prog) {
1013
1448
  handleError(err, o.json);
1014
1449
  }
1015
1450
  });
1016
- fraud.command("update").description("Update fraud rules").option("--self-referral <mode>", "Self-referral mode (off, detect, block)").option("--duplicate-ip <mode>", "Duplicate IP mode (off, detect, block)").option("--vpn-proxy <mode>", "VPN/Proxy mode (off, detect, block)").option("--suspicious-conversion <mode>", "Suspicious conversion mode (off, detect, block)").action(async function() {
1451
+ fraud.command("update").description("Update fraud rules").option("--self-referral-mode <mode>", "Self-referral mode (off, detect, block)").option("--cross-program-ban-mode <mode>", "Cross-program ban mode").option("--duplicate-payout-mode <mode>", "Duplicate payout mode").option("--suspicious-email-mode <mode>", "Suspicious email mode").option("--banned-referral-mode <mode>", "Banned referral mode").option("--paid-traffic-mode <mode>", "Paid traffic mode").option("--blocked-country-mode <mode>", "Blocked country mode").option("--banned-referral-config-json <json|@file>", "Banned referral config").option("--paid-traffic-config-json <json|@file>", "Paid traffic config").option("--blocked-country-config-json <json|@file>", "Blocked country config").action(async function() {
1017
1452
  const o = opts(this);
1018
1453
  try {
1019
- const client = await getClient(o);
1020
1454
  const params = {};
1021
- if (o.selfReferral !== void 0) params.self_referral = o.selfReferral;
1022
- if (o.duplicateIp !== void 0) params.duplicate_ip = o.duplicateIp;
1023
- if (o.vpnProxy !== void 0) params.vpn_proxy = o.vpnProxy;
1024
- if (o.suspiciousConversion !== void 0) params.suspicious_conversion = o.suspiciousConversion;
1455
+ if (o.selfReferralMode !== void 0) params.self_referral_mode = o.selfReferralMode;
1456
+ if (o.crossProgramBanMode !== void 0)
1457
+ params.cross_program_ban_mode = o.crossProgramBanMode;
1458
+ if (o.duplicatePayoutMode !== void 0)
1459
+ params.duplicate_payout_mode = o.duplicatePayoutMode;
1460
+ if (o.suspiciousEmailMode !== void 0)
1461
+ params.suspicious_email_mode = o.suspiciousEmailMode;
1462
+ if (o.bannedReferralMode !== void 0) params.banned_referral_mode = o.bannedReferralMode;
1463
+ if (o.paidTrafficMode !== void 0) params.paid_traffic_mode = o.paidTrafficMode;
1464
+ if (o.blockedCountryMode !== void 0) params.blocked_country_mode = o.blockedCountryMode;
1465
+ if (o.bannedReferralConfigJson !== void 0)
1466
+ params.banned_referral_config = parseJsonObject(
1467
+ o.bannedReferralConfigJson,
1468
+ "--banned-referral-config-json"
1469
+ );
1470
+ if (o.paidTrafficConfigJson !== void 0)
1471
+ params.paid_traffic_config = parseJsonObject(
1472
+ o.paidTrafficConfigJson,
1473
+ "--paid-traffic-config-json"
1474
+ );
1475
+ if (o.blockedCountryConfigJson !== void 0)
1476
+ params.blocked_country_config = parseJsonObject(
1477
+ o.blockedCountryConfigJson,
1478
+ "--blocked-country-config-json"
1479
+ );
1480
+ const client = await getClient(o);
1025
1481
  const result = await client.program.fraudRules.update(params);
1026
1482
  output(result, o);
1027
1483
  } catch (err) {
@@ -1041,22 +1497,29 @@ function registerPortal(prog) {
1041
1497
  handleError(err, o.json);
1042
1498
  }
1043
1499
  });
1044
- portal.command("update").description("Update portal settings").option("--primary-color <color>", "Primary color (hex)").option("--accent-color <color>", "Accent color (hex)").option("--logo-url <url>", "Logo URL").option("--favicon-url <url>", "Favicon URL").option("--custom-domain <domain>", "Custom domain").option("--terms-url <url>", "Terms URL").option("--privacy-url <url>", "Privacy URL").option("--onboarding-enabled", "Enable onboarding").option("--no-onboarding-enabled", "Disable onboarding").option("--resources-enabled", "Enable resources").option("--no-resources-enabled", "Disable resources").action(async function() {
1500
+ portal.command("update").description("Update portal settings").option("--single-program-portal", "Enable the single-program portal").option("--no-single-program-portal", "Disable the single-program portal").option("--hide-branding", "Hide Affonso branding").option("--no-hide-branding", "Show Affonso branding").option("--hide-details", "Hide program details").option("--no-hide-details", "Show program details").option("--primary-color <color>", "Primary color (hex)").option("--secondary-color <color>", "Secondary color (hex)").option("--show-leaderboard", "Show the leaderboard").option("--no-show-leaderboard", "Hide the leaderboard").option("--terms-conditions-status", "Enable terms and conditions").option("--no-terms-conditions-status", "Disable terms and conditions").option("--terms-conditions-value <value>", "Terms text or URL").option("--privacy-policy-status", "Enable the privacy policy").option("--no-privacy-policy-status", "Disable the privacy policy").option("--privacy-policy-value <value>", "Privacy policy text or URL").option("--support-email-status", "Show the support email").option("--no-support-email-status", "Hide the support email").option("--support-email-value <email>", "Support email").option("--custom-texts-json <json|@file>", "Custom texts as JSON or @file").action(async function() {
1045
1501
  const o = opts(this);
1046
1502
  try {
1047
- const client = await getClient(o);
1048
1503
  const params = {};
1504
+ if (o.singleProgramPortal !== void 0)
1505
+ params.single_program_portal = o.singleProgramPortal;
1506
+ if (o.hideBranding !== void 0) params.hide_branding = o.hideBranding;
1507
+ if (o.hideDetails !== void 0) params.hide_details = o.hideDetails;
1049
1508
  if (o.primaryColor !== void 0) params.primary_color = o.primaryColor;
1050
- if (o.accentColor !== void 0) params.accent_color = o.accentColor;
1051
- if (o.logoUrl !== void 0) params.logo_url = o.logoUrl;
1052
- if (o.faviconUrl !== void 0) params.favicon_url = o.faviconUrl;
1053
- if (o.customDomain !== void 0) params.custom_domain = o.customDomain;
1054
- if (o.termsUrl !== void 0) params.terms_url = o.termsUrl;
1055
- if (o.privacyUrl !== void 0) params.privacy_url = o.privacyUrl;
1056
- if (o.onboardingEnabled !== void 0)
1057
- params.onboarding_enabled = o.onboardingEnabled;
1058
- if (o.resourcesEnabled !== void 0)
1059
- params.resources_enabled = o.resourcesEnabled;
1509
+ if (o.secondaryColor !== void 0) params.secondary_color = o.secondaryColor;
1510
+ if (o.showLeaderboard !== void 0) params.show_leaderboard = o.showLeaderboard;
1511
+ if (o.termsConditionsStatus !== void 0)
1512
+ params.terms_conditions_status = o.termsConditionsStatus;
1513
+ if (o.termsConditionsValue !== void 0)
1514
+ params.terms_conditions_value = o.termsConditionsValue;
1515
+ if (o.privacyPolicyStatus !== void 0)
1516
+ params.privacy_policy_status = o.privacyPolicyStatus;
1517
+ if (o.privacyPolicyValue !== void 0) params.privacy_policy_value = o.privacyPolicyValue;
1518
+ if (o.supportEmailStatus !== void 0) params.support_email_status = o.supportEmailStatus;
1519
+ if (o.supportEmailValue !== void 0) params.support_email_value = o.supportEmailValue;
1520
+ if (o.customTextsJson !== void 0)
1521
+ params.custom_texts = parseJsonObject(o.customTextsJson, "--custom-texts-json");
1522
+ const client = await getClient(o);
1060
1523
  const result = await client.program.portal.update(params);
1061
1524
  output(result, o);
1062
1525
  } catch (err) {
@@ -1071,18 +1534,19 @@ function registerNotifications(prog) {
1071
1534
  try {
1072
1535
  const client = await getClient(o);
1073
1536
  const result = await client.program.notifications.list();
1074
- output(result, o, ["id", "email_type", "subject", "enabled", "recipient"]);
1537
+ output(result, o, ["email_type_id", "is_active", "custom_subject", "custom_body"]);
1075
1538
  } catch (err) {
1076
1539
  handleError(err, o.json);
1077
1540
  }
1078
1541
  });
1079
- notifications.command("update <id>").description("Update a notification setting").option("--subject <text>", "Email subject").option("--enabled", "Enable notification").option("--no-enabled", "Disable notification").action(async function(id) {
1542
+ notifications.command("update <id>").description("Update a notification setting").option("--custom-subject <text>", "Custom email subject").option("--custom-body <text>", "Custom email body").option("--active", "Enable notification").option("--no-active", "Disable notification").action(async function(id) {
1080
1543
  const o = opts(this);
1081
1544
  try {
1082
1545
  const client = await getClient(o);
1083
1546
  const params = {};
1084
- if (o.subject !== void 0) params.subject = o.subject;
1085
- if (o.enabled !== void 0) params.enabled = o.enabled;
1547
+ if (o.customSubject !== void 0) params.custom_subject = o.customSubject;
1548
+ if (o.customBody !== void 0) params.custom_body = o.customBody;
1549
+ if (o.active !== void 0) params.is_active = o.active;
1086
1550
  const result = await client.program.notifications.update(id, params);
1087
1551
  output(result, o);
1088
1552
  } catch (err) {
@@ -1099,7 +1563,14 @@ function registerGroups(prog) {
1099
1563
  const result = await client.program.groups.list({
1100
1564
  expand: o.expand
1101
1565
  });
1102
- output(result, o, ["id", "name", "description", "is_default", "affiliate_count", "created_at"]);
1566
+ output(result, o, [
1567
+ "id",
1568
+ "name",
1569
+ "description",
1570
+ "custom_website_url",
1571
+ "is_default",
1572
+ "created_at"
1573
+ ]);
1103
1574
  } catch (err) {
1104
1575
  handleError(err, o.json);
1105
1576
  }
@@ -1116,13 +1587,14 @@ function registerGroups(prog) {
1116
1587
  handleError(err, o.json);
1117
1588
  }
1118
1589
  });
1119
- groups.command("create").description("Create a group").requiredOption("--name <name>", "Group name").option("--description <text>", "Group description").option("--is-default", "Set as default group").action(async function() {
1590
+ groups.command("create").description("Create a group").requiredOption("--name <name>", "Group name").option("--description <text>", "Group description").option("--custom-website-url <url>", "Custom website URL").option("--is-default", "Set as default group").action(async function() {
1120
1591
  const o = opts(this);
1121
1592
  try {
1122
1593
  const client = await getClient(o);
1123
1594
  const result = await client.program.groups.create({
1124
1595
  name: o.name,
1125
1596
  description: o.description,
1597
+ custom_website_url: o.customWebsiteUrl,
1126
1598
  is_default: o.isDefault
1127
1599
  });
1128
1600
  output(result, o);
@@ -1130,13 +1602,14 @@ function registerGroups(prog) {
1130
1602
  handleError(err, o.json);
1131
1603
  }
1132
1604
  });
1133
- groups.command("update <id>").description("Update a group").option("--name <name>", "Group name").option("--description <text>", "Group description").option("--is-default", "Set as default group").option("--no-is-default", "Unset as default group").action(async function(id) {
1605
+ groups.command("update <id>").description("Update a group").option("--name <name>", "Group name").option("--description <text>", "Group description").option("--custom-website-url <url>", "Custom website URL").option("--is-default", "Set as default group").option("--no-is-default", "Unset as default group").action(async function(id) {
1134
1606
  const o = opts(this);
1135
1607
  try {
1136
1608
  const client = await getClient(o);
1137
1609
  const params = {};
1138
1610
  if (o.name !== void 0) params.name = o.name;
1139
1611
  if (o.description !== void 0) params.description = o.description;
1612
+ if (o.customWebsiteUrl !== void 0) params.custom_website_url = o.customWebsiteUrl;
1140
1613
  if (o.isDefault !== void 0) params.is_default = o.isDefault;
1141
1614
  const result = await client.program.groups.update(id, params);
1142
1615
  output(result, o);
@@ -1157,17 +1630,16 @@ function registerGroups(prog) {
1157
1630
  }
1158
1631
  function registerCreatives(prog) {
1159
1632
  const creatives = prog.command("creatives").description("Manage creatives");
1160
- creatives.command("list").description("List creatives").option("--limit <n>", "Items per page", "50").option("--page <n>", "Page number", "1").option("--type <type>", "Filter by type").option("--search <query>", "Search by name").action(async function() {
1633
+ creatives.command("list").description("List creatives").option("--limit <n>", "Items per page", "50").option("--page <n>", "Page number", "1").option("--category <category>", "Filter by category").action(async function() {
1161
1634
  const o = opts(this);
1162
1635
  try {
1163
1636
  const client = await getClient(o);
1164
1637
  const result = await client.program.creatives.list({
1165
1638
  limit: Number(o.limit),
1166
1639
  page: Number(o.page),
1167
- type: o.type,
1168
- search: o.search
1640
+ category: o.category
1169
1641
  });
1170
- output(result, o, ["id", "name", "type", "url", "created_at"]);
1642
+ output(result, o, ["id", "name", "category", "url", "created_at"]);
1171
1643
  } catch (err) {
1172
1644
  handleError(err, o.json);
1173
1645
  }
@@ -1182,36 +1654,48 @@ function registerCreatives(prog) {
1182
1654
  handleError(err, o.json);
1183
1655
  }
1184
1656
  });
1185
- creatives.command("create").description("Create a creative").requiredOption("--name <name>", "Creative name").requiredOption("--type <type>", "Creative type").option("--description <text>", "Description").option("--url <url>", "URL").option("--file-url <url>", "File URL").option("--width <n>", "Width in pixels").option("--height <n>", "Height in pixels").action(async function() {
1657
+ creatives.command("create").description("Create a creative").option("--name <name>", "Creative name").option("--category <category>", "Creative category").option("--subcategory <subcategory>", "Creative subcategory").option("--description <text>", "Description").option("--url <url>", "URL").option("--content <content>", "Text or embed content").option("--tags <tags>", "Tags (comma-separated)").option("--width <n>", "Width in pixels").option("--height <n>", "Height in pixels").option("--usage-notes <text>", "Usage notes").option("--restrictions <text>", "Usage restrictions").action(async function() {
1186
1658
  const o = opts(this);
1187
1659
  try {
1188
1660
  const client = await getClient(o);
1189
- const result = await client.program.creatives.create({
1661
+ if (o.width === void 0 !== (o.height === void 0))
1662
+ throw new Error("--width and --height must be provided together.");
1663
+ const params = {
1190
1664
  name: o.name,
1191
- type: o.type,
1665
+ category: o.category,
1666
+ subcategory: o.subcategory,
1192
1667
  description: o.description,
1193
1668
  url: o.url,
1194
- file_url: o.fileUrl,
1195
- width: o.width ? Number(o.width) : void 0,
1196
- height: o.height ? Number(o.height) : void 0
1197
- });
1669
+ content: o.content,
1670
+ tags: commaSeparated(o.tags),
1671
+ dimensions: o.width !== void 0 ? { width: Number(o.width), height: Number(o.height) } : void 0,
1672
+ usage_notes: o.usageNotes,
1673
+ restrictions: o.restrictions
1674
+ };
1675
+ const result = await client.program.creatives.create(params);
1198
1676
  output(result, o);
1199
1677
  } catch (err) {
1200
1678
  handleError(err, o.json);
1201
1679
  }
1202
1680
  });
1203
- creatives.command("update <id>").description("Update a creative").option("--name <name>", "Creative name").option("--type <type>", "Creative type").option("--description <text>", "Description").option("--url <url>", "URL").option("--file-url <url>", "File URL").option("--width <n>", "Width in pixels").option("--height <n>", "Height in pixels").action(async function(id) {
1681
+ creatives.command("update <id>").description("Update a creative").option("--name <name>", "Creative name").option("--category <category>", "Creative category").option("--subcategory <subcategory>", "Creative subcategory").option("--description <text>", "Description").option("--url <url>", "URL").option("--content <content>", "Text or embed content").option("--tags <tags>", "Tags (comma-separated)").option("--width <n>", "Width in pixels").option("--height <n>", "Height in pixels").option("--usage-notes <text>", "Usage notes").option("--restrictions <text>", "Usage restrictions").action(async function(id) {
1204
1682
  const o = opts(this);
1205
1683
  try {
1206
1684
  const client = await getClient(o);
1685
+ if (o.width === void 0 !== (o.height === void 0))
1686
+ throw new Error("--width and --height must be provided together.");
1207
1687
  const params = {};
1208
1688
  if (o.name !== void 0) params.name = o.name;
1209
- if (o.type !== void 0) params.type = o.type;
1689
+ if (o.category !== void 0) params.category = o.category;
1690
+ if (o.subcategory !== void 0) params.subcategory = o.subcategory;
1210
1691
  if (o.description !== void 0) params.description = o.description;
1211
1692
  if (o.url !== void 0) params.url = o.url;
1212
- if (o.fileUrl !== void 0) params.file_url = o.fileUrl;
1213
- if (o.width !== void 0) params.width = Number(o.width);
1214
- if (o.height !== void 0) params.height = Number(o.height);
1693
+ if (o.content !== void 0) params.content = o.content;
1694
+ if (o.tags !== void 0) params.tags = commaSeparated(o.tags);
1695
+ if (o.width !== void 0)
1696
+ params.dimensions = { width: Number(o.width), height: Number(o.height) };
1697
+ if (o.usageNotes !== void 0) params.usage_notes = o.usageNotes;
1698
+ if (o.restrictions !== void 0) params.restrictions = o.restrictions;
1215
1699
  const result = await client.program.creatives.update(id, params);
1216
1700
  output(result, o);
1217
1701
  } catch (err) {
@@ -1230,102 +1714,163 @@ function registerCreatives(prog) {
1230
1714
  });
1231
1715
  }
1232
1716
 
1233
- // src/commands/marketplace.ts
1234
- var import_sdk3 = require("@affonso/sdk");
1235
- function registerMarketplaceCommands(program2) {
1236
- const marketplace = program2.command("marketplace").description("Browse the affiliate marketplace (public, no auth required)");
1237
- marketplace.command("list").description("List marketplace programs").option("--limit <n>", "Items per page", "50").option("--page <n>", "Page number", "1").option("--category <cat>", "Filter by category").option("--search <query>", "Search programs").option("--sort <field:dir>", "Sort").action(async function() {
1717
+ // src/commands/referrals.ts
1718
+ function registerReferralCommands(program2) {
1719
+ const referrals = program2.command("referrals").description("Manage referrals");
1720
+ referrals.command("list").description("List referrals").option("--limit <n>", "Items per page", "50").option("--starting-after <id>", "Cursor: fetch items after this ID").option("--ending-before <id>", "Cursor: fetch items before this ID").option("--affiliate-id <id>", "Filter by affiliate ID").option("--external-user-id <id>", "Filter by external user ID").option("--status <status>", "Filter by status").option("--order <dir>", "Order (asc, desc)").option("--expand <fields>", "Expand fields").option("--created-gte <date>", "Created after date").option("--created-lte <date>", "Created before date").action(async function() {
1238
1721
  const o = opts(this);
1239
1722
  try {
1240
- const baseUrl = resolveBaseUrl(o.baseUrl);
1241
- const client = new import_sdk3.Affonso("public", { baseUrl });
1242
- const result = await client.marketplace.list({
1723
+ const client = await getClient(o);
1724
+ const result = await client.referrals.list({
1243
1725
  limit: Number(o.limit),
1244
- page: Number(o.page),
1245
- category: o.category,
1246
- search: o.search,
1247
- sort: o.sort
1726
+ starting_after: o.startingAfter,
1727
+ ending_before: o.endingBefore,
1728
+ affiliate_id: o.affiliateId,
1729
+ external_user_id: o.externalUserId,
1730
+ status: o.status,
1731
+ order: o.order,
1732
+ expand: o.expand,
1733
+ created_gte: o.createdGte,
1734
+ created_lte: o.createdLte
1248
1735
  });
1249
- output(result, o, ["id", "name", "category", "commission_type", "commission_rate", "cookie_lifetime"]);
1736
+ output(result, o, ["id", "affiliate_id", "email", "status", "created_at"]);
1250
1737
  } catch (err) {
1251
1738
  handleError(err, o.json);
1252
1739
  }
1253
1740
  });
1254
- marketplace.command("get <id>").description("Get a marketplace program by ID").action(async function(id) {
1741
+ referrals.command("get <id>").description("Get a referral by ID").option("--expand <fields>", "Expand fields").option("--include <fields>", "Include fields").action(async function(id) {
1255
1742
  const o = opts(this);
1256
1743
  try {
1257
- const baseUrl = resolveBaseUrl(o.baseUrl);
1258
- const client = new import_sdk3.Affonso("public", { baseUrl });
1259
- const result = await client.marketplace.retrieve(id);
1744
+ const client = await getClient(o);
1745
+ const result = await client.referrals.retrieve(id, {
1746
+ expand: o.expand,
1747
+ include: o.include
1748
+ });
1260
1749
  output(result, o);
1261
1750
  } catch (err) {
1262
1751
  handleError(err, o.json);
1263
1752
  }
1264
1753
  });
1265
- }
1266
-
1267
- // src/commands/embed-tokens.ts
1268
- function registerEmbedTokenCommands(program2) {
1269
- const embedTokens = program2.command("embed-tokens").description("Generate embed tokens");
1270
- embedTokens.command("create").description("Create an embed token").option("--affiliate-id <id>", "Affiliate ID").option("--external-user-id <id>", "External user ID").option("--email <email>", "Partner email").option("--name <name>", "Partner name").action(async function() {
1754
+ referrals.command("create").description("Create a referral").requiredOption("--email <email>", "Referral email").requiredOption("--affiliate-id <id>", "Affiliate ID").option("--subscription-id <id>", "Subscription ID").option("--customer-id <id>", "Customer ID").option("--click-id <id>", "Click ID").option("--status <status>", "Initial status").option("--name <name>", "Referral name").option("--created-at <date>", "Creation timestamp (ISO 8601)").option("--metadata-json <json|@file>", "Metadata as JSON or @file").action(async function() {
1271
1755
  const o = opts(this);
1272
1756
  try {
1757
+ const metadata = parseJsonObject(o.metadataJson, "--metadata-json");
1273
1758
  const client = await getClient(o);
1274
- const result = await client.embedTokens.create({
1275
- affiliate_id: o.affiliateId,
1276
- external_user_id: o.externalUserId,
1759
+ const result = await client.referrals.create({
1277
1760
  email: o.email,
1278
- name: o.name
1761
+ affiliate_id: o.affiliateId,
1762
+ subscription_id: o.subscriptionId,
1763
+ customer_id: o.customerId,
1764
+ click_id: o.clickId,
1765
+ status: o.status,
1766
+ name: o.name,
1767
+ created_at: o.createdAt,
1768
+ metadata
1279
1769
  });
1280
1770
  output(result, o);
1281
1771
  } catch (err) {
1282
1772
  handleError(err, o.json);
1283
1773
  }
1284
1774
  });
1775
+ referrals.command("update <id>").description("Update a referral").option("--email <email>", "Referral email").option("--status <status>", "Status").option("--subscription-id <id>", "Subscription ID").option("--customer-id <id>", "Customer ID").option("--name <name>", "Referral name").option("--metadata-json <json|@file>", "Metadata as JSON or @file").action(async function(id) {
1776
+ const o = opts(this);
1777
+ try {
1778
+ const params = {};
1779
+ if (o.email !== void 0) params.email = o.email;
1780
+ if (o.status !== void 0) params.status = o.status;
1781
+ if (o.subscriptionId !== void 0) params.subscription_id = o.subscriptionId;
1782
+ if (o.customerId !== void 0) params.customer_id = o.customerId;
1783
+ if (o.name !== void 0) params.name = o.name;
1784
+ if (o.metadataJson !== void 0)
1785
+ params.metadata = parseJsonObject(o.metadataJson, "--metadata-json");
1786
+ const client = await getClient(o);
1787
+ const result = await client.referrals.update(id, params);
1788
+ output(result, o);
1789
+ } catch (err) {
1790
+ handleError(err, o.json);
1791
+ }
1792
+ });
1793
+ referrals.command("delete <id>").description("Delete a referral").action(async function(id) {
1794
+ const o = opts(this);
1795
+ try {
1796
+ const client = await getClient(o);
1797
+ const result = await client.referrals.del(id);
1798
+ outputSuccess(result.message ?? "Referral deleted.", o);
1799
+ } catch (err) {
1800
+ handleError(err, o.json);
1801
+ }
1802
+ });
1285
1803
  }
1286
1804
 
1287
- // src/commands/login.ts
1288
- function registerLoginCommand(program2) {
1289
- program2.command("login").description("Log in via browser (OAuth 2.1)").action(async function() {
1805
+ // src/commands/signups.ts
1806
+ function registerSignupCommands(program2) {
1807
+ program2.command("signups").description("Manage server-side signups").command("create").description("Create a server-side signup").requiredOption("--click-id <id>", "Click ID").option("--email <email>", "Customer email").option("--external-user-id <id>", "External user ID").option("--name <name>", "Customer name").action(async function() {
1290
1808
  const o = opts(this);
1291
1809
  try {
1292
- const existing = resolveAuth();
1293
- if (existing?.source === "oauth") {
1294
- console.log("Already logged in. Run `affonso logout` first to switch accounts.");
1295
- return;
1296
- }
1297
- const baseUrl = resolveBaseUrl(o.baseUrl);
1298
- await login(baseUrl);
1299
- console.log("Successfully logged in!");
1810
+ const client = await getClient(o);
1811
+ output(
1812
+ await client.signups.create({
1813
+ click_id: o.clickId,
1814
+ email: o.email,
1815
+ external_user_id: o.externalUserId,
1816
+ name: o.name
1817
+ }),
1818
+ o
1819
+ );
1300
1820
  } catch (err) {
1301
1821
  handleError(err, o.json);
1302
1822
  }
1303
1823
  });
1304
1824
  }
1305
1825
 
1306
- // src/commands/logout.ts
1307
- function registerLogoutCommand(program2) {
1308
- program2.command("logout").description("Log out and remove stored credentials").action(async function() {
1826
+ // src/commands/sources.ts
1827
+ function registerSourceCommands(program2) {
1828
+ program2.command("sources").description("Ingest source events").command("ingest <source>").description(
1829
+ "Ingest a signed source event (custom or segment_webhook; configure its signing-secret environment variable)"
1830
+ ).requiredOption("--payload-json <json|@file>", "Source payload as JSON or @file").action(async function(source) {
1309
1831
  const o = opts(this);
1310
1832
  try {
1311
- const auth = loadAuth();
1312
- if (auth?.access_token) {
1313
- const baseUrl = resolveBaseUrl(o.baseUrl);
1314
- const issuer = baseUrl.replace(/\/v1\/?$/, "");
1315
- try {
1316
- await fetch(`${issuer}/oauth/revoke`, {
1317
- method: "POST",
1318
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
1319
- body: new URLSearchParams({
1320
- token: auth.access_token,
1321
- client_id: CLIENT_ID
1322
- })
1323
- });
1324
- } catch {
1325
- }
1326
- }
1327
- clearAuth();
1328
- console.log("Logged out.");
1833
+ const payload = parseJsonObject(o.payloadJson, "--payload-json");
1834
+ if (!payload) throw new Error("--payload-json is required.");
1835
+ const client = await getClient(o);
1836
+ output(await client.sources.ingest(source, payload), o);
1837
+ } catch (err) {
1838
+ handleError(err, o.json);
1839
+ }
1840
+ });
1841
+ }
1842
+
1843
+ // src/commands/tracking.ts
1844
+ var import_sdk4 = require("@affonso/sdk");
1845
+ function registerTrackingCommands(program2) {
1846
+ program2.command("tracking").description("Track public referral traffic").command("track").description("Resolve and record a public tracking request").requiredOption("--program-id <id>", "Program ID").option("--tracking-id <id>", "Affiliate tracking ID").option("--referrer <url>", "Referrer URL").option("--user-agent <value>", "User agent").option("--utm-source <value>", "UTM source").option("--utm-medium <value>", "UTM medium").option("--utm-campaign <value>", "UTM campaign").option("--utm-term <value>", "UTM term").option("--utm-content <value>", "UTM content").option("--sub1 <value>", "Sub-tracking parameter 1").option("--sub2 <value>", "Sub-tracking parameter 2").option("--sub3 <value>", "Sub-tracking parameter 3").option("--sub4 <value>", "Sub-tracking parameter 4").option("--sub5 <value>", "Sub-tracking parameter 5").option("--gclid <id>", "Google click ID").option("--fbclid <id>", "Meta click ID").option("--msclkid <id>", "Microsoft click ID").option("--ttclid <id>", "TikTok click ID").option("--has-consent", "Record that tracking consent was granted").action(async function() {
1847
+ const o = opts(this);
1848
+ try {
1849
+ const client = new import_sdk4.Affonso("public", { baseUrl: resolveBaseUrl(o.baseUrl) });
1850
+ output(
1851
+ await client.tracking.track({
1852
+ programId: o.programId,
1853
+ trackingId: o.trackingId,
1854
+ referrer: o.referrer,
1855
+ userAgent: o.userAgent,
1856
+ utmSource: o.utmSource,
1857
+ utmMedium: o.utmMedium,
1858
+ utmCampaign: o.utmCampaign,
1859
+ utmTerm: o.utmTerm,
1860
+ utmContent: o.utmContent,
1861
+ sub1: o.sub1,
1862
+ sub2: o.sub2,
1863
+ sub3: o.sub3,
1864
+ sub4: o.sub4,
1865
+ sub5: o.sub5,
1866
+ gclid: o.gclid,
1867
+ fbclid: o.fbclid,
1868
+ msclkid: o.msclkid,
1869
+ ttclid: o.ttclid,
1870
+ hasConsent: o.hasConsent || void 0
1871
+ }),
1872
+ o
1873
+ );
1329
1874
  } catch (err) {
1330
1875
  handleError(err, o.json);
1331
1876
  }
@@ -1363,58 +1908,10 @@ function registerWhoamiCommand(program2) {
1363
1908
  });
1364
1909
  }
1365
1910
 
1366
- // src/commands/config.ts
1367
- var VALID_KEYS = ["api-key", "base-url"];
1368
- var KEY_MAP = {
1369
- "api-key": "api_key",
1370
- "base-url": "base_url"
1371
- };
1372
- function registerConfigCommands(program2) {
1373
- const config = program2.command("config").description("Manage CLI configuration");
1374
- config.command("get <key>").description("Get a config value (api-key, base-url)").action(async function(key) {
1375
- const o = opts(this);
1376
- try {
1377
- if (!VALID_KEYS.includes(key)) {
1378
- console.error(`Unknown config key: ${key}. Valid keys: ${VALID_KEYS.join(", ")}`);
1379
- process.exit(1);
1380
- }
1381
- const stored = loadConfig();
1382
- const mappedKey = KEY_MAP[key];
1383
- const value = stored[mappedKey];
1384
- if (value) {
1385
- if (key === "api-key") {
1386
- const v = value;
1387
- console.log(`${v.slice(0, 10)}...${v.slice(-4)}`);
1388
- } else {
1389
- console.log(value);
1390
- }
1391
- } else {
1392
- console.log(`${key} is not set.`);
1393
- }
1394
- } catch (err) {
1395
- handleError(err, o.json);
1396
- }
1397
- });
1398
- config.command("set <key> <value>").description("Set a config value (api-key, base-url)").action(async function(key, value) {
1399
- const o = opts(this);
1400
- try {
1401
- if (!VALID_KEYS.includes(key)) {
1402
- console.error(`Unknown config key: ${key}. Valid keys: ${VALID_KEYS.join(", ")}`);
1403
- process.exit(1);
1404
- }
1405
- const mappedKey = KEY_MAP[key];
1406
- saveConfig({ [mappedKey]: value });
1407
- console.log(`${key} saved.`);
1408
- } catch (err) {
1409
- handleError(err, o.json);
1410
- }
1411
- });
1412
- }
1413
-
1414
1911
  // src/cli.ts
1415
1912
  function createProgram() {
1416
1913
  const program2 = new import_commander.Command();
1417
- program2.name("affonso").description("Affonso CLI \u2014 manage your affiliate program from the terminal").version("0.1.0").option("--json", "Output as JSON").option("--api-key <key>", "API key for this request").option("--base-url <url>", "Custom API base URL").option("--no-color", "Disable colored output");
1914
+ program2.name("affonso").description("Affonso CLI \u2014 manage your affiliate program from the terminal").version(package_default.version).option("--json", "Output as JSON").option("--api-key <key>", "API key for this request").option("--base-url <url>", "Custom API base URL").option("--no-color", "Disable colored output");
1418
1915
  registerLoginCommand(program2);
1419
1916
  registerLogoutCommand(program2);
1420
1917
  registerWhoamiCommand(program2);
@@ -1423,11 +1920,17 @@ function createProgram() {
1423
1920
  registerReferralCommands(program2);
1424
1921
  registerClickCommands(program2);
1425
1922
  registerCommissionCommands(program2);
1923
+ registerConversionCommands(program2);
1924
+ registerEventCommands(program2);
1925
+ registerSignupCommands(program2);
1926
+ registerSourceCommands(program2);
1426
1927
  registerCouponCommands(program2);
1427
1928
  registerPayoutCommands(program2);
1428
1929
  registerProgramCommands(program2);
1429
1930
  registerMarketplaceCommands(program2);
1430
1931
  registerEmbedTokenCommands(program2);
1932
+ registerOnboardingFormCommands(program2);
1933
+ registerTrackingCommands(program2);
1431
1934
  return program2;
1432
1935
  }
1433
1936