From 8bf8cbd780cf18c96f248fb28d6fbbef0f642c91 Mon Sep 17 00:00:00 2001 From: Aaron Silverman Date: Sat, 4 Oct 2025 09:31:39 -0400 Subject: [PATCH 1/4] conform to pino interface --- src/index.spec.ts | 12 +++++++--- src/index.ts | 43 +++++++++++++++++++++------------- src/isolatable-hybrid.store.ts | 4 ++-- 3 files changed, 38 insertions(+), 21 deletions(-) diff --git a/src/index.spec.ts b/src/index.spec.ts index b24238f..463de41 100644 --- a/src/index.spec.ts +++ b/src/index.spec.ts @@ -1679,9 +1679,15 @@ describe('EppoClient config', () => { }); expect(client).toBe(EppoPrecomputedJSClient.instance); - td.verify(applicationLogger.error('[Eppo SDK] Invalid precomputed configuration wire'), { - times: 1, - }); + td.verify( + applicationLogger.error( + td.matchers.contains({ err: td.matchers.anything() }), + '[Eppo SDK] Invalid precomputed configuration wire', + ), + { + times: 1, + }, + ); }); }); diff --git a/src/index.ts b/src/index.ts index daac6db..228750f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -424,12 +424,12 @@ export class EppoJSClient extends EppoClient { return ConfigLoaderStatus.COMPLETED; }) - .catch((e) => { + .catch((err) => { applicationLogger.warn( + { err }, 'Eppo SDK encountered an error initializing from the configuration store', - e, ); - initFromConfigStoreError = e; + initFromConfigStoreError = err; return ConfigLoaderStatus.FAILED; }) .then((status) => { @@ -457,10 +457,13 @@ export class EppoJSClient extends EppoClient { return ConfigLoaderStatus.DID_NOT_PRODUCE; } }) - .catch((e) => { - applicationLogger.warn('Eppo SDK encountered an error initializing from fetching', e); + .catch((err) => { + applicationLogger.warn( + { err }, + 'Eppo SDK encountered an error initializing from fetching', + ); // eslint-disable-next-line @typescript-eslint/no-unused-vars - initFromFetchError = e; + initFromFetchError = err; return ConfigLoaderStatus.FAILED; }) .then((status) => { @@ -501,7 +504,7 @@ export class EppoJSClient extends EppoClient { ? initFromConfigStoreError : new Error('Eppo SDK: No configuration source produced a valid configuration'); } - applicationLogger.debug('Initialization source', initializationSource); + applicationLogger.debug(`Initialization source: ${initializationSource}`); } catch (error: unknown) { initializationError = error instanceof Error ? error : new Error(String(error)); } @@ -544,7 +547,10 @@ export class EppoJSClient extends EppoClient { memoryOnlyConfigurationStore .setEntries(config.flagsConfiguration) .catch((err) => - applicationLogger.warn('Error setting flags for memory-only configuration store', err), + applicationLogger.warn( + { err }, + 'Error setting flags for memory-only configuration store', + ), ); this.setFlagConfigurationStore(memoryOnlyConfigurationStore); @@ -591,12 +597,13 @@ export class EppoJSClient extends EppoClient { forceMemoryOnly: true, }); this.useCustomAssignmentCache(assignmentCache); - } catch (error) { + } catch (err) { applicationLogger.warn( + { err }, 'Eppo SDK encountered an error initializing, assignment calls will return the default value and not be logged', ); if (throwOnFailedInitialization) { - throw error; + throw err; } } @@ -893,12 +900,12 @@ export function offlinePrecomputedInit( try { configurationWire = JSON.parse(config.precomputedConfiguration); if (!configurationWire.precomputed) throw new Error(); - } catch (error) { + } catch (err) { const errorMessage = 'Invalid precomputed configuration wire'; if (throwOnFailedInitialization) { throw new Error(errorMessage); } - applicationLogger.error(`[Eppo SDK] ${errorMessage}`); + applicationLogger.error({ err }, `[Eppo SDK] ${errorMessage}`); return EppoPrecomputedJSClient.instance; } const { subjectKey, subjectAttributes, response } = configurationWire.precomputed; @@ -909,7 +916,10 @@ export function offlinePrecomputedInit( memoryOnlyPrecomputedStore .setEntries(parsedResponse.flags) .catch((err) => - applicationLogger.warn('Error setting precomputed assignments for memory-only store', err), + applicationLogger.warn( + { err }, + 'Error setting precomputed assignments for memory-only store', + ), ); memoryOnlyPrecomputedStore.salt = parsedResponse.salt; @@ -917,7 +927,7 @@ export function offlinePrecomputedInit( memoryOnlyPrecomputedBanditStore .setEntries(parsedResponse.bandits) .catch((err) => - applicationLogger.warn('Error setting precomputed bandits for memory-only store', err), + applicationLogger.warn({ err }, 'Error setting precomputed bandits for memory-only store'), ); memoryOnlyPrecomputedBanditStore.salt = parsedResponse.salt; @@ -963,12 +973,13 @@ export function offlinePrecomputedInit( EppoPrecomputedJSClient.instance.setBanditLogger(config.banditLogger); } EppoPrecomputedJSClient.instance.useCustomAssignmentCache(assignmentCache); - } catch (error) { + } catch (err) { applicationLogger.warn( + { err }, '[Eppo SDK] Encountered an error initializing precomputed client, assignment calls will return the default value and not be logged', ); if (throwOnFailedInitialization) { - throw error; + throw err; } } diff --git a/src/isolatable-hybrid.store.ts b/src/isolatable-hybrid.store.ts index 8ea831b..adea4c3 100644 --- a/src/isolatable-hybrid.store.ts +++ b/src/isolatable-hybrid.store.ts @@ -29,8 +29,8 @@ export class IsolatableHybridConfigurationStore extends HybridConfigurationSt try { // always update persistent store await this.persistentStore.setEntries(entries); - } catch (e) { - applicationLogger.warn(`Failed to setEntries on persistent store: ${e}`); + } catch (err) { + applicationLogger.warn({ err }, `Failed to setEntries on persistent store`); } } From a4721d954752f253dabf12071040327f590070c6 Mon Sep 17 00:00:00 2001 From: Aaron Silverman Date: Sat, 4 Oct 2025 15:09:47 -0400 Subject: [PATCH 2/4] expose set log level --- js-client-sdk.api.md | 6 ++++++ src/index.ts | 25 +++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/js-client-sdk.api.md b/js-client-sdk.api.md index 05762c4..4ec328b 100644 --- a/js-client-sdk.api.md +++ b/js-client-sdk.api.md @@ -216,6 +216,9 @@ export interface IPrecomputedClientConfigSync { throwOnFailedInitialization?: boolean; } +// @public +export type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent'; + // Warning: (ae-internal-missing-underscore) The name "NO_OP_EVENT_DISPATCHER" should be prefixed with an underscore because the declaration is marked as @internal // // @internal (undocumented) @@ -232,6 +235,9 @@ export function offlinePrecomputedInit(config: IPrecomputedClientConfigSync): Ep // @public export function precomputedInit(config: IPrecomputedClientConfig): Promise; +// @public +export function setLogLevel(level: LogLevel): void; + // (No @packageDocumentation comment for this package) ``` diff --git a/src/index.ts b/src/index.ts index 228750f..cb9eade 100644 --- a/src/index.ts +++ b/src/index.ts @@ -48,6 +48,12 @@ import LocalStorageBackedNamedEventQueue from './events/local-storage-backed-nam import { IClientConfig, IPrecomputedClientConfig } from './i-client-config'; import { sdkName, sdkVersion } from './sdk-data'; +/** + * Valid log levels for the Eppo SDK logger. + * @public + */ +export type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent'; + /** * Configuration interface for synchronous client initialization. * @public @@ -1005,6 +1011,25 @@ export function getPrecomputedInstance(): EppoPrecomputedClient { return EppoPrecomputedJSClient.instance; } +/** + * Sets the log level for the Eppo SDK logger globally. + * This affects all logging across the entire SDK, including both + * EppoJSClient and EppoPrecomputedJSClient instances. + * + * @param level - The log level to set: + * - 'trace': Most verbose, logs everything + * - 'debug': Detailed debugging information + * - 'info': General informational messages + * - 'warn': Warning messages (default in production) + * - 'error': Error messages only + * - 'silent': Disable all logging + * + * @public + */ +export function setLogLevel(level: LogLevel): void { + applicationLogger.level = level; +} + function newEventDispatcher( sdkKey: string, config: IClientConfig['eventTracking'] = {}, From 0f710d41b22ace767b0cc033827bf1fe72cb7b0a Mon Sep 17 00:00:00 2001 From: Aaron Silverman Date: Sat, 4 Oct 2025 18:38:25 -0400 Subject: [PATCH 3/4] bump version --- docs/js-client-sdk.loglevel.md | 13 +++++++ docs/js-client-sdk.md | 37 ++++++++++++++++++ docs/js-client-sdk.setloglevel.md | 54 ++++++++++++++++++++++++++ package.json | 4 +- yarn.lock | 63 ++++++++++++++++++++----------- 5 files changed, 148 insertions(+), 23 deletions(-) create mode 100644 docs/js-client-sdk.loglevel.md create mode 100644 docs/js-client-sdk.setloglevel.md diff --git a/docs/js-client-sdk.loglevel.md b/docs/js-client-sdk.loglevel.md new file mode 100644 index 0000000..1c0545a --- /dev/null +++ b/docs/js-client-sdk.loglevel.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@eppo/js-client-sdk](./js-client-sdk.md) > [LogLevel](./js-client-sdk.loglevel.md) + +## LogLevel type + +Valid log levels for the Eppo SDK logger. + +**Signature:** + +```typescript +export declare type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent'; +``` diff --git a/docs/js-client-sdk.md b/docs/js-client-sdk.md index dabb2c4..660ed7f 100644 --- a/docs/js-client-sdk.md +++ b/docs/js-client-sdk.md @@ -164,6 +164,17 @@ This method should be called once on application startup. Initializes the Eppo precomputed client with configuration parameters. This method should be called once on application startup. + + + +[setLogLevel(level)](./js-client-sdk.setloglevel.md) + + + + +Sets the log level for the Eppo SDK logger globally. This affects all logging across the entire SDK, including both EppoJSClient and EppoPrecomputedJSClient instances. + + @@ -228,3 +239,29 @@ This interface is used for cases where precomputed assignments are available fro +## Type Aliases + + + +
+ +Type Alias + + + + +Description + + +
+ +[LogLevel](./js-client-sdk.loglevel.md) + + + + +Valid log levels for the Eppo SDK logger. + + +
+ diff --git a/docs/js-client-sdk.setloglevel.md b/docs/js-client-sdk.setloglevel.md new file mode 100644 index 0000000..4478f9f --- /dev/null +++ b/docs/js-client-sdk.setloglevel.md @@ -0,0 +1,54 @@ + + +[Home](./index.md) > [@eppo/js-client-sdk](./js-client-sdk.md) > [setLogLevel](./js-client-sdk.setloglevel.md) + +## setLogLevel() function + +Sets the log level for the Eppo SDK logger globally. This affects all logging across the entire SDK, including both EppoJSClient and EppoPrecomputedJSClient instances. + +**Signature:** + +```typescript +export declare function setLogLevel(level: LogLevel): void; +``` + +## Parameters + + + +
+ +Parameter + + + + +Type + + + + +Description + + +
+ +level + + + + +[LogLevel](./js-client-sdk.loglevel.md) + + + + +The log level to set: - 'trace': Most verbose, logs everything - 'debug': Detailed debugging information - 'info': General informational messages - 'warn': Warning messages (default in production) - 'error': Error messages only - 'silent': Disable all logging + + +
+ +**Returns:** + +void + diff --git a/package.json b/package.json index b85af90..205e22e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@eppo/js-client-sdk", - "version": "3.17.0", + "version": "3.18.0", "description": "Eppo SDK for client-side JavaScript applications", "main": "dist/index.js", "files": [ @@ -59,7 +59,7 @@ "webpack-cli": "^6.0.1" }, "dependencies": { - "@eppo/js-client-sdk-common": "4.15.1", + "@eppo/js-client-sdk-common": "/tmp/packages/js-sdk-common", "@types/chrome": "^0.0.313", "lz-string": "^1.5.0" }, diff --git a/yarn.lock b/yarn.lock index 5c7a771..4e86551 100644 --- a/yarn.lock +++ b/yarn.lock @@ -402,10 +402,8 @@ dependencies: tslib "^2.4.0" -"@eppo/js-client-sdk-common@4.15.1": - version "4.15.1" - resolved "https://registry.yarnpkg.com/@eppo/js-client-sdk-common/-/js-client-sdk-common-4.15.1.tgz#bf2d602b1462eb156224edd73f734a3c99267816" - integrity sha512-ZVyczDCfAMAnuUlfE293b6h2wfDOcZnfxXHS52r0OU9GktdTYD9EuC3Arpzw4JeTgzV1vW6iTzoz5HDJHwZz6A== +"@eppo/js-client-sdk-common@/tmp/packages/js-sdk-common": + version "4.15.3" dependencies: buffer "npm:@eppo/buffer@6.2.0" js-base64 "^3.7.7" @@ -413,6 +411,7 @@ semver "^7.5.4" spark-md5 "^3.0.2" uuid "^11.0.5" + yargs "^17.7.2" "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.1" @@ -1994,6 +1993,15 @@ cliui@^7.0.2: strip-ansi "^6.0.0" wrap-ansi "^7.0.0" +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + clone-deep@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" @@ -2753,11 +2761,6 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== -fast-redact@^3.1.1: - version "3.5.0" - resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.5.0.tgz#e9ea02f7e57d0cd8438180083e93077e496285e4" - integrity sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A== - fast-uri@^3.0.1: version "3.0.3" resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.3.tgz#892a1c91802d5d7860de728f18608a0573142241" @@ -3962,9 +3965,9 @@ jju@~1.4.0: integrity sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA== js-base64@^3.7.7: - version "3.7.7" - resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.7.7.tgz#e51b84bf78fbf5702b9541e2cb7bfcb893b43e79" - integrity sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw== + version "3.7.8" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.7.8.tgz#af44496bc09fa178ed9c4adf67eb2b46f5c6d2a4" + integrity sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow== js-tokens@^4.0.0: version "4.0.0" @@ -4573,19 +4576,19 @@ pino-std-serializers@^7.0.0: integrity sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA== pino@^9.5.0: - version "9.6.0" - resolved "https://registry.yarnpkg.com/pino/-/pino-9.6.0.tgz#6bc628159ba0cc81806d286718903b7fc6b13169" - integrity sha512-i85pKRCt4qMjZ1+L7sy2Ag4t1atFcdbEt76+7iRJn1g2BvsnRMGu9p8pivl9fs63M2kF/A0OacFZhTub+m/qMg== + version "9.13.1" + resolved "https://registry.yarnpkg.com/pino/-/pino-9.13.1.tgz#55f0230cf691af42510c6dee08eeaca7319418ea" + integrity sha512-Szuj+ViDTjKPQYiKumGmEn3frdl+ZPSdosHyt9SnUevFosOkMY2b7ipxlEctNKPmMD/VibeBI+ZcZCJK+4DPuw== dependencies: atomic-sleep "^1.0.0" - fast-redact "^3.1.1" on-exit-leak-free "^2.1.0" pino-abstract-transport "^2.0.0" pino-std-serializers "^7.0.0" - process-warning "^4.0.0" + process-warning "^5.0.0" quick-format-unescaped "^4.0.3" real-require "^0.2.0" safe-stable-stringify "^2.3.1" + slow-redact "^0.3.0" sonic-boom "^4.0.1" thread-stream "^3.0.0" @@ -4637,10 +4640,10 @@ pretty-format@^29.0.0, pretty-format@^29.7.0: ansi-styles "^5.0.0" react-is "^18.0.0" -process-warning@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-4.0.1.tgz#5c1db66007c67c756e4e09eb170cdece15da32fb" - integrity sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q== +process-warning@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-5.0.0.tgz#566e0bf79d1dff30a72d8bbbe9e8ecefe8d378d7" + integrity sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA== prompts@^2.0.1: version "2.4.2" @@ -5041,6 +5044,11 @@ slice-ansi@^7.1.0: ansi-styles "^6.2.1" is-fullwidth-code-point "^5.0.0" +slow-redact@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/slow-redact/-/slow-redact-0.3.1.tgz#4cb9ad7011dcba97b8a4b58ce8a5d660243100f6" + integrity sha512-NvFvl1GuLZNW4U046Tfi8b26zXo8aBzgCAS2f7yVJR/fArN93mOqSA99cB9uITm92ajSz01bsu1K7SCVVjIMpQ== + sonic-boom@^4.0.1: version "4.2.0" resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-4.2.0.tgz#e59a525f831210fa4ef1896428338641ac1c124d" @@ -5875,6 +5883,19 @@ yargs@^17.3.1: y18n "^5.0.5" yargs-parser "^21.0.0" +yargs@^17.7.2: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + yn@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" From fe3090ab0c79eaa4cf690cdbaf32efd69609b93b Mon Sep 17 00:00:00 2001 From: Aaron Silverman Date: Mon, 6 Oct 2025 12:02:56 -0400 Subject: [PATCH 4/4] use updated common --- package.json | 2 +- yarn.lock | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 205e22e..fa1bdda 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "webpack-cli": "^6.0.1" }, "dependencies": { - "@eppo/js-client-sdk-common": "/tmp/packages/js-sdk-common", + "@eppo/js-client-sdk-common": "4.15.3", "@types/chrome": "^0.0.313", "lz-string": "^1.5.0" }, diff --git a/yarn.lock b/yarn.lock index 4e86551..f49467e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -402,8 +402,10 @@ dependencies: tslib "^2.4.0" -"@eppo/js-client-sdk-common@/tmp/packages/js-sdk-common": +"@eppo/js-client-sdk-common@4.15.3": version "4.15.3" + resolved "https://registry.yarnpkg.com/@eppo/js-client-sdk-common/-/js-client-sdk-common-4.15.3.tgz#70fa31a240b5b482d3f0d654b16ec946525c26d2" + integrity sha512-boO/HetQAN5Qi+MAEzCetNteb+h5J4iC4qUcijaqlxLtWx2hUpAcAgRgUEQ4OpRtXSg3HjIgZWJzmhMj+zyYgg== dependencies: buffer "npm:@eppo/buffer@6.2.0" js-base64 "^3.7.7"