Skip to content

Commit dfe73a4

Browse files
authored
Upgrade to TS6 and remove helpers from mixins (#19)
1 parent 31595a5 commit dfe73a4

20 files changed

+1078
-1051
lines changed

package.json

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -51,26 +51,26 @@
5151
"test:watch": "jest --watch"
5252
},
5353
"dependencies": {
54-
"@t3-oss/env-core": "0.13.8",
55-
"axios": "1.13.2",
56-
"csv-parse": "6.1.0",
57-
"winston": "3.18.3",
58-
"zod": "4.1.11"
54+
"@t3-oss/env-core": "0.13.11",
55+
"axios": "1.13.6",
56+
"csv-parse": "6.2.1",
57+
"winston": "3.19.0",
58+
"zod": "4.3.6"
5959
},
6060
"devDependencies": {
61-
"@eslint/js": "9.39.1",
62-
"@jest/globals": "30.2.0",
63-
"@swc/core": "1.15.2",
61+
"@eslint/js": "10.0.1",
62+
"@jest/globals": "30.3.0",
63+
"@swc/core": "1.15.21",
6464
"@swc/jest": "0.2.39",
6565
"@types/jest": "30.0.0",
66-
"@types/node": "24.10.1",
67-
"@typescript-eslint/eslint-plugin": "8.47.0",
68-
"@typescript-eslint/parser": "8.47.0",
69-
"eslint": "9.39.1",
66+
"@types/node": "25.5.0",
67+
"@typescript-eslint/eslint-plugin": "8.57.2",
68+
"@typescript-eslint/parser": "8.57.2",
69+
"eslint": "10.1.0",
7070
"eslint-plugin-simple-import-sort": "12.1.1",
71-
"jest": "30.2.0",
72-
"prettier": "3.6.2",
73-
"typescript": "5.9.3"
71+
"jest": "30.3.0",
72+
"prettier": "3.8.1",
73+
"typescript": "6.0.2"
7474
},
7575
"sideEffects": false
7676
}

pnpm-lock.yaml

Lines changed: 689 additions & 751 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/client/base.ts

Lines changed: 49 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -32,25 +32,13 @@ export const DEFAULT_USER_AGENT = `iterable-api/${packageJson.version}`;
3232
*/
3333
export class BaseIterableClient {
3434
public client: AxiosInstance;
35-
#httpAgent?: http.Agent;
36-
#httpsAgent?: https.Agent;
3735

3836
constructor(config?: IterableConfig, injectedClient?: AxiosInstance) {
3937
const clientConfig = config || createIterableConfig();
4038

4139
if (injectedClient) {
4240
this.client = injectedClient;
4341
} else {
44-
// Create agents with keepAlive for better performance
45-
this.#httpAgent = new http.Agent({
46-
keepAlive: true,
47-
keepAliveMsecs: 1000,
48-
});
49-
this.#httpsAgent = new https.Agent({
50-
keepAlive: true,
51-
keepAliveMsecs: 1000,
52-
});
53-
5442
const defaultHeaders = {
5543
"Api-Key": clientConfig.apiKey,
5644
"Content-Type": "application/json",
@@ -64,8 +52,14 @@ export class BaseIterableClient {
6452
...(clientConfig.customHeaders || {}),
6553
},
6654
timeout: clientConfig.timeout || 30000,
67-
httpAgent: this.#httpAgent,
68-
httpsAgent: this.#httpsAgent,
55+
httpAgent: new http.Agent({
56+
keepAlive: true,
57+
keepAliveMsecs: 1000,
58+
}),
59+
httpsAgent: new https.Agent({
60+
keepAlive: true,
61+
keepAliveMsecs: 1000,
62+
}),
6963
maxRedirects: 5,
7064
});
7165
}
@@ -140,86 +134,55 @@ export class BaseIterableClient {
140134
}
141135

142136
/**
143-
* Parse NDJSON (newline-delimited JSON) response into an array of objects
137+
* Clean up HTTP agents to prevent Jest from hanging
138+
* Should be called when the client is no longer needed
144139
*/
145-
public parseNdjson(data: string): any[] {
146-
if (!data) {
147-
return [];
148-
}
149-
150-
const lines = data.trim().split("\n");
151-
const results: any[] = [];
152-
153-
for (const line of lines) {
154-
const trimmedLine = line.trim();
155-
if (trimmedLine) {
156-
try {
157-
const parsed = JSON.parse(trimmedLine);
158-
results.push(parsed);
159-
} catch (error) {
160-
// Skip invalid JSON lines but log them
161-
logger.warn("Failed to parse NDJSON line", {
162-
line: trimmedLine,
163-
error: error instanceof Error ? error.message : String(error),
164-
});
165-
}
166-
}
167-
}
168-
169-
return results;
140+
public destroy(): void {
141+
this.client.defaults.httpAgent?.destroy();
142+
this.client.defaults.httpsAgent?.destroy();
170143
}
144+
}
171145

172-
/**
173-
* Parse CSV response into an array of objects using csv-parse library
174-
* @throws IterableResponseValidationError if CSV parsing fails
175-
*/
176-
public parseCsv(response: AxiosResponse<string>): Record<string, string>[] {
177-
if (!response.data) {
178-
return [];
179-
}
180-
181-
try {
182-
return csvParse(response.data, {
183-
columns: true, // Use first line as headers
184-
skip_empty_lines: true,
185-
trim: true,
186-
});
187-
} catch (error) {
188-
// Throw validation error to maintain consistent error handling
189-
// This allows callers to handle parse failures appropriately
190-
throw new IterableResponseValidationError(
191-
200,
192-
response.data,
193-
`CSV parse error: ${error instanceof Error ? error.message : String(error)}`,
194-
response.config?.url
195-
);
196-
}
146+
/**
147+
* @throws IterableResponseValidationError if CSV parsing fails
148+
*/
149+
export function parseCsv(
150+
response: AxiosResponse<string>
151+
): Record<string, string>[] {
152+
if (!response.data) {
153+
return [];
197154
}
198155

199-
public validateResponse<T>(
200-
response: { data: unknown; config?: { url?: string } },
201-
schema: z.ZodSchema<T>
202-
): T {
203-
const result = schema.safeParse(response.data);
204-
if (!result.success) {
205-
throw new IterableResponseValidationError(
206-
200,
207-
response.data,
208-
result.error.message,
209-
response.config?.url
210-
);
211-
}
212-
return result.data;
156+
try {
157+
return csvParse(response.data, {
158+
columns: true,
159+
skip_empty_lines: true,
160+
trim: true,
161+
});
162+
} catch (error) {
163+
throw new IterableResponseValidationError(
164+
200,
165+
response.data,
166+
`CSV parse error: ${error instanceof Error ? error.message : String(error)}`,
167+
response.config?.url
168+
);
213169
}
170+
}
214171

215-
/**
216-
* Clean up HTTP agents to prevent Jest from hanging
217-
* Should be called when the client is no longer needed
218-
*/
219-
public destroy(): void {
220-
this.#httpAgent?.destroy();
221-
this.#httpsAgent?.destroy();
172+
export function validateResponse<T>(
173+
response: { data: unknown; config?: { url?: string } },
174+
schema: z.ZodSchema<T>
175+
): T {
176+
const result = schema.safeParse(response.data);
177+
if (!result.success) {
178+
throw new IterableResponseValidationError(
179+
200,
180+
response.data,
181+
result.error.message,
182+
response.config?.url
183+
);
222184
}
185+
return result.data;
223186
}
224187

225188
// Type helper for mixins

src/client/campaigns.ts

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
IterableSuccessResponseSchema,
3232
} from "../types/common.js";
3333
import type { BaseIterableClient, Constructor } from "./base.js";
34+
import { parseCsv, validateResponse } from "./base.js";
3435

3536
/**
3637
* Campaigns operations mixin
@@ -62,7 +63,7 @@ export function Campaigns<T extends Constructor<BaseIterableClient>>(Base: T) {
6263
url,
6364
opts?.signal ? { signal: opts.signal } : {}
6465
);
65-
return this.validateResponse(response, GetCampaignsResponseSchema);
66+
return validateResponse(response, GetCampaignsResponseSchema);
6667
}
6768

6869
async getCampaign(
@@ -73,7 +74,7 @@ export function Campaigns<T extends Constructor<BaseIterableClient>>(Base: T) {
7374
`/api/campaigns/${params.id}`,
7475
opts?.signal ? { signal: opts.signal } : {}
7576
);
76-
return this.validateResponse(response, GetCampaignResponseSchema);
77+
return validateResponse(response, GetCampaignResponseSchema);
7778
}
7879

7980
async createBlastCampaign(
@@ -83,14 +84,14 @@ export function Campaigns<T extends Constructor<BaseIterableClient>>(Base: T) {
8384
...params,
8485
scheduleSend: false,
8586
});
86-
return this.validateResponse(response, CreateCampaignResponseSchema);
87+
return validateResponse(response, CreateCampaignResponseSchema);
8788
}
8889

8990
async createTriggeredCampaign(
9091
params: CreateTriggeredCampaignParams
9192
): Promise<CreateCampaignResponse> {
9293
const response = await this.client.post("/api/campaigns/create", params);
93-
return this.validateResponse(response, CreateCampaignResponseSchema);
94+
return validateResponse(response, CreateCampaignResponseSchema);
9495
}
9596

9697
async getChildCampaigns(
@@ -118,7 +119,7 @@ export function Campaigns<T extends Constructor<BaseIterableClient>>(Base: T) {
118119
url,
119120
opts?.signal ? { signal: opts.signal } : {}
120121
);
121-
return this.validateResponse(response, GetChildCampaignsResponseSchema);
122+
return validateResponse(response, GetChildCampaignsResponseSchema);
122123
}
123124

124125
async getCampaignMetrics(
@@ -139,7 +140,7 @@ export function Campaigns<T extends Constructor<BaseIterableClient>>(Base: T) {
139140
);
140141

141142
// Parse CSV response into array of objects
142-
return this.parseCsv(response);
143+
return parseCsv(response);
143144
}
144145

145146
async scheduleCampaign(
@@ -150,7 +151,7 @@ export function Campaigns<T extends Constructor<BaseIterableClient>>(Base: T) {
150151
`/api/campaigns/${campaignId}/schedule`,
151152
scheduleParams
152153
);
153-
return this.validateResponse(response, IterableSuccessResponseSchema);
154+
return validateResponse(response, IterableSuccessResponseSchema);
154155
}
155156

156157
/**
@@ -161,7 +162,7 @@ export function Campaigns<T extends Constructor<BaseIterableClient>>(Base: T) {
161162
params: AbortCampaignParams
162163
): Promise<IterableSuccessResponse> {
163164
const response = await this.client.post("/api/campaigns/abort", params);
164-
return this.validateResponse(response, IterableSuccessResponseSchema);
165+
return validateResponse(response, IterableSuccessResponseSchema);
165166
}
166167

167168
/**
@@ -171,7 +172,7 @@ export function Campaigns<T extends Constructor<BaseIterableClient>>(Base: T) {
171172
params: CancelCampaignParams
172173
): Promise<IterableSuccessResponse> {
173174
const response = await this.client.post("/api/campaigns/cancel", params);
174-
return this.validateResponse(response, IterableSuccessResponseSchema);
175+
return validateResponse(response, IterableSuccessResponseSchema);
175176
}
176177

177178
/**
@@ -185,7 +186,7 @@ export function Campaigns<T extends Constructor<BaseIterableClient>>(Base: T) {
185186
"/api/campaigns/activateTriggered",
186187
params
187188
);
188-
return this.validateResponse(response, IterableSuccessResponseSchema);
189+
return validateResponse(response, IterableSuccessResponseSchema);
189190
}
190191

191192
/**
@@ -199,7 +200,7 @@ export function Campaigns<T extends Constructor<BaseIterableClient>>(Base: T) {
199200
"/api/campaigns/deactivateTriggered",
200201
params
201202
);
202-
return this.validateResponse(response, IterableSuccessResponseSchema);
203+
return validateResponse(response, IterableSuccessResponseSchema);
203204
}
204205

205206
/**
@@ -214,7 +215,7 @@ export function Campaigns<T extends Constructor<BaseIterableClient>>(Base: T) {
214215
params: ArchiveCampaignsParams
215216
): Promise<ArchiveCampaignsResponse> {
216217
const response = await this.client.post("/api/campaigns/archive", params);
217-
return this.validateResponse(response, ArchiveCampaignsResponseSchema);
218+
return validateResponse(response, ArchiveCampaignsResponseSchema);
218219
}
219220

220221
/**
@@ -224,7 +225,7 @@ export function Campaigns<T extends Constructor<BaseIterableClient>>(Base: T) {
224225
params: TriggerCampaignParams
225226
): Promise<IterableSuccessResponse> {
226227
const response = await this.client.post("/api/campaigns/trigger", params);
227-
return this.validateResponse(response, IterableSuccessResponseSchema);
228+
return validateResponse(response, IterableSuccessResponseSchema);
228229
}
229230

230231
/**
@@ -236,7 +237,7 @@ export function Campaigns<T extends Constructor<BaseIterableClient>>(Base: T) {
236237
const response = await this.client.post(
237238
`/api/campaigns/${params.campaignId}/send`
238239
);
239-
return this.validateResponse(response, IterableSuccessResponseSchema);
240+
return validateResponse(response, IterableSuccessResponseSchema);
240241
}
241242
};
242243
}

0 commit comments

Comments
 (0)