Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
e20ef73
detatched construction
typotter Jan 30, 2025
50e66aa
combine new and old constructors
typotter Jan 30, 2025
de9f653
use spark for md5 instead of non-exported member from common
typotter Jan 31, 2025
fa5baab
update to latest common, use exported members
typotter Jan 31, 2025
953c4e4
doc comments
typotter Jan 31, 2025
159df11
wip
typotter Jan 31, 2025
a73bf0c
skip initial config for now
typotter Jan 31, 2025
7e5abe1
exports
typotter Jan 31, 2025
92cdd1d
waitForReady
typotter Jan 31, 2025
c4b2717
clean up offline init method
typotter Jan 31, 2025
ddab6c0
no need to export
typotter Jan 31, 2025
d55d23d
DOCS
typotter Jan 31, 2025
3c18bc9
builder method
typotter Feb 4, 2025
4b8077f
polish
typotter Feb 5, 2025
621cccb
chore: Move initialization code from static to the instance
typotter Feb 11, 2025
ed3c4ce
docs
typotter Feb 11, 2025
5f96888
lint
typotter Feb 12, 2025
228e1e4
move reinit check
typotter Feb 13, 2025
4d35d4f
restore buffered init
typotter Feb 13, 2025
cf3c2ba
docs
typotter Feb 13, 2025
132c0a5
docs
typotter Feb 13, 2025
6141581
polish
typotter Feb 5, 2025
82ec342
test name
typotter Feb 5, 2025
81ff3b1
move comment
typotter Feb 11, 2025
fad43d3
move forceReinit
typotter Feb 13, 2025
febb3f8
docs
typotter Feb 13, 2025
212e26e
move members
typotter Feb 13, 2025
a943e90
refactor wip
typotter Feb 14, 2025
ba219f2
chore: Move initialization code from static to the instance
typotter Feb 11, 2025
5333574
docs
typotter Feb 11, 2025
aab1009
lint
typotter Feb 12, 2025
f93fa61
docs
typotter Feb 13, 2025
030aa33
docs
typotter Feb 14, 2025
e61ec6c
merge fixes
typotter Feb 14, 2025
a000205
fix the horrible diff and merge artifacts
typotter Feb 14, 2025
6f1a68e
docs
typotter Feb 14, 2025
654ffaa
cleamup merge
typotter Feb 14, 2025
74498b9
merge main
typotter Feb 18, 2025
9176d21
docs
typotter Feb 18, 2025
a179e32
merge main
typotter Feb 21, 2025
0734752
chore: lint
typotter Feb 21, 2025
fb76db9
undeprecate
typotter Feb 21, 2025
a384132
chore: additional comments
typotter Feb 21, 2025
3ae0ec7
chore: update docs
typotter Feb 21, 2025
98bd24a
chore: deprecate static EppoJSClient.initialized
typotter Feb 21, 2025
2d45fe5
v3.12.0
typotter Feb 21, 2025
5d3cabc
Merge branch 'main' into tp/namespace
typotter Feb 24, 2025
2712f6b
chore: nit
typotter Feb 24, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
"webpack-cli": "^6.0.1"
},
"dependencies": {
"@eppo/js-client-sdk-common": "4.8.4"
"@eppo/js-client-sdk-common": "4.9.0"
},
"packageManager": "[email protected]+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}
134 changes: 134 additions & 0 deletions src/client-options-converter.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import {
IConfigurationStore,
ObfuscatedFlag,
Flag,
EventDispatcher,
} from '@eppo/js-client-sdk-common';
import * as td from 'testdouble';

import { clientOptionsToParameters } from './client-options-converter';
import { IClientOptions } from './i-client-config';
import { sdkName, sdkVersion } from './sdk-data';

describe('clientOptionsToParameters', () => {
const mockStore = td.object<IConfigurationStore<Flag | ObfuscatedFlag>>();

it('converts basic client options', () => {
const options: IClientOptions = {
sdkKey: 'test-key',
baseUrl: 'https://test.eppo.cloud',
assignmentLogger: { logAssignment: jest.fn() },
};

const result = clientOptionsToParameters(options, mockStore);

expect(result.isObfuscated).toBe(true);
expect(result.flagConfigurationStore).toBeDefined();
expect(result.configurationRequestParameters).toEqual({
apiKey: 'test-key',
baseUrl: 'https://test.eppo.cloud',
sdkName,
sdkVersion,
numInitialRequestRetries: undefined,
numPollRequestRetries: undefined,
pollingIntervalMs: undefined,
requestTimeoutMs: undefined,
pollAfterFailedInitialization: undefined,
pollAfterSuccessfulInitialization: undefined,
throwOnFailedInitialization: undefined,
skipInitialPoll: undefined,
});
});

it('uses provided flag configuration store', () => {
const options: IClientOptions = {
sdkKey: 'test-key',
assignmentLogger: { logAssignment: jest.fn() },
};

const result = clientOptionsToParameters(options, mockStore);

expect(result.flagConfigurationStore).toBe(mockStore);
});

it('converts client options with event ingestion config', () => {
const options: IClientOptions = {
sdkKey: 'test-key',
assignmentLogger: { logAssignment: jest.fn() },
};
const mockDispatcher: EventDispatcher = td.object<EventDispatcher>();

const result = clientOptionsToParameters(options, mockStore, mockDispatcher);

expect(result.eventDispatcher).toBeDefined();
});

it('converts client options with polling configuration', () => {
const options: IClientOptions = {
sdkKey: 'test-key',
assignmentLogger: { logAssignment: jest.fn() },
pollingIntervalMs: 30000,
pollAfterSuccessfulInitialization: true,
pollAfterFailedInitialization: true,
skipInitialRequest: true,
};

const result = clientOptionsToParameters(options, mockStore);

expect(result.configurationRequestParameters).toMatchObject({
pollingIntervalMs: 30000,
pollAfterSuccessfulInitialization: true,
pollAfterFailedInitialization: true,
skipInitialPoll: true,
});
});

it('converts client options with retry configuration', () => {
const options: IClientOptions = {
sdkKey: 'test-key',
assignmentLogger: { logAssignment: jest.fn() },
requestTimeoutMs: 5000,
numInitialRequestRetries: 3,
numPollRequestRetries: 2,
};

const result = clientOptionsToParameters(options, mockStore);

expect(result.configurationRequestParameters).toMatchObject({
requestTimeoutMs: 5000,
numInitialRequestRetries: 3,
numPollRequestRetries: 2,
});
});

it('handles undefined optional parameters', () => {
const options: IClientOptions = {
sdkKey: 'test-key',
assignmentLogger: { logAssignment: jest.fn() },
};

const result = clientOptionsToParameters(options, mockStore);

expect(result.configurationRequestParameters).toMatchObject({
baseUrl: undefined,
pollingIntervalMs: undefined,
requestTimeoutMs: undefined,
numInitialRequestRetries: undefined,
numPollRequestRetries: undefined,
});
});

it('includes sdk metadata', () => {
const options: IClientOptions = {
sdkKey: 'test-key',
assignmentLogger: { logAssignment: jest.fn() },
};

const result = clientOptionsToParameters(options, mockStore);

expect(result.configurationRequestParameters).toMatchObject({
sdkName,
sdkVersion,
});
});
});
47 changes: 47 additions & 0 deletions src/client-options-converter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {
BanditParameters,

Check warning on line 2 in src/client-options-converter.ts

View workflow job for this annotation

GitHub Actions / lint-test-sdk (18)

'BanditParameters' is defined but never used

Check warning on line 2 in src/client-options-converter.ts

View workflow job for this annotation

GitHub Actions / lint-test-sdk (20)

'BanditParameters' is defined but never used

Check warning on line 2 in src/client-options-converter.ts

View workflow job for this annotation

GitHub Actions / lint-test-sdk (22)

'BanditParameters' is defined but never used

Check warning on line 2 in src/client-options-converter.ts

View workflow job for this annotation

GitHub Actions / lint-test-sdk (23)

'BanditParameters' is defined but never used
BanditVariation, EppoClientParameters,

Check warning on line 3 in src/client-options-converter.ts

View workflow job for this annotation

GitHub Actions / lint-test-sdk (18)

'BanditVariation' is defined but never used

Check warning on line 3 in src/client-options-converter.ts

View workflow job for this annotation

GitHub Actions / lint-test-sdk (18)

Insert `⏎·`

Check warning on line 3 in src/client-options-converter.ts

View workflow job for this annotation

GitHub Actions / lint-test-sdk (20)

'BanditVariation' is defined but never used

Check warning on line 3 in src/client-options-converter.ts

View workflow job for this annotation

GitHub Actions / lint-test-sdk (20)

Insert `⏎·`

Check warning on line 3 in src/client-options-converter.ts

View workflow job for this annotation

GitHub Actions / lint-test-sdk (22)

'BanditVariation' is defined but never used

Check warning on line 3 in src/client-options-converter.ts

View workflow job for this annotation

GitHub Actions / lint-test-sdk (22)

Insert `⏎·`

Check warning on line 3 in src/client-options-converter.ts

View workflow job for this annotation

GitHub Actions / lint-test-sdk (23)

'BanditVariation' is defined but never used

Check warning on line 3 in src/client-options-converter.ts

View workflow job for this annotation

GitHub Actions / lint-test-sdk (23)

Insert `⏎·`
EventDispatcher,
Flag,
FlagConfigurationRequestParameters,

Check warning on line 6 in src/client-options-converter.ts

View workflow job for this annotation

GitHub Actions / lint-test-sdk (18)

'FlagConfigurationRequestParameters' is defined but never used

Check warning on line 6 in src/client-options-converter.ts

View workflow job for this annotation

GitHub Actions / lint-test-sdk (20)

'FlagConfigurationRequestParameters' is defined but never used

Check warning on line 6 in src/client-options-converter.ts

View workflow job for this annotation

GitHub Actions / lint-test-sdk (22)

'FlagConfigurationRequestParameters' is defined but never used

Check warning on line 6 in src/client-options-converter.ts

View workflow job for this annotation

GitHub Actions / lint-test-sdk (23)

'FlagConfigurationRequestParameters' is defined but never used
IConfigurationStore,
ObfuscatedFlag,

Check warning on line 8 in src/client-options-converter.ts

View workflow job for this annotation

GitHub Actions / lint-test-sdk (18)

'ObfuscatedFlag' is defined but never used

Check warning on line 8 in src/client-options-converter.ts

View workflow job for this annotation

GitHub Actions / lint-test-sdk (20)

'ObfuscatedFlag' is defined but never used

Check warning on line 8 in src/client-options-converter.ts

View workflow job for this annotation

GitHub Actions / lint-test-sdk (22)

'ObfuscatedFlag' is defined but never used

Check warning on line 8 in src/client-options-converter.ts

View workflow job for this annotation

GitHub Actions / lint-test-sdk (23)

'ObfuscatedFlag' is defined but never used
} from '@eppo/js-client-sdk-common';

import { IClientOptions } from './i-client-config';
import { sdkName, sdkVersion } from './sdk-data';

/**
* Converts IClientOptions to EppoClientParameters
* @internal
*/
export function clientOptionsToParameters(
options: IClientOptions,
flagConfigurationStore: IConfigurationStore<Flag>,
eventDispatcher?: EventDispatcher,
): EppoClientParameters {
const parameters: EppoClientParameters = {
flagConfigurationStore,
isObfuscated: true,
};

parameters.eventDispatcher = eventDispatcher;

// Always include configuration request parameters
parameters.configurationRequestParameters = {
apiKey: options.sdkKey,
sdkVersion, // dynamically picks up version.
sdkName, // Hardcoded to `js-client-sdk`
baseUrl: options.baseUrl,
requestTimeoutMs: options.requestTimeoutMs,
numInitialRequestRetries: options.numInitialRequestRetries,
numPollRequestRetries: options.numPollRequestRetries,
pollAfterSuccessfulInitialization: options.pollAfterSuccessfulInitialization,
pollAfterFailedInitialization: options.pollAfterFailedInitialization,
pollingIntervalMs: options.pollingIntervalMs,
throwOnFailedInitialization: options.throwOnFailedInitialization,
skipInitialPoll: options.skipInitialRequest,
};

return parameters;
}
124 changes: 112 additions & 12 deletions src/i-client-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
IAssignmentLogger,
IAsyncStore,
IBanditLogger,
IConfigurationStore,
} from '@eppo/js-client-sdk-common';

import { ServingStoreUpdateStrategy } from './isolatable-hybrid.store';
Expand Down Expand Up @@ -104,10 +105,41 @@
}

/**
* Configuration for regular client initialization
* @public
* Base options for the EppoClient SDK
*/
export interface IClientConfig extends IBaseRequestConfig {
export type IApiOptions = {
/**
* Your key for accessing Eppo through the Eppo SDK.
*/
sdkKey: string;

/**
* Override the endpoint the SDK uses to load configuration.
*/
baseUrl?: string;

/**
* Force reinitialize the SDK if it is already initialized.
*/
forceReinitialize?: boolean;

/**
* Timeout in milliseconds for the HTTPS request for the experiment configuration. (Default: 5000)
*/
requestTimeoutMs?: number;

/**
* Number of additional times the initial configuration request will be attempted if it fails.
* This is the request typically synchronously waited (via await) for completion. A small wait will be
* done between requests. (Default: 1)
*/
numInitialRequestRetries?: number;

/**
* Skip the request for new configurations during initialization. (default: false)
*/
skipInitialRequest?: boolean;

/**
* Throw an error if unable to fetch an initial configuration during initialization. (default: true)
*/
Expand Down Expand Up @@ -135,18 +167,13 @@
updateOnFetch?: ServingStoreUpdateStrategy;

/**
* A custom class to use for storing flag configurations.
* This is useful for cases where you want to use a different storage mechanism
* than the default storage provided by the SDK.
* A configuration string to bootstrap the client without having to make a network fetch.
*/
persistentStore?: IAsyncStore<Flag>;
initialConfiguration: string;
};

/**
* Force reinitialize the SDK if it is already initialized.
*/
forceReinitialize?: boolean;

Check warning on line 175 in src/i-client-config.ts

View workflow job for this annotation

GitHub Actions / lint-test-sdk (18)

Delete `⏎`

Check warning on line 175 in src/i-client-config.ts

View workflow job for this annotation

GitHub Actions / lint-test-sdk (20)

Delete `⏎`

Check warning on line 175 in src/i-client-config.ts

View workflow job for this annotation

GitHub Actions / lint-test-sdk (22)

Delete `⏎`

Check warning on line 175 in src/i-client-config.ts

View workflow job for this annotation

GitHub Actions / lint-test-sdk (23)

Delete `⏎`
/** Configuration settings for the event dispatcher */
export type IEventOptions = {
eventIngestionConfig?: {
/** Number of milliseconds to wait between each batch delivery. Defaults to 10 seconds. */
deliveryIntervalMs?: number;
Expand All @@ -165,4 +192,77 @@
*/
maxQueueSize?: number;
};
};

export type IStorageOptions = {
/**
* Custom implementation of the flag configuration store for advanced use-cases.
*/
flagConfigurationStore?: IConfigurationStore<Flag>;

/**
* A custom class to use for storing flag configurations.
* This is useful for cases where you want to use a different storage mechanism
* than the default storage provided by the SDK.
*/
persistentStore?: IAsyncStore<Flag>;
};

export type IPollingOptions = {
/**
* Poll for new configurations even if the initial configuration request failed. (default: false)
*/
pollAfterFailedInitialization?: boolean;

/**
* Poll for new configurations (every `pollingIntervalMs`) after successfully requesting the initial configuration. (default: false)
*/
pollAfterSuccessfulInitialization?: boolean;

/**
* Amount of time to wait between API calls to refresh configuration data. Default of 30_000 (30 seconds).
*/
pollingIntervalMs?: number;

/**
* Number of additional times polling for updated configurations will be attempted before giving up.
* Polling is done after a successful initial request. Subsequent attempts are done using an exponential
* backoff. (Default: 7)
*/
numPollRequestRetries?: number;
};

export type ILoggers = {
/**
* Pass a logging implementation to send variation assignments to your data warehouse.
*/
assignmentLogger: IAssignmentLogger;

/**
* Pass a logging implementation to send bandit assignments to your data warehouse.
*/
banditLogger?: IBanditLogger;
};

/**
* Config shape for client v2.
*/
export type IClientOptions = IApiOptions &
ILoggers &
IEventOptions &
IStorageOptions &
IPollingOptions;

/**
* Configuration for regular client initialization
* @public
*/
export type IClientConfig = Omit<IClientOptions, 'sdkKey' | 'offline'> &
Pick<IBaseRequestConfig, 'apiKey'>;

export function convertClientOptionsToClientConfig(options: IClientOptions): IClientConfig {
return {
...options,
apiKey: options.sdkKey,
};
}
Loading
Loading