Skip to content

Commit

Permalink
Fix typing (#207)
Browse files Browse the repository at this point in the history
* Add tests

* Remove index.d

* fix index test

* rm StatsigOptions

* hide _instance
  • Loading branch information
daniel-statsig authored Nov 16, 2022
1 parent 905cede commit 8310318
Show file tree
Hide file tree
Showing 18 changed files with 342 additions and 490 deletions.
230 changes: 11 additions & 219 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,225 +1,17 @@
declare module 'statsig-node' {
import { IDataAdapter } from 'statsig-node/interfaces';
/**
* An object of properties relating to the current user
* Provide as many as possible to take advantage of advanced conditions in the statsig console
* A dictionary of additional fields can be provided under the "custom" field
*/
export type StatsigUser = {
userID?: string;
email?: string;
ip?: string;
userAgent?: string;
country?: string;
locale?: string;
appVersion?: string;
custom?: Record<
string,
string | number | boolean | Array<string> | undefined
>;
privateAttributes?: Record<
string,
string | number | boolean | Array<string> | undefined
>;
customIDs?: Record<string, string>;
statsigEnvironment?: StatsigEnvironment;
};

/**
* An object of properties for initializing the sdk with advanced options
*/
export type StatsigOptions = {
api?: string;
bootstrapValues?: string;
environment?: StatsigEnvironment;
localMode?: boolean;
rulesUpdatedCallback?: { (rulesJSON: string, time: number): void };
initTimeoutMs?: number;
dataAdapter?: IDataAdapter;
};

export type StatsigEnvironment = {
tier?: 'production' | 'staging' | 'development';
[key: string]: string | undefined;
};

/**
* Initializes the statsig server SDK. This must be called before checking gates/configs or logging events.
* @param {string} secretKey - The secret key for this project from the statsig console. Secret keys should be kept secure on the server side, and not used for client-side integrations
* @param {?StatsigOptions} [options={}] - manual sdk configuration for advanced setup
* @returns {Promise<void>} - a promise which rejects only if you fail to provide a proper SDK Key
* @throws Error if a Server Secret Key is not provided
*/
export function initialize(
secretKey: string,
options?: StatsigOptions,
): Promise<void>;

/**
* Check the value of a gate configured in the statsig console
* @param {StatsigUser} user - the user to check this gate value for
* @param {string} gateName - the name of the gate to check
* @returns {Promise<boolean>} - The value of the gate for the user. Gates are off (return false) by default
* @throws Error if initialize() was not called first
* @throws Error if the gateName is not provided or not a non-empty string
*/
export function checkGate(
user: StatsigUser,
gateName: string,
): Promise<boolean>;

/**
* Checks the value of a config for a given user
* @param {StatsigUser} user - the user to evaluate for the dyamic config
* @param {string} configName - the name of the dynamic config to get
* @returns {Promise<DynamicConfig>} - the config for the user
* @throws Error if initialize() was not called first
* @throws Error if the configName is not provided or not a non-empty string
*/
export function getConfig(
user: StatsigUser,
configName: string,
): Promise<DynamicConfig>;

/**
* Gets the experiment for a given user
* @param {StatsigUser} user - the user to evaluate for the experiment
* @param {string} experimentName - the name of the experiment to get
* @returns {Promise<DynamicConfig>} - the experiment for the user, represented by a Dynamic Config object
* @throws Error if initialize() was not called first
* @throws Error if the experimentName is not provided or not a non-empty string
*/
export function getExperiment(
user: StatsigUser,
experimentName: string,
): Promise<DynamicConfig>;

/**
* Checks the value of a Layer for a given user
* @param {StatsigUser} user - the user to evaluate for the layer
* @param {string} layerName - the name of the layer to get
* @returns {Promise<Layer>} - the layer for the user, represented by a Layer
* @throws Error if initialize() was not called first
* @throws Error if the layerName is not provided or not a non-empty string
*/
export function getLayer(
user: StatsigUser,
layerName: string,
): Promise<Layer>;

/**
* Log an event for data analysis and alerting or to measure the impact of an experiment
* @param {StatsigUser} user - the user associated with this event
* @param {string} eventName - the name of the event (name = Purchase)
* @param {?string | number} value - the value associated with the event (value = 10)
* @param {?Record<string, string>} metadata - other attributes associated with this event (metadata = {item_name: 'banana', currency: 'USD'})
* @throws Error if initialize() was not called first
*/
export function logEvent(
user: StatsigUser | null,
name: string,
value?: string | number,
metadata?: Record<string, string>,
): void;

export function logEventObject(eventObject: LogEventObject): void;

/**
* Informs the statsig SDK that the client is closing or shutting down
* so the SDK can clean up internal state
*/
export function shutdown(): void;

/**
* Flushes all the events that are currently in the queue to Statsig server right away
*/
export function flush(): Promise<void>;

/**
* Returns the initialize values for the given user
* Can be used to bootstrap a client SDK with up to date values
* @param user the user to evaluate configurations for
*/
export function getClientInitializeResponse(
user: StatsigUser,
): Record<string, unknown> | null;

/**
* Overrides the given gate with the provided value
* If no userID is provided, it will override for all users
* If a userID is provided, it will override the gate with the given value for that user only
*/
export function overrideGate(
gateName: string,
value: boolean,
userID?: string,
): void;

/**
* Overrides the given config or experiment with the provided value
* If no userID is provided, it will override for all users
* If a userID is provided, it will override the config/experiment with the given value for that user only
*/
export function overrideConfig(
gateName: string,
value: object,
userID?: string,
): void;

/**
* Returns the data for a DynamicConfig in the statsig console via typed get functions
*/
export class DynamicConfig {
value: object;
getValue(
key: string,
defaultValue: any | null,
): boolean | number | string | object | Array<any> | null;
get<T extends boolean | number | string | object | Array<any> | null>(
key: string,
defaultValue: T,
typeGuard?: (value: unknown) => boolean,
): T;
}

/**
* Returns the data for a Layer in the statsig console via typed get functions
*/
export class Layer {
getValue(
key: string,
defaultValue: any | null,
): boolean | number | string | object | Array<any> | null;
get<T extends boolean | number | string | object | Array<any> | null>(
key: string,
defaultValue: T,
typeGuard?: (value: unknown) => boolean,
): T;
}

export type LogEventObject = {
eventName: string;
user: StatsigUser | null;
value: string | number | null;
time: number | null;
metadata: Record<string, string> | null;
};
}

/**
* This module contains types and interfaces
* This module contains types and interfaces
* to allow for customizations of SDK features.
*/
declare module 'statsig-node/interfaces' {
export type AdapterResponse = {
result?: string,
time?: number,
error?: Error,
}
result?: string;
time?: number;
error?: Error;
};

/**
* An adapter for implementing custom storage of config specs.
* Useful for backing up data in memory.
* Useful for backing up data in memory.
* Can also be used to bootstrap Statsig server.
*/
export interface IDataAdapter {
Expand All @@ -228,23 +20,23 @@ declare module 'statsig-node/interfaces' {
* @param key - Key of stored item to fetch
*/
get(key: string): Promise<AdapterResponse>;

/**
* Updates data stored for each key
* @param key - Key of stored item to update
* @param value - New value to store
* @param time - Time of update
*/
set(key: string, value: string, time?: number): Promise<void>;

/**
* Startup tasks to run before any fetch/update calls can be made
*/
initialize(): Promise<void>;

/**
* Cleanup tasks to run when statsig is shutdown
*/
shutdown(): Promise<void>;
}
}
}
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions src/Evaluator.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import ConfigEvaluation from './ConfigEvaluation';

import { ConfigCondition, ConfigRule, ConfigSpec } from './ConfigSpec';
import SpecStore from './SpecStore';
import { StatsigUser } from './StatsigUser';
import { ConfigSpec, ConfigRule, ConfigCondition } from './ConfigSpec';

import { EvaluationDetails } from './EvaluationDetails';
import { ExplicitStatsigOptions } from './StatsigOptions';
import { notEmpty } from './utils/core';
import parseUserAgent from './utils/parseUserAgent';
import StatsigFetcher from './utils/StatsigFetcher';
import StatsigOptions from './StatsigOptions';
import { EvaluationDetails, EvaluationReason } from './EvaluationDetails';

const shajs = require('sha.js');
const ip3country = require('ip3country');
Expand Down Expand Up @@ -41,7 +41,7 @@ export default class Evaluator {

private store: SpecStore;

public constructor(fetcher: StatsigFetcher, options: StatsigOptions) {
public constructor(fetcher: StatsigFetcher, options: ExplicitStatsigOptions) {
this.store = new SpecStore(fetcher, options);
this.gateOverrides = {};
this.configOverrides = {};
Expand Down Expand Up @@ -827,12 +827,12 @@ function numberCompare(
): (a: unknown, b: unknown) => boolean {
return (a: unknown, b: unknown) => {
if (a == null || b == null) {
return false;
return false;
}
const numA = Number(a);
const numB = Number(b);
if (isNaN(numA) || isNaN(numB)) {
return false;
return false;
}
return fn(numA, numB);
};
Expand Down
6 changes: 3 additions & 3 deletions src/LogEventProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import LogEvent from './LogEvent';
import { StatsigUser } from './StatsigUser';
import ConfigEvaluation from './ConfigEvaluation';
import StatsigFetcher from './utils/StatsigFetcher';
import StatsigOptions from './StatsigOptions';
import { ExplicitStatsigOptions } from './StatsigOptions';
import { StatsigLocalModeNetworkError } from './Errors';
import { EvaluationDetails } from './EvaluationDetails';
import Layer from './Layer';
Expand All @@ -23,7 +23,7 @@ const ignoredMetadataKeys = new Set([
]);

export default class LogEventProcessor {
private options: StatsigOptions;
private options: ExplicitStatsigOptions;
private fetcher: StatsigFetcher;

private queue: LogEvent[];
Expand All @@ -33,7 +33,7 @@ export default class LogEventProcessor {
private deduper: Set<string>;
private deduperTimer: NodeJS.Timer | null;

public constructor(fetcher: StatsigFetcher, options: StatsigOptions) {
public constructor(fetcher: StatsigFetcher, options: ExplicitStatsigOptions) {
this.options = options;
this.fetcher = fetcher;

Expand Down
14 changes: 7 additions & 7 deletions src/SpecStore.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { ConfigSpec } from './ConfigSpec';
import StatsigOptions from './StatsigOptions';
import StatsigFetcher from './utils/StatsigFetcher';
const { getStatsigMetadata } = require('./utils/core');
import safeFetch from './utils/safeFetch';
import { StatsigLocalModeNetworkError } from './Errors';
import { DataAdapterKey, IDataAdapter } from './interfaces/IDataAdapter';
import { EvaluationReason } from './EvaluationDetails';
import IDListUtil, { IDList } from './utils/IDListUtil';
import { DataAdapterKey, IDataAdapter } from './interfaces/IDataAdapter';
import { ExplicitStatsigOptions } from './StatsigOptions';
import { poll } from './utils/core';
import IDListUtil, { IDList } from './utils/IDListUtil';
import safeFetch from './utils/safeFetch';
import StatsigFetcher from './utils/StatsigFetcher';
const { getStatsigMetadata } = require('./utils/core');

const SYNC_OUTDATED_MAX = 120 * 1000;

Expand Down Expand Up @@ -37,7 +37,7 @@ export default class SpecStore {
private syncFailureCount: number = 0;
private lastDownloadConfigSpecsSyncTime: number = Date.now();

public constructor(fetcher: StatsigFetcher, options: StatsigOptions) {
public constructor(fetcher: StatsigFetcher, options: ExplicitStatsigOptions) {
this.fetcher = fetcher;
this.api = options.api;
this.rulesUpdatedCallback = options.rulesUpdatedCallback ?? null;
Expand Down
Loading

0 comments on commit 8310318

Please sign in to comment.