Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
107 changes: 107 additions & 0 deletions packages/optimizely-sdk/lib/core/decision_service/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/**
* Copyright 2020, Optimizely
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

declare module '@optimizely/optimizely-sdk/lib/core/decision_service' {
import { LogHandler } from '@optimizely/js-sdk-logging';
import { ProjectConfig } from '@optimizely/optimizely-sdk/lib/core/project_config';

/**
* Creates an instance of the DecisionService.
* @param {Options} options Configuration options
* @return {DecisionService} An instance of the DecisionService
*/
export function createDecisionService(options: Options): DecisionService;

interface DecisionService {

/**
* Gets variation where visitor will be bucketed.
* @param {ProjectConfig} configObj The parsed project configuration object
* @param {string} experimentKey
* @param {string} userId
* @param {UserAttributes} attributes
* @return {string|null} The variation the user is bucketed into.
*/
getVariation(
configObj: ProjectConfig,
experimentKey: string,
userId: string,
attributes?: import('../../shared_types').UserAttributes
): string | null;

/**
* Given a feature, user ID, and attributes, returns an object representing a
* decision. If the user was bucketed into a variation for the given feature
* and attributes, the returned decision object will have variation and
* experiment properties (both objects), as well as a decisionSource property.
* decisionSource indicates whether the decision was due to a rollout or an
* experiment.
* @param {ProjectConfig} configObj The parsed project configuration object
* @param {FeatureFlag} feature A feature flag object from project configuration
* @param {string} userId A string identifying the user, for bucketing
* @param {unknown} attributes Optional user attributes
* @return {Decision} An object with experiment, variation, and decisionSource
* properties. If the user was not bucketed into a variation, the variation
* property is null.
*/
getVariationForFeature(
configObj: ProjectConfig,
feature: import('../project_config/entities').FeatureFlag,
userId: string,
attributes: unknown
): Decision;

/**
* Removes forced variation for given userId and experimentKey
* @param {unknown} userId String representing the user id
* @param {string} experimentId Number representing the experiment id
* @param {string} experimentKey Key representing the experiment id
* @throws If the user id is not valid or not in the forced variation map
*/
removeForcedVariation(userId: unknown, experimentId: string, experimentKey: string): void;

/**
* Gets the forced variation key for the given user and experiment.
* @param {ProjectConfig} configObj Object representing project configuration
* @param {string} experimentKey Key for experiment.
* @param {string} userId The user Id.
* @return {string|null} Variation key that specifies the variation which the given user and experiment should be forced into.
*/
getForcedVariation(configObj: ProjectConfig, experimentKey: string, userId: string): string | null;

/**
* Sets the forced variation for a user in a given experiment
* @param {ProjectConfig} configObj Object representing project configuration
* @param {string} experimentKey Key for experiment.
* @param {string} userId The user Id.
* @param {unknown} variationKey Key for variation. If null, then clear the existing experiment-to-variation mapping
* @return {boolean} A boolean value that indicates if the set completed successfully.
*/
setForcedVariation(configObj: ProjectConfig, experimentKey: string, userId: string, variationKey: unknown): boolean;
}

interface Options {
userProfileService: import('../../shared_types').UserProfileService | null;
logger: LogHandler;
UNSTABLE_conditionEvaluators: unknown;
}

interface Decision {
experiment: import('../../shared_types').Experiment | null;
variation: import('../../shared_types').Variation | null;
decisionSource: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might want to use an enum for this. Can be updated later if so.

}
}
99 changes: 41 additions & 58 deletions packages/optimizely-sdk/lib/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,56 +55,81 @@ declare module '@optimizely/optimizely-sdk' {
// TODO[OASIS-6649]: Don't use object type
// eslint-disable-next-line @typescript-eslint/ban-types
jsonSchemaValidator?: object;
userProfileService?: UserProfileService | null;
userProfileService?: import('./shared_types').UserProfileService | null;
eventBatchSize?: number;
eventFlushInterval?: number;
sdkKey?: string;
}

export interface Client {
notificationCenter: NotificationCenter;
activate(experimentKey: string, userId: string, attributes?: UserAttributes): string | null;
track(eventKey: string, userId: string, attributes?: UserAttributes, eventTags?: EventTags): void;
getVariation(experimentKey: string, userId: string, attributes?: UserAttributes): string | null;
activate(
experimentKey: string,
userId: string,
attributes?: import('./shared_types').UserAttributes
): string | null;
track(
eventKey: string,
userId: string,
attributes?: import('./shared_types').UserAttributes,
eventTags?: EventTags
): void;
getVariation(
experimentKey: string,
userId: string,
attributes?: import('./shared_types').UserAttributes
): string | null;
setForcedVariation(experimentKey: string, userId: string, variationKey: string | null): boolean;
getForcedVariation(experimentKey: string, userId: string): string | null;
isFeatureEnabled(featureKey: string, userId: string, attributes?: UserAttributes): boolean;
getEnabledFeatures(userId: string, attributes?: UserAttributes): string[];
getFeatureVariable(featureKey: string, variableKey: string, userId: string, attributes?: UserAttributes): unknown
isFeatureEnabled(
featureKey: string,
userId: string,
attributes?: import('./shared_types').UserAttributes
): boolean;
getEnabledFeatures(
userId: string,
attributes?: import('./shared_types').UserAttributes
): string[];
getFeatureVariable(
featureKey: string,
variableKey: string,
userId: string,
attributes?: import('./shared_types').UserAttributes
): unknown;
getFeatureVariableBoolean(
featureKey: string,
variableKey: string,
userId: string,
attributes?: UserAttributes
attributes?: import('./shared_types').UserAttributes
): boolean | null;
getFeatureVariableDouble(
featureKey: string,
variableKey: string,
userId: string,
attributes?: UserAttributes
attributes?: import('./shared_types').UserAttributes
): number | null;
getFeatureVariableInteger(
featureKey: string,
variableKey: string,
userId: string,
attributes?: UserAttributes
attributes?: import('./shared_types').UserAttributes
): number | null;
getFeatureVariableString(
featureKey: string,
variableKey: string,
userId: string,
attributes?: UserAttributes
attributes?: import('./shared_types').UserAttributes
): string | null;
getFeatureVariableJSON(
featureKey: string,
variableKey: string,
userId: string,
attributes?: UserAttributes
attributes?: import('./shared_types').UserAttributes
): unknown;
getAllFeatureVariables(
featureKey: string,
userId: string,
attributes?: UserAttributes
attributes?: import('./shared_types').UserAttributes
): { [variableKey: string]: unknown };
getOptimizelyConfig(): OptimizelyConfig | null;
onReady(options?: { timeout?: number }): Promise<{ success: boolean; reason?: string }>;
Expand Down Expand Up @@ -135,11 +160,6 @@ declare module '@optimizely/optimizely-sdk' {
dispatchEvent: (event: Event, callback: () => void) => void;
}

export interface UserProfileService {
lookup: (userId: string) => UserProfile;
save: (profile: UserProfile) => void;
}

// NotificationCenter-related types
export interface NotificationCenter {
addNotificationListener<T extends ListenerPayload>(
Expand All @@ -155,21 +175,15 @@ declare module '@optimizely/optimizely-sdk' {

export interface ListenerPayload {
userId: string;
attributes: UserAttributes;
attributes: import('./shared_types').UserAttributes;
}

export interface ActivateListenerPayload extends ListenerPayload {
experiment: Experiment;
variation: Variation;
experiment: import('./shared_types').Experiment;
variation: import('./shared_types').Variation;
logEvent: Event;
}

export type UserAttributes = {
// TODO[OASIS-6649]: Don't use any type
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[name: string]: any;
};

export type EventTags = {
[key: string]: string | number | boolean;
};
Expand All @@ -180,37 +194,6 @@ declare module '@optimizely/optimizely-sdk' {
logEvent: Event;
}

interface Experiment {
id: string;
key: string;
status: string;
layerId: string;
variations: Variation[];
trafficAllocation: Array<{
entityId: string;
endOfRange: number;
}>;
audienceIds: string[];
// TODO[OASIS-6649]: Don't use object type
// eslint-disable-next-line @typescript-eslint/ban-types
forcedVariations: object;
}

interface Variation {
id: string;
key: string;
}

// Information about past bucketing decisions for a user.
export interface UserProfile {
user_id: string;
experiment_bucket_map: {
[experiment_id: string]: {
variation_id: string;
};
};
}

/**
* Optimizely Config Entities
*/
Expand Down
42 changes: 39 additions & 3 deletions packages/optimizely-sdk/lib/shared_types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,41 @@
export type UserAttributes = {
// TODO[OASIS-6649]: Don't use any type
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[name: string]: any;
// TODO[OASIS-6649]: Don't use any type
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[name: string]: any;
}

export interface Variation {
id: string;
key: string;
}

export interface Experiment {
id: string;
key: string;
status: string;
layerId: string;
variations: Variation[];
trafficAllocation: Array<{
entityId: string;
endOfRange: number;
}>;
audienceIds: string[];
// TODO[OASIS-6649]: Don't use object type
// eslint-disable-next-line @typescript-eslint/ban-types
forcedVariations: object;
}

// Information about past bucketing decisions for a user.
export interface UserProfile {
user_id: string;
experiment_bucket_map: {
[experiment_id: string]: {
variation_id: string;
};
};
}

export interface UserProfileService {
lookup(userId: string): UserProfile;
save(profile: UserProfile): void;
}