Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/node/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ export const DEFAULT_OPTIONS: Options = {
// By default, events flush on the next event loop
uploadIntervalInSec: 0,
minIdLength: null,
// By default, set the request timeout to 10 seconds.
requestCancelTimeout: 10000,
};
7 changes: 3 additions & 4 deletions packages/node/src/transports/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@ export interface HTTPRequest {
): http.ClientRequest;
}

// Automatially cancel requests that have been waiting for 10+ s
const REQUEST_CANCEL_TIMEOUT = 10 * 1000;

/** Base Transport class implementation */
export class HTTPTransport implements Transport {
/** The Agent used for corresponding transport */
Expand All @@ -34,6 +31,7 @@ export class HTTPTransport implements Transport {

/** Create instance and set this.dsn */
public constructor(public options: TransportOptions) {
this.options = options;
if (options.serverUrl.startsWith('http://')) {
this.module = http;
} else if (options.serverUrl.startsWith('https://')) {
Expand All @@ -51,7 +49,7 @@ export class HTTPTransport implements Transport {

// Queue up the call to send the payload.
// Wait 10 seconds for each request in queue before removing it
return await this._requestQueue.addToQueue(call, REQUEST_CANCEL_TIMEOUT);
return await this._requestQueue.addToQueue(call, this.options.requestCancelTimeout);
}

/** Returns a build request option object used by request */
Expand Down Expand Up @@ -108,6 +106,7 @@ export class HTTPTransport implements Transport {

export const setupDefaultTransport = (options: Options): Transport => {
const transportOptions: TransportOptions = {
requestCancelTimeout: options.requestCancelTimeout,
serverUrl: options.serverUrl,
headers: {
'Content-Type': 'application/json',
Expand Down
5 changes: 4 additions & 1 deletion packages/types/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,8 @@ export interface Options {
* Optional parameter allowing users to set minimum permitted length for user_id & device_id fields
* As described here: https://developers.amplitude.com/docs/http-api-v2#schemaRequestOptions
*/
minIdLength?: number | null;
minIdLength: number | null;

/** If you'd like to configure a custom timeout for each request, set it here in milliseconds. */
requestCancelTimeout: number;
}
1 change: 1 addition & 0 deletions packages/types/src/transport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,5 @@ export interface TransportOptions {
serverUrl: string;
/** Define custom headers */
headers: { [key: string]: string };
requestCancelTimeout: number;
}
6 changes: 6 additions & 0 deletions packages/utils/src/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const isValidEvent = (event: Event): boolean => {

const hasDeviceId = event.device_id !== undefined;
const hasUserId = event.user_id !== undefined;
const hasEventProperties = event.event_properties !== undefined;

if (!hasDeviceId && !hasUserId) {
logger.warn('Invalid event: expected at least one of device or user id');
Expand All @@ -25,5 +26,10 @@ export const isValidEvent = (event: Event): boolean => {
return false;
}

if (hasEventProperties && typeof event.event_properties !== 'object') {
logger.warn('Invalid event properties: expected event properties to be type object');
return false;
}

return true;
};
20 changes: 20 additions & 0 deletions packages/utils/test/validate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,24 @@ describe('isValidEvent', () => {

expect(isValidEvent(invalidEvent)).toBe(false);
});

it('should pass on valid events and object for event properties', () => {
const validEvent: Event = {
event_type: 'VALID_BUT_FAKE_EVENT_TYPE',
device_id: 'VALID_BUT_FAKE_DEVICE_ID',
event_properties: { fake_but_valid_key: 'fake_but_valid_value' },
};

expect(isValidEvent(validEvent)).toBe(true);
});

it('should fail on valid events with invalid event properties', () => {
const invalidEvent: Event = {
event_type: 'VALID_BUT_FAKE_EVENT_TYPE',
device_id: 'VALID_BUT_FAKE_DEVICE_ID',
event_properties: 3,
} as any;

expect(isValidEvent(invalidEvent)).toBe(false);
});
});