@affonso/cli 0.1.4 → 0.1.5

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 (2) hide show
  1. package/dist/index.js +1214 -305
  2. package/package.json +5 -3
package/dist/index.js CHANGED
@@ -26,13 +26,880 @@ 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
- // src/lib/client.ts
30
- var import_sdk = require("@affonso/sdk");
29
+ // package.json
30
+ var package_default = {
31
+ name: "@affonso/cli",
32
+ version: "0.1.5",
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": "^0.2.0",
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
+
74
+ // node_modules/@affonso/sdk/dist/index.mjs
75
+ var AffonsoError = class extends Error {
76
+ status;
77
+ code;
78
+ field;
79
+ details;
80
+ headers;
81
+ constructor(message, opts2) {
82
+ super(message);
83
+ this.name = "AffonsoError";
84
+ this.status = opts2?.status;
85
+ this.code = opts2?.code;
86
+ this.field = opts2?.field;
87
+ this.details = opts2?.details;
88
+ this.headers = opts2?.headers;
89
+ }
90
+ };
91
+ var AuthenticationError = class extends AffonsoError {
92
+ constructor(message, opts2) {
93
+ super(message, { ...opts2, status: 401 });
94
+ this.name = "AuthenticationError";
95
+ }
96
+ };
97
+ var PermissionError = class extends AffonsoError {
98
+ constructor(message, opts2) {
99
+ super(message, { ...opts2, status: 403 });
100
+ this.name = "PermissionError";
101
+ }
102
+ };
103
+ var NotFoundError = class extends AffonsoError {
104
+ constructor(message, opts2) {
105
+ super(message, { ...opts2, status: 404 });
106
+ this.name = "NotFoundError";
107
+ }
108
+ };
109
+ var ValidationError = class extends AffonsoError {
110
+ details;
111
+ constructor(message, details, opts2) {
112
+ super(message, { ...opts2, status: 400, details });
113
+ this.name = "ValidationError";
114
+ this.details = details;
115
+ }
116
+ };
117
+ var DuplicateError = class extends AffonsoError {
118
+ constructor(message, opts2) {
119
+ super(message, { ...opts2, status: 409 });
120
+ this.name = "DuplicateError";
121
+ }
122
+ };
123
+ var RateLimitError = class extends AffonsoError {
124
+ retryAfter;
125
+ constructor(message, retryAfter, opts2) {
126
+ super(message, { ...opts2, status: 429 });
127
+ this.name = "RateLimitError";
128
+ this.retryAfter = retryAfter;
129
+ }
130
+ };
131
+ var InternalError = class extends AffonsoError {
132
+ constructor(message, opts2) {
133
+ super(message, opts2);
134
+ this.name = "InternalError";
135
+ }
136
+ };
137
+ var ConnectionError = class extends AffonsoError {
138
+ constructor(message) {
139
+ super(message, { status: void 0 });
140
+ this.name = "ConnectionError";
141
+ }
142
+ };
143
+ function errorFromResponse(status, body, headers) {
144
+ const err = body.error ?? {};
145
+ const message = err.message ?? `Request failed with status ${status}`;
146
+ const code = err.code;
147
+ const opts2 = { status, code, field: err.field, details: err.details, headers };
148
+ if (code === "VALIDATION_ERROR" || !code && status === 400) {
149
+ return new ValidationError(message, err.details ?? [], opts2);
150
+ }
151
+ if (code === "RATE_LIMIT_EXCEEDED" || !code && status === 429) {
152
+ const retry = headers.get("x-ratelimit-reset");
153
+ return new RateLimitError(message, retry ? Number(retry) : void 0, opts2);
154
+ }
155
+ if (code === "UNAUTHORIZED" || !code && status === 401) {
156
+ return new AuthenticationError(message, opts2);
157
+ }
158
+ if (code === "FORBIDDEN" || !code && status === 403) {
159
+ return new PermissionError(message, opts2);
160
+ }
161
+ if (code === "NOT_FOUND" || !code && status === 404) {
162
+ return new NotFoundError(message, opts2);
163
+ }
164
+ if (code === "DUPLICATE_ERROR" || !code && status === 409) {
165
+ return new DuplicateError(message, opts2);
166
+ }
167
+ if (status >= 500) return new InternalError(message, opts2);
168
+ return new AffonsoError(message, opts2);
169
+ }
170
+ var VERSION = true ? "0.2.0" : "0.1.0";
171
+ function buildQueryString(params) {
172
+ const parts = [];
173
+ for (const [key, value] of Object.entries(params)) {
174
+ if (value === void 0 || value === null) continue;
175
+ if (Array.isArray(value)) {
176
+ for (const v of value) {
177
+ parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(v))}`);
178
+ }
179
+ } else {
180
+ parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
181
+ }
182
+ }
183
+ return parts.length > 0 ? `?${parts.join("&")}` : "";
184
+ }
185
+ function isRetryable(status) {
186
+ return status === 429 || status >= 500;
187
+ }
188
+ function sleep(ms) {
189
+ return new Promise((resolve) => setTimeout(resolve, ms));
190
+ }
191
+ function isNode() {
192
+ return typeof process !== "undefined" && process.versions != null && process.versions.node != null;
193
+ }
194
+ var HttpClient = class {
195
+ config;
196
+ constructor(config) {
197
+ this.config = config;
198
+ }
199
+ async request(opts2) {
200
+ const url = `${this.config.baseUrl}${opts2.path}${opts2.query ? buildQueryString(opts2.query) : ""}`;
201
+ const headers = {
202
+ Authorization: `Bearer ${this.config.apiKey}`,
203
+ "Content-Type": "application/json"
204
+ };
205
+ if (isNode()) {
206
+ headers["User-Agent"] = `affonso-sdk/${VERSION}`;
207
+ }
208
+ let lastError;
209
+ for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {
210
+ const controller = new AbortController();
211
+ const timeoutId = setTimeout(
212
+ () => controller.abort(new Error("Request timed out")),
213
+ this.config.timeout
214
+ );
215
+ try {
216
+ const response = await this.config.fetch(url, {
217
+ method: opts2.method,
218
+ headers,
219
+ body: opts2.body ? JSON.stringify(opts2.body) : void 0,
220
+ signal: controller.signal
221
+ });
222
+ clearTimeout(timeoutId);
223
+ if (response.status === 204) {
224
+ return void 0;
225
+ }
226
+ let body;
227
+ try {
228
+ body = await response.json();
229
+ } catch {
230
+ throw new AffonsoError(
231
+ `Expected JSON response but received unparseable body (status ${response.status})`,
232
+ { status: response.status, headers: response.headers }
233
+ );
234
+ }
235
+ if (!response.ok || body.success === false) {
236
+ const error = errorFromResponse(response.status, body, response.headers);
237
+ if (isRetryable(response.status) && attempt < this.config.maxRetries) {
238
+ lastError = error;
239
+ const waitMs = this.getRetryDelay(attempt, response.headers);
240
+ await sleep(waitMs);
241
+ continue;
242
+ }
243
+ throw error;
244
+ }
245
+ return body;
246
+ } catch (err) {
247
+ clearTimeout(timeoutId);
248
+ if (err instanceof Error && err.name === "AbortError") {
249
+ const connErr = new ConnectionError("Request timed out");
250
+ if (attempt < this.config.maxRetries) {
251
+ lastError = connErr;
252
+ await sleep(this.getRetryDelay(attempt));
253
+ continue;
254
+ }
255
+ throw connErr;
256
+ }
257
+ if (err instanceof AffonsoError) {
258
+ throw err;
259
+ }
260
+ if (err instanceof Error) {
261
+ const connErr = new ConnectionError(err.message);
262
+ if (attempt < this.config.maxRetries) {
263
+ lastError = connErr;
264
+ await sleep(this.getRetryDelay(attempt));
265
+ continue;
266
+ }
267
+ throw connErr;
268
+ }
269
+ throw err;
270
+ }
271
+ }
272
+ throw lastError ?? new ConnectionError("Request failed after retries");
273
+ }
274
+ getRetryDelay(attempt, headers) {
275
+ if (headers) {
276
+ const reset = headers.get("x-ratelimit-reset");
277
+ if (reset) {
278
+ const resetMs = Number(reset) * 1e3 - Date.now();
279
+ if (resetMs > 0 && resetMs < 6e4) return resetMs;
280
+ }
281
+ }
282
+ return Math.min(1e3 * 2 ** attempt, 1e4);
283
+ }
284
+ };
285
+ var OffsetPage = class _OffsetPage {
286
+ data;
287
+ pagination;
288
+ httpClient;
289
+ requestOpts;
290
+ constructor(data, pagination, httpClient, requestOpts) {
291
+ this.data = data;
292
+ this.pagination = pagination;
293
+ this.httpClient = httpClient;
294
+ this.requestOpts = requestOpts;
295
+ }
296
+ async getNextPage() {
297
+ if (!this.pagination.has_next_page) return null;
298
+ const nextOpts = {
299
+ ...this.requestOpts,
300
+ query: {
301
+ ...this.requestOpts.query,
302
+ page: this.pagination.page + 1
303
+ }
304
+ };
305
+ const response = await this.httpClient.request(nextOpts);
306
+ return new _OffsetPage(response.data, response.pagination, this.httpClient, nextOpts);
307
+ }
308
+ async *autoPaginate(maxPages = 1e3) {
309
+ let page = this;
310
+ let pageCount = 0;
311
+ while (page && pageCount < maxPages) {
312
+ for (const item of page.data) {
313
+ yield item;
314
+ }
315
+ pageCount++;
316
+ page = await page.getNextPage();
317
+ }
318
+ }
319
+ };
320
+ var CursorPage = class _CursorPage {
321
+ data;
322
+ hasMore;
323
+ httpClient;
324
+ requestOpts;
325
+ constructor(data, hasMore, httpClient, requestOpts) {
326
+ this.data = data;
327
+ this.hasMore = hasMore;
328
+ this.httpClient = httpClient;
329
+ this.requestOpts = requestOpts;
330
+ }
331
+ async getNextPage() {
332
+ if (!this.hasMore || this.data.length === 0) return null;
333
+ const lastId = this.data[this.data.length - 1].id;
334
+ const nextOpts = {
335
+ ...this.requestOpts,
336
+ query: {
337
+ ...this.requestOpts.query,
338
+ starting_after: lastId
339
+ }
340
+ };
341
+ const response = await this.httpClient.request(nextOpts);
342
+ return new _CursorPage(response.data, response.has_more, this.httpClient, nextOpts);
343
+ }
344
+ async *autoPaginate(maxPages = 1e3) {
345
+ let page = this;
346
+ let pageCount = 0;
347
+ while (page && pageCount < maxPages) {
348
+ for (const item of page.data) {
349
+ yield item;
350
+ }
351
+ pageCount++;
352
+ page = await page.getNextPage();
353
+ }
354
+ }
355
+ };
356
+ var Affiliates = class {
357
+ httpClient;
358
+ constructor(httpClient) {
359
+ this.httpClient = httpClient;
360
+ }
361
+ async list(params) {
362
+ const query = params ? { ...params } : {};
363
+ const requestOpts = { method: "GET", path: "/affiliates", query };
364
+ const response = await this.httpClient.request(requestOpts);
365
+ return new OffsetPage(response.data, response.pagination, this.httpClient, requestOpts);
366
+ }
367
+ async retrieve(id, params) {
368
+ const query = params ? { ...params } : void 0;
369
+ const response = await this.httpClient.request({
370
+ method: "GET",
371
+ path: `/affiliates/${encodeURIComponent(id)}`,
372
+ query
373
+ });
374
+ return response.data;
375
+ }
376
+ async create(params) {
377
+ const response = await this.httpClient.request({
378
+ method: "POST",
379
+ path: "/affiliates",
380
+ body: params
381
+ });
382
+ return response.data;
383
+ }
384
+ async update(id, params) {
385
+ const response = await this.httpClient.request({
386
+ method: "PUT",
387
+ path: `/affiliates/${encodeURIComponent(id)}`,
388
+ body: params
389
+ });
390
+ return response.data;
391
+ }
392
+ async del(id) {
393
+ return this.httpClient.request({
394
+ method: "DELETE",
395
+ path: `/affiliates/${encodeURIComponent(id)}`
396
+ });
397
+ }
398
+ };
399
+ var Clicks = class {
400
+ httpClient;
401
+ constructor(httpClient) {
402
+ this.httpClient = httpClient;
403
+ }
404
+ async create(params) {
405
+ const response = await this.httpClient.request({
406
+ method: "POST",
407
+ path: "/clicks",
408
+ body: params
409
+ });
410
+ return response.data;
411
+ }
412
+ };
413
+ var Commissions = class {
414
+ httpClient;
415
+ constructor(httpClient) {
416
+ this.httpClient = httpClient;
417
+ }
418
+ async list(params) {
419
+ const query = params ? { ...params } : {};
420
+ const requestOpts = { method: "GET", path: "/commissions", query };
421
+ const response = await this.httpClient.request(requestOpts);
422
+ return new OffsetPage(response.data, response.pagination, this.httpClient, requestOpts);
423
+ }
424
+ async retrieve(id, params) {
425
+ const query = params ? { ...params } : void 0;
426
+ const response = await this.httpClient.request({
427
+ method: "GET",
428
+ path: `/commissions/${encodeURIComponent(id)}`,
429
+ query
430
+ });
431
+ return response.data;
432
+ }
433
+ async create(params) {
434
+ const response = await this.httpClient.request({
435
+ method: "POST",
436
+ path: "/commissions",
437
+ body: params
438
+ });
439
+ return response.data;
440
+ }
441
+ async update(id, params) {
442
+ const response = await this.httpClient.request({
443
+ method: "PUT",
444
+ path: `/commissions/${encodeURIComponent(id)}`,
445
+ body: params
446
+ });
447
+ return response.data;
448
+ }
449
+ async del(id) {
450
+ return this.httpClient.request({
451
+ method: "DELETE",
452
+ path: `/commissions/${encodeURIComponent(id)}`
453
+ });
454
+ }
455
+ };
456
+ var Coupons = class {
457
+ httpClient;
458
+ constructor(httpClient) {
459
+ this.httpClient = httpClient;
460
+ }
461
+ async list(params) {
462
+ const query = params ? { ...params } : {};
463
+ const requestOpts = { method: "GET", path: "/coupons", query };
464
+ const response = await this.httpClient.request(requestOpts);
465
+ return new OffsetPage(response.data, response.pagination, this.httpClient, requestOpts);
466
+ }
467
+ async retrieve(id, params) {
468
+ const query = params ? { ...params } : void 0;
469
+ const response = await this.httpClient.request({
470
+ method: "GET",
471
+ path: `/coupons/${encodeURIComponent(id)}`,
472
+ query
473
+ });
474
+ return response.data;
475
+ }
476
+ async create(params) {
477
+ const response = await this.httpClient.request({
478
+ method: "POST",
479
+ path: "/coupons",
480
+ body: params
481
+ });
482
+ return response.data;
483
+ }
484
+ async del(id) {
485
+ return this.httpClient.request({
486
+ method: "DELETE",
487
+ path: `/coupons/${encodeURIComponent(id)}`
488
+ });
489
+ }
490
+ };
491
+ var EmbedTokens = class {
492
+ httpClient;
493
+ constructor(httpClient) {
494
+ this.httpClient = httpClient;
495
+ }
496
+ async create(params) {
497
+ const response = await this.httpClient.request({
498
+ method: "POST",
499
+ path: "/embed/token",
500
+ body: params
501
+ });
502
+ return response.data;
503
+ }
504
+ };
505
+ var Marketplace = class {
506
+ httpClient;
507
+ constructor(httpClient) {
508
+ this.httpClient = httpClient;
509
+ }
510
+ async list(params) {
511
+ const query = params ? { ...params } : {};
512
+ const requestOpts = { method: "GET", path: "/marketplace", query };
513
+ const response = await this.httpClient.request(requestOpts);
514
+ return new OffsetPage(response.data, response.pagination, this.httpClient, requestOpts);
515
+ }
516
+ async retrieve(id) {
517
+ const response = await this.httpClient.request({
518
+ method: "GET",
519
+ path: `/marketplace/${encodeURIComponent(id)}`
520
+ });
521
+ return response.data;
522
+ }
523
+ };
524
+ var Payouts = class {
525
+ httpClient;
526
+ constructor(httpClient) {
527
+ this.httpClient = httpClient;
528
+ }
529
+ async list(params) {
530
+ const query = params ? { ...params } : {};
531
+ const requestOpts = { method: "GET", path: "/payouts", query };
532
+ const response = await this.httpClient.request(requestOpts);
533
+ return new OffsetPage(response.data, response.pagination, this.httpClient, requestOpts);
534
+ }
535
+ async retrieve(id) {
536
+ const response = await this.httpClient.request({
537
+ method: "GET",
538
+ path: `/payouts/${encodeURIComponent(id)}`
539
+ });
540
+ return response.data;
541
+ }
542
+ async update(id, params) {
543
+ const response = await this.httpClient.request({
544
+ method: "PUT",
545
+ path: `/payouts/${encodeURIComponent(id)}`,
546
+ body: params
547
+ });
548
+ return response.data;
549
+ }
550
+ };
551
+ var ProgramCreatives = class {
552
+ httpClient;
553
+ constructor(httpClient) {
554
+ this.httpClient = httpClient;
555
+ }
556
+ async list(params) {
557
+ const query = params ? { ...params } : {};
558
+ const requestOpts = { method: "GET", path: "/program/creatives", query };
559
+ const response = await this.httpClient.request(requestOpts);
560
+ return new OffsetPage(response.data, response.pagination, this.httpClient, requestOpts);
561
+ }
562
+ async retrieve(id) {
563
+ const response = await this.httpClient.request({
564
+ method: "GET",
565
+ path: `/program/creatives/${encodeURIComponent(id)}`
566
+ });
567
+ return response.data;
568
+ }
569
+ async create(params) {
570
+ const response = await this.httpClient.request({
571
+ method: "POST",
572
+ path: "/program/creatives",
573
+ body: params
574
+ });
575
+ return response.data;
576
+ }
577
+ async update(id, params) {
578
+ const response = await this.httpClient.request({
579
+ method: "PATCH",
580
+ path: `/program/creatives/${encodeURIComponent(id)}`,
581
+ body: params
582
+ });
583
+ return response.data;
584
+ }
585
+ async del(id) {
586
+ return this.httpClient.request({
587
+ method: "DELETE",
588
+ path: `/program/creatives/${encodeURIComponent(id)}`
589
+ });
590
+ }
591
+ };
592
+ var ProgramFraudRules = class {
593
+ httpClient;
594
+ constructor(httpClient) {
595
+ this.httpClient = httpClient;
596
+ }
597
+ async retrieve() {
598
+ const response = await this.httpClient.request({
599
+ method: "GET",
600
+ path: "/program/fraud-rules"
601
+ });
602
+ return response.data;
603
+ }
604
+ async update(params) {
605
+ const response = await this.httpClient.request({
606
+ method: "PATCH",
607
+ path: "/program/fraud-rules",
608
+ body: params
609
+ });
610
+ return response.data;
611
+ }
612
+ };
613
+ var ProgramGroups = class {
614
+ httpClient;
615
+ constructor(httpClient) {
616
+ this.httpClient = httpClient;
617
+ }
618
+ async list(params) {
619
+ const query = params ? { ...params } : void 0;
620
+ const response = await this.httpClient.request({
621
+ method: "GET",
622
+ path: "/program/groups",
623
+ query
624
+ });
625
+ return response.data;
626
+ }
627
+ async retrieve(id, params) {
628
+ const query = params ? { ...params } : void 0;
629
+ const response = await this.httpClient.request({
630
+ method: "GET",
631
+ path: `/program/groups/${encodeURIComponent(id)}`,
632
+ query
633
+ });
634
+ return response.data;
635
+ }
636
+ async create(params) {
637
+ const response = await this.httpClient.request({
638
+ method: "POST",
639
+ path: "/program/groups",
640
+ body: params
641
+ });
642
+ return response.data;
643
+ }
644
+ async update(id, params) {
645
+ const response = await this.httpClient.request({
646
+ method: "PATCH",
647
+ path: `/program/groups/${encodeURIComponent(id)}`,
648
+ body: params
649
+ });
650
+ return response.data;
651
+ }
652
+ async del(id) {
653
+ return this.httpClient.request({
654
+ method: "DELETE",
655
+ path: `/program/groups/${encodeURIComponent(id)}`
656
+ });
657
+ }
658
+ };
659
+ var ProgramNotifications = class {
660
+ httpClient;
661
+ constructor(httpClient) {
662
+ this.httpClient = httpClient;
663
+ }
664
+ async list() {
665
+ const response = await this.httpClient.request({
666
+ method: "GET",
667
+ path: "/program/notifications"
668
+ });
669
+ return response.data;
670
+ }
671
+ async update(emailTypeId, params) {
672
+ const response = await this.httpClient.request({
673
+ method: "PATCH",
674
+ path: `/program/notifications/${encodeURIComponent(emailTypeId)}`,
675
+ body: params
676
+ });
677
+ return response.data;
678
+ }
679
+ };
680
+ var ProgramPaymentTerms = class {
681
+ httpClient;
682
+ constructor(httpClient) {
683
+ this.httpClient = httpClient;
684
+ }
685
+ async retrieve() {
686
+ const response = await this.httpClient.request({
687
+ method: "GET",
688
+ path: "/program/payment-terms"
689
+ });
690
+ return response.data;
691
+ }
692
+ async update(params) {
693
+ const response = await this.httpClient.request({
694
+ method: "PATCH",
695
+ path: "/program/payment-terms",
696
+ body: params
697
+ });
698
+ return response.data;
699
+ }
700
+ };
701
+ var ProgramPortal = class {
702
+ httpClient;
703
+ constructor(httpClient) {
704
+ this.httpClient = httpClient;
705
+ }
706
+ async retrieve() {
707
+ const response = await this.httpClient.request({
708
+ method: "GET",
709
+ path: "/program/portal"
710
+ });
711
+ return response.data;
712
+ }
713
+ async update(params) {
714
+ const response = await this.httpClient.request({
715
+ method: "PATCH",
716
+ path: "/program/portal",
717
+ body: params
718
+ });
719
+ return response.data;
720
+ }
721
+ };
722
+ var ProgramRestrictions = class {
723
+ httpClient;
724
+ constructor(httpClient) {
725
+ this.httpClient = httpClient;
726
+ }
727
+ async retrieve() {
728
+ const response = await this.httpClient.request({
729
+ method: "GET",
730
+ path: "/program/restrictions"
731
+ });
732
+ return response.data;
733
+ }
734
+ async update(params) {
735
+ const response = await this.httpClient.request({
736
+ method: "PATCH",
737
+ path: "/program/restrictions",
738
+ body: params
739
+ });
740
+ return response.data;
741
+ }
742
+ };
743
+ var ProgramSettingsResource = class {
744
+ httpClient;
745
+ constructor(httpClient) {
746
+ this.httpClient = httpClient;
747
+ }
748
+ async retrieve() {
749
+ const response = await this.httpClient.request({
750
+ method: "GET",
751
+ path: "/program"
752
+ });
753
+ return response.data;
754
+ }
755
+ async update(params) {
756
+ const response = await this.httpClient.request({
757
+ method: "PATCH",
758
+ path: "/program",
759
+ body: params
760
+ });
761
+ return response.data;
762
+ }
763
+ };
764
+ var ProgramTracking = class {
765
+ httpClient;
766
+ constructor(httpClient) {
767
+ this.httpClient = httpClient;
768
+ }
769
+ async retrieve() {
770
+ const response = await this.httpClient.request({
771
+ method: "GET",
772
+ path: "/program/tracking"
773
+ });
774
+ return response.data;
775
+ }
776
+ async update(params) {
777
+ const response = await this.httpClient.request({
778
+ method: "PATCH",
779
+ path: "/program/tracking",
780
+ body: params
781
+ });
782
+ return response.data;
783
+ }
784
+ };
785
+ var Program = class {
786
+ paymentTerms;
787
+ tracking;
788
+ restrictions;
789
+ groups;
790
+ creatives;
791
+ notifications;
792
+ portal;
793
+ fraudRules;
794
+ settings;
795
+ constructor(httpClient) {
796
+ this.settings = new ProgramSettingsResource(httpClient);
797
+ this.paymentTerms = new ProgramPaymentTerms(httpClient);
798
+ this.tracking = new ProgramTracking(httpClient);
799
+ this.restrictions = new ProgramRestrictions(httpClient);
800
+ this.groups = new ProgramGroups(httpClient);
801
+ this.creatives = new ProgramCreatives(httpClient);
802
+ this.notifications = new ProgramNotifications(httpClient);
803
+ this.portal = new ProgramPortal(httpClient);
804
+ this.fraudRules = new ProgramFraudRules(httpClient);
805
+ }
806
+ async retrieve() {
807
+ return this.settings.retrieve();
808
+ }
809
+ async update(params) {
810
+ return this.settings.update(params);
811
+ }
812
+ };
813
+ var Referrals = class {
814
+ httpClient;
815
+ constructor(httpClient) {
816
+ this.httpClient = httpClient;
817
+ }
818
+ async list(params) {
819
+ const query = params ? { ...params } : {};
820
+ const requestOpts = { method: "GET", path: "/referrals", query };
821
+ const response = await this.httpClient.request(requestOpts);
822
+ return new CursorPage(response.data, response.has_more, this.httpClient, requestOpts);
823
+ }
824
+ async retrieve(id, params) {
825
+ const query = params ? { ...params } : void 0;
826
+ const response = await this.httpClient.request({
827
+ method: "GET",
828
+ path: `/referrals/${encodeURIComponent(id)}`,
829
+ query
830
+ });
831
+ return response.data;
832
+ }
833
+ async create(params) {
834
+ const response = await this.httpClient.request({
835
+ method: "POST",
836
+ path: "/referrals",
837
+ body: params
838
+ });
839
+ return response.data;
840
+ }
841
+ async update(id, params) {
842
+ const response = await this.httpClient.request({
843
+ method: "PUT",
844
+ path: `/referrals/${encodeURIComponent(id)}`,
845
+ body: params
846
+ });
847
+ return response.data;
848
+ }
849
+ async del(id) {
850
+ return this.httpClient.request({
851
+ method: "DELETE",
852
+ path: `/referrals/${encodeURIComponent(id)}`
853
+ });
854
+ }
855
+ };
856
+ var DEFAULT_BASE_URL = "https://api.affonso.io/v1";
857
+ var DEFAULT_TIMEOUT = 3e4;
858
+ var DEFAULT_MAX_RETRIES = 2;
859
+ var Affonso = class {
860
+ affiliates;
861
+ referrals;
862
+ clicks;
863
+ commissions;
864
+ coupons;
865
+ payouts;
866
+ program;
867
+ embedTokens;
868
+ marketplace;
869
+ constructor(apiKey, config) {
870
+ if (!apiKey) {
871
+ throw new Error(
872
+ "An API key is required. Pass it as the first argument: new Affonso('sk_...')"
873
+ );
874
+ }
875
+ const httpConfig = {
876
+ apiKey,
877
+ baseUrl: config?.baseUrl ?? DEFAULT_BASE_URL,
878
+ timeout: config?.timeout ?? DEFAULT_TIMEOUT,
879
+ maxRetries: config?.maxRetries ?? DEFAULT_MAX_RETRIES,
880
+ fetch: config?.fetch ?? ((...args) => globalThis.fetch(...args))
881
+ };
882
+ const httpClient = new HttpClient(httpConfig);
883
+ this.affiliates = new Affiliates(httpClient);
884
+ this.referrals = new Referrals(httpClient);
885
+ this.clicks = new Clicks(httpClient);
886
+ this.commissions = new Commissions(httpClient);
887
+ this.coupons = new Coupons(httpClient);
888
+ this.payouts = new Payouts(httpClient);
889
+ this.program = new Program(httpClient);
890
+ this.embedTokens = new EmbedTokens(httpClient);
891
+ this.marketplace = new Marketplace(httpClient);
892
+ }
893
+ };
894
+
895
+ // src/auth/oauth.ts
896
+ var import_node_crypto = __toESM(require("crypto"));
897
+ var import_node_http = __toESM(require("http"));
31
898
 
32
899
  // src/auth/storage.ts
33
900
  var import_node_fs = __toESM(require("fs"));
34
- var import_node_path = __toESM(require("path"));
35
901
  var import_node_os = __toESM(require("os"));
902
+ var import_node_path = __toESM(require("path"));
36
903
  var CONFIG_DIR = import_node_path.default.join(import_node_os.default.homedir(), ".config", "affonso");
37
904
  var AUTH_FILE = import_node_path.default.join(CONFIG_DIR, "auth.json");
38
905
  var CONFIG_FILE = import_node_path.default.join(CONFIG_DIR, "config.json");
@@ -85,38 +952,7 @@ function saveConfig(config) {
85
952
  });
86
953
  }
87
954
 
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
955
  // src/auth/oauth.ts
118
- var import_node_crypto = __toESM(require("crypto"));
119
- var import_node_http = __toESM(require("http"));
120
956
  var CLIENT_ID = "d4e5f6a7-b8c9-4d0e-a1f2-b3c4d5e6f7a8";
121
957
  var SCOPES = "read write";
122
958
  var LOGIN_TIMEOUT_MS = 5 * 60 * 1e3;
@@ -139,7 +975,7 @@ async function login(baseUrl) {
139
975
  const { verifier, challenge } = generatePKCE();
140
976
  return new Promise((resolve, reject) => {
141
977
  const server = import_node_http.default.createServer(async (req, res) => {
142
- const url = new URL(req.url ?? "/", `http://localhost`);
978
+ const url = new URL(req.url ?? "/", "http://localhost");
143
979
  if (url.pathname !== "/callback") {
144
980
  res.writeHead(404);
145
981
  res.end("Not found");
@@ -254,17 +1090,46 @@ async function refreshToken(baseUrl, refreshTokenValue) {
254
1090
  return false;
255
1091
  }
256
1092
  }
257
- function successPage() {
258
- return `<!DOCTYPE html><html><body style="font-family:system-ui;text-align:center;padding:60px">
259
- <h1>&#10003; Logged in to Affonso</h1>
260
- <p>You can close this window and return to the terminal.</p>
261
- </body></html>`;
262
- }
263
- function errorPage(message) {
264
- return `<!DOCTYPE html><html><body style="font-family:system-ui;text-align:center;padding:60px">
265
- <h1>Authentication Error</h1>
266
- <p>${escapeHtml(message)}</p>
267
- </body></html>`;
1093
+ function successPage() {
1094
+ return `<!DOCTYPE html><html><body style="font-family:system-ui;text-align:center;padding:60px">
1095
+ <h1>&#10003; Logged in to Affonso</h1>
1096
+ <p>You can close this window and return to the terminal.</p>
1097
+ </body></html>`;
1098
+ }
1099
+ function errorPage(message) {
1100
+ return `<!DOCTYPE html><html><body style="font-family:system-ui;text-align:center;padding:60px">
1101
+ <h1>Authentication Error</h1>
1102
+ <p>${escapeHtml(message)}</p>
1103
+ </body></html>`;
1104
+ }
1105
+
1106
+ // src/auth/resolve.ts
1107
+ function resolveAuth(flagApiKey) {
1108
+ if (flagApiKey) {
1109
+ return { apiKey: flagApiKey, source: "flag" };
1110
+ }
1111
+ const envKey = process.env.AFFONSO_API_KEY;
1112
+ if (envKey) {
1113
+ return { apiKey: envKey, source: "env" };
1114
+ }
1115
+ const config = loadConfig();
1116
+ if (config.api_key) {
1117
+ return { apiKey: config.api_key, source: "config" };
1118
+ }
1119
+ const auth = loadAuth();
1120
+ if (auth?.access_token) {
1121
+ if (auth.expires_at && Date.now() > auth.expires_at) {
1122
+ return null;
1123
+ }
1124
+ return { apiKey: auth.access_token, source: "oauth" };
1125
+ }
1126
+ return null;
1127
+ }
1128
+ function resolveBaseUrl(flagBaseUrl) {
1129
+ if (flagBaseUrl) return flagBaseUrl;
1130
+ const config = loadConfig();
1131
+ if (config.base_url) return config.base_url;
1132
+ return "https://api.affonso.io/v1";
268
1133
  }
269
1134
 
270
1135
  // src/lib/client.ts
@@ -278,7 +1143,9 @@ async function getClient(opts2) {
278
1143
  if (refreshed) {
279
1144
  auth = resolveAuth(opts2.apiKey);
280
1145
  } else {
281
- console.error("Error: Session expired and token refresh failed. Run `affonso login` to re-authenticate.");
1146
+ console.error(
1147
+ "Error: Session expired and token refresh failed. Run `affonso login` to re-authenticate."
1148
+ );
282
1149
  process.exit(1);
283
1150
  }
284
1151
  }
@@ -287,13 +1154,12 @@ async function getClient(opts2) {
287
1154
  console.error("Error: Authentication required. Run `affonso login` or set AFFONSO_API_KEY.");
288
1155
  process.exit(1);
289
1156
  }
290
- return new import_sdk.Affonso(auth.apiKey, { baseUrl });
1157
+ return new Affonso(auth.apiKey, { baseUrl });
291
1158
  }
292
1159
 
293
1160
  // src/lib/errors.ts
294
- var import_sdk2 = require("@affonso/sdk");
295
1161
  function handleError(err, json) {
296
- if (err instanceof import_sdk2.AffonsoError) {
1162
+ if (err instanceof AffonsoError) {
297
1163
  if (json) {
298
1164
  console.error(
299
1165
  JSON.stringify(
@@ -334,7 +1200,13 @@ function handleError(err, json) {
334
1200
  }
335
1201
  if (err instanceof Error) {
336
1202
  if (json) {
337
- console.error(JSON.stringify({ success: false, error: { code: "CLI_ERROR", message: err.message } }, null, 2));
1203
+ console.error(
1204
+ JSON.stringify(
1205
+ { success: false, error: { code: "CLI_ERROR", message: err.message } },
1206
+ null,
1207
+ 2
1208
+ )
1209
+ );
338
1210
  } else {
339
1211
  console.error(`Error: ${err.message}`);
340
1212
  }
@@ -388,9 +1260,11 @@ function formatTable(data, columns) {
388
1260
  return truncated.padEnd(widths[col]);
389
1261
  }).join(" ")
390
1262
  );
391
- return [header, dim("\u2500".repeat(header.replace(/\x1b\[[0-9;]*m/g, "").length)), ...rows].join(
392
- "\n"
1263
+ const tableWidth = cols.reduce(
1264
+ (total, col) => total + widths[col],
1265
+ Math.max(0, cols.length - 1) * 2
393
1266
  );
1267
+ return [header, dim("\u2500".repeat(tableWidth)), ...rows].join("\n");
394
1268
  }
395
1269
  function formatValue(val) {
396
1270
  if (val === null || val === void 0) return "\u2014";
@@ -422,10 +1296,8 @@ function output(result, opts2, columns) {
422
1296
  console.log(formatTable(result.data, columns));
423
1297
  if (result.pagination) {
424
1298
  const p = result.pagination;
425
- console.log(
426
- `
427
- Page ${p.page}/${p.total_pages} (${p.total} total)`
428
- );
1299
+ console.log(`
1300
+ Page ${p.page}/${p.total_pages} (${p.total} total)`);
429
1301
  }
430
1302
  return;
431
1303
  }
@@ -469,7 +1341,14 @@ function registerAffiliateCommands(program2) {
469
1341
  dateFrom: o.dateFrom,
470
1342
  dateTo: o.dateTo
471
1343
  });
472
- output(result, o, ["id", "name", "email", "partnership_status", "tracking_id", "created_at"]);
1344
+ output(result, o, [
1345
+ "id",
1346
+ "name",
1347
+ "email",
1348
+ "partnership_status",
1349
+ "tracking_id",
1350
+ "created_at"
1351
+ ]);
473
1352
  } catch (err) {
474
1353
  handleError(err, o.json);
475
1354
  }
@@ -536,88 +1415,6 @@ function registerAffiliateCommands(program2) {
536
1415
  });
537
1416
  }
538
1417
 
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() {
576
- const o = opts(this);
577
- try {
578
- 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);
589
- } catch (err) {
590
- handleError(err, o.json);
591
- }
592
- });
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) {
594
- const o = opts(this);
595
- try {
596
- 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);
605
- } catch (err) {
606
- handleError(err, o.json);
607
- }
608
- });
609
- referrals.command("delete <id>").description("Delete a referral").action(async function(id) {
610
- const o = opts(this);
611
- try {
612
- const client = await getClient(o);
613
- const result = await client.referrals.del(id);
614
- outputSuccess(result.message ?? "Referral deleted.", o);
615
- } catch (err) {
616
- handleError(err, o.json);
617
- }
618
- });
619
- }
620
-
621
1418
  // src/commands/clicks.ts
622
1419
  function registerClickCommands(program2) {
623
1420
  const clicks = program2.command("clicks").description("Track click events");
@@ -732,86 +1529,253 @@ function registerCommissionCommands(program2) {
732
1529
  handleError(err, o.json);
733
1530
  }
734
1531
  });
735
- commissions.command("delete <id>").description("Delete a commission").action(async function(id) {
1532
+ commissions.command("delete <id>").description("Delete a commission").action(async function(id) {
1533
+ const o = opts(this);
1534
+ try {
1535
+ const client = await getClient(o);
1536
+ const result = await client.commissions.del(id);
1537
+ outputSuccess(result.message ?? "Commission deleted.", o);
1538
+ } catch (err) {
1539
+ handleError(err, o.json);
1540
+ }
1541
+ });
1542
+ }
1543
+
1544
+ // src/commands/config.ts
1545
+ var VALID_KEYS = ["api-key", "base-url"];
1546
+ var KEY_MAP = {
1547
+ "api-key": "api_key",
1548
+ "base-url": "base_url"
1549
+ };
1550
+ function registerConfigCommands(program2) {
1551
+ const config = program2.command("config").description("Manage CLI configuration");
1552
+ config.command("get <key>").description("Get a config value (api-key, base-url)").action(async function(key) {
1553
+ const o = opts(this);
1554
+ try {
1555
+ if (!VALID_KEYS.includes(key)) {
1556
+ console.error(`Unknown config key: ${key}. Valid keys: ${VALID_KEYS.join(", ")}`);
1557
+ process.exit(1);
1558
+ }
1559
+ const stored = loadConfig();
1560
+ const mappedKey = KEY_MAP[key];
1561
+ const value = stored[mappedKey];
1562
+ if (value) {
1563
+ if (key === "api-key") {
1564
+ const v = value;
1565
+ console.log(`${v.slice(0, 10)}...${v.slice(-4)}`);
1566
+ } else {
1567
+ console.log(value);
1568
+ }
1569
+ } else {
1570
+ console.log(`${key} is not set.`);
1571
+ }
1572
+ } catch (err) {
1573
+ handleError(err, o.json);
1574
+ }
1575
+ });
1576
+ config.command("set <key> <value>").description("Set a config value (api-key, base-url)").action(async function(key, value) {
1577
+ const o = opts(this);
1578
+ try {
1579
+ if (!VALID_KEYS.includes(key)) {
1580
+ console.error(`Unknown config key: ${key}. Valid keys: ${VALID_KEYS.join(", ")}`);
1581
+ process.exit(1);
1582
+ }
1583
+ const mappedKey = KEY_MAP[key];
1584
+ saveConfig({ [mappedKey]: value });
1585
+ console.log(`${key} saved.`);
1586
+ } catch (err) {
1587
+ handleError(err, o.json);
1588
+ }
1589
+ });
1590
+ }
1591
+
1592
+ // src/commands/coupons.ts
1593
+ function registerCouponCommands(program2) {
1594
+ const coupons = program2.command("coupons").description("Manage coupons");
1595
+ 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() {
1596
+ const o = opts(this);
1597
+ try {
1598
+ const client = await getClient(o);
1599
+ const result = await client.coupons.list({
1600
+ limit: Number(o.limit),
1601
+ page: Number(o.page),
1602
+ affiliate_id: o.affiliateId,
1603
+ program_id: o.programId,
1604
+ search: o.search,
1605
+ expand: o.expand,
1606
+ sort: o.sort
1607
+ });
1608
+ output(result, o, [
1609
+ "id",
1610
+ "affiliate_id",
1611
+ "code",
1612
+ "discount_type",
1613
+ "discount_value",
1614
+ "duration",
1615
+ "created_at"
1616
+ ]);
1617
+ } catch (err) {
1618
+ handleError(err, o.json);
1619
+ }
1620
+ });
1621
+ coupons.command("get <id>").description("Get a coupon by ID").option("--expand <fields>", "Expand fields").action(async function(id) {
1622
+ const o = opts(this);
1623
+ try {
1624
+ const client = await getClient(o);
1625
+ const result = await client.coupons.retrieve(id, {
1626
+ expand: o.expand
1627
+ });
1628
+ output(result, o);
1629
+ } catch (err) {
1630
+ handleError(err, o.json);
1631
+ }
1632
+ });
1633
+ coupons.command("create").description("Create a coupon").requiredOption("--affiliate-id <id>", "Affiliate ID").requiredOption("--code <code>", "Coupon code").requiredOption("--discount-type <type>", "Discount type (percentage, fixed)").requiredOption("--discount-value <n>", "Discount value").requiredOption("--duration <dur>", "Duration (forever, once, repeating)").option("--duration-in-months <n>", "Duration in months (for repeating)").option("--currency <code>", "Currency code").option("--product-ids <ids>", "Product IDs (comma-separated)").action(async function() {
1634
+ const o = opts(this);
1635
+ try {
1636
+ const client = await getClient(o);
1637
+ const result = await client.coupons.create({
1638
+ affiliate_id: o.affiliateId,
1639
+ code: o.code,
1640
+ discount_type: o.discountType,
1641
+ discount_value: Number(o.discountValue),
1642
+ duration: o.duration,
1643
+ duration_in_months: o.durationInMonths ? Number(o.durationInMonths) : void 0,
1644
+ currency: o.currency,
1645
+ product_ids: o.productIds?.split(",")
1646
+ });
1647
+ output(result, o);
1648
+ } catch (err) {
1649
+ handleError(err, o.json);
1650
+ }
1651
+ });
1652
+ coupons.command("delete <id>").description("Delete a coupon").action(async function(id) {
1653
+ const o = opts(this);
1654
+ try {
1655
+ const client = await getClient(o);
1656
+ const result = await client.coupons.del(id);
1657
+ outputSuccess(result.message ?? "Coupon deleted.", o);
1658
+ } catch (err) {
1659
+ handleError(err, o.json);
1660
+ }
1661
+ });
1662
+ }
1663
+
1664
+ // src/commands/embed-tokens.ts
1665
+ function registerEmbedTokenCommands(program2) {
1666
+ const embedTokens = program2.command("embed-tokens").description("Generate embed tokens");
1667
+ 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() {
1668
+ const o = opts(this);
1669
+ try {
1670
+ const client = await getClient(o);
1671
+ const result = await client.embedTokens.create({
1672
+ affiliate_id: o.affiliateId,
1673
+ external_user_id: o.externalUserId,
1674
+ email: o.email,
1675
+ name: o.name
1676
+ });
1677
+ output(result, o);
1678
+ } catch (err) {
1679
+ handleError(err, o.json);
1680
+ }
1681
+ });
1682
+ }
1683
+
1684
+ // src/commands/login.ts
1685
+ function registerLoginCommand(program2) {
1686
+ program2.command("login").description("Log in via browser (OAuth 2.1)").action(async function() {
736
1687
  const o = opts(this);
737
1688
  try {
738
- const client = await getClient(o);
739
- const result = await client.commissions.del(id);
740
- outputSuccess(result.message ?? "Commission deleted.", o);
1689
+ const existing = resolveAuth();
1690
+ if (existing?.source === "oauth") {
1691
+ console.log("Already logged in. Run `affonso logout` first to switch accounts.");
1692
+ return;
1693
+ }
1694
+ const baseUrl = resolveBaseUrl(o.baseUrl);
1695
+ await login(baseUrl);
1696
+ console.log("Successfully logged in!");
741
1697
  } catch (err) {
742
1698
  handleError(err, o.json);
743
1699
  }
744
1700
  });
745
1701
  }
746
1702
 
747
- // src/commands/coupons.ts
748
- function registerCouponCommands(program2) {
749
- 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() {
1703
+ // src/commands/logout.ts
1704
+ function registerLogoutCommand(program2) {
1705
+ program2.command("logout").description("Log out and remove stored credentials").action(async function() {
751
1706
  const o = opts(this);
752
1707
  try {
753
- const client = await getClient(o);
754
- const result = await client.coupons.list({
755
- limit: Number(o.limit),
756
- page: Number(o.page),
757
- affiliate_id: o.affiliateId,
758
- program_id: o.programId,
759
- search: o.search,
760
- expand: o.expand,
761
- sort: o.sort
762
- });
763
- output(result, o, ["id", "affiliate_id", "code", "discount_type", "discount_value", "duration", "created_at"]);
1708
+ const auth = loadAuth();
1709
+ if (auth?.access_token) {
1710
+ const baseUrl = resolveBaseUrl(o.baseUrl);
1711
+ const issuer = baseUrl.replace(/\/v1\/?$/, "");
1712
+ try {
1713
+ await fetch(`${issuer}/oauth/revoke`, {
1714
+ method: "POST",
1715
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
1716
+ body: new URLSearchParams({
1717
+ token: auth.access_token,
1718
+ client_id: CLIENT_ID
1719
+ })
1720
+ });
1721
+ } catch {
1722
+ }
1723
+ }
1724
+ clearAuth();
1725
+ console.log("Logged out.");
764
1726
  } catch (err) {
765
1727
  handleError(err, o.json);
766
1728
  }
767
1729
  });
768
- coupons.command("get <id>").description("Get a coupon by ID").option("--expand <fields>", "Expand fields").action(async function(id) {
1730
+ }
1731
+
1732
+ // src/commands/marketplace.ts
1733
+ function registerMarketplaceCommands(program2) {
1734
+ const marketplace = program2.command("marketplace").description("Browse the affiliate marketplace (public, no auth required)");
1735
+ 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() {
769
1736
  const o = opts(this);
770
1737
  try {
771
- const client = await getClient(o);
772
- const result = await client.coupons.retrieve(id, {
773
- expand: o.expand
1738
+ const baseUrl = resolveBaseUrl(o.baseUrl);
1739
+ const client = new Affonso("public", { baseUrl });
1740
+ const result = await client.marketplace.list({
1741
+ limit: Number(o.limit),
1742
+ page: Number(o.page),
1743
+ category: o.category,
1744
+ search: o.search,
1745
+ sort: o.sort
774
1746
  });
775
- output(result, o);
1747
+ output(result, o, [
1748
+ "id",
1749
+ "name",
1750
+ "category",
1751
+ "commission_type",
1752
+ "commission_rate",
1753
+ "cookie_lifetime"
1754
+ ]);
776
1755
  } catch (err) {
777
1756
  handleError(err, o.json);
778
1757
  }
779
1758
  });
780
- coupons.command("create").description("Create a coupon").requiredOption("--affiliate-id <id>", "Affiliate ID").requiredOption("--code <code>", "Coupon code").requiredOption("--discount-type <type>", "Discount type (percentage, fixed)").requiredOption("--discount-value <n>", "Discount value").requiredOption("--duration <dur>", "Duration (forever, once, repeating)").option("--duration-in-months <n>", "Duration in months (for repeating)").option("--currency <code>", "Currency code").option("--product-ids <ids>", "Product IDs (comma-separated)").action(async function() {
1759
+ marketplace.command("get <id>").description("Get a marketplace program by ID").action(async function(id) {
781
1760
  const o = opts(this);
782
1761
  try {
783
- const client = await getClient(o);
784
- const result = await client.coupons.create({
785
- affiliate_id: o.affiliateId,
786
- code: o.code,
787
- discount_type: o.discountType,
788
- discount_value: Number(o.discountValue),
789
- duration: o.duration,
790
- duration_in_months: o.durationInMonths ? Number(o.durationInMonths) : void 0,
791
- currency: o.currency,
792
- product_ids: o.productIds?.split(",")
793
- });
1762
+ const baseUrl = resolveBaseUrl(o.baseUrl);
1763
+ const client = new Affonso("public", { baseUrl });
1764
+ const result = await client.marketplace.retrieve(id);
794
1765
  output(result, o);
795
1766
  } catch (err) {
796
1767
  handleError(err, o.json);
797
1768
  }
798
1769
  });
799
- coupons.command("delete <id>").description("Delete a coupon").action(async function(id) {
800
- const o = opts(this);
801
- try {
802
- const client = await getClient(o);
803
- const result = await client.coupons.del(id);
804
- outputSuccess(result.message ?? "Coupon deleted.", o);
805
- } catch (err) {
806
- handleError(err, o.json);
807
- }
808
- });
809
1770
  }
810
1771
 
811
1772
  // src/commands/payouts.ts
812
1773
  function registerPayoutCommands(program2) {
813
1774
  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() {
1775
+ payouts.command("list").description("List payouts").option("--limit <n>", "Items per page", "50").option("--page <n>", "Page number", "1").option(
1776
+ "--status <status>",
1777
+ "Filter by status (pending, processing, completed, failed, cancelled)"
1778
+ ).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() {
815
1779
  const o = opts(this);
816
1780
  try {
817
1781
  const client = await getClient(o);
@@ -824,7 +1788,14 @@ function registerPayoutCommands(program2) {
824
1788
  dateFrom: o.dateFrom,
825
1789
  dateTo: o.dateTo
826
1790
  });
827
- output(result, o, ["id", "affiliate_id", "amount", "status", "payment_method", "created_at"]);
1791
+ output(result, o, [
1792
+ "id",
1793
+ "affiliate_id",
1794
+ "amount",
1795
+ "status",
1796
+ "payment_method",
1797
+ "created_at"
1798
+ ]);
828
1799
  } catch (err) {
829
1800
  handleError(err, o.json);
830
1801
  }
@@ -1021,7 +1992,8 @@ function registerFraudRules(prog) {
1021
1992
  if (o.selfReferral !== void 0) params.self_referral = o.selfReferral;
1022
1993
  if (o.duplicateIp !== void 0) params.duplicate_ip = o.duplicateIp;
1023
1994
  if (o.vpnProxy !== void 0) params.vpn_proxy = o.vpnProxy;
1024
- if (o.suspiciousConversion !== void 0) params.suspicious_conversion = o.suspiciousConversion;
1995
+ if (o.suspiciousConversion !== void 0)
1996
+ params.suspicious_conversion = o.suspiciousConversion;
1025
1997
  const result = await client.program.fraudRules.update(params);
1026
1998
  output(result, o);
1027
1999
  } catch (err) {
@@ -1053,10 +2025,8 @@ function registerPortal(prog) {
1053
2025
  if (o.customDomain !== void 0) params.custom_domain = o.customDomain;
1054
2026
  if (o.termsUrl !== void 0) params.terms_url = o.termsUrl;
1055
2027
  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;
2028
+ if (o.onboardingEnabled !== void 0) params.onboarding_enabled = o.onboardingEnabled;
2029
+ if (o.resourcesEnabled !== void 0) params.resources_enabled = o.resourcesEnabled;
1060
2030
  const result = await client.program.portal.update(params);
1061
2031
  output(result, o);
1062
2032
  } catch (err) {
@@ -1099,7 +2069,14 @@ function registerGroups(prog) {
1099
2069
  const result = await client.program.groups.list({
1100
2070
  expand: o.expand
1101
2071
  });
1102
- output(result, o, ["id", "name", "description", "is_default", "affiliate_count", "created_at"]);
2072
+ output(result, o, [
2073
+ "id",
2074
+ "name",
2075
+ "description",
2076
+ "is_default",
2077
+ "affiliate_count",
2078
+ "created_at"
2079
+ ]);
1103
2080
  } catch (err) {
1104
2081
  handleError(err, o.json);
1105
2082
  }
@@ -1230,51 +2207,53 @@ function registerCreatives(prog) {
1230
2207
  });
1231
2208
  }
1232
2209
 
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() {
2210
+ // src/commands/referrals.ts
2211
+ function registerReferralCommands(program2) {
2212
+ const referrals = program2.command("referrals").description("Manage referrals");
2213
+ 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() {
1238
2214
  const o = opts(this);
1239
2215
  try {
1240
- const baseUrl = resolveBaseUrl(o.baseUrl);
1241
- const client = new import_sdk3.Affonso("public", { baseUrl });
1242
- const result = await client.marketplace.list({
2216
+ const client = await getClient(o);
2217
+ const result = await client.referrals.list({
1243
2218
  limit: Number(o.limit),
1244
- page: Number(o.page),
1245
- category: o.category,
1246
- search: o.search,
1247
- sort: o.sort
2219
+ starting_after: o.startingAfter,
2220
+ ending_before: o.endingBefore,
2221
+ affiliate_id: o.affiliateId,
2222
+ status: o.status,
2223
+ order: o.order,
2224
+ expand: o.expand,
2225
+ created_gte: o.createdGte,
2226
+ created_lte: o.createdLte
1248
2227
  });
1249
- output(result, o, ["id", "name", "category", "commission_type", "commission_rate", "cookie_lifetime"]);
2228
+ output(result, o, ["id", "affiliate_id", "email", "status", "created_at"]);
1250
2229
  } catch (err) {
1251
2230
  handleError(err, o.json);
1252
2231
  }
1253
2232
  });
1254
- marketplace.command("get <id>").description("Get a marketplace program by ID").action(async function(id) {
2233
+ 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
2234
  const o = opts(this);
1256
2235
  try {
1257
- const baseUrl = resolveBaseUrl(o.baseUrl);
1258
- const client = new import_sdk3.Affonso("public", { baseUrl });
1259
- const result = await client.marketplace.retrieve(id);
2236
+ const client = await getClient(o);
2237
+ const result = await client.referrals.retrieve(id, {
2238
+ expand: o.expand,
2239
+ include: o.include
2240
+ });
1260
2241
  output(result, o);
1261
2242
  } catch (err) {
1262
2243
  handleError(err, o.json);
1263
2244
  }
1264
2245
  });
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() {
2246
+ 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() {
1271
2247
  const o = opts(this);
1272
2248
  try {
1273
2249
  const client = await getClient(o);
1274
- const result = await client.embedTokens.create({
1275
- affiliate_id: o.affiliateId,
1276
- external_user_id: o.externalUserId,
2250
+ const result = await client.referrals.create({
1277
2251
  email: o.email,
2252
+ affiliate_id: o.affiliateId,
2253
+ subscription_id: o.subscriptionId,
2254
+ customer_id: o.customerId,
2255
+ click_id: o.clickId,
2256
+ status: o.status,
1278
2257
  name: o.name
1279
2258
  });
1280
2259
  output(result, o);
@@ -1282,50 +2261,28 @@ function registerEmbedTokenCommands(program2) {
1282
2261
  handleError(err, o.json);
1283
2262
  }
1284
2263
  });
1285
- }
1286
-
1287
- // src/commands/login.ts
1288
- function registerLoginCommand(program2) {
1289
- program2.command("login").description("Log in via browser (OAuth 2.1)").action(async function() {
2264
+ 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) {
1290
2265
  const o = opts(this);
1291
2266
  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!");
2267
+ const client = await getClient(o);
2268
+ const params = {};
2269
+ if (o.email !== void 0) params.email = o.email;
2270
+ if (o.status !== void 0) params.status = o.status;
2271
+ if (o.subscriptionId !== void 0) params.subscription_id = o.subscriptionId;
2272
+ if (o.customerId !== void 0) params.customer_id = o.customerId;
2273
+ if (o.name !== void 0) params.name = o.name;
2274
+ const result = await client.referrals.update(id, params);
2275
+ output(result, o);
1300
2276
  } catch (err) {
1301
2277
  handleError(err, o.json);
1302
2278
  }
1303
2279
  });
1304
- }
1305
-
1306
- // src/commands/logout.ts
1307
- function registerLogoutCommand(program2) {
1308
- program2.command("logout").description("Log out and remove stored credentials").action(async function() {
2280
+ referrals.command("delete <id>").description("Delete a referral").action(async function(id) {
1309
2281
  const o = opts(this);
1310
2282
  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.");
2283
+ const client = await getClient(o);
2284
+ const result = await client.referrals.del(id);
2285
+ outputSuccess(result.message ?? "Referral deleted.", o);
1329
2286
  } catch (err) {
1330
2287
  handleError(err, o.json);
1331
2288
  }
@@ -1363,58 +2320,10 @@ function registerWhoamiCommand(program2) {
1363
2320
  });
1364
2321
  }
1365
2322
 
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
2323
  // src/cli.ts
1415
2324
  function createProgram() {
1416
2325
  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");
2326
+ 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
2327
  registerLoginCommand(program2);
1419
2328
  registerLogoutCommand(program2);
1420
2329
  registerWhoamiCommand(program2);