Skip to content

Commit

Permalink
feat: allow appending custom parts to the user agent (#602)
Browse files Browse the repository at this point in the history
  • Loading branch information
B4nan authored Oct 31, 2024
1 parent b2e108f commit d07452b
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 30 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "apify-client",
"version": "2.9.7",
"version": "2.9.8",
"description": "Apify API client for JavaScript",
"main": "dist/index.js",
"module": "dist/index.mjs",
Expand Down
3 changes: 3 additions & 0 deletions src/apify_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export class ApifyClient {
requestInterceptors: ow.optional.array,
timeoutSecs: ow.optional.number,
token: ow.optional.string,
userAgentSuffix: ow.optional.any(ow.string, ow.array.ofType(ow.string)),
}));

const {
Expand All @@ -77,6 +78,7 @@ export class ApifyClient {
timeoutSecs,
logger: this.logger,
token: this.token,
userAgentSuffix: options.userAgentSuffix,
});
}

Expand Down Expand Up @@ -341,4 +343,5 @@ export interface ApifyClientOptions {
/** @default 360 */
timeoutSecs?: number;
token?: string;
userAgentSuffix?: string | string[];
}
20 changes: 11 additions & 9 deletions src/http_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import KeepAliveAgent from 'agentkeepalive';
import retry, { RetryFunction } from 'async-retry';
import axios, {
AxiosError,
AxiosHeaders,
AxiosInstance,
AxiosRequestConfig,
InternalAxiosRequestConfig,
AxiosResponse,
AxiosHeaders,
InternalAxiosRequestConfig,
} from 'axios';

import { ApifyApiError } from './apify_api_error';
Expand All @@ -21,12 +21,7 @@ import {
responseInterceptors,
} from './interceptors';
import { Statistics } from './statistics';
import {
isNode,
getVersionData,
cast,
isStream,
} from './utils';
import { asArray, cast, getVersionData, isNode, isStream } from './utils';

const { version } = getVersionData();

Expand Down Expand Up @@ -116,7 +111,12 @@ export class HttpClient {
if (isNode()) {
// Works only in Node. Cannot be set in browser
const isAtHome = !!process.env[APIFY_ENV_VARS.IS_AT_HOME];
const userAgent = `ApifyClient/${version} (${os.type()}; Node/${process.version}); isAtHome/${isAtHome}`;
let userAgent = `ApifyClient/${version} (${os.type()}; Node/${process.version}); isAtHome/${isAtHome}`;

if (options.userAgentSuffix) {
userAgent += `; ${asArray(options.userAgentSuffix).join('; ')}`;
}

this.axios.defaults.headers['User-Agent'] = userAgent;
}

Expand Down Expand Up @@ -288,4 +288,6 @@ export interface HttpClientOptions {
logger: Log;
token?: string;
workflowKey?: string;
/** @internal */
userAgentSuffix?: string | string[];
}
8 changes: 8 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,14 @@ export function cast<T>(input: unknown): T {
return input as T;
}

export function asArray<T>(value: T | T[]): T[] {
if (Array.isArray(value)) {
return value;
}

return [value];
}

export type Dictionary<T = unknown> = Record<PropertyKey, T>;

export type DistributiveOptional<T, K extends keyof T> = T extends any ? Omit<T, K> & Partial<Pick<T, K>> : never;
26 changes: 8 additions & 18 deletions test/http_client.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,7 @@ describe('HttpClient', () => {
baseUrl,
timeoutSecs: 1,
maxRetries: 0,
requestInterceptors: [(config) => {
config.headers = {};
return config;
}],
userAgentSuffix: ['SDK/3.1.1', 'Crawlee/3.11.5'],
});
});
afterEach(async () => {
Expand All @@ -41,20 +38,13 @@ describe('HttpClient', () => {
const context = { delayMillis: 3000 };
const resourceId = Buffer.from(JSON.stringify(context)).toString('hex');

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

try {
const r = await page.evaluate((rId) => client.task(rId).get(), resourceId);
expect(r).toBeDefined();
} catch (err) {
expect(err).toBeInstanceOf(Error);
// this is failing after axios upgrade, the error is returned with a wrong name and message
// expect(err.message).toMatch('timeout of 1000ms exceeded');
}
await expect(page.evaluate((rId) => client.task(rId).get(), resourceId)).rejects.toThrow();
// this is failing after axios upgrade, the error is returned with a wrong name and message
// expect(err.message).toMatch('timeout of 1000ms exceeded');
});
});

0 comments on commit d07452b

Please sign in to comment.