Skip to content

Commit d07452b

Browse files
authored
feat: allow appending custom parts to the user agent (#602)
Related apify/apify-sdk-js#331
1 parent b2e108f commit d07452b

File tree

6 files changed

+33
-30
lines changed

6 files changed

+33
-30
lines changed

package-lock.json

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

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "apify-client",
3-
"version": "2.9.7",
3+
"version": "2.9.8",
44
"description": "Apify API client for JavaScript",
55
"main": "dist/index.js",
66
"module": "dist/index.mjs",

src/apify_client.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export class ApifyClient {
5353
requestInterceptors: ow.optional.array,
5454
timeoutSecs: ow.optional.number,
5555
token: ow.optional.string,
56+
userAgentSuffix: ow.optional.any(ow.string, ow.array.ofType(ow.string)),
5657
}));
5758

5859
const {
@@ -77,6 +78,7 @@ export class ApifyClient {
7778
timeoutSecs,
7879
logger: this.logger,
7980
token: this.token,
81+
userAgentSuffix: options.userAgentSuffix,
8082
});
8183
}
8284

@@ -341,4 +343,5 @@ export interface ApifyClientOptions {
341343
/** @default 360 */
342344
timeoutSecs?: number;
343345
token?: string;
346+
userAgentSuffix?: string | string[];
344347
}

src/http_client.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ import KeepAliveAgent from 'agentkeepalive';
66
import retry, { RetryFunction } from 'async-retry';
77
import axios, {
88
AxiosError,
9+
AxiosHeaders,
910
AxiosInstance,
1011
AxiosRequestConfig,
11-
InternalAxiosRequestConfig,
1212
AxiosResponse,
13-
AxiosHeaders,
13+
InternalAxiosRequestConfig,
1414
} from 'axios';
1515

1616
import { ApifyApiError } from './apify_api_error';
@@ -21,12 +21,7 @@ import {
2121
responseInterceptors,
2222
} from './interceptors';
2323
import { Statistics } from './statistics';
24-
import {
25-
isNode,
26-
getVersionData,
27-
cast,
28-
isStream,
29-
} from './utils';
24+
import { asArray, cast, getVersionData, isNode, isStream } from './utils';
3025

3126
const { version } = getVersionData();
3227

@@ -116,7 +111,12 @@ export class HttpClient {
116111
if (isNode()) {
117112
// Works only in Node. Cannot be set in browser
118113
const isAtHome = !!process.env[APIFY_ENV_VARS.IS_AT_HOME];
119-
const userAgent = `ApifyClient/${version} (${os.type()}; Node/${process.version}); isAtHome/${isAtHome}`;
114+
let userAgent = `ApifyClient/${version} (${os.type()}; Node/${process.version}); isAtHome/${isAtHome}`;
115+
116+
if (options.userAgentSuffix) {
117+
userAgent += `; ${asArray(options.userAgentSuffix).join('; ')}`;
118+
}
119+
120120
this.axios.defaults.headers['User-Agent'] = userAgent;
121121
}
122122

@@ -288,4 +288,6 @@ export interface HttpClientOptions {
288288
logger: Log;
289289
token?: string;
290290
workflowKey?: string;
291+
/** @internal */
292+
userAgentSuffix?: string | string[];
291293
}

src/utils.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,14 @@ export function cast<T>(input: unknown): T {
238238
return input as T;
239239
}
240240

241+
export function asArray<T>(value: T | T[]): T[] {
242+
if (Array.isArray(value)) {
243+
return value;
244+
}
245+
246+
return [value];
247+
}
248+
241249
export type Dictionary<T = unknown> = Record<PropertyKey, T>;
242250

243251
export type DistributiveOptional<T, K extends keyof T> = T extends any ? Omit<T, K> & Partial<Pick<T, K>> : never;

test/http_client.test.js

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,7 @@ describe('HttpClient', () => {
2727
baseUrl,
2828
timeoutSecs: 1,
2929
maxRetries: 0,
30-
requestInterceptors: [(config) => {
31-
config.headers = {};
32-
return config;
33-
}],
30+
userAgentSuffix: ['SDK/3.1.1', 'Crawlee/3.11.5'],
3431
});
3532
});
3633
afterEach(async () => {
@@ -41,20 +38,13 @@ describe('HttpClient', () => {
4138
const context = { delayMillis: 3000 };
4239
const resourceId = Buffer.from(JSON.stringify(context)).toString('hex');
4340

44-
expect.assertions(2);
45-
try {
46-
await client.actor(resourceId).get();
47-
} catch (err) {
48-
expect(err.message).toMatch('timeout of 1000ms exceeded');
49-
}
41+
await expect(client.actor(resourceId).get()).rejects.toThrow('timeout of 1000ms exceeded');
42+
const ua = mockServer.getLastRequest().headers['user-agent'];
43+
expect(ua).toMatch(/ApifyClient\/\d+\.\d+\.\d+/);
44+
expect(ua).toMatch('isAtHome/false; SDK/3.1.1; Crawlee/3.11.5');
5045

51-
try {
52-
const r = await page.evaluate((rId) => client.task(rId).get(), resourceId);
53-
expect(r).toBeDefined();
54-
} catch (err) {
55-
expect(err).toBeInstanceOf(Error);
56-
// this is failing after axios upgrade, the error is returned with a wrong name and message
57-
// expect(err.message).toMatch('timeout of 1000ms exceeded');
58-
}
46+
await expect(page.evaluate((rId) => client.task(rId).get(), resourceId)).rejects.toThrow();
47+
// this is failing after axios upgrade, the error is returned with a wrong name and message
48+
// expect(err.message).toMatch('timeout of 1000ms exceeded');
5949
});
6050
});

0 commit comments

Comments
 (0)