Skip to content

Commit 2b6753e

Browse files
authored
chore(events): Enforce max event length (#210)
1 parent 29e95b7 commit 2b6753e

File tree

7 files changed

+223
-16
lines changed

7 files changed

+223
-16
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ test/data
1313
.idea
1414

1515
.DS_Store
16+
.vscode

.vscode/settings.json

Lines changed: 0 additions & 7 deletions
This file was deleted.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
"jest-environment-jsdom": "^29.7.0",
6161
"lodash": "^4.17.21",
6262
"prettier": "^3.4.2",
63+
"prettier-eslint": "^16.3.0",
6364
"terser-webpack-plugin": "^5.3.3",
6465
"testdouble": "^3.20.1",
6566
"ts-jest": "^29.1.1",

src/client/eppo-client.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,7 +1004,6 @@ export default class EppoClient {
10041004

10051005
/**
10061006
* Enqueues an arbitrary event. Events must have a type and a payload.
1007-
* TODO: enforce max message size
10081007
*/
10091008
track(type: string, payload: Record<string, unknown>) {
10101009
this.eventDispatcher.dispatch({
@@ -1030,7 +1029,9 @@ export default class EppoClient {
10301029
return {
10311030
configFetchedAt: this.flagConfigurationStore.getConfigFetchedAt() ?? '',
10321031
configPublishedAt: this.flagConfigurationStore.getConfigPublishedAt() ?? '',
1033-
configEnvironment: this.flagConfigurationStore.getEnvironment() ?? { name: '' },
1032+
configEnvironment: this.flagConfigurationStore.getEnvironment() ?? {
1033+
name: '',
1034+
},
10341035
configFormat: this.flagConfigurationStore.getFormat() ?? '',
10351036
};
10361037
}

src/events/default-event-dispatcher.spec.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,4 +318,35 @@ describe('DefaultEventDispatcher', () => {
318318
expect(dispatcher).toBeInstanceOf(DefaultEventDispatcher);
319319
});
320320
});
321+
322+
describe('validation', () => {
323+
it('should throw an error if the serialized event is too long', () => {
324+
const { dispatcher } = createDispatcher();
325+
// craft a payload that is over the limit
326+
const payload = 'a'.repeat(5000);
327+
expect(() =>
328+
dispatcher.dispatch({
329+
uuid: 'foo-1',
330+
payload: { foo: payload },
331+
timestamp: new Date().getTime(),
332+
type: 'foo',
333+
}),
334+
).toThrow();
335+
});
336+
337+
it('should not throw an error if the serialized event is within the limit', () => {
338+
const { dispatcher } = createDispatcher();
339+
const payload = 'a'.repeat(4000);
340+
const fetch = global.fetch as jest.Mock;
341+
fetch.mockResolvedValue({ ok: true, json: () => Promise.resolve([]) });
342+
expect(() =>
343+
dispatcher.dispatch({
344+
uuid: 'foo-1',
345+
payload: { foo: payload },
346+
timestamp: new Date().getTime(),
347+
type: 'foo',
348+
}),
349+
).not.toThrow();
350+
});
351+
});
321352
});

src/events/default-event-dispatcher.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export type EventDispatcherConfig = {
2525
maxRetries?: number;
2626
};
2727

28+
export const MAX_EVENT_SERIALIZED_LENGTH = 4096;
2829
export const DEFAULT_EVENT_DISPATCHER_BATCH_SIZE = 1_000;
2930
export const DEFAULT_EVENT_DISPATCHER_CONFIG: Omit<
3031
EventDispatcherConfig,
@@ -75,10 +76,17 @@ export default class DefaultEventDispatcher implements EventDispatcher {
7576
}
7677

7778
dispatch(event: Event) {
79+
this.ensureValidEvent(event);
7880
this.batchProcessor.push(event);
7981
this.maybeScheduleNextDelivery();
8082
}
8183

84+
private ensureValidEvent(event: Event) {
85+
if (JSON.stringify(event).length > MAX_EVENT_SERIALIZED_LENGTH) {
86+
throw new Error('Event serialized length exceeds maximum allowed length of 4096');
87+
}
88+
}
89+
8290
private async deliverNextBatch() {
8391
if (this.isOffline) {
8492
logger.warn('[EventDispatcher] Skipping delivery; network status is offline.');

0 commit comments

Comments
 (0)