Skip to content

Commit 53576c7

Browse files
committed
fix(pencil): custom properties and iso8601
1 parent d08fc0b commit 53576c7

18 files changed

Lines changed: 137 additions & 113 deletions

src/agent-manager.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export default class AgentManager {
1717
private lazyOperation: Promise<any> = Promise.resolve();
1818
private isAgentStarted: boolean = false;
1919
private heartBeatManager: HeartBeatManager;
20-
private configUpdateTs = 0;
20+
private configUpdateTs: number =0;
2121

2222
constructor(
2323
public moduleManager: ModuleManager,
@@ -67,8 +67,8 @@ export default class AgentManager {
6767
return;
6868
}
6969

70-
if (config.ts > this.configUpdateTs) {
71-
this.configUpdateTs = config.ts;
70+
if (config.timestamp > this.configUpdateTs) {
71+
this.configUpdateTs = config.timestamp;
7272
}
7373

7474
// enforce all rules

src/api-manager.spec.ts

Lines changed: 76 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,16 @@ import { v4 } from 'uuid';
1414
import ModuleManager from './module-manager';
1515
import AgentLoginEvent from './events/agent-login-event';
1616
import AgentLogoutEvent from './events/agent-logout-event';
17-
import { delay } from './utils/utils';
17+
import { delay, fromEntries } from './utils/utils';
1818
import RequestEvent from './events/request-event';
1919

2020
chai.use(chaiAsPromised);
2121
const expect = chai.expect;
2222

2323
const sdkEvent: EventOptions = {
24-
eventType: EventType.LOG_IN,
25-
user: {
26-
id: 'USER_ID',
24+
event: EventType.LOG_IN,
25+
userId: 'USER_ID',
26+
userTraits: {
2727
name: 'USER_NAME',
2828
email: 'USER_EMAIL',
2929
},
@@ -34,10 +34,12 @@ const sdkEvent: EventOptions = {
3434
'user-agent': 'Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405',
3535
},
3636
},
37-
params: {
38-
param_1: 'CUSTOM_PARAM_VALUE',
37+
properties: {
38+
prop1: 'CUSTOM_PARAM_VALUE',
39+
prop2: true,
40+
prop3: 3,
3941
},
40-
timestamp: Date.now(),
42+
timestamp: new Date(),
4143
};
4244

4345
describe('ApiManager', () => {
@@ -65,20 +67,20 @@ describe('ApiManager', () => {
6567

6668
expect(eventPayload).to.be.not.null;
6769
//timestamp
68-
expect(eventPayload).to.have.property('ts', sdkEvent.timestamp);
70+
expect(eventPayload).to.have.property('timestamp', sdkEvent.timestamp.toISOString());
6971
//event type
70-
expect(eventPayload).to.have.property('eventType', sdkEvent.eventType);
72+
expect(eventPayload).to.have.property('eventType', sdkEvent.event);
7173
//user
72-
expect(eventPayload).to.have.property('user');
73-
expect(eventPayload.user).to.have.property('id', sdkEvent.user.id);
74-
expect(eventPayload.user).to.have.property('name', sdkEvent.user.name);
75-
expect(eventPayload.user).to.have.property('email', sdkEvent.user.email);
76-
//params
77-
78-
expect(eventPayload).to.have.property('params');
79-
expect(Object.keys(eventPayload.params)).to.have.lengthOf(Object.keys(sdkEvent.params).length, 'Incorrect number of params');
80-
Object.entries(eventPayload.params).forEach(([key, val]) => {
81-
expect(eventPayload.params).to.have.property(key, val, 'Invalid param value');
74+
expect(eventPayload).to.have.property('userId', sdkEvent.userId);
75+
expect(eventPayload).to.have.property('userTraits');
76+
expect(eventPayload.userTraits).to.have.property('name', sdkEvent.userTraits.name);
77+
expect(eventPayload.userTraits).to.have.property('email', sdkEvent.userTraits.email);
78+
//properties
79+
80+
expect(eventPayload).to.have.property('properties');
81+
expect(Object.keys(eventPayload.properties)).to.have.lengthOf(Object.keys(sdkEvent.properties).length, 'Incorrect number of custom properties');
82+
Object.entries(eventPayload.properties).forEach(([key, val]) => {
83+
expect(eventPayload.properties).to.have.property(key, val, 'Invalid param value');
8284
});
8385
//request context
8486
expect(eventPayload).to.have.property('request');
@@ -98,6 +100,34 @@ describe('ApiManager', () => {
98100
}
99101
});
100102

103+
it('Should throw when sending more than 10 custom properties to track event', async () => {
104+
const options: SecureNativeOptions = {
105+
apiKey: 'YOUR_API_KEY',
106+
autoSend: true,
107+
interval: 10,
108+
};
109+
110+
const fetch = fetchMock.sandbox().mock(`${options.apiUrl}/${ApiRoute.Track}`, 200);
111+
const eventManager = new EventManager(fetch, options);
112+
eventManager.startEventsPersist();
113+
const apiManager = new ApiManager(eventManager, options);
114+
115+
const props = fromEntries(Array.from({ length: 11 }, (x, i) => [`prop${i}`, `val${i}`]));
116+
117+
try {
118+
// track async event
119+
apiManager.track({
120+
event: EventType.LOG_IN,
121+
properties: props,
122+
});
123+
} catch (ex) {
124+
expect(ex).to.throw;
125+
} finally {
126+
await eventManager.stopEventsPersist();
127+
fetch.restore();
128+
}
129+
});
130+
101131
it('Should not call track event when automatic persistance disabled', async () => {
102132
const options: SecureNativeOptions = {
103133
apiKey: 'YOUR_API_KEY',
@@ -182,19 +212,18 @@ describe('ApiManager', () => {
182212

183213
expect(eventPayload).to.be.not.null;
184214
//timestamp
185-
expect(eventPayload).to.have.property('ts', sdkEvent.timestamp);
215+
expect(eventPayload).to.have.property('timestamp', sdkEvent.timestamp.toISOString());
186216
//event type
187-
expect(eventPayload).to.have.property('eventType', sdkEvent.eventType);
217+
expect(eventPayload).to.have.property('eventType', sdkEvent.event);
188218
//user
189-
expect(eventPayload).to.have.property('user');
190-
expect(eventPayload.user).to.have.property('id', sdkEvent.user.id);
191-
expect(eventPayload.user).to.have.property('name', sdkEvent.user.name);
192-
expect(eventPayload.user).to.have.property('email', sdkEvent.user.email);
193-
//params
194-
expect(eventPayload).to.have.property('params');
195-
expect(Object.keys(eventPayload.params)).to.have.lengthOf(Object.keys(sdkEvent.params).length, 'Incorrect number of params');
196-
Object.entries(eventPayload.params).forEach(([key, val]) => {
197-
expect(eventPayload.params).to.have.property(key, val, 'Invalid param value');
219+
expect(eventPayload).to.have.property('userId', sdkEvent.userId);
220+
expect(eventPayload.userTraits).to.have.property('name', sdkEvent.userTraits.name);
221+
expect(eventPayload.userTraits).to.have.property('email', sdkEvent.userTraits.email);
222+
//properties
223+
expect(eventPayload).to.have.property('properties');
224+
expect(Object.keys(eventPayload.properties)).to.have.lengthOf(Object.keys(sdkEvent.properties).length, 'Incorrect number of custom properties');
225+
Object.entries(eventPayload.properties).forEach(([key, val]) => {
226+
expect(eventPayload.properties).to.have.property(key, val, 'Invalid param value');
198227
});
199228
//request context
200229
expect(eventPayload).to.have.property('request');
@@ -243,7 +272,7 @@ describe('ApiManager', () => {
243272
const apiManager = new ApiManager(eventManager, options);
244273

245274
const riskEvent: EventOptions = {
246-
eventType: EventType.RISK,
275+
event: EventType.RISK,
247276
};
248277

249278
try {
@@ -255,17 +284,14 @@ describe('ApiManager', () => {
255284

256285
expect(eventPayload).to.be.not.null;
257286
//timestamp
258-
expect(eventPayload).to.have.property('ts');
287+
expect(eventPayload).to.have.property('timestamp');
259288
//event type
260-
expect(eventPayload).to.have.property('eventType', riskEvent.eventType);
289+
expect(eventPayload).to.have.property('eventType', riskEvent.event);
261290
//user
262-
expect(eventPayload).to.have.property('user');
263-
expect(eventPayload.user).to.have.property('id', '');
264-
expect(eventPayload.user).to.have.property('name', '');
265-
expect(eventPayload.user).to.have.property('email', '');
266-
//params
267-
expect(eventPayload).to.have.property('params');
268-
expect(Object.keys(eventPayload.params)).to.have.lengthOf(0, 'Incorrect number of params');
291+
expect(eventPayload).to.have.property('userId', '');
292+
expect(eventPayload).to.have.property('userTraits');
293+
expect(eventPayload.userTraits).to.have.property('name', '');
294+
expect(eventPayload.userTraits).to.have.property('email', '');
269295

270296
//request context
271297
expect(eventPayload).to.have.property('request');
@@ -304,8 +330,8 @@ describe('ApiManager', () => {
304330

305331
expect(eventPayload).to.be.not.null;
306332
//timestamp
307-
expect(eventPayload).to.have.property('ts');
308-
expect(eventPayload.ts).to.be.greaterThan(0, 'Invalid timestamp');
333+
expect(eventPayload).to.have.property('timestamp');
334+
expect(eventPayload.timestamp).to.be.not.empty;
309335
//event type
310336
expect(eventPayload).to.have.property('eventType', EventType.HEART_BEAT);
311337
//app name
@@ -338,11 +364,11 @@ describe('ApiManager', () => {
338364

339365
const fetchOptions = fetch.lastOptions();
340366
const eventPayload: AgentLoginEvent = JSON.parse(fetchOptions.body.toString());
341-
367+
342368
expect(eventPayload).to.be.not.null;
343369
//timestamp
344-
expect(eventPayload).to.have.property('ts');
345-
expect(eventPayload.ts).to.be.greaterThan(0, 'Invalid timestamp');
370+
expect(eventPayload).to.have.property('timestamp');
371+
expect(eventPayload.timestamp).to.be.not.empty;
346372
//event type
347373
expect(eventPayload).to.have.property('eventType', EventType.AGENT_LOG_IN);
348374
//app name
@@ -380,8 +406,8 @@ describe('ApiManager', () => {
380406

381407
expect(eventPayload).to.be.not.null;
382408
//timestamp
383-
expect(eventPayload).to.have.property('ts');
384-
expect(eventPayload.ts).to.be.greaterThan(0, 'Invalid timestamp');
409+
expect(eventPayload).to.have.property('timestamp');
410+
expect(eventPayload.timestamp).to.be.not.empty;
385411
//event type
386412
expect(eventPayload).to.have.property('eventType', EventType.AGENT_LOG_OUT);
387413
} finally {
@@ -416,8 +442,8 @@ describe('ApiManager', () => {
416442

417443
expect(eventPayload).to.be.not.null;
418444
//timestamp
419-
expect(eventPayload).to.have.property('ts');
420-
expect(eventPayload.ts).to.be.greaterThan(0, 'Invalid timestamp');
445+
expect(eventPayload).to.have.property('timestamp');
446+
expect(eventPayload.timestamp).to.be.not.empty;
421447
//event type
422448
expect(eventPayload).to.have.property('eventType', EventType.AGENT_CONFIG);
423449
} finally {
@@ -449,7 +475,7 @@ describe('ApiManager', () => {
449475

450476
expect(eventPayload).to.be.not.null;
451477
//timestamp
452-
expect(eventPayload).to.have.property('ts');
478+
expect(eventPayload).to.have.property('timestamp');
453479
expect(eventPayload).to.have.property('message', 'Some unexpected error');
454480
expect(eventPayload).to.have.property('name', 'Error');
455481
//event type

src/api-manager.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@ import FailoveStrategy from './enums/failover-strategy';
2121
import RequestEvent from './events/request-event';
2222
import { RequestOptions } from './types/request-options';
2323

24-
const MAX_CUSTOM_PARAMS = 6;
24+
const MAX_CUSTOM_PROPERTIES = 10;
2525

2626
export default class ApiManager {
2727
constructor(private eventManager: EventManager, private options: SecureNativeOptions) {}
2828

2929
public track(opts: EventOptions) {
3030
Logger.debug('Track event call', opts);
31-
if (opts && opts.params && Object.keys(opts.params).length > MAX_CUSTOM_PARAMS) {
32-
throw new Error(`You can only specify maximum of ${MAX_CUSTOM_PARAMS} params`);
31+
if (opts && opts.properties && Object.keys(opts.properties).length > MAX_CUSTOM_PROPERTIES) {
32+
throw new Error(`You can only specify maximum of ${MAX_CUSTOM_PROPERTIES} custom properties`);
3333
}
3434

3535
const requestUrl = `${this.options.apiUrl}/${ApiRoute.Track}`;

src/event-manager.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const expect = chai.expect;
1111

1212
const event: IEvent = {
1313
eventType: 'custom-event',
14-
ts: Date.now(),
14+
timestamp: new Date().toISOString(),
1515
};
1616

1717
describe('EventManager', () => {
@@ -39,7 +39,7 @@ describe('EventManager', () => {
3939

4040
expect(eventPayload).to.be.not.null;
4141
//timestamp
42-
expect(eventPayload).to.have.property('ts', event.ts);
42+
expect(eventPayload).to.have.property('timestamp', event.timestamp);
4343
//event type
4444
expect(eventPayload).to.have.property('eventType', event.eventType);
4545
} finally {
@@ -72,7 +72,7 @@ describe('EventManager', () => {
7272

7373
expect(eventPayload).to.be.not.null;
7474
//timestamp
75-
expect(eventPayload).to.have.property('ts', event.ts);
75+
expect(eventPayload).to.have.property('timestamp', event.timestamp);
7676
//event type
7777
expect(eventPayload).to.have.property('eventType', event.eventType);
7878
} finally {
@@ -190,7 +190,7 @@ describe('EventManager', () => {
190190

191191
expect(eventPayload).to.be.not.null;
192192
//timestamp
193-
expect(eventPayload).to.have.property('ts', event.ts);
193+
expect(eventPayload).to.have.property('timestamp', event.timestamp);
194194
//event type
195195
expect(eventPayload).to.have.property('eventType', event.eventType);
196196
} finally {

src/events/agent-config-event.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ export default class AgentConfigEvent implements IEvent {
55
public eventType = EventType.AGENT_CONFIG;
66
public hostId: string;
77
public appName: string;
8+
public timestamp: string;
89
public ts: number;
910

1011
constructor(hostId: string, appName: string, ts: number) {
1112
this.hostId = hostId;
1213
this.appName = appName;
14+
this.timestamp = new Date().toISOString();
1315
this.ts = ts;
1416
}
1517
}

src/events/agent-heartbeat-event.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ const PACKAGE_FILE_NAME = 'package.json';
99

1010
export default class AgentHeartBeatEvent implements IEvent {
1111
public eventType = EventType.HEART_BEAT;
12-
public ts: number;
12+
public timestamp: string;
1313
private hostId: string;
1414
private hostname: string;
1515
private agentVersion: string;
1616
private runtime: string;
1717
private static agentPkg: Package = PackageManager.getPackage(join(process.cwd(), '/node_modules/@securenative/sdk/', PACKAGE_FILE_NAME));
1818

1919
constructor(private appName: string) {
20-
this.ts = Date.now();
20+
this.timestamp = new Date().toISOString();
2121
this.hostId = getHostIdSync();
2222
this.hostname = hostname();
2323
this.agentVersion = AgentHeartBeatEvent.agentPkg?.version;

src/events/agent-login-event.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const PACKAGE_FILE_NAME = 'package.json';
99

1010
export default class AgentLoginEvent implements IEvent {
1111
public eventType = EventType.AGENT_LOG_IN;
12-
public ts: number;
12+
public timestamp: string;
1313
public package: {
1414
name: string;
1515
description: string;
@@ -93,6 +93,6 @@ export default class AgentLoginEvent implements IEvent {
9393
path: __dirname
9494
};
9595

96-
this.ts = Date.now();
96+
this.timestamp = new Date().toISOString();
9797
}
9898
}

src/events/agent-logout-event.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import IEvent from './event';
33

44
export default class AgentLogoutEvent implements IEvent {
55
public eventType = EventType.AGENT_LOG_OUT;
6-
public ts: number;
6+
public timestamp: string;
77

88
constructor() {
9-
this.ts = Date.now();
9+
this.timestamp = new Date().toISOString();
1010
}
1111
}

src/events/error-event.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ export default class ErrorEvent implements IEvent {
66
private message: string;
77
private stackTrace: string;
88
eventType: string = EventType.ERROR;
9-
ts: number;
9+
timestamp: string;
1010

1111
constructor(err: Error) {
1212
this.name = err.name;
1313
this.message = err.message;
1414
this.stackTrace = err.stack;
15-
this.ts = Date.now();
15+
this.timestamp = new Date().toISOString();
1616
}
1717
}

src/events/event.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
export default interface IEvent {
22
eventType: string;
3-
ts: number;
3+
timestamp: string;
44
}

0 commit comments

Comments
 (0)