Skip to content

Commit 065b8e7

Browse files
committed
[FSSDK-10989] refactor notification center types
1 parent c2880e9 commit 065b8e7

File tree

9 files changed

+280
-212
lines changed

9 files changed

+280
-212
lines changed

lib/export_types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ export {
3939
ListenerPayload,
4040
OptimizelyDecision,
4141
OptimizelyUserContext,
42-
NotificationListener,
4342
Config,
4443
Client,
4544
ActivateListenerPayload,

lib/notification_center/index.tests.js

Lines changed: 136 additions & 135 deletions
Large diffs are not rendered by default.

lib/notification_center/index.ts

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2020, 2022, Optimizely
2+
* Copyright 2020, 2022, 2024, Optimizely
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,14 +15,16 @@
1515
*/
1616
import { LogHandler, ErrorHandler } from '../modules/logging';
1717
import { objectValues } from '../utils/fns';
18-
import { NotificationListener, ListenerPayload } from '../shared_types';
1918

2019
import {
2120
LOG_LEVEL,
2221
LOG_MESSAGES,
23-
NOTIFICATION_TYPES,
2422
} from '../utils/enums';
2523

24+
import { NOTIFICATION_TYPES } from './type';
25+
import { NotificationType, NotificationPayload } from './type';
26+
import { Consumer } from '../utils/type';
27+
2628
const MODULE_NAME = 'NOTIFICATION_CENTER';
2729

2830
interface NotificationCenterOptions {
@@ -40,13 +42,30 @@ type NotificationListeners = {
4042
[key: string]: ListenerEntry[];
4143
}
4244

45+
export interface NotificationCenter {
46+
addNotificationListener<N extends NotificationType>(
47+
notificationType: N,
48+
callback: Consumer<NotificationPayload[N]>
49+
): number
50+
removeNotificationListener(listenerId: number): boolean;
51+
clearAllNotificationListeners(): void;
52+
clearNotificationListeners(notificationType: NotificationType): void;
53+
}
54+
55+
export interface NotificationSender {
56+
sendNotifications<N extends NotificationType>(
57+
notificationType: N,
58+
notificationData: NotificationPayload[N]
59+
): void;
60+
}
61+
4362
/**
4463
* NotificationCenter allows registration and triggering of callback functions using
4564
* notification event types defined in NOTIFICATION_TYPES of utils/enums/index.js:
4665
* - ACTIVATE: An impression event will be sent to Optimizely.
4766
* - TRACK a conversion event will be sent to Optimizely
4867
*/
49-
export class NotificationCenter {
68+
export class DefaultNotificationCenter implements NotificationCenter, NotificationSender {
5069
private logger: LogHandler;
5170
private errorHandler: ErrorHandler;
5271
private notificationListeners: NotificationListeners;
@@ -80,9 +99,9 @@ export class NotificationCenter {
8099
* can happen if the first argument is not a valid notification type, or if the same callback
81100
* function was already added as a listener by a prior call to this function.
82101
*/
83-
addNotificationListener<T extends ListenerPayload>(
84-
notificationType: string,
85-
callback: NotificationListener<T>
102+
addNotificationListener<N extends NotificationType>(
103+
notificationType: N,
104+
callback: Consumer<NotificationPayload[N]>
86105
): number {
87106
try {
88107
const notificationTypeValues: string[] = objectValues(NOTIFICATION_TYPES);
@@ -187,7 +206,7 @@ export class NotificationCenter {
187206
* Remove all previously added notification listeners for the argument type
188207
* @param {NOTIFICATION_TYPES} notificationType One of NOTIFICATION_TYPES
189208
*/
190-
clearNotificationListeners(notificationType: NOTIFICATION_TYPES): void {
209+
clearNotificationListeners(notificationType: NotificationType): void {
191210
try {
192211
this.notificationListeners[notificationType] = [];
193212
} catch (e: any) {
@@ -202,9 +221,9 @@ export class NotificationCenter {
202221
* @param {string} notificationType One of NOTIFICATION_TYPES
203222
* @param {Object} notificationData Will be passed to callbacks called
204223
*/
205-
sendNotifications<T extends ListenerPayload>(
206-
notificationType: string,
207-
notificationData?: T
224+
sendNotifications<N extends NotificationType>(
225+
notificationType: N,
226+
notificationData: NotificationPayload[N]
208227
): void {
209228
try {
210229
(this.notificationListeners[notificationType] || []).forEach(
@@ -235,12 +254,6 @@ export class NotificationCenter {
235254
* @param {NotificationCenterOptions} options
236255
* @returns {NotificationCenter} An instance of NotificationCenter
237256
*/
238-
export function createNotificationCenter(options: NotificationCenterOptions): NotificationCenter {
239-
return new NotificationCenter(options);
240-
}
241-
242-
export interface NotificationSender {
243-
// TODO[OASIS-6649]: Don't use any type
244-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
245-
sendNotifications(notificationType: NOTIFICATION_TYPES, notificationData?: any): void
257+
export function createNotificationCenter(options: NotificationCenterOptions): DefaultNotificationCenter {
258+
return new DefaultNotificationCenter(options);
246259
}

lib/notification_center/type.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { LogEvent } from '../event_processor/event_dispatcher/event_dispatcher';
2+
import { EventTags, Experiment, UserAttributes, Variation } from '../shared_types';
3+
4+
export type UserEventListenerPayload = {
5+
userId: string;
6+
attributes?: UserAttributes;
7+
}
8+
9+
export type ActivateListenerPayload = UserEventListenerPayload & {
10+
experiment: Experiment | null;
11+
variation: Variation | null;
12+
logEvent: LogEvent;
13+
}
14+
15+
export type TrackListenerPayload = UserEventListenerPayload & {
16+
eventKey: string;
17+
eventTags?: EventTags;
18+
logEvent: LogEvent;
19+
}
20+
21+
export const DECISION_NOTIFICATION_TYPES = {
22+
AB_TEST: 'ab-test',
23+
FEATURE: 'feature',
24+
FEATURE_TEST: 'feature-test',
25+
FEATURE_VARIABLE: 'feature-variable',
26+
ALL_FEATURE_VARIABLES: 'all-feature-variables',
27+
FLAG: 'flag',
28+
} as const;
29+
30+
export type DecisionNotificationType = typeof DECISION_NOTIFICATION_TYPES[keyof typeof DECISION_NOTIFICATION_TYPES];
31+
32+
// TODO: Add more specific types for decision info
33+
export type OptimizelyDecisionInfo = Record<string, any>;
34+
35+
export type DecisionListenerPayload = UserEventListenerPayload & {
36+
type: DecisionNotificationType;
37+
decisionInfo: OptimizelyDecisionInfo;
38+
}
39+
40+
export type LogEventListenerPayload = LogEvent;
41+
42+
export type OptimizelyConfigUpdateListenerPayload = undefined;
43+
44+
export type NotificationPayload = {
45+
ACTIVATE: ActivateListenerPayload;
46+
DECISION: DecisionListenerPayload;
47+
TRACK: TrackListenerPayload;
48+
LOG_EVENT: LogEventListenerPayload;
49+
OPTIMIZELY_CONFIG_UPDATE: OptimizelyConfigUpdateListenerPayload;
50+
};
51+
52+
export type NotificationType = keyof NotificationPayload;
53+
54+
export type NotiticationTypeValues = {
55+
[key in NotificationType]: key;
56+
}
57+
58+
export const NOTIFICATION_TYPES: NotiticationTypeValues = {
59+
ACTIVATE: 'ACTIVATE',
60+
DECISION: 'DECISION',
61+
LOG_EVENT: 'LOG_EVENT',
62+
OPTIMIZELY_CONFIG_UPDATE: 'OPTIMIZELY_CONFIG_UPDATE',
63+
TRACK: 'TRACK',
64+
};

0 commit comments

Comments
 (0)