diff --git a/package.json b/package.json index 6d2da602..1db9deac 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@eppo/js-client-sdk-common", - "version": "4.7.0", + "version": "4.7.1", "description": "Common library for Eppo JavaScript SDKs (web, react native, and node)", "main": "dist/index.js", "files": [ diff --git a/src/configuration-requestor.ts b/src/configuration-requestor.ts index 543c10b4..14ead0b7 100644 --- a/src/configuration-requestor.ts +++ b/src/configuration-requestor.ts @@ -1,14 +1,7 @@ import { IConfigurationStore } from './configuration-store/configuration-store'; import { hydrateConfigurationStore } from './configuration-store/configuration-store-utils'; import { IHttpClient } from './http-client'; -import { - BanditVariation, - BanditParameters, - Flag, - BanditReference, -} from './interfaces'; - -type Entry = Flag | BanditVariation[] | BanditParameters; +import { BanditVariation, BanditParameters, Flag, BanditReference } from './interfaces'; // Requests AND stores flag configurations export default class ConfigurationRequestor { @@ -63,7 +56,8 @@ export default class ConfigurationRequestor { entries: banditResponse.bandits, environment: configResponse.environment, createdAt: configResponse.createdAt, - format: configResponse.format,}); + format: configResponse.format, + }); this.banditModelVersions = this.getLoadedBanditModelVersionsFromStore( this.banditModelConfigurationStore, diff --git a/src/evaluator.ts b/src/evaluator.ts index f9f4f114..452e3b95 100644 --- a/src/evaluator.ts +++ b/src/evaluator.ts @@ -142,6 +142,7 @@ export class Evaluator { configDetails.configFormat, ); } catch (err: any) { + console.error('>>>>', err); const flagEvaluationDetails = flagEvaluationDetailsBuilder.gracefulBuild( 'ASSIGNMENT_ERROR', `Assignment Error: ${err.message}`, diff --git a/src/events/default-event-dispatcher.spec.ts b/src/events/default-event-dispatcher.spec.ts index ec05d9b3..50d423c8 100644 --- a/src/events/default-event-dispatcher.spec.ts +++ b/src/events/default-event-dispatcher.spec.ts @@ -12,6 +12,7 @@ global.fetch = jest.fn(); const mockNetworkStatusListener = { isOffline: () => false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars onNetworkStatusChange: (_: (_: boolean) => void) => null as unknown as void, }; @@ -154,6 +155,7 @@ describe('DefaultEventDispatcher', () => { describe('offline handling', () => { it('skips delivery when offline', async () => { let isOffline = false; + // eslint-disable-next-line @typescript-eslint/no-unused-vars let cb = (_: boolean) => null as unknown as void; const networkStatusListener = { isOffline: () => isOffline, @@ -188,6 +190,7 @@ describe('DefaultEventDispatcher', () => { it('resumes delivery when back online', async () => { let isOffline = true; + // eslint-disable-next-line @typescript-eslint/no-unused-vars let cb = (_: boolean) => null as unknown as void; const networkStatusListener = { isOffline: () => isOffline, diff --git a/src/events/no-op-event-dispatcher.ts b/src/events/no-op-event-dispatcher.ts index 213ee3a6..6d1b007c 100644 --- a/src/events/no-op-event-dispatcher.ts +++ b/src/events/no-op-event-dispatcher.ts @@ -2,6 +2,7 @@ import Event from './event'; import EventDispatcher from './event-dispatcher'; export default class NoOpEventDispatcher implements EventDispatcher { + // eslint-disable-next-line @typescript-eslint/no-unused-vars dispatch(_: Event): void { // Do nothing } diff --git a/src/flag-evaluation-details-builder.ts b/src/flag-evaluation-details-builder.ts index a30dd0dd..8f45bb35 100644 --- a/src/flag-evaluation-details-builder.ts +++ b/src/flag-evaluation-details-builder.ts @@ -11,7 +11,7 @@ export const flagEvaluationCodes = [ 'BANDIT_ERROR', ] as const; -export type FlagEvaluationCode = typeof flagEvaluationCodes[number]; +export type FlagEvaluationCode = (typeof flagEvaluationCodes)[number]; export enum AllocationEvaluationCode { UNEVALUATED = 'UNEVALUATED', diff --git a/src/obfuscation.spec.ts b/src/obfuscation.spec.ts index fca3edb7..ad3b7420 100644 --- a/src/obfuscation.spec.ts +++ b/src/obfuscation.spec.ts @@ -17,6 +17,17 @@ describe('obfuscation', () => { }); }); + it('encodes/decodes special characters', () => { + const strings = ['kümmert', 'піклуватися', '照顾', '🤗🌸']; + + strings.forEach((string) => { + expect(decodeBase64(encodeBase64(string))).toEqual(string); + expect(decodeBase64(encodeBase64(string))).toEqual(string); + }); + + expect(decodeBase64('a8O8bW1lcnQ=')).toEqual('kümmert'); + }); + describe('salt', () => { it('converts from bytes to base64 string', () => { const chars = new Uint8Array([101, 112, 112, 111]); // eppo diff --git a/src/obfuscation.ts b/src/obfuscation.ts index 703d1f06..8bcff7a4 100644 --- a/src/obfuscation.ts +++ b/src/obfuscation.ts @@ -8,11 +8,11 @@ export function getMD5Hash(input: string, salt = ''): string { } export function encodeBase64(input: string) { - return base64.btoaPolyfill(input); + return base64.encode(input); } export function decodeBase64(input: string) { - return base64.atobPolyfill(input); + return base64.decode(input); } export function obfuscatePrecomputedFlags( diff --git a/test/testHelpers.ts b/test/testHelpers.ts index 0379253b..ebf49798 100644 --- a/test/testHelpers.ts +++ b/test/testHelpers.ts @@ -1,10 +1,10 @@ import * as fs from 'fs'; -import { AttributeType, VariationType } from '../src'; -import { IAssignmentDetails } from '../src/client/eppo-client'; +import { isEqual } from 'lodash'; + +import { AttributeType, ContextAttributes, IAssignmentDetails, VariationType } from '../src'; import { IFlagEvaluationDetails } from '../src/flag-evaluation-details-builder'; import { IBanditParametersResponse, IUniversalFlagConfigResponse } from '../src/http-client'; -import { ContextAttributes } from '../src/types'; export const TEST_DATA_DIR = './test/data/ufc/'; export const ASSIGNMENT_TEST_DATA_DIR = TEST_DATA_DIR + 'tests/'; @@ -125,16 +125,17 @@ export function validateTestAssignments( flag: string, ) { for (const { subject, assignment } of assignments) { - if (typeof assignment !== 'object') { - // the expect works well for objects, but this comparison does not - if (assignment !== subject.assignment) { - throw new Error( - `subject ${ - subject.subjectKey - } was assigned ${assignment?.toString()} when expected ${subject.assignment?.toString()} for flag ${flag}`, - ); - } + if (!isEqual(assignment, subject.assignment)) { + // More friendly error message + console.error( + `subject ${subject.subjectKey} was assigned ${JSON.stringify( + assignment, + undefined, + 2, + )} when expected ${JSON.stringify(subject.assignment, undefined, 2)} for flag ${flag}`, + ); } - expect(subject.assignment).toEqual(assignment); + + expect(assignment).toEqual(subject.assignment); } }