From 36b851da57da4b28a309734e8e613ada2d4690b8 Mon Sep 17 00:00:00 2001 From: Raju Ahmed Date: Fri, 23 May 2025 03:25:52 +0600 Subject: [PATCH] opaque --- lib/error/error_notifier_factory.ts | 14 +++++-- ...ent_processor_factory.react_native.spec.ts | 2 +- .../event_processor_factory.ts | 13 +++++-- lib/logging/logger_factory.ts | 37 +++++++++++++++---- lib/odp/odp_manager_factory.ts | 12 ++++-- lib/project_config/config_manager_factory.ts | 23 ++++++------ 6 files changed, 72 insertions(+), 29 deletions(-) diff --git a/lib/error/error_notifier_factory.ts b/lib/error/error_notifier_factory.ts index 994564f1a..d08639165 100644 --- a/lib/error/error_notifier_factory.ts +++ b/lib/error/error_notifier_factory.ts @@ -16,11 +16,12 @@ import { errorResolver } from "../message/message_resolver"; import { Maybe } from "../utils/type"; import { ErrorHandler } from "./error_handler"; -import { DefaultErrorNotifier } from "./error_notifier"; +import { DefaultErrorNotifier, ErrorNotifier } from "./error_notifier"; export const INVALID_ERROR_HANDLER = 'Invalid error handler'; const errorNotifierSymbol = Symbol(); +const errorNotifierKey = {}; export type OpaqueErrorNotifier = { [errorNotifierSymbol]: unknown; @@ -34,15 +35,20 @@ const validateErrorHandler = (errorHandler: ErrorHandler) => { export const createErrorNotifier = (errorHandler: ErrorHandler): OpaqueErrorNotifier => { validateErrorHandler(errorHandler); + const weakMap = new WeakMap(); + weakMap.set(errorNotifierKey, new DefaultErrorNotifier(errorHandler, errorResolver)); + return { - [errorNotifierSymbol]: new DefaultErrorNotifier(errorHandler, errorResolver), + [errorNotifierSymbol]: weakMap, } } export const extractErrorNotifier = (errorNotifier: Maybe): Maybe => { - if (!errorNotifier || typeof errorNotifier !== 'object') { + if (!errorNotifier || typeof errorNotifier !== 'object' || + !(errorNotifier[errorNotifierSymbol] instanceof WeakMap)) { return undefined; } - return errorNotifier[errorNotifierSymbol] as Maybe; + const weakMap = errorNotifier[errorNotifierSymbol] as WeakMap; + return weakMap.get(errorNotifierKey); } diff --git a/lib/event_processor/event_processor_factory.react_native.spec.ts b/lib/event_processor/event_processor_factory.react_native.spec.ts index 630417a5e..6d0ac973e 100644 --- a/lib/event_processor/event_processor_factory.react_native.spec.ts +++ b/lib/event_processor/event_processor_factory.react_native.spec.ts @@ -79,7 +79,7 @@ describe('createForwardingEventProcessor', () => { mockGetForwardingEventProcessor.mockClear(); }); - it('returns forwarding event processor by calling getForwardingEventProcessor with the provided dispatcher', () => { + it.only('returns forwarding event processor by calling getForwardingEventProcessor with the provided dispatcher', () => { const eventDispatcher = { dispatchEvent: vi.fn(), }; diff --git a/lib/event_processor/event_processor_factory.ts b/lib/event_processor/event_processor_factory.ts index dd50c72f2..760bb3234 100644 --- a/lib/event_processor/event_processor_factory.ts +++ b/lib/event_processor/event_processor_factory.ts @@ -51,6 +51,7 @@ export const getPrefixEventStore = (store: Store): Store => }; const eventProcessorSymbol: unique symbol = Symbol(); +const eventProcessorKey = {}; export type OpaqueEventProcessor = { [eventProcessorSymbol]: unknown; @@ -168,8 +169,11 @@ export const getBatchEventProcessor = ( } export const wrapEventProcessor = (eventProcessor: EventProcessor): OpaqueEventProcessor => { + const weakMap = new WeakMap(); + weakMap.set(eventProcessorKey, eventProcessor); + return { - [eventProcessorSymbol]: eventProcessor, + [eventProcessorSymbol]: weakMap, }; } @@ -181,10 +185,13 @@ export const getOpaqueBatchEventProcessor = ( } export const extractEventProcessor = (eventProcessor: Maybe): Maybe => { - if (!eventProcessor || typeof eventProcessor !== 'object') { + if (!eventProcessor || typeof eventProcessor !== 'object' || + !(eventProcessor[eventProcessorSymbol] instanceof WeakMap)) { return undefined; } - return eventProcessor[eventProcessorSymbol] as Maybe; + + const weakMap = eventProcessor[eventProcessorSymbol] as WeakMap; + return weakMap.get(eventProcessorKey); } diff --git a/lib/logging/logger_factory.ts b/lib/logging/logger_factory.ts index 2aee1b535..f1f251b20 100644 --- a/lib/logging/logger_factory.ts +++ b/lib/logging/logger_factory.ts @@ -49,13 +49,24 @@ const errorPreset: LevelPreset = { } const levelPresetSymbol = Symbol(); +const levelPresetKey = {}; + export type OpaqueLevelPreset = { [levelPresetSymbol]: unknown; }; + +// export const DEBUG: OpaqueLevelPreset = { +// [levelPresetSymbol]: debugPreset, +// }; + export const DEBUG: OpaqueLevelPreset = { - [levelPresetSymbol]: debugPreset, + [levelPresetSymbol]: function () { + const weakMap = new WeakMap(); + weakMap.set(levelPresetKey, debugPreset); + return weakMap; + }, }; export const INFO: OpaqueLevelPreset = { @@ -71,13 +82,21 @@ export const ERROR: OpaqueLevelPreset = { }; export const extractLevelPreset = (preset: OpaqueLevelPreset): LevelPreset => { - if (!preset || typeof preset !== 'object' || !preset[levelPresetSymbol]) { + if (!preset || typeof preset !== 'object' || !preset[levelPresetSymbol] + || !(preset[levelPresetSymbol] instanceof WeakMap)) { throw new Error(INVALID_LEVEL_PRESET); } - return preset[levelPresetSymbol] as LevelPreset; + + const weakMap = preset[levelPresetSymbol] as WeakMap; + if (!weakMap.has(levelPresetKey)) { + throw new Error(INVALID_LEVEL_PRESET); + } + + return weakMap.get(levelPresetKey) as LevelPreset; } -const loggerSymbol = Symbol(); +const loggerSymbol: unique symbol = Symbol(); +const loggerKey = {}; export type OpaqueLogger = { [loggerSymbol]: unknown; @@ -115,15 +134,19 @@ export const createLogger = (config: LoggerConfig): OpaqueLogger => { }; export const wrapLogger = (logger: OptimizelyLogger): OpaqueLogger => { + const weakMap = new WeakMap(); + weakMap.set(loggerKey, logger); return { - [loggerSymbol]: logger, + [loggerSymbol]: weakMap, }; }; export const extractLogger = (logger: Maybe): Maybe => { - if (!logger || typeof logger !== 'object') { + if (!logger || typeof logger !== 'object' || + !(logger[loggerSymbol] instanceof WeakMap)) { return undefined; } - return logger[loggerSymbol] as Maybe; + const weakMap = logger[loggerSymbol] as WeakMap; + return weakMap.get(loggerKey); }; diff --git a/lib/odp/odp_manager_factory.ts b/lib/odp/odp_manager_factory.ts index 9fd689964..f82f88235 100644 --- a/lib/odp/odp_manager_factory.ts +++ b/lib/odp/odp_manager_factory.ts @@ -39,6 +39,7 @@ export const INVALID_CACHE = 'Invalid cache'; export const INVALID_CACHE_METHOD = 'Invalid cache method %s'; const odpManagerSymbol: unique symbol = Symbol(); +const odpManagerKey = {}; export type OpaqueOdpManager = { [odpManagerSymbol]: unknown; @@ -124,15 +125,20 @@ export const getOdpManager = (options: OdpManagerFactoryOptions): OdpManager => }; export const getOpaqueOdpManager = (options: OdpManagerFactoryOptions): OpaqueOdpManager => { + const weakMap = new WeakMap(); + weakMap.set(odpManagerKey, getOdpManager(options)); + return { - [odpManagerSymbol]: getOdpManager(options), + [odpManagerSymbol]: weakMap, }; }; export const extractOdpManager = (manager: Maybe): Maybe => { - if (!manager || typeof manager !== 'object') { + if (!manager || typeof manager !== 'object' || + !(manager[odpManagerSymbol] instanceof WeakMap)) { return undefined; } - return manager[odpManagerSymbol] as Maybe; + const weakMap = manager[odpManagerSymbol] as WeakMap; + return weakMap.get(odpManagerKey); } diff --git a/lib/project_config/config_manager_factory.ts b/lib/project_config/config_manager_factory.ts index 89c60593c..7fb0b023c 100644 --- a/lib/project_config/config_manager_factory.ts +++ b/lib/project_config/config_manager_factory.ts @@ -29,6 +29,7 @@ import { Store } from "../utils/cache/store"; export const INVALID_CONFIG_MANAGER = "Invalid config manager"; const configManagerSymbol: unique symbol = Symbol(); +const configManagerKey = {}; export type OpaqueConfigManager = { [configManagerSymbol]: unknown; @@ -42,9 +43,7 @@ export type StaticConfigManagerConfig = { export const createStaticProjectConfigManager = ( config: StaticConfigManagerConfig ): OpaqueConfigManager => { - return { - [configManagerSymbol]: new ProjectConfigManagerImpl(config), - } + return wrapConfigManager(new ProjectConfigManagerImpl(config)); }; export type PollingConfigManagerConfig = { @@ -99,26 +98,28 @@ export const getPollingConfigManager = ( }; export const getOpaquePollingConfigManager = (opt: PollingConfigManagerFactoryOptions): OpaqueConfigManager => { - return { - [configManagerSymbol]: getPollingConfigManager(opt), - }; + return wrapConfigManager(getPollingConfigManager(opt)); }; export const wrapConfigManager = (configManager: ProjectConfigManager): OpaqueConfigManager => { + const weakMap = new WeakMap(); + weakMap.set(configManagerKey, configManager); return { - [configManagerSymbol]: configManager, + [configManagerSymbol]: weakMap, }; }; export const extractConfigManager = (opaqueConfigManager: OpaqueConfigManager): ProjectConfigManager => { - if (!opaqueConfigManager || typeof opaqueConfigManager !== 'object') { + if (!opaqueConfigManager || typeof opaqueConfigManager !== 'object' || + !(opaqueConfigManager[configManagerSymbol] instanceof WeakMap)) { throw new Error(INVALID_CONFIG_MANAGER); } - const configManager = opaqueConfigManager[configManagerSymbol]; + const weakMap = opaqueConfigManager[configManagerSymbol] as WeakMap; + const configManager = weakMap.get(configManagerKey); + if (!configManager) { throw new Error(INVALID_CONFIG_MANAGER); } - - return opaqueConfigManager[configManagerSymbol] as ProjectConfigManager; + return configManager; };