@sprig-technologies/sprig-browser
Version:
npm package for the sprig web sdk
1,639 lines (1,517 loc) • 67.5 kB
TypeScript
declare type attributes = {
[key: string]: string | number | true | null;
};
declare type cdataNode = {
type: NodeType.CDATA;
textContent: '';
};
declare type commentNode = {
type: NodeType.Comment;
textContent: string;
};
declare type DataURLOptions = Partial<{
type: string;
quality: number;
}>;
declare type documentNode = {
type: NodeType.Document;
childNodes: serializedNodeWithId[];
compatMode?: string;
};
declare type documentTypeNode = {
type: NodeType.DocumentType;
name: string;
publicId: string;
systemId: string;
};
declare type elementNode = {
type: NodeType.Element;
tagName: string;
attributes: attributes;
childNodes: serializedNodeWithId[];
isSVG?: true;
needBlock?: boolean;
isCustom?: true;
};
declare interface IMirror<TNode> {
getId(n: TNode | undefined | null): number;
getNode(id: number): TNode | null;
getIds(): number[];
getMeta(n: TNode): serializedNodeWithId | null;
removeNodeFromMap(n: TNode): void;
has(id: number): boolean;
hasNode(node: TNode): boolean;
add(n: TNode, meta: serializedNodeWithId): void;
replace(id: number, n: TNode): void;
reset(): void;
}
declare type MaskInputFn = (text: string, element: HTMLElement) => string;
declare type MaskInputOptions = Partial<{
color: boolean;
date: boolean;
'datetime-local': boolean;
email: boolean;
month: boolean;
number: boolean;
range: boolean;
search: boolean;
tel: boolean;
text: boolean;
time: boolean;
url: boolean;
week: boolean;
textarea: boolean;
select: boolean;
password: boolean;
}>;
declare type MaskTextFn = (text: string, element: HTMLElement | null) => string;
declare class Mirror implements IMirror<Node> {
private idNodeMap;
private nodeMetaMap;
getId(n: Node | undefined | null): number;
getNode(id: number): Node | null;
getIds(): number[];
getMeta(n: Node): serializedNodeWithId | null;
removeNodeFromMap(n: Node): void;
has(id: number): boolean;
hasNode(node: Node): boolean;
add(n: Node, meta: serializedNodeWithId): void;
replace(id: number, n: Node): void;
reset(): void;
}
declare enum NodeType {
Document = 0,
DocumentType = 1,
Element = 2,
Text = 3,
CDATA = 4,
Comment = 5
}
declare type serializedNode = (documentNode | documentTypeNode | elementNode | textNode | cdataNode | commentNode) & {
rootId?: number;
isShadowHost?: boolean;
isShadow?: boolean;
};
declare type serializedNodeWithId = serializedNode & {
id: number;
};
declare type SlimDOMOptions = Partial<{
script: boolean;
comment: boolean;
headFavicon: boolean;
headWhitespace: boolean;
headMetaDescKeywords: boolean;
headMetaSocial: boolean;
headMetaRobots: boolean;
headMetaHttpEquiv: boolean;
headMetaAuthorship: boolean;
headMetaVerification: boolean;
headTitleMutations: boolean;
}>;
declare type textNode = {
type: NodeType.Text;
textContent: string;
isStyle?: true;
};
declare type addedNodeMutation = {
parentId: number;
previousId?: number | null;
nextId: number | null;
node: serializedNodeWithId;
};
declare type adoptedStyleSheetData = {
source: IncrementalSource.AdoptedStyleSheet;
} & adoptedStyleSheetParam;
declare type adoptedStyleSheetParam = {
id: number;
styles?: {
styleId: number;
rules: styleSheetAddRule[];
}[];
styleIds: number[];
};
declare type attributeMutation = {
id: number;
attributes: {
[key: string]: string | styleOMValue | null;
};
};
declare type blockClass = string | RegExp;
declare enum CanvasContext {
'2D' = 0,
WebGL = 1,
WebGL2 = 2
}
declare type canvasMutationCallback = (p: canvasMutationParam) => void;
declare type canvasMutationCommand = {
property: string;
args: Array<unknown>;
setter?: true;
};
declare type canvasMutationData = {
source: IncrementalSource.CanvasMutation;
} & canvasMutationParam;
declare type canvasMutationParam = {
id: number;
type: CanvasContext;
commands: canvasMutationCommand[];
} | ({
id: number;
type: CanvasContext;
} & canvasMutationCommand);
declare type customElementCallback = (c: customElementParam) => void;
declare type customElementData = {
source: IncrementalSource.CustomElement;
} & customElementParam;
declare type customElementParam = {
define?: {
name: string;
};
};
declare type customEvent<T = unknown> = {
type: EventType.Custom;
data: {
tag: string;
payload: T;
};
};
declare type domContentLoadedEvent = {
type: EventType.DomContentLoaded;
data: unknown;
};
declare enum EventType {
DomContentLoaded = 0,
Load = 1,
FullSnapshot = 2,
IncrementalSnapshot = 3,
Meta = 4,
Custom = 5,
Plugin = 6
}
declare type eventWithoutTime = domContentLoadedEvent | loadedEvent | fullSnapshotEvent | incrementalSnapshotEvent | metaEvent | customEvent | pluginEvent;
declare type eventWithTime = eventWithoutTime & {
timestamp: number;
delay?: number;
};
declare type fontCallback = (p: fontParam) => void;
declare type fontData = {
source: IncrementalSource.Font;
} & fontParam;
declare type fontParam = {
family: string;
fontSource: string;
buffer: boolean;
descriptors?: FontFaceDescriptors;
};
declare type fullSnapshotEvent = {
type: EventType.FullSnapshot;
data: {
node: serializedNodeWithId;
initialOffset: {
top: number;
left: number;
};
};
};
declare type hooksParam = {
mutation?: mutationCallBack;
mousemove?: mousemoveCallBack;
mouseInteraction?: mouseInteractionCallBack;
scroll?: scrollCallback;
viewportResize?: viewportResizeCallback;
input?: inputCallback;
mediaInteaction?: mediaInteractionCallback;
styleSheetRule?: styleSheetRuleCallback;
styleDeclaration?: styleDeclarationCallback;
canvasMutation?: canvasMutationCallback;
font?: fontCallback;
selection?: selectionCallback;
customElement?: customElementCallback;
};
declare interface ICrossOriginIframeMirror {
getId(iframe: HTMLIFrameElement, remoteId: number, parentToRemoteMap?: Map<number, number>, remoteToParentMap?: Map<number, number>): number;
getIds(iframe: HTMLIFrameElement, remoteId: number[]): number[];
getRemoteId(iframe: HTMLIFrameElement, parentId: number, map?: Map<number, number>): number;
getRemoteIds(iframe: HTMLIFrameElement, parentId: number[]): number[];
reset(iframe?: HTMLIFrameElement): void;
}
declare type incrementalData = mutationData | mousemoveData | mouseInteractionData | scrollData | viewportResizeData | inputData | mediaInteractionData | styleSheetRuleData | canvasMutationData | fontData | selectionData | styleDeclarationData | adoptedStyleSheetData | customElementData;
declare type incrementalSnapshotEvent = {
type: EventType.IncrementalSnapshot;
data: incrementalData;
};
declare enum IncrementalSource {
Mutation = 0,
MouseMove = 1,
MouseInteraction = 2,
Scroll = 3,
ViewportResize = 4,
Input = 5,
TouchMove = 6,
MediaInteraction = 7,
StyleSheetRule = 8,
CanvasMutation = 9,
Font = 10,
Log = 11,
Drag = 12,
StyleDeclaration = 13,
Selection = 14,
AdoptedStyleSheet = 15,
CustomElement = 16
}
declare type inputCallback = (v: inputValue & {
id: number;
}) => void;
declare type inputData = {
source: IncrementalSource.Input;
id: number;
} & inputValue;
declare type inputValue = {
text: string;
isChecked: boolean;
userTriggered?: boolean;
};
declare type IWindow = Window & typeof globalThis;
declare type KeepIframeSrcFn = (src: string) => boolean;
declare type listenerHandler = () => void;
declare type loadedEvent = {
type: EventType.Load;
data: unknown;
};
declare type maskTextClass = string | RegExp;
declare type mediaInteractionCallback = (p: mediaInteractionParam) => void;
declare type mediaInteractionData = {
source: IncrementalSource.MediaInteraction;
} & mediaInteractionParam;
declare type mediaInteractionParam = {
type: MediaInteractions;
id: number;
currentTime?: number;
volume?: number;
muted?: boolean;
loop?: boolean;
playbackRate?: number;
};
declare enum MediaInteractions {
Play = 0,
Pause = 1,
Seeked = 2,
VolumeChange = 3,
RateChange = 4
}
declare type metaEvent = {
type: EventType.Meta;
data: {
href: string;
width: number;
height: number;
};
};
declare type mouseInteractionCallBack = (d: mouseInteractionParam) => void;
declare type mouseInteractionData = {
source: IncrementalSource.MouseInteraction;
} & mouseInteractionParam;
declare type mouseInteractionParam = {
type: MouseInteractions;
id: number;
x?: number;
y?: number;
pointerType?: PointerTypes;
};
declare enum MouseInteractions {
MouseUp = 0,
MouseDown = 1,
Click = 2,
ContextMenu = 3,
DblClick = 4,
Focus = 5,
Blur = 6,
TouchStart = 7,
TouchMove_Departed = 8,
TouchEnd = 9,
TouchCancel = 10
}
declare type mousemoveCallBack = (p: mousePosition[], source: IncrementalSource.MouseMove | IncrementalSource.TouchMove | IncrementalSource.Drag) => void;
declare type mousemoveData = {
source: IncrementalSource.MouseMove | IncrementalSource.TouchMove | IncrementalSource.Drag;
positions: mousePosition[];
};
declare type mousePosition = {
x: number;
y: number;
id: number;
timeOffset: number;
};
declare type mutationCallBack = (m: mutationCallbackParam) => void;
declare type mutationCallbackParam = {
texts: textMutation[];
attributes: attributeMutation[];
removes: removedNodeMutation[];
adds: addedNodeMutation[];
isAttachIframe?: true;
};
declare type mutationData = {
source: IncrementalSource.Mutation;
} & mutationCallbackParam;
declare type PackFn = (event: eventWithTime) => string;
declare type pluginEvent<T = unknown> = {
type: EventType.Plugin;
data: {
plugin: string;
payload: T;
};
};
declare enum PointerTypes {
Mouse = 0,
Pen = 1,
Touch = 2
}
declare type RecordPlugin<TOptions = unknown> = {
name: string;
observer?: (cb: (...args: Array<unknown>) => void, win: IWindow, options: TOptions) => listenerHandler;
eventProcessor?: <TExtend>(event: eventWithTime) => eventWithTime & TExtend;
getMirror?: (mirrors: {
nodeMirror: Mirror;
crossOriginIframeMirror: ICrossOriginIframeMirror;
crossOriginIframeStyleMirror: ICrossOriginIframeMirror;
}) => void;
options: TOptions;
};
declare type removedNodeMutation = {
parentId: number;
id: number;
isShadow?: boolean;
};
declare type SamplingStrategy = Partial<{
mousemove: boolean | number;
mousemoveCallback: number;
mouseInteraction: boolean | Record<string, boolean | undefined>;
scroll: number;
media: number;
input: 'all' | 'last';
canvas: 'all' | number;
}>;
declare type scrollCallback = (p: scrollPosition) => void;
declare type scrollData = {
source: IncrementalSource.Scroll;
} & scrollPosition;
declare type scrollPosition = {
id: number;
x: number;
y: number;
};
declare type selectionCallback = (p: selectionParam) => void;
declare type selectionData = {
source: IncrementalSource.Selection;
} & selectionParam;
declare type selectionParam = {
ranges: Array<SelectionRange>;
};
declare type SelectionRange = {
start: number;
startOffset: number;
end: number;
endOffset: number;
};
declare type styleDeclarationCallback = (s: styleDeclarationParam) => void;
declare type styleDeclarationData = {
source: IncrementalSource.StyleDeclaration;
} & styleDeclarationParam;
declare type styleDeclarationParam = {
id?: number;
styleId?: number;
index: number[];
set?: {
property: string;
value: string | null;
priority: string | undefined;
};
remove?: {
property: string;
};
};
declare type styleOMValue = {
[key: string]: styleValueWithPriority | string | false;
};
declare type styleSheetAddRule = {
rule: string;
index?: number | number[];
};
declare type styleSheetDeleteRule = {
index: number | number[];
};
declare type styleSheetRuleCallback = (s: styleSheetRuleParam) => void;
declare type styleSheetRuleData = {
source: IncrementalSource.StyleSheetRule;
} & styleSheetRuleParam;
declare type styleSheetRuleParam = {
id?: number;
styleId?: number;
removes?: styleSheetDeleteRule[];
adds?: styleSheetAddRule[];
replace?: string;
replaceSync?: string;
};
declare type styleValueWithPriority = [string, string];
declare type textMutation = {
id: number;
value: string | null;
};
declare type viewportResizeCallback = (d: viewportResizeDimension) => void;
declare type viewportResizeData = {
source: IncrementalSource.ViewportResize;
} & viewportResizeDimension;
declare type viewportResizeDimension = {
width: number;
height: number;
};
declare global {
interface Window {
FontFace: typeof FontFace;
}
}
declare type ErrorHandler = (error: unknown) => void | boolean;
declare type recordOptions<T> = {
emit?: (e: T, isCheckout?: boolean) => void;
checkoutEveryNth?: number;
checkoutEveryNms?: number;
blockClass?: blockClass;
blockSelector?: string;
ignoreClass?: string;
ignoreSelector?: string;
maskTextClass?: maskTextClass;
maskTextSelector?: string;
maskAllInputs?: boolean;
maskInputOptions?: MaskInputOptions;
maskInputFn?: MaskInputFn;
maskTextFn?: MaskTextFn;
slimDOMOptions?: SlimDOMOptions | 'all' | true;
ignoreCSSAttributes?: Set<string>;
inlineStylesheet?: boolean;
hooks?: hooksParam;
packFn?: PackFn;
sampling?: SamplingStrategy;
dataURLOptions?: DataURLOptions;
recordDOM?: boolean;
recordCanvas?: boolean;
recordCrossOriginIframes?: boolean;
recordAfter?: 'DOMContentLoaded' | 'load';
userTriggeredOnInput?: boolean;
collectFonts?: boolean;
inlineImages?: boolean;
plugins?: RecordPlugin[];
mousemoveWait?: number;
keepIframeSrcFn?: KeepIframeSrcFn;
errorHandler?: ErrorHandler;
};
declare function record<T = eventWithTime>(options?: recordOptions<T>): listenerHandler | undefined;
declare namespace record {
var addCustomEvent: <T>(tag: string, payload: T) => void;
var freezePage: () => void;
var takeFullSnapshot: (isCheckout?: boolean | undefined) => void;
var mirror: Mirror;
}
declare namespace record {
var addCustomEvent: <T>(tag: string, payload: T) => void;
var freezePage: () => void;
var takeFullSnapshot: (isCheckout?: boolean | undefined) => void;
var mirror: Mirror;
}
declare global {
interface Window {
FontFace: typeof FontFace;
Array: typeof Array;
}
}
declare const _rrweb_record_record: typeof record;
declare namespace _rrweb_record {
export { _rrweb_record_record as record };
}
interface XhrResponse {
body: Object | string;
statusCode: number;
method: string;
headers: XhrHeaders;
url: string;
rawRequest: XMLHttpRequest;
}
interface XhrHeaders {
[key: string]: string;
}
declare type ChunkedStreamIterableOptions = {
defaultChunkSize?: number;
minChunkSize?: number;
maxChunkSize?: number;
};
declare class ChunkedStreamIterable implements AsyncIterable<Blob> {
protected readableStream: ReadableStream<Uint8Array | Blob>;
protected _chunkSize: number | undefined;
protected defaultChunkSize: number;
readonly minChunkSize: number;
readonly maxChunkSize: number;
constructor(readableStream: ReadableStream<Uint8Array | Blob>, options?: ChunkedStreamIterableOptions);
get chunkSize(): number;
set chunkSize(value: number);
get chunkByteSize(): number;
[Symbol.asyncIterator](): AsyncIterator<Blob>;
}
declare type EventName = 'attempt' | 'attemptFailure' | 'chunkSuccess' | 'error' | 'offline' | 'online' | 'progress' | 'success';
declare type AllowedMethods = 'PUT' | 'POST' | 'PATCH';
interface UpChunkOptions {
endpoint: string | ((file?: File) => Promise<string>);
file: File;
method?: AllowedMethods;
headers?: XhrHeaders | (() => XhrHeaders) | (() => Promise<XhrHeaders>);
maxFileSize?: number;
chunkSize?: number;
attempts?: number;
delayBeforeAttempt?: number;
retryCodes?: number[];
dynamicChunkSize?: boolean;
maxChunkSize?: number;
minChunkSize?: number;
}
declare class UpChunk {
static createUpload(options: UpChunkOptions): UpChunk;
endpoint: string | ((file?: File) => Promise<string>);
file: File;
headers: XhrHeaders | (() => XhrHeaders) | (() => Promise<XhrHeaders>);
method: AllowedMethods;
attempts: number;
delayBeforeAttempt: number;
retryCodes: number[];
dynamicChunkSize: boolean;
protected chunkedStreamIterable: ChunkedStreamIterable;
protected chunkedStreamIterator: AsyncIterator<Blob, any, undefined>;
protected pendingChunk?: Blob;
private chunkCount;
private maxFileBytes;
private endpointValue;
private totalChunks;
private attemptCount;
private offline;
private _paused;
private success;
private currentXhr?;
private lastChunkStart;
private nextChunkRangeStart;
private eventTarget;
constructor(options: UpChunkOptions);
protected get maxChunkSize(): number;
protected get minChunkSize(): number;
get chunkSize(): number;
set chunkSize(value: number);
get chunkByteSize(): number;
get totalChunkSize(): number;
/**
* Subscribe to an event
*/
on(eventName: EventName, fn: (event: CustomEvent) => void): void;
/**
* Subscribe to an event once
*/
once(eventName: EventName, fn: (event: CustomEvent) => void): void;
/**
* Unsubscribe to an event
*/
off(eventName: EventName, fn: (event: CustomEvent) => void): void;
get paused(): boolean;
abort(): void;
pause(): void;
resume(): void;
/**
* Dispatch an event
*/
private dispatch;
/**
* Validate options and throw errors if expectations are violated.
*/
private validateOptions;
/**
* Endpoint can either be a URL or a function that returns a promise that resolves to a string.
*/
private getEndpoint;
private xhrPromise;
/**
* Send chunk of the file with appropriate headers
*/
protected sendChunk(chunk: Blob): Promise<XhrResponse>;
protected sendChunkWithRetries(chunk: Blob): Promise<boolean>;
/**
* Manage the whole upload by calling getChunk & sendChunk
* handle errors & retries and dispatch events
*/
private sendChunks;
}
declare const createUpload: typeof UpChunk.createUpload;
declare enum NOTIFICATION_TYPES {
ACTIVATE = "ACTIVATE:experiment, user_id,attributes, variation, event",
DECISION = "DECISION:type, userId, attributes, decisionInfo",
LOG_EVENT = "LOG_EVENT:logEvent",
OPTIMIZELY_CONFIG_UPDATE = "OPTIMIZELY_CONFIG_UPDATE",
TRACK = "TRACK:event_key, user_id, attributes, event_tags, event"
}
declare type UserAttributes = {
[name: string]: any;
};
declare type EventTags = {
[key: string]: string | number | null;
};
interface ListenerPayload {
userId: string;
attributes?: UserAttributes;
}
declare type NotificationListener<T extends ListenerPayload> = (notificationData: T) => void;
interface NotificationCenter {
addNotificationListener<T extends ListenerPayload>(notificationType: string, callback: NotificationListener<T>): number;
removeNotificationListener(listenerId: number): boolean;
clearAllNotificationListeners(): void;
clearNotificationListeners(notificationType: NOTIFICATION_TYPES): void;
}
declare enum OptimizelyDecideOption {
DISABLE_DECISION_EVENT = "DISABLE_DECISION_EVENT",
ENABLED_FLAGS_ONLY = "ENABLED_FLAGS_ONLY",
IGNORE_USER_PROFILE_SERVICE = "IGNORE_USER_PROFILE_SERVICE",
INCLUDE_REASONS = "INCLUDE_REASONS",
EXCLUDE_VARIABLES = "EXCLUDE_VARIABLES"
}
/**
* Optimizely Config Entities
*/
interface OptimizelyExperiment {
id: string;
key: string;
audiences: string;
variationsMap: {
[variationKey: string]: OptimizelyVariation;
};
}
interface OptimizelyVariable {
id: string;
key: string;
type: string;
value: string;
}
interface Client {
notificationCenter: NotificationCenter;
createUserContext(userId: string, attributes?: UserAttributes): OptimizelyUserContext | null;
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;
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;
getFeatureVariableBoolean(featureKey: string, variableKey: string, userId: string, attributes?: UserAttributes): boolean | null;
getFeatureVariableDouble(featureKey: string, variableKey: string, userId: string, attributes?: UserAttributes): number | null;
getFeatureVariableInteger(featureKey: string, variableKey: string, userId: string, attributes?: UserAttributes): number | null;
getFeatureVariableString(featureKey: string, variableKey: string, userId: string, attributes?: UserAttributes): string | null;
getFeatureVariableJSON(featureKey: string, variableKey: string, userId: string, attributes?: UserAttributes): unknown;
getAllFeatureVariables(featureKey: string, userId: string, attributes?: UserAttributes): {
[variableKey: string]: unknown;
} | null;
getOptimizelyConfig(): OptimizelyConfig | null;
onReady(options?: {
timeout?: number;
}): Promise<{
success: boolean;
reason?: string;
}>;
close(): Promise<{
success: boolean;
reason?: string;
}>;
}
declare type OptimizelyExperimentsMap = {
[experimentKey: string]: OptimizelyExperiment;
};
declare type OptimizelyVariablesMap = {
[variableKey: string]: OptimizelyVariable;
};
declare type OptimizelyFeaturesMap = {
[featureKey: string]: OptimizelyFeature;
};
declare type OptimizelyAttribute = {
id: string;
key: string;
};
declare type OptimizelyAudience = {
id: string;
name: string;
conditions: string;
};
declare type OptimizelyEvent = {
id: string;
key: string;
experimentsIds: string[];
};
interface OptimizelyFeature {
id: string;
key: string;
experimentRules: OptimizelyExperiment[];
deliveryRules: OptimizelyExperiment[];
variablesMap: OptimizelyVariablesMap;
/**
* @deprecated Use experimentRules and deliveryRules
*/
experimentsMap: OptimizelyExperimentsMap;
}
interface OptimizelyVariation {
id: string;
key: string;
featureEnabled?: boolean;
variablesMap: OptimizelyVariablesMap;
}
interface OptimizelyConfig {
environmentKey: string;
sdkKey: string;
revision: string;
/**
* This experimentsMap is for experiments of legacy projects only.
* For flag projects, experiment keys are not guaranteed to be unique
* across multiple flags, so this map may not include all experiments
* when keys conflict.
*/
experimentsMap: OptimizelyExperimentsMap;
featuresMap: OptimizelyFeaturesMap;
attributes: OptimizelyAttribute[];
audiences: OptimizelyAudience[];
events: OptimizelyEvent[];
getDatafile(): string;
}
interface OptimizelyUserContext {
getUserId(): string;
getAttributes(): UserAttributes;
setAttribute(key: string, value: unknown): void;
decide(key: string, options?: OptimizelyDecideOption[]): OptimizelyDecision;
decideForKeys(keys: string[], options?: OptimizelyDecideOption[]): {
[key: string]: OptimizelyDecision;
};
decideAll(options?: OptimizelyDecideOption[]): {
[key: string]: OptimizelyDecision;
};
trackEvent(eventName: string, eventTags?: EventTags): void;
setForcedDecision(context: OptimizelyDecisionContext, decision: OptimizelyForcedDecision): boolean;
getForcedDecision(context: OptimizelyDecisionContext): OptimizelyForcedDecision | null;
removeForcedDecision(context: OptimizelyDecisionContext): boolean;
removeAllForcedDecisions(): boolean;
}
interface OptimizelyDecision {
variationKey: string | null;
enabled: boolean;
variables: {
[variableKey: string]: unknown;
};
ruleKey: string | null;
flagKey: string;
userContext: OptimizelyUserContext;
reasons: string[];
}
interface OptimizelyDecisionContext {
flagKey: string;
ruleKey?: string;
}
interface OptimizelyForcedDecision {
variationKey: string;
}
declare type EventMap = {
[eventName: string]: Array<unknown>;
};
declare type InternalEventNames = 'newListener' | 'removeListener';
declare type InternalListener<Events extends EventMap> = Listener<[
eventName: keyof Events,
listener: Listener<Array<unknown>>
]>;
declare type Listener<Data extends Array<unknown>> = (...data: Data) => void;
/**
* Node.js-compatible implementation of `EventEmitter`.
*
* @example
* const emitter = new Emitter<{ hello: [string] }>()
* emitter.on('hello', (name) => console.log(name))
* emitter.emit('hello', 'John')
*/
declare class Emitter<Events extends EventMap> {
private events;
private maxListeners;
private hasWarnedAboutPotentialMemoryLeak;
static defaultMaxListeners: number;
static listenerCount<Events extends EventMap>(emitter: Emitter<EventMap>, eventName: keyof Events): number;
constructor();
private _emitInternalEvent;
private _getListeners;
private _removeListener;
private _wrapOnceListener;
setMaxListeners(maxListeners: number): this;
/**
* Returns the current max listener value for the `Emitter` which is
* either set by `emitter.setMaxListeners(n)` or defaults to
* `Emitter.defaultMaxListeners`.
*/
getMaxListeners(): number;
/**
* Returns an array listing the events for which the emitter has registered listeners.
* The values in the array will be strings or Symbols.
*/
eventNames(): Array<keyof Events>;
/**
* Synchronously calls each of the listeners registered for the event named `eventName`,
* in the order they were registered, passing the supplied arguments to each.
* Returns `true` if the event has listeners, `false` otherwise.
*
* @example
* const emitter = new Emitter<{ hello: [string] }>()
* emitter.emit('hello', 'John')
*/
emit<EventName extends keyof Events>(eventName: EventName, ...data: Events[EventName]): boolean;
addListener(eventName: InternalEventNames, listener: InternalListener<Events>): this;
addListener<EventName extends keyof Events>(eventName: EventName, listener: Listener<Events[EventName]>): this;
on(eventName: InternalEventNames, listener: InternalListener<Events>): this;
on<EventName extends keyof Events>(eventName: EventName, listener: Listener<Events[EventName]>): this;
once(eventName: InternalEventNames, listener: InternalListener<Events>): this;
once<EventName extends keyof Events>(eventName: EventName, listener: Listener<Events[EventName]>): this;
prependListener(eventName: InternalEventNames, listener: InternalListener<Events>): this;
prependListener<EventName extends keyof Events>(eventName: EventName, listener: Listener<Events[EventName]>): this;
prependOnceListener(eventName: InternalEventNames, listener: InternalListener<Events>): this;
prependOnceListener<EventName extends keyof Events>(eventName: EventName, listener: Listener<Events[EventName]>): this;
removeListener(eventName: InternalEventNames, listener: InternalListener<Events>): this;
removeListener<EventName extends keyof Events>(eventName: EventName, listener: Listener<Events[EventName]>): this;
off(eventName: InternalEventNames, listener: InternalListener<Events>): this;
off<EventName extends keyof Events>(eventName: EventName, listener: Listener<Events[EventName]>): this;
removeAllListeners(eventName?: InternalEventNames): this;
removeAllListeners<EventName extends keyof Events>(eventName?: EventName): this;
listeners(eventName: InternalEventNames): Array<Listener<any>>;
listeners<EventName extends keyof Events>(eventName: EventName): Array<Listener<Events[EventName]>>;
listenerCount(eventName: InternalEventNames): number;
listenerCount<EventName extends keyof Events>(eventName: EventName): number;
rawListeners<EventName extends keyof Events>(eventName: EventName): Array<Listener<Events[EventName]>>;
}
type MediaType = "video" | "audio" | "screen";
type TaskStatus = "abandoned" | "given.up" | "completed";
interface PassthroughData {
questionId: number;
surveyId: number;
visitorId: string | null;
responseGroupUid: UUID;
}
interface RecordedTaskResponseValueType {
mediaRecordingUids?: string[] | null;
taskDurationMillisecond?: number;
taskStatus: TaskStatus;
}
declare const BOOLEAN_OPERATOR: {
readonly And: 1;
readonly Or: 2;
};
type BooleanOperator = (typeof BOOLEAN_OPERATOR)[keyof typeof BOOLEAN_OPERATOR];
type CardType = "consentlegal" | "likert" | "matrix" | "multiplechoice" | "multipleselect" | "nps" | "open" | "rankorder" | "recordedtask" | "texturlprompt" | "thanks" | "uploading" | "videovoice";
type ConceptUrl = string | null;
interface BaseCard {
name: number;
surveyId: number;
updatedAt: string;
value?: unknown;
type: CardType;
groupId?: number;
}
type Comparator = "answered" | "contains" | "notcontains" | "list_dni" | "eq" | "given_up" | "gt" | "gte" | "lt" | "lte" | "list_all" | "list_alo" | "list_exact" | "neq" | "partial" | "skipped";
type Randomize = "none" | "all";
type DefaultComparator = Extract<Comparator, "answered" | "skipped">;
type RoutingOption<C extends Comparator = DefaultComparator> = OldRoutingOption<C> | GroupRoutingOption;
type OldRoutingOption<C extends Comparator = DefaultComparator> = {
comparator: C;
target: number;
/** @example '', 'option_2', ['option_1'] */
value: number | string | string[];
};
type GroupRoutingOption = {
group: (RoutingGroupOption | BooleanOperator)[];
target: number;
};
type RoutingGroupOption = {
comparator: Comparator;
questionIndex: number;
value: number | string | string[] | {
skipped: true;
} | null | undefined;
};
type RoutingOptions<C extends Comparator = DefaultComparator> = RoutingOption<C | DefaultComparator>[] | null;
/** @example <p>Body</p> */
type RichTextBody = string;
declare enum PromptActionTypeEnum {
CONTINUE = "CONTINUE",
EXTERNAL = "EXTERNAL",
NO_BUTTON = "NO_BUTTON"
}
type PromptActionType = keyof typeof PromptActionTypeEnum;
interface TextUrlPromptCard extends BaseCard {
props: {
message: string;
options: [];
properties: {
body: string;
buttonText?: string;
skipButtonText?: string;
buttonUrl?: string;
conceptUrl: ConceptUrl;
promptActionType: PromptActionType;
required: boolean;
richTextBody: RichTextBody;
questionHtml?: string;
};
routingOptions: RoutingOptions;
};
type: "texturlprompt";
}
type AvPermission = "camera" | "microphone" | "screen";
interface ConsentLegalCard extends BaseCard {
props: {
message: string;
options: [];
properties: {
body: string;
captionText: string;
collectName: boolean;
conceptUrl: ConceptUrl;
consentDocument?: {
originalFilename: string;
url: string;
};
consentText: string;
nameLabelText: string;
required: boolean;
richTextBody: RichTextBody;
skipButtonText: string;
submitButtonText: string;
questionHtml?: string;
};
routingOptions: RoutingOptions;
};
type: "consentlegal";
}
interface BaseTaskPage {
buttonText: string;
headline: string;
type: RecordedTaskPageType;
}
type RecordedTaskPageType = "av_permission" | "screen_permission" | "start_task" | "complete_task";
interface PermissionTaskPage extends BaseTaskPage {
captionText: string;
headline: string;
permissionDeniedBody: string;
permissionDeniedHeadline: string;
permissionDescriptors: AvPermission[];
permissionGrantedCaptionText?: string;
permissionGrantedHeadline?: string;
skipButtonText?: string;
svg: string;
tryAgainButtonText: string;
type: "av_permission";
}
interface ScreenTaskPage extends BaseTaskPage {
captionText: string;
permissionDeniedCaptionText: string;
permissionDeniedHeadline: string;
selectTabText: string;
skipButtonText: string;
type: "screen_permission";
}
interface StartTaskPage extends BaseTaskPage {
captionText?: string;
skipButtonText: string;
taskDetail: string;
type: "start_task";
}
interface CompleteTaskPage extends BaseTaskPage {
captionText?: string;
skipButtonText: string;
taskDetail: string;
type: "complete_task";
}
type RecordedTaskPage = PermissionTaskPage | ScreenTaskPage | StartTaskPage | CompleteTaskPage;
interface RecordedTaskCardProperties {
captionText: string;
conceptUrl: ConceptUrl;
pages: RecordedTaskPage[];
permissions: AvPermission[];
required: boolean;
taskDetail: string;
}
interface RecordedTaskCard extends BaseCard {
props: {
message: string;
options: [];
properties: RecordedTaskCardProperties;
routingOptions: RoutingOptions<"given_up">;
};
type: "recordedtask";
}
interface Labels {
left: string;
right: string;
}
interface RatingIcon {
idx?: number;
svg: string;
}
type ScaleLabelType = "number" | "smiley" | "star";
interface LikertCard extends BaseCard {
props: {
labels: Labels;
message: string;
options: [];
properties: {
captionText: string;
buttonText?: string;
conceptUrl: ConceptUrl;
labels: Labels;
range: string;
ratingIcons: RatingIcon[];
scaleLabelType: ScaleLabelType;
required: boolean;
};
routingOptions: RoutingOptions<"eq" | "given_up" | "gt" | "gte" | "lt" | "lte" | "neq">;
};
type: "likert";
}
interface OpenTextCard extends BaseCard {
props: {
message: string;
options: [];
properties: {
body: string;
buttonText?: string;
captionText?: string;
conceptUrl: ConceptUrl;
footerHtml?: string;
openTextPlaceholder?: string;
required: boolean;
richTextBody: RichTextBody;
skipButtonText?: string;
};
routingOptions: RoutingOptions<"contains" | "notcontains">;
};
type: "open";
}
interface MultipleChoiceOption {
createdAt: string;
deletedAt: null;
id: number;
label: string;
optionProperties: null | {
allowsTextEntry?: boolean;
noneOfTheAbove?: boolean;
isPinned?: boolean;
};
order: number;
productId: number;
surveyId: number;
surveyQuestionId: number;
updatedAt: string;
value: string;
}
interface CommonMultipleChoiceProps {
message: string;
options: MultipleChoiceOption[];
properties: {
buttonText?: string;
captionText: string;
conceptUrl: ConceptUrl;
isDropdown?: boolean;
/**
* Placeholder text on the dropdown button when no items are selected
*/
dropdownPlaceholderText?: string;
/**
* Text when multiple items are selected, such as "2 items selected" / "3 items selected"
*/
dropdownMultiselectedText?: string;
randomize: Randomize;
required: boolean;
};
}
interface MultiChoiceCard<C extends Comparator = DefaultComparator> extends BaseCard {
props: CommonMultipleChoiceProps & {
routingOptions: RoutingOptions<C>;
};
}
interface MultipleChoiceSingleSelectCard extends MultiChoiceCard<"eq" | "neq" | "list_alo" | "list_dni"> {
type: "multiplechoice";
}
interface MultipleChoiceMultiSelectCard extends MultiChoiceCard<"list_all" | "list_alo" | "list_exact" | "list_dni"> {
type: "multipleselect";
}
interface MatrixCard extends BaseCard {
props: {
options: MultipleChoiceOption[];
message: string;
routingOptions: RoutingOptions<"skipped" | "partial" | "answered">;
properties: {
buttonText?: string;
captionText: string;
conceptUrl: ConceptUrl;
displayMatrixAsAccordion?: boolean;
matrixColumn: {
label: string;
value: string;
}[];
randomize: Randomize;
required: boolean;
};
};
type: "matrix";
}
interface NPSCard extends BaseCard {
props: {
labels: Labels;
message: string;
options: [];
properties: {
buttonText?: string;
captionText: string;
conceptUrl: null;
labels: Labels;
required: boolean;
};
routingOptions: RoutingOptions<"eq" | "gt" | "gte" | "lt" | "lte" | "neq">;
};
type: "nps";
}
interface RankOrderOption {
createdAt: string;
deletedAt: null;
id: number;
label: string;
order: number;
productId: number;
surveyId: number;
surveyQuestionId: number;
updatedAt: string;
value: string;
}
interface RankOderType extends BaseCard {
props: {
labels: Labels;
message: string;
options: RankOrderOption[];
properties: {
captionText: string;
buttonText?: string;
conceptUrl: ConceptUrl;
labels: Labels;
required: boolean;
randomize: Randomize;
};
routingOptions: RoutingOptions<"eq" | "gt" | "gte" | "lt" | "lte" | "neq">;
};
type: "rankorder";
}
interface VideoVoiceCard extends BaseCard {
props: {
message: string;
options: [];
properties: {
buttonText: string;
captionText: string;
conceptUrl: null;
hideRecordedPrompt?: boolean;
mediaType: "video" | "audio";
required: boolean;
skipButtonText: string;
uploadId: string;
videoUrl: string;
};
routingOptions: RoutingOptions;
};
type: "videovoice";
}
type Card = TextUrlPromptCard | ConsentLegalCard | RecordedTaskCard | LikertCard | OpenTextCard | MatrixCard | MultipleChoiceSingleSelectCard | MultipleChoiceMultiSelectCard | NPSCard | RankOderType | VideoVoiceCard;
type InteractiveMatchType = "exactly" | "legacy";
type PageUrlMatchType = "contains" | "exactly" | "legacy" | "notContains" | "regex" | "startsWith";
interface InteractiveEvent {
id: number;
matchType: InteractiveMatchType;
name: string;
pattern: string;
properties: {
innerText: string;
selector?: string;
type?: "click";
};
}
interface PageUrlEvent {
id: number;
matchType: PageUrlMatchType;
pattern: string;
}
declare enum DismissReason {
Closed = "close.click",// user clicked the close button
Complete = "survey.completed",// user answered all questions
FeedbackClosed = "feedback.closed",// user either clicked on feedback button or close button
PageChange = "page.change",// productConfig.dismissOnPageChange == true and we detected a page change (excludes hash/query param changes)
API = "api",// JS called Sprig('dismissActiveSurvey')
Override = "override"
}
type StudyType = "feedbackButton" | "inProductSurvey" | "longFormSurvey";
declare enum SprigEvent {
ReplayCapture = "replay.capture",
ReplayPaused = "replay.paused",
ReplayResumed = "replay.resumed",
FeedbackButtonLoaded = "feedback.button.loaded",
SDKReady = "sdk.ready",
SurveyAppeared = "survey.appeared",
SurveyCloseRequested = "survey.closeRequested",//This event signals to mobile the survey overlay can close
SurveyClosed = "survey.closed",
SurveyDimensions = "survey.dimensions",
SurveyFadingOut = "survey.fadingOut",
SurveyHeight = "survey.height",
SurveyPresented = "survey.presented",
SurveyLifeCycle = "survey.lifeCycle",
SurveyWidth = "survey.width",
SurveyWillClose = "survey.willClose",
SurveyWillPresent = "survey.will.present",
CloseSurveyOnOverlayClick = "close.survey.overlayClick",
VisitorIDUpdated = "visitor.id.updated",
QuestionAnswered = "question.answered"
}
declare const EVENTS: {
FEEDBACK_BUTTON_LOADED: SprigEvent;
SDK_READY: SprigEvent;
SURVEY_APPEARED: SprigEvent;
SURVEY_CLOSED: SprigEvent;
SURVEY_DIMENSIONS: SprigEvent;
SURVEY_FADING_OUT: SprigEvent;
SURVEY_HEIGHT: SprigEvent;
SURVEY_WIDTH: SprigEvent;
SURVEY_PRESENTED: SprigEvent;
SURVEY_LIFE_CYCLE: SprigEvent;
SURVEY_WILL_CLOSE: SprigEvent;
SURVEY_WILL_PRESENT: SprigEvent;
QUESTION_ANSWERED: SprigEvent;
REPLAY_CAPTURE: SprigEvent;
CLOSE_SURVEY_ON_OVERLAY_CLICK: SprigEvent;
VISITOR_ID_UPDATED: SprigEvent;
DATA: {
DISMISS_REASONS: {
API: DismissReason;
CLOSED: DismissReason;
COMPLETE: DismissReason;
PAGE_CHANGE: DismissReason;
OVERRIDE: DismissReason;
};
SURVEY_ID: string;
};
};
type Metric = "sdk_event_queue_latency_seconds" | "sdk_replay_add_event_batch_seconds" | "sdk_replay_cleanup_seconds" | "sdk_replay_compression_seconds" | "sdk_replay_get_events_between_seconds" | "sdk_replay_snapshot_seconds" | "sdk_mutations_nodes_added" | "sdk_mutations_nodes_removed" | "sdk_mutations_attributes_changed" | "sdk_mutations_character_data" | "sdk_dom_nodes_count" | "sdk_page_html_characters";
type ThresholdType = "max" | "min";
interface MetricThreshold {
metric: Metric;
type: ThresholdType;
value: number;
}
interface RecordedTaskResponseType {
questionId: number;
type: CardType;
value: RecordedTaskResponseValueType;
}
type SurveyState = "ready" | "no survey";
type ReplayDurationType = "after" | "before" | "beforeAndAfter";
interface MobileReplayConfig {
mobileMetricsReportingEnabled?: boolean;
metricsReportingInterval?: number;
metricsThresholds?: MetricThreshold[];
maxMobileReplayDurationSeconds?: number;
mobileReplaySettings?: {
hideAllFormContents: boolean;
hidePasswordsOnly: boolean;
hideAllImages: boolean;
};
}
type SprigEventMap = {
"survey.question": [
{
qid: number;
props: unknown;
}
];
"recorded.task.permission.screen": [];
"recorded.task.start": [];
"survey.complete": [number];
"verify.view.version": [
{
"view.version": string;
}
];
[SprigEvent.CloseSurveyOnOverlayClick]: [];
[SprigEvent.FeedbackButtonLoaded]: [
{
name: string;
"survey.id"?: number;
}
];
[SprigEvent.SDKReady]: [MobileReplayConfig];
[SprigEvent.SurveyAppeared]: [
{
name: string;
"survey.id": number;
}
];
[SprigEvent.SurveyDimensions]: [
{
contentFrameHeight: number;
contentFrameWidth: number;
name: string;
"survey.id": number;
}
];
[SprigEvent.SurveyClosed]: [
{
initiator?: string;
name: string;
studyType?: StudyType;
"survey.id": number;
}
];
[SprigEvent.SurveyFadingOut]: [];
[SprigEvent.SurveyHeight]: [
{
name: string;
contentFrameHeight: number;
"survey.id": number;
}
];
[SprigEvent.SurveyWidth]: [
{
name: string;
contentFrameWidth: number;
"survey.id": number;
}
];
[SprigEvent.SurveyLifeCycle]: [{
state: string;
}];
[SprigEvent.SurveyPresented]: [
{
name: string;
"survey.id": number;
}
];
[SprigEvent.SurveyCloseRequested]: [
{
initiator: DismissReason;
name?: string;
studyType?: StudyType;
"survey.id": number;
}
];
[SprigEvent.SurveyWillClose]: [
{
initiator: DismissReason;
name?: string;
studyType?: StudyType;
"survey.id": number;
}
];
[SprigEvent.SurveyWillPresent]: [
{
name: string;
"survey.id": number;
}
];
[SprigEvent.VisitorIDUpdated]: [{
visitorId: string | null;
}];
[SprigEvent.QuestionAnswered]: [
{
answeredAt?: number;
questionIndex?: number;
value: unknown;
"survey.id": number;
}
];
[SprigEvent.ReplayCapture]: [
{
responseGroupUid: string;
hasQuestions: boolean;
uploadId: string;
seconds: number;
replayType: ReplayDurationType;
generateVideoUploadUrlPayload: {
isReplay: boolean;
mediaRecordingUid: string;
mediaType: MediaType;
questionId: number;
responseGroupUid: string;
surveyId: number;
updatedAt: string;
visitorId: string | null;
};
surveyId: number;
}
];
[SprigEvent.ReplayPaused]: [];
[SprigEvent.ReplayResumed]: [];
"av.permission": [
{
"stream.ready": (avStream: MediaStream | null, captureStream?: MediaStream | null) => void;
"permission.descriptors": AvPermission[];
}
];
"begin.recording": [
{
"recording.media.types": MediaType[];
"start.recording.callback": (mediaRecordingUids: UUID[]) => void;
}
];
"finish.task": [
{
"begin.callback": (mediaRecordingUid: UUID) => void;
"current.index": number;
"passthrough.data": PassthroughData;
"progress.callback": (mediaRecordingUid: UUID, data: {
detail: number;
}) => void;
"task.complete.callback": (taskDurationMillisecond: number) => void;
"task.response": RecordedTaskResponseType;
"upload.callback": (mediaRecordingUid: UUID | null, successOrError: true | unknown) => void;
}
];
"permission.status": [
{
"permission.status.callback": (avStream: MediaStream | undefined, hasVideoPermission: boolean, hasScreenPermission: boolean, captureStream: MediaStream | undefined) => void;
}
];
"screen.permission": [
{
"screen.permission.requested"?: (data: boolean) => void;
"stream.ready.callback": (avStream: MediaStream | null, captureStream: MediaStream | null) => void;
}
];
"start.task": [];
};
declare const eventEmitter: Emitter<SprigEventMap>;
type SprigEventEmitter = typeof eventEmitter;
type FramePosition = "bottomLeft" | "bottomRight" | "center" | "topLeft" | "topRight";
type Platform = "email" | "link" | "web";
type InstallationMethod = "web-npm" | "web-npm-bundled" | "web-gtm" | "web-segment" | "android-segment" | "react-native-segment" | "ios-segment" | "web-snippet";
interface Answer {
questionId: number;
value: unknown;
}
type FeedbackPlacement = "center-left" | "center-right" | "bottom-left" | "bottom-right";
type FeedbackDesktopDisplay = "center-modal" | "slider";
interface AppProductConfig {
framePosition?: FramePosition;
desktopDisplay?: FeedbackDesktopDisplay;
placement?: FeedbackPlacement;
}
interface Config extends MobileReplayConfig {
allResponses: unknown[];
answers?: Answer[];
apiURL: string;
/** @example "#000000" */
border: string;
cards: Card[];
configureExitOnOverlayClick: (cb: () => void) => void;
context: {