From c98a5bfb2ef7a01da4cfdfa6e06f6d98b48b295a Mon Sep 17 00:00:00 2001 From: Matt Carroll Date: Tue, 6 Aug 2019 19:49:40 -0700 Subject: [PATCH 1/9] Add notification types as an enum in utils --- packages/utils/src/index.ts | 41 +++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index b8012872e..3a91638cc 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -102,3 +102,44 @@ export function sprintf(format: string, ...args: any[]): string { } }) } +/* + * Notification types for use with NotificationCenter + * Format is EVENT: + * + * SDK consumers can use these to register callbacks with the notification center. + * + * @deprecated since 3.1.0 + * ACTIVATE: An impression event will be sent to Optimizely + * Callbacks will receive an object argument with the following properties: + * - experiment {Object} + * - userId {string} + * - attributes {Object|undefined} + * - variation {Object} + * - logEvent {Object} + * + * DECISION: A decision is made in the system. i.e. user activation, + * feature access or feature-variable value retrieval + * Callbacks will receive an object argument with the following properties: + * - type {string} + * - userId {string} + * - attributes {Object|undefined} + * - decisionInfo {Object|undefined} + * + * OPTIMIZELY_CONFIG_UPDATE: This Optimizely instance has been updated with a new + * config + * + * TRACK: A conversion event will be sent to Optimizely + * Callbacks will receive the an object argument with the following properties: + * - eventKey {string} + * - userId {string} + * - attributes {Object|undefined} + * - eventTags {Object|undefined} + * - logEvent {Object} + * + */ +export enum NOTIFICATION_TYPES { + ACTIVATE = "ACTIVATE:experiment, user_id,attributes, variation, event", + DECISION = "DECISION:type, userId, attributes, decisionInfo", + OPTIMIZELY_CONFIG_UPDATE = "OPTIMIZELY_CONFIG_UPDATE", + TRACK = "TRACK:event_key, user_id, attributes, event_tags, event" +} From 7080436f9612c020b47ce6ca649978c458b5344c Mon Sep 17 00:00:00 2001 From: Matt Carroll Date: Tue, 6 Aug 2019 20:02:15 -0700 Subject: [PATCH 2/9] Add log event notification type --- packages/utils/src/index.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 3a91638cc..a2de59505 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -138,8 +138,9 @@ export function sprintf(format: string, ...args: any[]): string { * */ export enum NOTIFICATION_TYPES { - ACTIVATE = "ACTIVATE:experiment, user_id,attributes, variation, event", - DECISION = "DECISION:type, userId, attributes, decisionInfo", - OPTIMIZELY_CONFIG_UPDATE = "OPTIMIZELY_CONFIG_UPDATE", - TRACK = "TRACK:event_key, user_id, attributes, event_tags, event" + ACTIVATE = 'ACTIVATE:experiment, user_id,attributes, variation, event', + DECISION = 'DECISION:type, userId, attributes, decisionInfo', + LOG_EVENT = 'LOG_EVENT:logEvent', + OPTIMIZELY_CONFIG_UPDATE = 'OPTIMIZELY_CONFIG_UPDATE', + TRACK = 'TRACK:event_key, user_id, attributes, event_tags, event', } From 2f01faf9962fc08057d4ae67bd69ecb06106f7c1 Mon Sep 17 00:00:00 2001 From: Matt Carroll Date: Tue, 6 Aug 2019 20:08:17 -0700 Subject: [PATCH 3/9] Add comment for new notification type --- packages/utils/src/index.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index a2de59505..5a395c944 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -125,6 +125,13 @@ export function sprintf(format: string, ...args: any[]): string { * - attributes {Object|undefined} * - decisionInfo {Object|undefined} * + * LOG_EVENT: A batch of events, which could contain impressions and/or conversions, + * was sent to Optimizely + * Callbacks will receive an object argument with the following properties: + * - url {string} + * - httpVerb {string} + * - params {object} + * * OPTIMIZELY_CONFIG_UPDATE: This Optimizely instance has been updated with a new * config * From a97dea664dbb54139df92bfd8c8bfa473ee54c73 Mon Sep 17 00:00:00 2001 From: Matt Carroll Date: Tue, 6 Aug 2019 20:08:57 -0700 Subject: [PATCH 4/9] Capitalize Object --- packages/utils/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 5a395c944..b706c79ad 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -130,7 +130,7 @@ export function sprintf(format: string, ...args: any[]): string { * Callbacks will receive an object argument with the following properties: * - url {string} * - httpVerb {string} - * - params {object} + * - params {Object} * * OPTIMIZELY_CONFIG_UPDATE: This Optimizely instance has been updated with a new * config From f2d6fa4503fd7feefd4cf3565b4034834810b763 Mon Sep 17 00:00:00 2001 From: Matt Carroll Date: Tue, 6 Aug 2019 20:38:05 -0700 Subject: [PATCH 5/9] Add NotificationCenter interface --- packages/utils/src/index.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index b706c79ad..c8458df7f 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -151,3 +151,7 @@ export enum NOTIFICATION_TYPES { OPTIMIZELY_CONFIG_UPDATE = 'OPTIMIZELY_CONFIG_UPDATE', TRACK = 'TRACK:event_key, user_id, attributes, event_tags, event', } + +export interface NotificationCenter { + sendNotifications(notificationType: NOTIFICATION_TYPES, notificationData?: any): void +} From eec268cb8c16cf54997716b371a5fe24d7ef6d2d Mon Sep 17 00:00:00 2001 From: Matt Carroll Date: Wed, 7 Aug 2019 08:10:35 -0700 Subject: [PATCH 6/9] Fix language - will be sent, not was sent --- packages/utils/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index c8458df7f..41b62621e 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -126,7 +126,7 @@ export function sprintf(format: string, ...args: any[]): string { * - decisionInfo {Object|undefined} * * LOG_EVENT: A batch of events, which could contain impressions and/or conversions, - * was sent to Optimizely + * will be sent to Optimizely * Callbacks will receive an object argument with the following properties: * - url {string} * - httpVerb {string} From f7235776189c7b486115ed006ad4d34c6bbe653a Mon Sep 17 00:00:00 2001 From: Matt Carroll Date: Wed, 7 Aug 2019 08:38:34 -0700 Subject: [PATCH 7/9] Send notification when event queued for dispatch --- .../__tests__/v1EventProcessor.spec.ts | 25 +++++++++++++++++++ .../event-processor/src/eventProcessor.ts | 12 +++++++++ 2 files changed, 37 insertions(+) diff --git a/packages/event-processor/__tests__/v1EventProcessor.spec.ts b/packages/event-processor/__tests__/v1EventProcessor.spec.ts index 639617274..c68f1b4bf 100644 --- a/packages/event-processor/__tests__/v1EventProcessor.spec.ts +++ b/packages/event-processor/__tests__/v1EventProcessor.spec.ts @@ -23,6 +23,7 @@ import { } from '../src/eventDispatcher' import { EventProcessor } from '../src/eventProcessor' import { buildImpressionEventV1, makeBatchedEventV1 } from '../src/v1/buildEventV1' +import { NotificationCenter, NOTIFICATION_TYPES } from '@optimizely/js-sdk-utils'; function sleep(time = 0): Promise { return new Promise(resolve => { @@ -644,6 +645,30 @@ describe('LogTierV1EventProcessor', () => { result: false, }) }) + + it('should trigger a notification when the event dispatcher dispatches an event', () => { + const dispatcher: EventDispatcher = { + dispatchEvent: jest.fn() + } + + const notificationCenter: NotificationCenter = { + sendNotifications: jest.fn() + } + + processor = new LogTierV1EventProcessor({ + dispatcher, + notificationCenter, + maxQueueSize: 1, + }) + processor.start() + + const impressionEvent1 = createImpressionEvent() + processor.process(impressionEvent1, testProjectConfig) + + expect(notificationCenter.sendNotifications).toBeCalledTimes(1) + const event = (dispatcher.dispatchEvent as jest.Mock).mock.calls[0][0] + expect(notificationCenter.sendNotifications).toBeCalledWith(NOTIFICATION_TYPES.LOG_EVENT, event) + }) }) }) }) diff --git a/packages/event-processor/src/eventProcessor.ts b/packages/event-processor/src/eventProcessor.ts index 33ebf4e4f..8f02d1bb0 100644 --- a/packages/event-processor/src/eventProcessor.ts +++ b/packages/event-processor/src/eventProcessor.ts @@ -23,6 +23,7 @@ import { } from './eventDispatcher' import { EventQueue, DefaultEventQueue, SingleEventQueue } from './eventQueue' import { getLogger } from '@optimizely/js-sdk-logging' +import { NOTIFICATION_TYPES, NotificationCenter } from '@optimizely/js-sdk-utils' const logger = getLogger('EventProcessor') @@ -56,6 +57,7 @@ export abstract class AbstractEventProcessor implements EventProcessor { protected callbacks: EventCallback[] protected dispatcher: EventDispatcher protected queue: EventQueue + private notificationCenter?: NotificationCenter constructor({ dispatcher, @@ -64,6 +66,7 @@ export abstract class AbstractEventProcessor implements EventProcessor { callbacks = [], flushInterval = 30000, maxQueueSize = 3000, + notificationCenter, }: { dispatcher: EventDispatcher transformers?: EventTransformer[] @@ -71,6 +74,7 @@ export abstract class AbstractEventProcessor implements EventProcessor { callbacks?: EventCallback[] flushInterval?: number maxQueueSize?: number + notificationCenter?: NotificationCenter }) { this.dispatcher = dispatcher @@ -90,6 +94,7 @@ export abstract class AbstractEventProcessor implements EventProcessor { this.transformers = transformers this.interceptors = interceptors this.callbacks = callbacks + this.notificationCenter = notificationCenter } drainQueue(buffer: ProcessableEvents[]): Promise { @@ -113,6 +118,13 @@ export abstract class AbstractEventProcessor implements EventProcessor { resolve() }) + + if (this.notificationCenter) { + this.notificationCenter.sendNotifications( + NOTIFICATION_TYPES.LOG_EVENT, + formattedEvent + ) + } }) }) From 04f65d48f804444fa65c0c44d1fb67969528fedc Mon Sep 17 00:00:00 2001 From: Matt Carroll Date: Thu, 8 Aug 2019 13:57:58 -0700 Subject: [PATCH 8/9] Move notification center test to its own describe block --- .../event-processor/__tests__/v1EventProcessor.spec.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/event-processor/__tests__/v1EventProcessor.spec.ts b/packages/event-processor/__tests__/v1EventProcessor.spec.ts index 015d3e36a..2f30dc01a 100644 --- a/packages/event-processor/__tests__/v1EventProcessor.spec.ts +++ b/packages/event-processor/__tests__/v1EventProcessor.spec.ts @@ -342,6 +342,9 @@ describe('LogTierV1EventProcessor', () => { expect(dispatchStub).toHaveBeenCalledTimes(1) }) + }) + + describe('when a notification center is provided', () => { it('should trigger a notification when the event dispatcher dispatches an event', () => { const dispatcher: EventDispatcher = { dispatchEvent: jest.fn() @@ -351,7 +354,7 @@ describe('LogTierV1EventProcessor', () => { sendNotifications: jest.fn() } - processor = new LogTierV1EventProcessor({ + const processor = new LogTierV1EventProcessor({ dispatcher, notificationCenter, maxQueueSize: 1, @@ -359,7 +362,7 @@ describe('LogTierV1EventProcessor', () => { processor.start() const impressionEvent1 = createImpressionEvent() - processor.process(impressionEvent1, testProjectConfig) + processor.process(impressionEvent1) expect(notificationCenter.sendNotifications).toBeCalledTimes(1) const event = (dispatcher.dispatchEvent as jest.Mock).mock.calls[0][0] From bc7c0473e9d9ec1b3eb6aa6cf7291b37a38ea1af Mon Sep 17 00:00:00 2001 From: Matt Carroll Date: Thu, 8 Aug 2019 14:11:56 -0700 Subject: [PATCH 9/9] Update js-sdk-utils to 0.2.0 --- packages/event-processor/package-lock.json | 16 +++++++++++++--- packages/event-processor/package.json | 2 +- packages/utils/package-lock.json | 2 +- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/packages/event-processor/package-lock.json b/packages/event-processor/package-lock.json index 3903cc5fd..c65822e61 100644 --- a/packages/event-processor/package-lock.json +++ b/packages/event-processor/package-lock.json @@ -38,12 +38,22 @@ "integrity": "sha512-Bs2zHvsdNIk2QSg05P6mKIlROHoBIRNStbrVwlePm603CucojKRPlFJG4rt7sFZQOo8xS8I7z1BmE4QI3/ZE9A==", "requires": { "@optimizely/js-sdk-utils": "^0.1.0" + }, + "dependencies": { + "@optimizely/js-sdk-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@optimizely/js-sdk-utils/-/js-sdk-utils-0.1.0.tgz", + "integrity": "sha512-p7499GgVaX94YmkrwOiEtLgxgjXTPbUQsvETaAil5J7zg1TOA4Wl8ClalLSvCh+AKWkxGdkL4/uM/zfbxPSNNw==", + "requires": { + "uuid": "^3.3.2" + } + } } }, "@optimizely/js-sdk-utils": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@optimizely/js-sdk-utils/-/js-sdk-utils-0.1.0.tgz", - "integrity": "sha512-p7499GgVaX94YmkrwOiEtLgxgjXTPbUQsvETaAil5J7zg1TOA4Wl8ClalLSvCh+AKWkxGdkL4/uM/zfbxPSNNw==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@optimizely/js-sdk-utils/-/js-sdk-utils-0.2.0.tgz", + "integrity": "sha512-aHEccRVc5YjWAdIVtniKfUE3tuzHriIWZTS4sLEq/lXkNTITSL1jrBEJD91CVY5BahWu/aG/aOafrA7XGH3sDQ==", "requires": { "uuid": "^3.3.2" } diff --git a/packages/event-processor/package.json b/packages/event-processor/package.json index 40de23765..727bf6231 100644 --- a/packages/event-processor/package.json +++ b/packages/event-processor/package.json @@ -38,7 +38,7 @@ }, "dependencies": { "@optimizely/js-sdk-logging": "^0.1.0", - "@optimizely/js-sdk-utils": "^0.1.0" + "@optimizely/js-sdk-utils": "^0.2.0" }, "devDependencies": { "@types/jest": "^24.0.9", diff --git a/packages/utils/package-lock.json b/packages/utils/package-lock.json index 3e5ad3ac6..5afb33344 100644 --- a/packages/utils/package-lock.json +++ b/packages/utils/package-lock.json @@ -1,6 +1,6 @@ { "name": "@optimizely/js-sdk-utils", - "version": "0.1.0", + "version": "0.2.0", "lockfileVersion": 1, "requires": true, "dependencies": {