Skip to content

Commit

Permalink
feat: set User-Agent for proper activity log sources in Customer.io (#93
Browse files Browse the repository at this point in the history
)
  • Loading branch information
mike-engel authored Jan 27, 2022
1 parent d38c131 commit ea61e27
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 1 deletion.
16 changes: 16 additions & 0 deletions lib/request.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { request } from 'https';
import type { RequestOptions } from 'https';
import { URL } from 'url';
import fs from 'fs';
import { resolve } from 'path';
import { CustomerIORequestError } from './utils';

export type BasicAuth = {
Expand All @@ -20,6 +22,7 @@ export type RequestHandlerOptions = {
};

const TIMEOUT = 10_000;
const PACKAGE_JSON = fs.readFileSync(resolve(__dirname, '..', 'package.json'));

export default class CIORequest {
apikey?: BasicAuth['apikey'];
Expand Down Expand Up @@ -49,10 +52,23 @@ export default class CIORequest {

options(uri: string, method: RequestOptions['method'], data?: RequestData): RequestHandlerOptions {
const body = data ? JSON.stringify(data) : null;
let libraryVersion = 'Unknown';

try {
let json = JSON.parse(PACKAGE_JSON.toString());

libraryVersion = json.version;
} catch {
console.warn(
'WARN: package.json contents could not be read. Activity source data in Customer.io will be incorrect.',
);
}

const headers = {
Authorization: this.auth,
'Content-Type': 'application/json',
'Content-Length': body ? Buffer.byteLength(body, 'utf8') : 0,
'User-Agent': `Customer.io Node Client/${libraryVersion}`,
};

return { method, uri, headers, body };
Expand Down
26 changes: 25 additions & 1 deletion test/request-track-api.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import avaTest, { TestInterface } from 'ava';
import https, { RequestOptions } from 'https';
import https from 'https';
import sinon, { SinonStub } from 'sinon';
import { PassThrough } from 'stream';
import fs from 'fs';
import { resolve } from 'path';
import Request from '../lib/request';

type TestContext = { req: Request; httpsReq: sinon.SinonStub };
Expand All @@ -14,12 +16,14 @@ const apikey = 'abc';
const uri = 'https://track.customer.io/api/v1/customers/1';
const data = { first_name: 'Bruce', last_name: 'Wayne' };
const auth = `Basic ${Buffer.from(`${siteid}:${apikey}`).toString('base64')}`;
const PACKAGE_VERSION = JSON.parse(fs.readFileSync(resolve(__dirname, '..', 'package.json')).toString()).version;
const baseOptions = {
uri,
headers: {
Authorization: auth,
'Content-Type': 'application/json',
'Content-Length': 0,
'User-Agent': `Customer.io Node Client/${PACKAGE_VERSION}`,
},
};
const putOptions = Object.assign({}, baseOptions, {
Expand Down Expand Up @@ -108,6 +112,26 @@ test('#options sets Content-Length using body length in bytes', (t) => {
t.deepEqual(resultOptions, expectedOptions);
});

test('#options sets User-Agent even if package.json cannot be read', (t) => {
const jsonParseStub = sinon.stub(JSON, 'parse').throws();
const body = { bad_agent: true };
const method = 'POST';
const expectedOptions = {
...baseOptions,
method,
headers: {
...baseOptions.headers,
'Content-Length': 18,
'User-Agent': 'Customer.io Node Client/Unknown',
},
body: JSON.stringify(body),
};
const resultOptions = t.context.req.options(uri, method, body);

t.deepEqual(resultOptions, expectedOptions);
jsonParseStub.restore();
});

test('#handler returns a promise', (t) => {
createMockRequest(t.context.httpsReq, 200);
const promise = t.context.req.handler(putOptions);
Expand Down

0 comments on commit ea61e27

Please sign in to comment.