trackrev 0.1.0 → 0.3.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 (47) hide show
  1. package/README.md +988 -42
  2. package/package.json +21 -3
  3. package/src/commands/affiliates.js +162 -0
  4. package/src/commands/analytics.js +128 -0
  5. package/src/commands/attribution.js +55 -0
  6. package/src/commands/auth.js +41 -0
  7. package/src/commands/domains.js +60 -0
  8. package/src/commands/folders.js +69 -0
  9. package/src/commands/keys.js +54 -0
  10. package/src/commands/links.js +203 -0
  11. package/src/commands/me.js +25 -0
  12. package/src/commands/money.js +96 -0
  13. package/src/commands/people.js +94 -0
  14. package/src/commands/retargeting.js +49 -0
  15. package/src/commands/revenue.js +87 -0
  16. package/src/commands/settings.js +64 -0
  17. package/src/commands/webhooks.js +79 -0
  18. package/src/index.js +43 -294
  19. package/src/lib/api.js +87 -0
  20. package/src/lib/config.js +52 -0
  21. package/src/lib/output.js +95 -0
  22. package/src/lib/prompt.js +55 -0
  23. package/src/registry.d.ts +58 -0
  24. package/src/registry.js +840 -0
  25. package/src/sdk/client.js +177 -0
  26. package/src/sdk/index.d.ts +534 -0
  27. package/src/sdk/index.js +1 -0
  28. package/src/sdk/resources/attribution.js +20 -0
  29. package/src/sdk/resources/channels.js +16 -0
  30. package/src/sdk/resources/clicks.js +16 -0
  31. package/src/sdk/resources/commissions.js +40 -0
  32. package/src/sdk/resources/credits.js +23 -0
  33. package/src/sdk/resources/domains.js +35 -0
  34. package/src/sdk/resources/export.js +15 -0
  35. package/src/sdk/resources/folders.js +55 -0
  36. package/src/sdk/resources/keys.js +28 -0
  37. package/src/sdk/resources/links.js +131 -0
  38. package/src/sdk/resources/orders.js +15 -0
  39. package/src/sdk/resources/partners.js +37 -0
  40. package/src/sdk/resources/payouts.js +22 -0
  41. package/src/sdk/resources/programs.js +55 -0
  42. package/src/sdk/resources/referrals.js +83 -0
  43. package/src/sdk/resources/retargeting.js +23 -0
  44. package/src/sdk/resources/revenue.js +53 -0
  45. package/src/sdk/resources/settings.js +29 -0
  46. package/src/sdk/resources/visitors.js +25 -0
  47. package/src/sdk/resources/webhooks.js +41 -0
@@ -0,0 +1,177 @@
1
+ import { attribution } from "./resources/attribution.js";
2
+ import { channels } from "./resources/channels.js";
3
+ import { clicks } from "./resources/clicks.js";
4
+ import { commissions } from "./resources/commissions.js";
5
+ import { credits } from "./resources/credits.js";
6
+ import { domains } from "./resources/domains.js";
7
+ import { exportCsv } from "./resources/export.js";
8
+ import { folders } from "./resources/folders.js";
9
+ import { keys } from "./resources/keys.js";
10
+ import { links } from "./resources/links.js";
11
+ import { orders } from "./resources/orders.js";
12
+ import { partners } from "./resources/partners.js";
13
+ import { payouts } from "./resources/payouts.js";
14
+ import { programs } from "./resources/programs.js";
15
+ import { referrals } from "./resources/referrals.js";
16
+ import { retargeting } from "./resources/retargeting.js";
17
+ import { revenue } from "./resources/revenue.js";
18
+ import { settings } from "./resources/settings.js";
19
+ import { visitors } from "./resources/visitors.js";
20
+ import { webhooks } from "./resources/webhooks.js";
21
+ export const VERSION = "0.3.0";
22
+ const DEFAULT_API_URL = "https://app.trackrev.io/api/v1";
23
+
24
+ const RETRYABLE_POSTS = new Set([
25
+ "/referrals/enroll",
26
+ "/referrals/report-signup",
27
+ "/referrals/report-purchase"
28
+ ])
29
+
30
+ const sleep = (ms) => new Promise ((resolve)=> setTimeout(resolve, ms))
31
+
32
+ export class TrackRevError extends Error {
33
+ constructor({ status, code, message }) {
34
+ super(message);
35
+
36
+ this.name = "TrackRevError";
37
+ this.status = status;
38
+ this.code = code;
39
+ }
40
+ }
41
+ export class TrackRevConnectionError extends TrackRevError {
42
+ constructor(message) {
43
+ super({
44
+ status: 0,
45
+ code: "connection_error",
46
+ message
47
+ });
48
+
49
+ this.name = "TrackRevConnectionError";
50
+ }
51
+ }
52
+
53
+ export class TrackRev {
54
+ constructor(key, {
55
+ apiUrl = DEFAULT_API_URL,
56
+ timeoutMs=15000,
57
+ maxRetries=3
58
+ } = {}) {
59
+ this.key = key;
60
+ this.apiUrl = apiUrl;
61
+ this.timeoutMs = timeoutMs;
62
+ this.maxRetries = maxRetries;
63
+ // One way to reach the API, handed to every resource, so a resource
64
+ // file never touches fetch or the key itself.
65
+ const call = (method, path, options) => this.request(method, path, options);
66
+
67
+ this.attribution = attribution(call);
68
+ this.channels = channels(call);
69
+ this.clicks = clicks(call);
70
+ this.commissions = commissions(call);
71
+ this.credits = credits(call);
72
+ this.domains = domains(call);
73
+ this.export = exportCsv(call);
74
+ this.folders = folders(call);
75
+ this.keys = keys(call);
76
+ this.links = links(call);
77
+ this.orders = orders(call);
78
+ this.partners = partners(call);
79
+ this.payouts = payouts(call);
80
+ this.programs = programs(call);
81
+ this.referrals = referrals(call);
82
+ this.retargeting = retargeting(call);
83
+ this.revenue = revenue(call);
84
+ this.settings = settings(call);
85
+ this.visitors = visitors(call);
86
+ this.webhooks = webhooks(call);
87
+ }
88
+
89
+ // Who am I, and what can this key do.
90
+ me() {
91
+ return this.request("GET", "/me");
92
+ }
93
+
94
+
95
+ async request(method, path, options) {
96
+ const bare = path.split("?")[0];
97
+
98
+ const safeToRepeat =
99
+ method === "GET" || RETRYABLE_POSTS.has(bare);
100
+
101
+ for (let attempt = 0; ; attempt++) {
102
+ try {
103
+ return await this.#send(method, path, options);
104
+ } catch (e) {
105
+ const mightWorkLater =
106
+ e instanceof TrackRevConnectionError ||
107
+ e.status === 429 ||
108
+ e.status >= 500;
109
+
110
+ if (
111
+ !safeToRepeat ||
112
+ !mightWorkLater ||
113
+ attempt >= this.maxRetries
114
+ ) {
115
+ throw e;
116
+ }
117
+
118
+ const waitMs =
119
+ e.retryAfterMs ??
120
+ 400 * 2 ** attempt + Math.random() * 200;
121
+
122
+ await sleep(waitMs);
123
+ }
124
+ }
125
+ }
126
+ async #send(method, path, { body } = {}) {
127
+ const url = this.apiUrl + path;
128
+ const payload = body ? JSON.stringify(body) : undefined;
129
+ let response;
130
+ let text;
131
+ try {
132
+ response = await fetch(url, {
133
+ method,
134
+ headers: {
135
+ Authorization: `Bearer ${this.key}`,
136
+ "Content-Type": "application/json"
137
+ },
138
+ body: payload,
139
+ signal: this.timeoutMs > 0 ? AbortSignal.timeout(this.timeoutMs): undefined
140
+ });
141
+ text= await response.text();
142
+ } catch (e) {
143
+ // fetch itself failed — server unreachable, DNS error. No response exists, timeout
144
+ if(e.name === 'TimeoutError'){
145
+ throw new TrackRevConnectionError(`Request timed out after ${this.timeoutMs}ms`);
146
+ }
147
+ throw new TrackRevConnectionError(e.message || "Network error");
148
+ }
149
+
150
+ // The API sends { error: { code, message } }, but never assume the
151
+ // body parses — a proxy in front of it can send HTML or nothing.
152
+ let data = text;
153
+ if(response.headers.get("Content-Type")?.includes("application/json")){
154
+ try {
155
+ data = JSON.parse(text);
156
+ } catch {
157
+ data = null;
158
+ }
159
+ }
160
+
161
+
162
+ if (!response.ok) {
163
+ const err = new TrackRevError({
164
+ status: response.status,
165
+ code: data?.error?.code ?? "unknown_error",
166
+ message: data?.error?.message ?? `HTTP ${response.status}`
167
+ });
168
+ const retryAfter = Number(response.headers.get('Retry-After'));
169
+ if(retryAfter>0){
170
+ err.retryAfterMs = retryAfter * 1000;
171
+ }
172
+ throw err;
173
+ }
174
+
175
+ return data;
176
+ }
177
+ }