@vigneshreddy/cms-sdk 1.0.8 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -65
- package/dist/src/client.d.ts +18 -4
- package/dist/src/client.js +116 -37
- package/dist/src/errors/base.d.ts +4 -2
- package/dist/src/errors/base.js +7 -0
- package/dist/src/errors/index.js +1 -1
- package/dist/src/errors.d.ts +3 -3
- package/dist/src/errors.js +45 -35
- package/dist/src/generated/api.d.ts +82 -16
- package/dist/src/generated/api.js +40 -26
- package/dist/src/generated/base.js +1 -1
- package/dist/src/index.d.ts +2 -6
- package/dist/src/index.js +1 -28
- package/package.json +9 -18
- package/dist/src/funcs/index.d.ts +0 -2
- package/dist/src/funcs/index.js +0 -7
- package/dist/src/funcs/trackLead.d.ts +0 -44
- package/dist/src/funcs/trackLead.js +0 -55
- package/dist/src/funcs/trackSale.d.ts +0 -46
- package/dist/src/funcs/trackSale.js +0 -57
package/README.md
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
Official TypeScript/JavaScript SDK for the CutMeShort CMS API.
|
|
4
4
|
|
|
5
5
|
Use this package to send:
|
|
6
|
-
- lead tracking events (`trackLead`)
|
|
7
|
-
- sale tracking events (`trackSale`)
|
|
6
|
+
- lead tracking events (`cms.trackLead`)
|
|
7
|
+
- sale tracking events (`cms.trackSale`)
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
@@ -49,7 +49,7 @@ console.log(response);
|
|
|
49
49
|
|
|
50
50
|
## API Methods
|
|
51
51
|
|
|
52
|
-
### `trackLead(leadData, options?)`
|
|
52
|
+
### `cms.trackLead(leadData, options?)`
|
|
53
53
|
|
|
54
54
|
```ts
|
|
55
55
|
import { CMS } from "@vigneshreddy/cms-sdk";
|
|
@@ -64,79 +64,68 @@ await cms.trackLead({
|
|
|
64
64
|
```
|
|
65
65
|
|
|
66
66
|
Lead payload fields:
|
|
67
|
-
- `clickId: string`
|
|
67
|
+
- `clickId: string` (optional in **deferred** follow-up calls)
|
|
68
68
|
- `eventName: string`
|
|
69
69
|
- `customerId: string`
|
|
70
|
+
- `timestamp?: string` (ISO 8601, e.g. `new Date().toISOString()`)
|
|
71
|
+
- `customerExternalId?: string`
|
|
72
|
+
- `customerName?: string`
|
|
73
|
+
- `customerEmail?: string`
|
|
74
|
+
- `customerAvatar?: string`
|
|
70
75
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
```ts
|
|
74
|
-
import { CMS } from "@vigneshreddy/cms-sdk";
|
|
75
|
-
|
|
76
|
-
const cms = new CMS({ apiKey: "sk_live_xxx" });
|
|
77
|
-
|
|
78
|
-
await cms.trackSale({
|
|
79
|
-
clickId: "id_123",
|
|
80
|
-
eventName: "purchase_completed",
|
|
81
|
-
invoiceId: "inv_987",
|
|
82
|
-
amount: 4999,
|
|
83
|
-
currency: "USD",
|
|
84
|
-
});
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
Sale payload fields:
|
|
88
|
-
- `clickId: string`
|
|
89
|
-
- `eventName: string`
|
|
90
|
-
- `invoiceId: string`
|
|
91
|
-
- `amount: number` (in cents)
|
|
92
|
-
- `currency: string` (3-letter code, e.g. `USD`)
|
|
93
|
-
|
|
94
|
-
## Functional Style (Result Pattern)
|
|
95
|
-
|
|
96
|
-
If you prefer not to use `try/catch`, use helper functions that return `Result`.
|
|
76
|
+
#### Deferred mode (two-step lead attribution)
|
|
97
77
|
|
|
98
|
-
|
|
78
|
+
If you can’t reliably send the `clickId` at the moment you want to record a lead event, you can use **deferred mode**:
|
|
99
79
|
|
|
100
80
|
```ts
|
|
101
|
-
import { CMS
|
|
81
|
+
import { CMS } from "@vigneshreddy/cms-sdk";
|
|
102
82
|
|
|
103
83
|
const cms = new CMS({ apiKey: "sk_live_xxx" });
|
|
104
84
|
|
|
105
|
-
|
|
85
|
+
// Step 1: store the clickId <-> customerId association
|
|
86
|
+
await cms.trackLead({
|
|
106
87
|
clickId: "id_123",
|
|
107
88
|
eventName: "signup_started",
|
|
108
89
|
customerId: "user_42",
|
|
90
|
+
mode: "deferred",
|
|
109
91
|
});
|
|
110
92
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
93
|
+
// Step 2: later, track using just customerId (no clickId)
|
|
94
|
+
await cms.trackLead({
|
|
95
|
+
eventName: "email_verified",
|
|
96
|
+
customerId: "user_42",
|
|
97
|
+
mode: "deferred",
|
|
98
|
+
});
|
|
116
99
|
```
|
|
117
100
|
|
|
118
|
-
###
|
|
101
|
+
### `cms.trackSale(saleData, options?)`
|
|
119
102
|
|
|
120
103
|
```ts
|
|
121
|
-
import { CMS
|
|
104
|
+
import { CMS } from "@vigneshreddy/cms-sdk";
|
|
122
105
|
|
|
123
106
|
const cms = new CMS({ apiKey: "sk_live_xxx" });
|
|
124
107
|
|
|
125
|
-
|
|
108
|
+
await cms.trackSale({
|
|
126
109
|
clickId: "id_123",
|
|
127
110
|
eventName: "purchase_completed",
|
|
128
111
|
invoiceId: "inv_987",
|
|
129
112
|
amount: 4999,
|
|
130
113
|
currency: "USD",
|
|
131
114
|
});
|
|
132
|
-
|
|
133
|
-
if (result.ok) {
|
|
134
|
-
console.log("Tracked sale:", result.value);
|
|
135
|
-
} else {
|
|
136
|
-
console.error("Sale error:", result.error);
|
|
137
|
-
}
|
|
138
115
|
```
|
|
139
116
|
|
|
117
|
+
Sale payload fields:
|
|
118
|
+
- `clickId: string`
|
|
119
|
+
- `eventName: string`
|
|
120
|
+
- `timestamp?: string` (ISO 8601, e.g. `new Date().toISOString()`)
|
|
121
|
+
- `customerExternalId?: string`
|
|
122
|
+
- `customerName?: string`
|
|
123
|
+
- `customerEmail?: string`
|
|
124
|
+
- `customerAvatar?: string`
|
|
125
|
+
- `invoiceId: string`
|
|
126
|
+
- `amount: number` (in cents)
|
|
127
|
+
- `currency: string` (3-letter code, e.g. `USD`)
|
|
128
|
+
|
|
140
129
|
## Configuration
|
|
141
130
|
|
|
142
131
|
`new CMS(config)` accepts:
|
|
@@ -144,18 +133,22 @@ if (result.ok) {
|
|
|
144
133
|
```ts
|
|
145
134
|
type CMSConfig = {
|
|
146
135
|
apiKey: string;
|
|
136
|
+
baseUrl?: string;
|
|
147
137
|
timeout?: number;
|
|
148
138
|
maxRetries?: number;
|
|
149
139
|
retryDelayMs?: number;
|
|
140
|
+
retryMaxDelayMs?: number;
|
|
150
141
|
retryOnStatuses?: number[];
|
|
151
142
|
retryOnNetworkError?: boolean;
|
|
152
143
|
};
|
|
153
144
|
```
|
|
154
145
|
|
|
155
146
|
Defaults:
|
|
147
|
+
- `baseUrl`: `https://www.cutmeshort.com/sdk`
|
|
156
148
|
- `timeout`: `10000`
|
|
157
149
|
- `maxRetries`: `2`
|
|
158
150
|
- `retryDelayMs`: `500`
|
|
151
|
+
- `retryMaxDelayMs`: `10000`
|
|
159
152
|
- `retryOnStatuses`: `[429, 500, 502, 503, 504]`
|
|
160
153
|
- `retryOnNetworkError`: `true`
|
|
161
154
|
|
|
@@ -212,26 +205,13 @@ try {
|
|
|
212
205
|
}
|
|
213
206
|
```
|
|
214
207
|
|
|
215
|
-
##
|
|
216
|
-
|
|
217
|
-
```ts
|
|
218
|
-
import type {
|
|
219
|
-
TrackLeadRequest,
|
|
220
|
-
TrackSaleRequest,
|
|
221
|
-
TrackResponse,
|
|
222
|
-
RequestOptions,
|
|
223
|
-
CMSConfig,
|
|
224
|
-
} from "@vigneshreddy/cms-sdk";
|
|
225
|
-
```
|
|
208
|
+
## Public API
|
|
226
209
|
|
|
227
|
-
|
|
210
|
+
This package intentionally exposes only:
|
|
211
|
+
- `CMS` (use `cms.trackLead` and `cms.trackSale`)
|
|
212
|
+
- `CMSAPIError` (for `instanceof` checks)
|
|
228
213
|
|
|
229
|
-
|
|
230
|
-
- `CMS`
|
|
231
|
-
- `trackLead`, `trackSale`
|
|
232
|
-
- `CMSAPIError` and specific error classes
|
|
233
|
-
- `ok`, `err`, `Result`
|
|
234
|
-
- generated request/response types
|
|
214
|
+
Deep imports (example: `@vigneshreddy/cms-sdk/client`) are intentionally blocked.
|
|
235
215
|
|
|
236
216
|
## Security Best Practice
|
|
237
217
|
|
package/dist/src/client.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { EventsApi } from "./generated";
|
|
2
|
-
export type LeadPayload =
|
|
3
|
-
export type SalePayload =
|
|
1
|
+
import { EventsApi, TrackLeadRequest, TrackSaleRequest } from "./generated";
|
|
2
|
+
export type LeadPayload = TrackLeadRequest;
|
|
3
|
+
export type SalePayload = TrackSaleRequest;
|
|
4
4
|
export interface CMSConfig {
|
|
5
5
|
apiKey: string;
|
|
6
|
+
/** Base URL for the CMS API */
|
|
7
|
+
baseUrl?: string;
|
|
6
8
|
/**
|
|
7
9
|
* Optional timeout in milliseconds for HTTP requests.
|
|
8
10
|
* This is implemented using AbortController around the native fetch API.
|
|
@@ -12,6 +14,8 @@ export interface CMSConfig {
|
|
|
12
14
|
maxRetries?: number;
|
|
13
15
|
/** Base delay (in ms) between retries for transient failures */
|
|
14
16
|
retryDelayMs?: number;
|
|
17
|
+
/** Maximum delay cap (in ms) for retry backoff */
|
|
18
|
+
retryMaxDelayMs?: number;
|
|
15
19
|
/** HTTP status codes that should be retried */
|
|
16
20
|
retryOnStatuses?: number[];
|
|
17
21
|
/** Whether to retry on network errors (no response / timeout) */
|
|
@@ -27,6 +31,8 @@ export interface RequestOptions {
|
|
|
27
31
|
maxRetries?: number;
|
|
28
32
|
/** Override retry delay for this specific request */
|
|
29
33
|
retryDelayMs?: number;
|
|
34
|
+
/** Override retry max delay for this specific request */
|
|
35
|
+
retryMaxDelayMs?: number;
|
|
30
36
|
/** Override retry status codes for this specific request */
|
|
31
37
|
retryOnStatuses?: number[];
|
|
32
38
|
/** Override retry on network error setting for this specific request */
|
|
@@ -36,11 +42,19 @@ export declare class CMS {
|
|
|
36
42
|
readonly events: EventsApi;
|
|
37
43
|
private readonly maxRetries;
|
|
38
44
|
private readonly retryDelayMs;
|
|
45
|
+
private readonly retryMaxDelayMs;
|
|
39
46
|
private readonly retryOnStatuses;
|
|
40
47
|
private readonly retryOnNetworkError;
|
|
41
48
|
constructor(config: CMSConfig);
|
|
42
|
-
private isRetryableError;
|
|
43
49
|
private sleep;
|
|
50
|
+
private normalizeBaseUrl;
|
|
51
|
+
private resolveNonNegativeInt;
|
|
52
|
+
private resolvePositiveInt;
|
|
53
|
+
private resolveRetryStatuses;
|
|
54
|
+
private getHeaderValue;
|
|
55
|
+
private parseRetryAfterMs;
|
|
56
|
+
private getRetryDelayMs;
|
|
57
|
+
private toGeneratedRequestOptions;
|
|
44
58
|
private withRetry;
|
|
45
59
|
private isRetryableErrorWithOptions;
|
|
46
60
|
trackLead(leadData: LeadPayload, options?: RequestOptions): Promise<import("./generated").TrackResponse>;
|
package/dist/src/client.js
CHANGED
|
@@ -4,27 +4,32 @@ exports.CMS = void 0;
|
|
|
4
4
|
// src/client.ts
|
|
5
5
|
const generated_1 = require("./generated");
|
|
6
6
|
const errors_1 = require("./errors");
|
|
7
|
+
const DEFAULT_BASE_URL = "https://www.cutmeshort.com";
|
|
8
|
+
const DEFAULT_TIMEOUT_MS = 10000;
|
|
9
|
+
const DEFAULT_MAX_RETRIES = 2;
|
|
10
|
+
const DEFAULT_RETRY_DELAY_MS = 500;
|
|
11
|
+
const DEFAULT_RETRY_MAX_DELAY_MS = 10000;
|
|
12
|
+
const DEFAULT_RETRY_STATUSES = [429, 500, 502, 503, 504];
|
|
7
13
|
class CMS {
|
|
8
14
|
constructor(config) {
|
|
9
|
-
var _a, _b, _c, _d
|
|
15
|
+
var _a, _b, _c, _d;
|
|
10
16
|
if (!config.apiKey) {
|
|
11
17
|
throw new Error("CMS SDK: apiKey is required.");
|
|
12
18
|
}
|
|
13
|
-
|
|
14
|
-
// per-endpoint paths like /track/lead; callers just hit this base.
|
|
15
|
-
const basePath = "http://localhost:5000/sdk";
|
|
19
|
+
const basePath = this.normalizeBaseUrl((_a = config.baseUrl) !== null && _a !== void 0 ? _a : DEFAULT_BASE_URL);
|
|
16
20
|
// Retry configuration with sensible defaults
|
|
17
|
-
this.maxRetries = (
|
|
18
|
-
this.retryDelayMs = (
|
|
19
|
-
this.
|
|
20
|
-
this.
|
|
21
|
+
this.maxRetries = this.resolveNonNegativeInt(config.maxRetries, DEFAULT_MAX_RETRIES, "maxRetries");
|
|
22
|
+
this.retryDelayMs = this.resolvePositiveInt(config.retryDelayMs, DEFAULT_RETRY_DELAY_MS, "retryDelayMs");
|
|
23
|
+
this.retryMaxDelayMs = this.resolvePositiveInt(config.retryMaxDelayMs, DEFAULT_RETRY_MAX_DELAY_MS, "retryMaxDelayMs");
|
|
24
|
+
this.retryOnStatuses = this.resolveRetryStatuses((_b = config.retryOnStatuses) !== null && _b !== void 0 ? _b : DEFAULT_RETRY_STATUSES);
|
|
25
|
+
this.retryOnNetworkError = (_c = config.retryOnNetworkError) !== null && _c !== void 0 ? _c : true;
|
|
21
26
|
// Create the Configuration object
|
|
22
27
|
const apiConfig = new generated_1.Configuration({
|
|
23
28
|
basePath,
|
|
24
29
|
accessToken: config.apiKey,
|
|
25
30
|
baseOptions: {
|
|
26
31
|
// Ensure generated client uses the same timeout & headers
|
|
27
|
-
timeout: (
|
|
32
|
+
timeout: (_d = config.timeout) !== null && _d !== void 0 ? _d : DEFAULT_TIMEOUT_MS,
|
|
28
33
|
headers: {
|
|
29
34
|
'Content-Type': 'application/json'
|
|
30
35
|
},
|
|
@@ -34,33 +39,113 @@ class CMS {
|
|
|
34
39
|
// The underlying implementation uses the global `fetch` API.
|
|
35
40
|
this.events = new generated_1.EventsApi(apiConfig, basePath);
|
|
36
41
|
}
|
|
37
|
-
|
|
42
|
+
async sleep(ms) {
|
|
43
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
44
|
+
}
|
|
45
|
+
normalizeBaseUrl(baseUrl) {
|
|
46
|
+
try {
|
|
47
|
+
const parsed = new URL(baseUrl);
|
|
48
|
+
return parsed.toString().replace(/\/+$/, "");
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
throw new Error("CMS SDK: baseUrl must be a valid absolute URL.");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
resolveNonNegativeInt(value, fallback, key) {
|
|
55
|
+
if (typeof value === "undefined") {
|
|
56
|
+
return fallback;
|
|
57
|
+
}
|
|
58
|
+
if (!Number.isInteger(value) || value < 0) {
|
|
59
|
+
throw new Error(`CMS SDK: ${key} must be a non-negative integer.`);
|
|
60
|
+
}
|
|
61
|
+
return value;
|
|
62
|
+
}
|
|
63
|
+
resolvePositiveInt(value, fallback, key) {
|
|
64
|
+
if (typeof value === "undefined") {
|
|
65
|
+
return fallback;
|
|
66
|
+
}
|
|
67
|
+
if (!Number.isInteger(value) || value <= 0) {
|
|
68
|
+
throw new Error(`CMS SDK: ${key} must be a positive integer.`);
|
|
69
|
+
}
|
|
70
|
+
return value;
|
|
71
|
+
}
|
|
72
|
+
resolveRetryStatuses(statuses) {
|
|
73
|
+
const invalid = statuses.find((status) => !Number.isInteger(status) || status < 100 || status > 599);
|
|
74
|
+
if (typeof invalid !== "undefined") {
|
|
75
|
+
throw new Error("CMS SDK: retryOnStatuses must contain valid HTTP status codes.");
|
|
76
|
+
}
|
|
77
|
+
return new Set(statuses);
|
|
78
|
+
}
|
|
79
|
+
getHeaderValue(headers, headerName) {
|
|
38
80
|
var _a;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (this.retryOnNetworkError && (!axiosError.response || axiosError.code === "ECONNABORTED")) {
|
|
42
|
-
return true;
|
|
81
|
+
if (!headers) {
|
|
82
|
+
return undefined;
|
|
43
83
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
return true;
|
|
84
|
+
const normalizedName = headerName.toLowerCase();
|
|
85
|
+
if (headers instanceof Headers) {
|
|
86
|
+
return (_a = headers.get(headerName)) !== null && _a !== void 0 ? _a : undefined;
|
|
48
87
|
}
|
|
49
|
-
|
|
88
|
+
if (Array.isArray(headers)) {
|
|
89
|
+
const match = headers.find(([key]) => String(key).toLowerCase() === normalizedName);
|
|
90
|
+
return match ? String(match[1]) : undefined;
|
|
91
|
+
}
|
|
92
|
+
if (typeof headers === "object") {
|
|
93
|
+
const entries = Object.entries(headers);
|
|
94
|
+
const match = entries.find(([key]) => key.toLowerCase() === normalizedName);
|
|
95
|
+
return match ? String(match[1]) : undefined;
|
|
96
|
+
}
|
|
97
|
+
return undefined;
|
|
50
98
|
}
|
|
51
|
-
|
|
52
|
-
|
|
99
|
+
parseRetryAfterMs(value) {
|
|
100
|
+
if (!value) {
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
const seconds = Number(value);
|
|
104
|
+
if (Number.isFinite(seconds) && seconds >= 0) {
|
|
105
|
+
return Math.floor(seconds * 1000);
|
|
106
|
+
}
|
|
107
|
+
const timestamp = Date.parse(value);
|
|
108
|
+
if (Number.isFinite(timestamp)) {
|
|
109
|
+
const diff = timestamp - Date.now();
|
|
110
|
+
if (diff > 0) {
|
|
111
|
+
return Math.floor(diff);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
getRetryDelayMs(error, attempt, retryDelayMs, retryMaxDelayMs) {
|
|
117
|
+
var _a;
|
|
118
|
+
const responseHeaders = (_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.headers;
|
|
119
|
+
const retryAfterHeader = this.getHeaderValue(responseHeaders, "retry-after");
|
|
120
|
+
const retryAfterMs = this.parseRetryAfterMs(retryAfterHeader);
|
|
121
|
+
if (typeof retryAfterMs === "number") {
|
|
122
|
+
return Math.min(retryAfterMs, retryMaxDelayMs);
|
|
123
|
+
}
|
|
124
|
+
const exponentialBase = Math.min(retryDelayMs * Math.pow(2, Math.max(0, attempt - 1)), retryMaxDelayMs);
|
|
125
|
+
const jitter = Math.floor(Math.random() * Math.max(1, Math.floor(exponentialBase * 0.25)));
|
|
126
|
+
return Math.min(exponentialBase + jitter, retryMaxDelayMs);
|
|
127
|
+
}
|
|
128
|
+
toGeneratedRequestOptions(options) {
|
|
129
|
+
if (!options) {
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
const requestOptions = {};
|
|
133
|
+
if (typeof options.timeout === "number") {
|
|
134
|
+
requestOptions.timeout = options.timeout;
|
|
135
|
+
}
|
|
136
|
+
return requestOptions;
|
|
53
137
|
}
|
|
54
138
|
async withRetry(fn, options) {
|
|
55
|
-
var _a
|
|
139
|
+
var _a;
|
|
56
140
|
let attempt = 0;
|
|
57
141
|
// Use per-request options if provided, otherwise use instance defaults
|
|
58
|
-
const maxRetries = (
|
|
59
|
-
const retryDelayMs = (
|
|
142
|
+
const maxRetries = this.resolveNonNegativeInt(options === null || options === void 0 ? void 0 : options.maxRetries, this.maxRetries, "maxRetries");
|
|
143
|
+
const retryDelayMs = this.resolvePositiveInt(options === null || options === void 0 ? void 0 : options.retryDelayMs, this.retryDelayMs, "retryDelayMs");
|
|
144
|
+
const retryMaxDelayMs = this.resolvePositiveInt(options === null || options === void 0 ? void 0 : options.retryMaxDelayMs, this.retryMaxDelayMs, "retryMaxDelayMs");
|
|
60
145
|
const retryOnStatuses = (options === null || options === void 0 ? void 0 : options.retryOnStatuses)
|
|
61
|
-
?
|
|
146
|
+
? this.resolveRetryStatuses(options.retryOnStatuses)
|
|
62
147
|
: this.retryOnStatuses;
|
|
63
|
-
const retryOnNetworkError = (
|
|
148
|
+
const retryOnNetworkError = (_a = options === null || options === void 0 ? void 0 : options.retryOnNetworkError) !== null && _a !== void 0 ? _a : this.retryOnNetworkError;
|
|
64
149
|
// attempt 0 + maxRetries additional retries
|
|
65
150
|
// e.g. maxRetries=2 -> attempts: 0,1,2
|
|
66
151
|
const maxAttempts = maxRetries + 1;
|
|
@@ -77,7 +162,7 @@ class CMS {
|
|
|
77
162
|
// Final failure, let our error handler wrap it
|
|
78
163
|
return (0, errors_1.handleApiError)(error);
|
|
79
164
|
}
|
|
80
|
-
const delay =
|
|
165
|
+
const delay = this.getRetryDelayMs(error, attempt, retryDelayMs, retryMaxDelayMs);
|
|
81
166
|
await this.sleep(delay);
|
|
82
167
|
}
|
|
83
168
|
}
|
|
@@ -97,21 +182,15 @@ class CMS {
|
|
|
97
182
|
return false;
|
|
98
183
|
}
|
|
99
184
|
async trackLead(leadData, options) {
|
|
100
|
-
const
|
|
101
|
-
type: "lead",
|
|
102
|
-
lead: leadData,
|
|
103
|
-
};
|
|
185
|
+
const requestOptions = this.toGeneratedRequestOptions(options);
|
|
104
186
|
return this.withRetry(async () => {
|
|
105
|
-
return this.events.trackLead(
|
|
187
|
+
return this.events.trackLead(leadData, requestOptions);
|
|
106
188
|
}, options);
|
|
107
189
|
}
|
|
108
190
|
async trackSale(saleData, options) {
|
|
109
|
-
const
|
|
110
|
-
type: "sale",
|
|
111
|
-
sale: saleData,
|
|
112
|
-
};
|
|
191
|
+
const requestOptions = this.toGeneratedRequestOptions(options);
|
|
113
192
|
return this.withRetry(async () => {
|
|
114
|
-
return this.events.trackSale(
|
|
193
|
+
return this.events.trackSale(saleData, requestOptions);
|
|
115
194
|
}, options);
|
|
116
195
|
}
|
|
117
196
|
}
|
|
@@ -6,12 +6,14 @@ export declare class CMSAPIError extends Error {
|
|
|
6
6
|
readonly statusCode: number;
|
|
7
7
|
readonly type: string;
|
|
8
8
|
readonly rawError: any;
|
|
9
|
-
readonly
|
|
9
|
+
readonly cause?: unknown;
|
|
10
|
+
request?: {
|
|
10
11
|
url?: string;
|
|
11
12
|
method?: string;
|
|
12
13
|
headers?: Record<string, any>;
|
|
14
|
+
timeout?: number;
|
|
13
15
|
};
|
|
14
|
-
|
|
16
|
+
response?: {
|
|
15
17
|
status: number;
|
|
16
18
|
statusText: string;
|
|
17
19
|
data?: any;
|
package/dist/src/errors/base.js
CHANGED
|
@@ -12,13 +12,20 @@ class CMSAPIError extends Error {
|
|
|
12
12
|
this.statusCode = statusCode;
|
|
13
13
|
this.type = type;
|
|
14
14
|
this.rawError = rawError;
|
|
15
|
+
this.cause = rawError;
|
|
15
16
|
this.request = request;
|
|
16
17
|
this.response = response;
|
|
18
|
+
// Ensure proper prototype chain in transpiled output
|
|
19
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
20
|
+
if (typeof Error.captureStackTrace === "function") {
|
|
21
|
+
Error.captureStackTrace(this, new.target);
|
|
22
|
+
}
|
|
17
23
|
// Make heavy properties non-enumerable so console.log / inspection
|
|
18
24
|
// stays focused on the high-level error information.
|
|
19
25
|
try {
|
|
20
26
|
Object.defineProperties(this, {
|
|
21
27
|
rawError: { enumerable: false },
|
|
28
|
+
cause: { enumerable: false },
|
|
22
29
|
request: { enumerable: false },
|
|
23
30
|
response: { enumerable: false },
|
|
24
31
|
});
|
package/dist/src/errors/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createSpecificError = exports.GatewayTimeoutError = exports.ServiceUnavailableError = exports.BadGatewayError = exports.InternalServerError = exports.RateLimitError = exports.UnprocessableEntityError = exports.ConflictError = exports.NotFoundError = exports.ForbiddenError = exports.UnauthorizedError = exports.BadRequestError = exports.handleApiError = exports.CMSAPIError = void 0;
|
|
4
|
-
// Re-export base error
|
|
4
|
+
// Re-export base error and handler for convenience
|
|
5
5
|
var base_1 = require("./base");
|
|
6
6
|
Object.defineProperty(exports, "CMSAPIError", { enumerable: true, get: function () { return base_1.CMSAPIError; } });
|
|
7
7
|
var errors_1 = require("../errors");
|
package/dist/src/errors.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { CMSAPIError } from "./errors/base";
|
|
2
2
|
export { CMSAPIError };
|
|
3
|
-
export { BadRequestError, UnauthorizedError, ForbiddenError, NotFoundError, ConflictError, UnprocessableEntityError, RateLimitError, InternalServerError, BadGatewayError, ServiceUnavailableError, GatewayTimeoutError, createSpecificError, } from "./errors/
|
|
3
|
+
export { BadRequestError, UnauthorizedError, ForbiddenError, NotFoundError, ConflictError, UnprocessableEntityError, RateLimitError, InternalServerError, BadGatewayError, ServiceUnavailableError, GatewayTimeoutError, createSpecificError, } from "./errors/specific";
|
|
4
4
|
/**
|
|
5
|
-
* Parses fetch/network errors into a clean CMSAPIError
|
|
5
|
+
* Parses fetch/network errors into a clean CMSAPIError (or specific subclass)
|
|
6
6
|
* Uses specific error types when possible for better type safety
|
|
7
7
|
*/
|
|
8
|
-
export declare function handleApiError(error:
|
|
8
|
+
export declare function handleApiError(error: unknown, request?: unknown, response?: unknown): never;
|
package/dist/src/errors.js
CHANGED
|
@@ -5,64 +5,74 @@ exports.handleApiError = handleApiError;
|
|
|
5
5
|
// src/errors.ts
|
|
6
6
|
const base_1 = require("./errors/base");
|
|
7
7
|
Object.defineProperty(exports, "CMSAPIError", { enumerable: true, get: function () { return base_1.CMSAPIError; } });
|
|
8
|
+
const specific_1 = require("./errors/specific");
|
|
8
9
|
// Re-export specific error types
|
|
9
|
-
var
|
|
10
|
-
Object.defineProperty(exports, "BadRequestError", { enumerable: true, get: function () { return
|
|
11
|
-
Object.defineProperty(exports, "UnauthorizedError", { enumerable: true, get: function () { return
|
|
12
|
-
Object.defineProperty(exports, "ForbiddenError", { enumerable: true, get: function () { return
|
|
13
|
-
Object.defineProperty(exports, "NotFoundError", { enumerable: true, get: function () { return
|
|
14
|
-
Object.defineProperty(exports, "ConflictError", { enumerable: true, get: function () { return
|
|
15
|
-
Object.defineProperty(exports, "UnprocessableEntityError", { enumerable: true, get: function () { return
|
|
16
|
-
Object.defineProperty(exports, "RateLimitError", { enumerable: true, get: function () { return
|
|
17
|
-
Object.defineProperty(exports, "InternalServerError", { enumerable: true, get: function () { return
|
|
18
|
-
Object.defineProperty(exports, "BadGatewayError", { enumerable: true, get: function () { return
|
|
19
|
-
Object.defineProperty(exports, "ServiceUnavailableError", { enumerable: true, get: function () { return
|
|
20
|
-
Object.defineProperty(exports, "GatewayTimeoutError", { enumerable: true, get: function () { return
|
|
21
|
-
Object.defineProperty(exports, "createSpecificError", { enumerable: true, get: function () { return
|
|
10
|
+
var specific_2 = require("./errors/specific");
|
|
11
|
+
Object.defineProperty(exports, "BadRequestError", { enumerable: true, get: function () { return specific_2.BadRequestError; } });
|
|
12
|
+
Object.defineProperty(exports, "UnauthorizedError", { enumerable: true, get: function () { return specific_2.UnauthorizedError; } });
|
|
13
|
+
Object.defineProperty(exports, "ForbiddenError", { enumerable: true, get: function () { return specific_2.ForbiddenError; } });
|
|
14
|
+
Object.defineProperty(exports, "NotFoundError", { enumerable: true, get: function () { return specific_2.NotFoundError; } });
|
|
15
|
+
Object.defineProperty(exports, "ConflictError", { enumerable: true, get: function () { return specific_2.ConflictError; } });
|
|
16
|
+
Object.defineProperty(exports, "UnprocessableEntityError", { enumerable: true, get: function () { return specific_2.UnprocessableEntityError; } });
|
|
17
|
+
Object.defineProperty(exports, "RateLimitError", { enumerable: true, get: function () { return specific_2.RateLimitError; } });
|
|
18
|
+
Object.defineProperty(exports, "InternalServerError", { enumerable: true, get: function () { return specific_2.InternalServerError; } });
|
|
19
|
+
Object.defineProperty(exports, "BadGatewayError", { enumerable: true, get: function () { return specific_2.BadGatewayError; } });
|
|
20
|
+
Object.defineProperty(exports, "ServiceUnavailableError", { enumerable: true, get: function () { return specific_2.ServiceUnavailableError; } });
|
|
21
|
+
Object.defineProperty(exports, "GatewayTimeoutError", { enumerable: true, get: function () { return specific_2.GatewayTimeoutError; } });
|
|
22
|
+
Object.defineProperty(exports, "createSpecificError", { enumerable: true, get: function () { return specific_2.createSpecificError; } });
|
|
22
23
|
/**
|
|
23
|
-
* Parses fetch/network errors into a clean CMSAPIError
|
|
24
|
+
* Parses fetch/network errors into a clean CMSAPIError (or specific subclass)
|
|
24
25
|
* Uses specific error types when possible for better type safety
|
|
25
26
|
*/
|
|
26
27
|
function handleApiError(error, request, response) {
|
|
27
|
-
var _a, _b, _c;
|
|
28
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
29
|
+
if (error instanceof base_1.CMSAPIError) {
|
|
30
|
+
throw error; // preserve original error metadata/type
|
|
31
|
+
}
|
|
28
32
|
const sanitizeRequest = (req) => {
|
|
29
33
|
if (!req || typeof req !== "object")
|
|
30
34
|
return undefined;
|
|
35
|
+
const r = req;
|
|
31
36
|
return {
|
|
32
|
-
url:
|
|
33
|
-
method:
|
|
37
|
+
url: typeof r.url === "string" ? r.url : undefined,
|
|
38
|
+
method: typeof r.method === "string" ? r.method : undefined,
|
|
39
|
+
timeout: typeof r.timeout === "number" ? r.timeout : undefined,
|
|
40
|
+
headers: typeof r.headers === "object" && r.headers !== null
|
|
41
|
+
? r.headers
|
|
42
|
+
: undefined,
|
|
34
43
|
};
|
|
35
44
|
};
|
|
36
45
|
// Error with response from server
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
const errorWithResponse = (_a = error === null || error === void 0 ? void 0 : error.response) !== null && _a !== void 0 ? _a : response;
|
|
47
|
+
if (errorWithResponse) {
|
|
48
|
+
const res = errorWithResponse;
|
|
49
|
+
const statusCode = (_c = (_b = res.status) !== null && _b !== void 0 ? _b : res.statusCode) !== null && _c !== void 0 ? _c : 500;
|
|
50
|
+
const message = (_f = (_e = (_d = res.data) === null || _d === void 0 ? void 0 : _d.message) !== null && _e !== void 0 ? _e : res.statusText) !== null && _f !== void 0 ? _f : "Unknown API Error";
|
|
51
|
+
// Prefer typed error subclasses when possible
|
|
52
|
+
const typedError = (0, specific_1.createSpecificError)(statusCode, `CMS API Error: ${statusCode} - ${message}`, (_g = res.data) !== null && _g !== void 0 ? _g : error);
|
|
53
|
+
typedError.request = sanitizeRequest(request !== null && request !== void 0 ? request : error === null || error === void 0 ? void 0 : error.request);
|
|
54
|
+
typedError.response = {
|
|
45
55
|
status: statusCode,
|
|
46
56
|
statusText: res.statusText || "",
|
|
47
57
|
data: res.data,
|
|
48
58
|
headers: res.headers,
|
|
49
|
-
}
|
|
50
|
-
throw
|
|
59
|
+
};
|
|
60
|
+
throw typedError;
|
|
51
61
|
}
|
|
52
62
|
// Error where request was made but no response received
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
63
|
+
const errorWithRequest = (_h = error === null || error === void 0 ? void 0 : error.request) !== null && _h !== void 0 ? _h : request;
|
|
64
|
+
if (errorWithRequest) {
|
|
65
|
+
const req = sanitizeRequest(errorWithRequest);
|
|
66
|
+
const isTimeout = (error === null || error === void 0 ? void 0 : error.code) === "ECONNABORTED" ||
|
|
67
|
+
(typeof (error === null || error === void 0 ? void 0 : error.message) === "string" &&
|
|
68
|
+
error.message.toLowerCase().includes("timeout"));
|
|
58
69
|
if (isTimeout) {
|
|
59
70
|
throw new base_1.CMSAPIError("Timeout Error: CMS API did not respond in time.", 0, "timeout_error", error, req);
|
|
60
71
|
}
|
|
61
72
|
throw new base_1.CMSAPIError("Network Error: No response received from CMS API. Please check your internet connection.", 0, "network_error", error, req);
|
|
62
73
|
}
|
|
63
74
|
// Fallback: unexpected or non-network error
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
: "Unexpected client error while calling CMS API.";
|
|
75
|
+
const errMessage = typeof (error === null || error === void 0 ? void 0 : error.message) === "string" ? error.message : undefined;
|
|
76
|
+
const message = errMessage !== null && errMessage !== void 0 ? errMessage : "Unexpected client error while calling CMS API.";
|
|
67
77
|
throw new base_1.CMSAPIError(`Client Error: ${message}`, -1, "client_error", error);
|
|
68
78
|
}
|
|
@@ -1,28 +1,74 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CMS API
|
|
3
|
-
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
|
4
|
-
*
|
|
5
|
-
* The version of the OpenAPI document: 1.0.0
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
|
9
|
-
* https://openapi-generator.tech
|
|
10
|
-
* Do not edit the class manually.
|
|
11
|
-
*/
|
|
12
1
|
import type { Configuration } from './configuration';
|
|
13
2
|
import type { RequestArgs, RequestOptions } from './base';
|
|
14
3
|
import { BaseAPI } from './base';
|
|
15
|
-
export
|
|
4
|
+
export type TrackLeadRequest = {
|
|
16
5
|
/**
|
|
17
|
-
* The `
|
|
6
|
+
* The `cms_id` from the cookie.
|
|
18
7
|
*/
|
|
19
8
|
'clickId': string;
|
|
20
9
|
'eventName': string;
|
|
21
10
|
/**
|
|
22
|
-
* Unique User ID.
|
|
11
|
+
* Unique User ID. Used for deduplication (user cannot signup twice).
|
|
23
12
|
*/
|
|
24
13
|
'customerId': string;
|
|
25
|
-
|
|
14
|
+
/**
|
|
15
|
+
* When set to `"deferred"`, the API may associate `clickId` to `customerId`
|
|
16
|
+
* for later attribution.
|
|
17
|
+
*/
|
|
18
|
+
'mode'?: 'deferred';
|
|
19
|
+
/**
|
|
20
|
+
* Optional event timestamp in ISO 8601 format.
|
|
21
|
+
*/
|
|
22
|
+
'timestamp'?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Optional external customer identifier used in your system.
|
|
25
|
+
*/
|
|
26
|
+
'customerExternalId'?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Optional customer display name.
|
|
29
|
+
*/
|
|
30
|
+
'customerName'?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Optional customer email address.
|
|
33
|
+
*/
|
|
34
|
+
'customerEmail'?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Optional URL to a customer avatar image.
|
|
37
|
+
*/
|
|
38
|
+
'customerAvatar'?: string;
|
|
39
|
+
} | {
|
|
40
|
+
/**
|
|
41
|
+
* In deferred mode, a follow-up call can omit `clickId` and only provide
|
|
42
|
+
* `customerId` (and `eventName`) to attribute using the stored association.
|
|
43
|
+
*/
|
|
44
|
+
'clickId'?: never;
|
|
45
|
+
'eventName': string;
|
|
46
|
+
/**
|
|
47
|
+
* Unique User ID. Used for deduplication (user cannot signup twice).
|
|
48
|
+
*/
|
|
49
|
+
'customerId': string;
|
|
50
|
+
'mode': 'deferred';
|
|
51
|
+
/**
|
|
52
|
+
* Optional event timestamp in ISO 8601 format.
|
|
53
|
+
*/
|
|
54
|
+
'timestamp'?: string;
|
|
55
|
+
/**
|
|
56
|
+
* Optional external customer identifier used in your system.
|
|
57
|
+
*/
|
|
58
|
+
'customerExternalId'?: string;
|
|
59
|
+
/**
|
|
60
|
+
* Optional customer display name.
|
|
61
|
+
*/
|
|
62
|
+
'customerName'?: string;
|
|
63
|
+
/**
|
|
64
|
+
* Optional customer email address.
|
|
65
|
+
*/
|
|
66
|
+
'customerEmail'?: string;
|
|
67
|
+
/**
|
|
68
|
+
* Optional URL to a customer avatar image.
|
|
69
|
+
*/
|
|
70
|
+
'customerAvatar'?: string;
|
|
71
|
+
};
|
|
26
72
|
export interface TrackResponse {
|
|
27
73
|
'status'?: string;
|
|
28
74
|
}
|
|
@@ -33,7 +79,27 @@ export interface TrackSaleRequest {
|
|
|
33
79
|
'clickId': string;
|
|
34
80
|
'eventName': string;
|
|
35
81
|
/**
|
|
36
|
-
*
|
|
82
|
+
* Optional event timestamp in ISO 8601 format.
|
|
83
|
+
*/
|
|
84
|
+
'timestamp'?: string;
|
|
85
|
+
/**
|
|
86
|
+
* Optional external customer identifier used in your system.
|
|
87
|
+
*/
|
|
88
|
+
'customerExternalId'?: string;
|
|
89
|
+
/**
|
|
90
|
+
* Optional customer display name.
|
|
91
|
+
*/
|
|
92
|
+
'customerName'?: string;
|
|
93
|
+
/**
|
|
94
|
+
* Optional customer email address.
|
|
95
|
+
*/
|
|
96
|
+
'customerEmail'?: string;
|
|
97
|
+
/**
|
|
98
|
+
* Optional URL to a customer avatar image.
|
|
99
|
+
*/
|
|
100
|
+
'customerAvatar'?: string;
|
|
101
|
+
/**
|
|
102
|
+
* Unique Transaction ID. Used for deduplication (charge cannot happen twice).
|
|
37
103
|
*/
|
|
38
104
|
'invoiceId': string;
|
|
39
105
|
/**
|
|
@@ -1,21 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/* tslint:disable */
|
|
3
|
-
/* eslint-disable */
|
|
4
|
-
/**
|
|
5
|
-
* CMS API
|
|
6
|
-
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
|
7
|
-
*
|
|
8
|
-
* The version of the OpenAPI document: 1.0.0
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
|
12
|
-
* https://openapi-generator.tech
|
|
13
|
-
* Do not edit the class manually.
|
|
14
|
-
*/
|
|
15
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
3
|
exports.EventsApi = exports.EventsApiFactory = exports.EventsApiFp = exports.EventsApiAxiosParamCreator = void 0;
|
|
17
|
-
// Some imports not used depending on template conditions
|
|
18
|
-
// @ts-ignore
|
|
19
4
|
const common_1 = require("./common");
|
|
20
5
|
// @ts-ignore
|
|
21
6
|
const base_1 = require("./base");
|
|
@@ -34,9 +19,7 @@ const EventsApiAxiosParamCreator = function (configuration) {
|
|
|
34
19
|
trackLead: async (trackLeadRequest, options = {}) => {
|
|
35
20
|
// verify required parameter 'trackLeadRequest' is not null or undefined
|
|
36
21
|
(0, common_1.assertParamExists)('trackLead', 'trackLeadRequest', trackLeadRequest);
|
|
37
|
-
|
|
38
|
-
// so we do not append any additional path segments here.
|
|
39
|
-
const localVarPath = ``;
|
|
22
|
+
const localVarPath = `/track/lead`;
|
|
40
23
|
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
|
41
24
|
const localVarUrlObj = new URL(localVarPath, common_1.DUMMY_BASE_URL);
|
|
42
25
|
let baseOptions;
|
|
@@ -70,9 +53,7 @@ const EventsApiAxiosParamCreator = function (configuration) {
|
|
|
70
53
|
trackSale: async (trackSaleRequest, options = {}) => {
|
|
71
54
|
// verify required parameter 'trackSaleRequest' is not null or undefined
|
|
72
55
|
(0, common_1.assertParamExists)('trackSale', 'trackSaleRequest', trackSaleRequest);
|
|
73
|
-
|
|
74
|
-
// so we do not append any additional path segments here.
|
|
75
|
-
const localVarPath = ``;
|
|
56
|
+
const localVarPath = `/track/sale`;
|
|
76
57
|
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
|
77
58
|
const localVarUrlObj = new URL(localVarPath, common_1.DUMMY_BASE_URL);
|
|
78
59
|
let baseOptions;
|
|
@@ -200,7 +181,6 @@ exports.EventsApi = EventsApi;
|
|
|
200
181
|
* operate without changes.
|
|
201
182
|
*/
|
|
202
183
|
async function performFetchRequest(requestArgs, basePath) {
|
|
203
|
-
var _a;
|
|
204
184
|
const url = (basePath !== null && basePath !== void 0 ? basePath : base_1.BASE_PATH).replace(/\/+$/, "") + requestArgs.url;
|
|
205
185
|
const { timeout, data, ...restOptions } = requestArgs.options;
|
|
206
186
|
if (typeof fetch !== "function") {
|
|
@@ -217,10 +197,25 @@ async function performFetchRequest(requestArgs, basePath) {
|
|
|
217
197
|
// The generated client stores the request payload on `data` (Axios-style),
|
|
218
198
|
// but the fetch API expects it on `body`. Translate between the two.
|
|
219
199
|
if (typeof data !== "undefined") {
|
|
220
|
-
const
|
|
221
|
-
|
|
200
|
+
const rawHeaders = fetchOptions.headers;
|
|
201
|
+
let headers = {};
|
|
202
|
+
if (rawHeaders instanceof Headers) {
|
|
203
|
+
rawHeaders.forEach((value, key) => {
|
|
204
|
+
headers[key] = value;
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
else if (Array.isArray(rawHeaders)) {
|
|
208
|
+
headers = Object.fromEntries(rawHeaders.map(([key, value]) => [String(key), String(value)]));
|
|
209
|
+
}
|
|
210
|
+
else if (rawHeaders && typeof rawHeaders === "object") {
|
|
211
|
+
headers = Object.fromEntries(Object.entries(rawHeaders).map(([key, value]) => [key, String(value)]));
|
|
212
|
+
}
|
|
213
|
+
const requestContentTypeHeader = Object.keys(headers).find((h) => h.toLowerCase() === "content-type");
|
|
214
|
+
const requestContentType = requestContentTypeHeader
|
|
215
|
+
? headers[requestContentTypeHeader]
|
|
216
|
+
: undefined;
|
|
222
217
|
// If Content-Type is JSON (our default), ensure the body is a JSON string.
|
|
223
|
-
if (requestContentType
|
|
218
|
+
if (requestContentType === null || requestContentType === void 0 ? void 0 : requestContentType.toLowerCase().includes("application/json")) {
|
|
224
219
|
fetchOptions.body =
|
|
225
220
|
typeof data === "string" ? data : JSON.stringify(data);
|
|
226
221
|
}
|
|
@@ -231,13 +226,32 @@ async function performFetchRequest(requestArgs, basePath) {
|
|
|
231
226
|
const response = await fetch(url, fetchOptions);
|
|
232
227
|
const responseContentType = response.headers.get("content-type") || "";
|
|
233
228
|
const isJson = responseContentType.toLowerCase().includes("application/json");
|
|
234
|
-
|
|
229
|
+
let dataResult = null;
|
|
230
|
+
if (response.status !== 204 && response.status !== 205) {
|
|
231
|
+
const responseText = await response.text();
|
|
232
|
+
if (isJson && responseText) {
|
|
233
|
+
try {
|
|
234
|
+
dataResult = JSON.parse(responseText);
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
dataResult = responseText;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
dataResult = responseText;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
235
244
|
if (!response.ok) {
|
|
245
|
+
const responseHeaders = {};
|
|
246
|
+
response.headers.forEach((value, key) => {
|
|
247
|
+
responseHeaders[key] = value;
|
|
248
|
+
});
|
|
236
249
|
const error = new Error(`Request failed with status code ${response.status}`);
|
|
237
250
|
error.response = {
|
|
238
251
|
status: response.status,
|
|
239
252
|
statusText: response.statusText,
|
|
240
253
|
data: dataResult,
|
|
254
|
+
headers: responseHeaders,
|
|
241
255
|
};
|
|
242
256
|
throw error;
|
|
243
257
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.operationServerMap = exports.RequiredError = exports.BaseAPI = exports.COLLECTION_FORMATS = exports.BASE_PATH = void 0;
|
|
4
|
-
exports.BASE_PATH = "https://www.cutmeshort.com
|
|
4
|
+
exports.BASE_PATH = "https://www.cutmeshort.com".replace(/\/+$/, "");
|
|
5
5
|
exports.COLLECTION_FORMATS = {
|
|
6
6
|
csv: ",",
|
|
7
7
|
ssv: " ",
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,6 +1,2 @@
|
|
|
1
|
-
export { CMS
|
|
2
|
-
export { CMSAPIError
|
|
3
|
-
export * from "./errors/index";
|
|
4
|
-
export { trackLead, trackSale, type TrackLeadError, type TrackSaleError } from "./funcs";
|
|
5
|
-
export { ok, err, type Result } from "./types/result";
|
|
6
|
-
export type { TrackLeadRequest, TrackSaleRequest, TrackResponse, } from "./generated/api";
|
|
1
|
+
export { CMS } from "./client";
|
|
2
|
+
export { CMSAPIError } from "./errors";
|
package/dist/src/index.js
CHANGED
|
@@ -1,34 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// src/index.ts
|
|
3
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
-
if (k2 === undefined) k2 = k;
|
|
5
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
-
}
|
|
9
|
-
Object.defineProperty(o, k2, desc);
|
|
10
|
-
}) : (function(o, m, k, k2) {
|
|
11
|
-
if (k2 === undefined) k2 = k;
|
|
12
|
-
o[k2] = m[k];
|
|
13
|
-
}));
|
|
14
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
15
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
16
|
-
};
|
|
17
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
-
exports.
|
|
19
|
-
// Main client
|
|
3
|
+
exports.CMSAPIError = exports.CMS = void 0;
|
|
20
4
|
var client_1 = require("./client");
|
|
21
5
|
Object.defineProperty(exports, "CMS", { enumerable: true, get: function () { return client_1.CMS; } });
|
|
22
|
-
// Errors
|
|
23
6
|
var errors_1 = require("./errors");
|
|
24
7
|
Object.defineProperty(exports, "CMSAPIError", { enumerable: true, get: function () { return errors_1.CMSAPIError; } });
|
|
25
|
-
Object.defineProperty(exports, "handleApiError", { enumerable: true, get: function () { return errors_1.handleApiError; } });
|
|
26
|
-
__exportStar(require("./errors/index"), exports);
|
|
27
|
-
// Functional helpers (Result pattern)
|
|
28
|
-
var funcs_1 = require("./funcs");
|
|
29
|
-
Object.defineProperty(exports, "trackLead", { enumerable: true, get: function () { return funcs_1.trackLead; } });
|
|
30
|
-
Object.defineProperty(exports, "trackSale", { enumerable: true, get: function () { return funcs_1.trackSale; } });
|
|
31
|
-
// Result type utilities
|
|
32
|
-
var result_1 = require("./types/result");
|
|
33
|
-
Object.defineProperty(exports, "ok", { enumerable: true, get: function () { return result_1.ok; } });
|
|
34
|
-
Object.defineProperty(exports, "err", { enumerable: true, get: function () { return result_1.err; } });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vigneshreddy/cms-sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
4
4
|
"description": "Official TypeScript SDK for CutMeShort CMS API",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"types": "dist/src/index.d.ts",
|
|
@@ -10,21 +10,6 @@
|
|
|
10
10
|
"require": "./dist/src/index.js",
|
|
11
11
|
"import": "./dist/src/index.js",
|
|
12
12
|
"types": "./dist/src/index.d.ts"
|
|
13
|
-
},
|
|
14
|
-
"./client": {
|
|
15
|
-
"require": "./dist/src/client.js",
|
|
16
|
-
"import": "./dist/src/client.js",
|
|
17
|
-
"types": "./dist/src/client.d.ts"
|
|
18
|
-
},
|
|
19
|
-
"./errors": {
|
|
20
|
-
"require": "./dist/src/errors/index.js",
|
|
21
|
-
"import": "./dist/src/errors/index.js",
|
|
22
|
-
"types": "./dist/src/errors/index.d.ts"
|
|
23
|
-
},
|
|
24
|
-
"./funcs": {
|
|
25
|
-
"require": "./dist/src/funcs/index.js",
|
|
26
|
-
"import": "./dist/src/funcs/index.js",
|
|
27
|
-
"types": "./dist/src/funcs/index.d.ts"
|
|
28
13
|
}
|
|
29
14
|
},
|
|
30
15
|
"files": [
|
|
@@ -43,9 +28,15 @@
|
|
|
43
28
|
],
|
|
44
29
|
"repository": {
|
|
45
30
|
"type": "git",
|
|
46
|
-
"url": "https://github.com/
|
|
31
|
+
"url": "https://github.com/vigneshreddy/cms-sdk.git"
|
|
32
|
+
},
|
|
33
|
+
"homepage": "https://github.com/vigneshreddy/cms-sdk#readme",
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://github.com/vigneshreddy/cms-sdk/issues"
|
|
36
|
+
},
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=18"
|
|
47
39
|
},
|
|
48
|
-
"homepage": "https://github.com/YOUR_USERNAME/cms-sdk#readme",
|
|
49
40
|
"publishConfig": {
|
|
50
41
|
"access": "public"
|
|
51
42
|
},
|
package/dist/src/funcs/index.js
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.trackSale = exports.trackLead = void 0;
|
|
4
|
-
var trackLead_1 = require("./trackLead");
|
|
5
|
-
Object.defineProperty(exports, "trackLead", { enumerable: true, get: function () { return trackLead_1.trackLead; } });
|
|
6
|
-
var trackSale_1 = require("./trackSale");
|
|
7
|
-
Object.defineProperty(exports, "trackSale", { enumerable: true, get: function () { return trackSale_1.trackSale; } });
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { CMS, type LeadPayload } from "../client";
|
|
2
|
-
import type { TrackResponse } from "../generated/api";
|
|
3
|
-
import { Result } from "../types/result";
|
|
4
|
-
import { CMSAPIError, BadRequestError, UnauthorizedError, ForbiddenError, NotFoundError, ConflictError, UnprocessableEntityError, RateLimitError, InternalServerError, BadGatewayError, ServiceUnavailableError, GatewayTimeoutError } from "../errors";
|
|
5
|
-
export type TrackLeadError = BadRequestError | UnauthorizedError | ForbiddenError | NotFoundError | ConflictError | UnprocessableEntityError | RateLimitError | InternalServerError | BadGatewayError | ServiceUnavailableError | GatewayTimeoutError | CMSAPIError;
|
|
6
|
-
/**
|
|
7
|
-
* Track a lead for a short link.
|
|
8
|
-
*
|
|
9
|
-
* Functional helper that returns a Result instead of throwing.
|
|
10
|
-
* This allows for explicit error handling without try/catch.
|
|
11
|
-
*
|
|
12
|
-
* This helper automatically wraps the user-provided data so that the
|
|
13
|
-
* underlying SDK receives:
|
|
14
|
-
*
|
|
15
|
-
* {
|
|
16
|
-
* type: "lead",
|
|
17
|
-
* lead: { ...userData }
|
|
18
|
-
* }
|
|
19
|
-
*
|
|
20
|
-
* @param client - The CMSSDK instance
|
|
21
|
-
* @param leadData - Arbitrary user-provided lead data
|
|
22
|
-
* @returns A Result containing either the TrackResponse or an error
|
|
23
|
-
*
|
|
24
|
-
* @example
|
|
25
|
-
* ```ts
|
|
26
|
-
* import { CMS } from "cms/client";
|
|
27
|
-
* import { trackLead } from "cms/funcs/trackLead";
|
|
28
|
-
*
|
|
29
|
-
* const sdk = new CMS({ apiKey: "sk_test_123" });
|
|
30
|
-
*
|
|
31
|
-
* const res = await trackLead(sdk, {
|
|
32
|
-
* clickId: "dub_123",
|
|
33
|
-
* eventName: "signup_started",
|
|
34
|
-
* customerId: "user_42",
|
|
35
|
-
* });
|
|
36
|
-
*
|
|
37
|
-
* if (res.ok) {
|
|
38
|
-
* console.log("Success:", res.value);
|
|
39
|
-
* } else {
|
|
40
|
-
* console.error("Error:", res.error);
|
|
41
|
-
* }
|
|
42
|
-
* ```
|
|
43
|
-
*/
|
|
44
|
-
export declare function trackLead(client: CMS, leadData: LeadPayload): Promise<Result<TrackResponse, TrackLeadError>>;
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.trackLead = trackLead;
|
|
4
|
-
const result_1 = require("../types/result");
|
|
5
|
-
const errors_1 = require("../errors");
|
|
6
|
-
/**
|
|
7
|
-
* Track a lead for a short link.
|
|
8
|
-
*
|
|
9
|
-
* Functional helper that returns a Result instead of throwing.
|
|
10
|
-
* This allows for explicit error handling without try/catch.
|
|
11
|
-
*
|
|
12
|
-
* This helper automatically wraps the user-provided data so that the
|
|
13
|
-
* underlying SDK receives:
|
|
14
|
-
*
|
|
15
|
-
* {
|
|
16
|
-
* type: "lead",
|
|
17
|
-
* lead: { ...userData }
|
|
18
|
-
* }
|
|
19
|
-
*
|
|
20
|
-
* @param client - The CMSSDK instance
|
|
21
|
-
* @param leadData - Arbitrary user-provided lead data
|
|
22
|
-
* @returns A Result containing either the TrackResponse or an error
|
|
23
|
-
*
|
|
24
|
-
* @example
|
|
25
|
-
* ```ts
|
|
26
|
-
* import { CMS } from "cms/client";
|
|
27
|
-
* import { trackLead } from "cms/funcs/trackLead";
|
|
28
|
-
*
|
|
29
|
-
* const sdk = new CMS({ apiKey: "sk_test_123" });
|
|
30
|
-
*
|
|
31
|
-
* const res = await trackLead(sdk, {
|
|
32
|
-
* clickId: "dub_123",
|
|
33
|
-
* eventName: "signup_started",
|
|
34
|
-
* customerId: "user_42",
|
|
35
|
-
* });
|
|
36
|
-
*
|
|
37
|
-
* if (res.ok) {
|
|
38
|
-
* console.log("Success:", res.value);
|
|
39
|
-
* } else {
|
|
40
|
-
* console.error("Error:", res.error);
|
|
41
|
-
* }
|
|
42
|
-
* ```
|
|
43
|
-
*/
|
|
44
|
-
async function trackLead(client, leadData) {
|
|
45
|
-
try {
|
|
46
|
-
const value = await client.trackLead(leadData);
|
|
47
|
-
return (0, result_1.ok)(value);
|
|
48
|
-
}
|
|
49
|
-
catch (error) {
|
|
50
|
-
if (error instanceof errors_1.CMSAPIError) {
|
|
51
|
-
return (0, result_1.err)(error);
|
|
52
|
-
}
|
|
53
|
-
return (0, result_1.err)(new errors_1.CMSAPIError(error instanceof Error ? error.message : "Unknown error", -1, "client_error", error));
|
|
54
|
-
}
|
|
55
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { CMS, type SalePayload } from "../client";
|
|
2
|
-
import type { TrackResponse } from "../generated/api";
|
|
3
|
-
import { Result } from "../types/result";
|
|
4
|
-
import { CMSAPIError, BadRequestError, UnauthorizedError, ForbiddenError, NotFoundError, ConflictError, UnprocessableEntityError, RateLimitError, InternalServerError, BadGatewayError, ServiceUnavailableError, GatewayTimeoutError } from "../errors";
|
|
5
|
-
export type TrackSaleError = BadRequestError | UnauthorizedError | ForbiddenError | NotFoundError | ConflictError | UnprocessableEntityError | RateLimitError | InternalServerError | BadGatewayError | ServiceUnavailableError | GatewayTimeoutError | CMSAPIError;
|
|
6
|
-
/**
|
|
7
|
-
* Track a sale for a short link.
|
|
8
|
-
*
|
|
9
|
-
* Functional helper that returns a Result instead of throwing.
|
|
10
|
-
* This allows for explicit error handling without try/catch.
|
|
11
|
-
*
|
|
12
|
-
* This helper automatically wraps the user-provided data so that the
|
|
13
|
-
* underlying SDK receives:
|
|
14
|
-
*
|
|
15
|
-
* {
|
|
16
|
-
* type: "sale",
|
|
17
|
-
* sale: { ...userData }
|
|
18
|
-
* }
|
|
19
|
-
*
|
|
20
|
-
* @param client - The CMSSDK instance
|
|
21
|
-
* @param saleData - Arbitrary user-provided sale data
|
|
22
|
-
* @returns A Result containing either the TrackResponse or an error
|
|
23
|
-
*
|
|
24
|
-
* @example
|
|
25
|
-
* ```ts
|
|
26
|
-
* import { CMS } from "cms/client";
|
|
27
|
-
* import { trackSale } from "cms/funcs/trackSale";
|
|
28
|
-
*
|
|
29
|
-
* const sdk = new CMS({ apiKey: "sk_test_123" });
|
|
30
|
-
*
|
|
31
|
-
* const res = await trackSale(sdk, {
|
|
32
|
-
* clickId: "dub_123",
|
|
33
|
-
* eventName: "purchase_completed",
|
|
34
|
-
* invoiceId: "inv_987",
|
|
35
|
-
* amount: 4999,
|
|
36
|
-
* currency: "USD",
|
|
37
|
-
* });
|
|
38
|
-
*
|
|
39
|
-
* if (res.ok) {
|
|
40
|
-
* console.log("Success:", res.value);
|
|
41
|
-
* } else {
|
|
42
|
-
* console.error("Error:", res.error);
|
|
43
|
-
* }
|
|
44
|
-
* ```
|
|
45
|
-
*/
|
|
46
|
-
export declare function trackSale(client: CMS, saleData: SalePayload): Promise<Result<TrackResponse, TrackSaleError>>;
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.trackSale = trackSale;
|
|
4
|
-
const result_1 = require("../types/result");
|
|
5
|
-
const errors_1 = require("../errors");
|
|
6
|
-
/**
|
|
7
|
-
* Track a sale for a short link.
|
|
8
|
-
*
|
|
9
|
-
* Functional helper that returns a Result instead of throwing.
|
|
10
|
-
* This allows for explicit error handling without try/catch.
|
|
11
|
-
*
|
|
12
|
-
* This helper automatically wraps the user-provided data so that the
|
|
13
|
-
* underlying SDK receives:
|
|
14
|
-
*
|
|
15
|
-
* {
|
|
16
|
-
* type: "sale",
|
|
17
|
-
* sale: { ...userData }
|
|
18
|
-
* }
|
|
19
|
-
*
|
|
20
|
-
* @param client - The CMSSDK instance
|
|
21
|
-
* @param saleData - Arbitrary user-provided sale data
|
|
22
|
-
* @returns A Result containing either the TrackResponse or an error
|
|
23
|
-
*
|
|
24
|
-
* @example
|
|
25
|
-
* ```ts
|
|
26
|
-
* import { CMS } from "cms/client";
|
|
27
|
-
* import { trackSale } from "cms/funcs/trackSale";
|
|
28
|
-
*
|
|
29
|
-
* const sdk = new CMS({ apiKey: "sk_test_123" });
|
|
30
|
-
*
|
|
31
|
-
* const res = await trackSale(sdk, {
|
|
32
|
-
* clickId: "dub_123",
|
|
33
|
-
* eventName: "purchase_completed",
|
|
34
|
-
* invoiceId: "inv_987",
|
|
35
|
-
* amount: 4999,
|
|
36
|
-
* currency: "USD",
|
|
37
|
-
* });
|
|
38
|
-
*
|
|
39
|
-
* if (res.ok) {
|
|
40
|
-
* console.log("Success:", res.value);
|
|
41
|
-
* } else {
|
|
42
|
-
* console.error("Error:", res.error);
|
|
43
|
-
* }
|
|
44
|
-
* ```
|
|
45
|
-
*/
|
|
46
|
-
async function trackSale(client, saleData) {
|
|
47
|
-
try {
|
|
48
|
-
const value = await client.trackSale(saleData);
|
|
49
|
-
return (0, result_1.ok)(value);
|
|
50
|
-
}
|
|
51
|
-
catch (error) {
|
|
52
|
-
if (error instanceof errors_1.CMSAPIError) {
|
|
53
|
-
return (0, result_1.err)(error);
|
|
54
|
-
}
|
|
55
|
-
return (0, result_1.err)(new errors_1.CMSAPIError(error instanceof Error ? error.message : "Unknown error", -1, "client_error", error));
|
|
56
|
-
}
|
|
57
|
-
}
|