@amplitude/experiment-tag 0.25.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Binary file
@@ -1,4 +1,6 @@
1
1
  import { BehavioralTargetingRules } from '../types';
2
+ import { RelayClient } from './relay-client';
3
+ import { RelaySyncResult } from './relay-sync-result';
2
4
  /**
3
5
  * Manages all behavioral targeting functionality including event storage,
4
6
  * session management, and rule evaluation.
@@ -10,7 +12,7 @@ export declare class BehavioralTargetingManager {
10
12
  private readonly rules;
11
13
  private readonly matchedBehaviors;
12
14
  private readonly eventToBehaviors;
13
- constructor(apiKey: string, initialRules?: BehavioralTargetingRules);
15
+ constructor(apiKey: string, initialRules?: BehavioralTargetingRules, sessionTimeoutMs?: number);
14
16
  /**
15
17
  * Track an event for behavioral targeting evaluation.
16
18
  * Automatically updates the active behavior state for affected flags.
@@ -18,6 +20,19 @@ export declare class BehavioralTargetingManager {
18
20
  * @param properties Event properties
19
21
  */
20
22
  trackEvent(eventType: string, properties: Record<string, unknown>): void;
23
+ /**
24
+ * Attach the relay client for cross-subdomain event dual-write.
25
+ */
26
+ setRelayClient(relayClient: RelayClient | null): void;
27
+ /**
28
+ * Inject relay iframe (non-blocking init) and run the relay merge.
29
+ *
30
+ * This only reads/merges relay state and reports the outcome; it never
31
+ * attaches the relay for dual-write. The caller owns relay lifecycle and
32
+ * decides whether to attach (via {@link setRelayClient}) based on the
33
+ * result and whether this client is still the active one.
34
+ */
35
+ beginRelaySync(relayClient: RelayClient): Promise<RelaySyncResult>;
21
36
  /**
22
37
  * Check if a flag has behavioral targeting rules.
23
38
  * @param flagKey The flag key to check
@@ -63,6 +78,11 @@ export declare class BehavioralTargetingManager {
63
78
  * @param flagKey The flag key to evaluate
64
79
  */
65
80
  private evaluateFlag;
81
+ /**
82
+ * Stable JSON snapshot of matched behaviors (sorted behavior IDs per flag),
83
+ * used to detect whether a relay sync changed the matched set.
84
+ */
85
+ private serializeMatchedBehaviors;
66
86
  /**
67
87
  * Evaluate a specific behavior ID for a flag.
68
88
  * Updates only the specified behavior ID in the matchedBehaviors state.
@@ -1,8 +1,25 @@
1
+ import { RelayClient } from './relay-client';
2
+ import { RelayEventStorage } from './relay-protocol';
1
3
  import { SessionManager } from './session-manager';
4
+ /**
5
+ * Dedup key for cross-subdomain merge. Uses the event's uuid (minted once at
6
+ * creation in {@link EventStorageManager.addEvent}) so the SDK and relay.js
7
+ * agree on identity. (event_type + timestamp is not unique — two distinct
8
+ * same-type events in the same millisecond would collapse.)
9
+ */
10
+ export declare function eventDedupKey(event: {
11
+ uuid: string;
12
+ }): string;
2
13
  /**
3
14
  * Represents a stored event record.
4
15
  */
5
16
  export interface EventRecord {
17
+ /** Stable per-event identity; the cross-subdomain dedup key (see eventDedupKey). */
18
+ uuid: string;
19
+ /**
20
+ * Per-origin monotonic counter. Retained for debugging only — identity and
21
+ * dedup use uuid, ordering uses timestamp, and FIFO uses array order.
22
+ */
6
23
  id: number;
7
24
  event_type: string;
8
25
  timestamp: number;
@@ -22,6 +39,7 @@ export declare class EventStorageManager {
22
39
  private hasPendingWrites;
23
40
  private persistedEvents?;
24
41
  private storageKey;
42
+ private relayClient;
25
43
  constructor(apiKey: string, sessionManager: SessionManager, persistedEvents?: Set<string>);
26
44
  /**
27
45
  * Adds an event to in-memory cache with automatic session tracking.
@@ -29,6 +47,23 @@ export declare class EventStorageManager {
29
47
  * If persistedEvents is set, only events with matching event types will be stored.
30
48
  */
31
49
  addEvent(eventType: string, properties?: Record<string, unknown>, eventTime?: number): void;
50
+ /**
51
+ * Attach or detach the relay client for cross-subdomain dual-write.
52
+ */
53
+ setRelayClient(relayClient: RelayClient | null): void;
54
+ /**
55
+ * Flushes pending relay writes (e.g. on page unload).
56
+ */
57
+ flushRelay(): void;
58
+ /**
59
+ * Merges relay events into the in-memory cache. Relay wins on dedup conflicts.
60
+ */
61
+ mergeFromRelay(relayStore: RelayEventStorage): void;
62
+ /**
63
+ * Pass 2 sync: migrate local store to relay if needed, then merge relay events.
64
+ * Returns true when sync completed; false when relay unavailable or RPC failed.
65
+ */
66
+ syncFromRelay(relayClient?: RelayClient): Promise<boolean>;
32
67
  /**
33
68
  * Gets all events from in-memory cache (for testing/debugging).
34
69
  */
@@ -1,2 +1,4 @@
1
1
  export { BehavioralTargetingManager } from './behavioral-targeting-manager';
2
2
  export { BehavioralTargeting, BehavioralCondition, BehavioralConditionSet, } from './types';
3
+ export * from './relay-protocol';
4
+ export * from './relay-client';
@@ -0,0 +1,40 @@
1
+ import { RelayEventRecord, RelayEventStorage } from './relay-protocol';
2
+ export declare function getRelayUrl(apiKey: string, serverZone?: string, relayUrl?: string): string;
3
+ export declare class RelayClient {
4
+ private readonly apiKey;
5
+ private readonly webExpIdV2;
6
+ private readonly relayUrl;
7
+ private iframe;
8
+ private iframeWindow;
9
+ private relayOrigin;
10
+ private available;
11
+ private pendingWrites;
12
+ private readonly pendingRequests;
13
+ private messageListener;
14
+ private initPromise;
15
+ private initTimeoutId;
16
+ private initResolve;
17
+ private cancelBodyReadyPoll;
18
+ private destroyed;
19
+ private availablePromise;
20
+ private resolveAvailable;
21
+ constructor(apiKey: string, webExpIdV2: string, relayUrl: string);
22
+ private createRelayRequest;
23
+ get relayAvailable(): boolean;
24
+ private notifyAvailable;
25
+ /**
26
+ * Resolves when the relay becomes available, or after timeout.
27
+ * Use after init() when the init timer may have fired before RELAY_READY.
28
+ */
29
+ waitForAvailable(timeoutMs?: number): Promise<boolean>;
30
+ init(): Promise<void>;
31
+ private sendRequest;
32
+ readEvents(): Promise<RelayEventStorage>;
33
+ writeEvent(event: RelayEventRecord): void;
34
+ private removeConfirmedWrite;
35
+ private sendPendingWrite;
36
+ flush(): void;
37
+ checkMigrated(origin: string): Promise<boolean>;
38
+ migrateEvents(origin: string, store: RelayEventStorage): Promise<void>;
39
+ destroy(): void;
40
+ }
@@ -0,0 +1,36 @@
1
+ export declare const RELAY_READY_MESSAGE = "AMP_RELAY_READY";
2
+ export declare const RELAY_RPC_TIMEOUT_MS = 2000;
3
+ export type RelayMessageType = 'WRITE_EVENT' | 'READ_EVENTS' | 'MIGRATE_EVENTS' | 'CHECK_MIGRATED' | 'MIGRATE_ACK';
4
+ export interface RelayEventRecord {
5
+ /** Stable per-event identity minted by the SDK; the cross-subdomain dedup key. */
6
+ uuid: string;
7
+ id: number;
8
+ event_type: string;
9
+ timestamp: number;
10
+ session_id: string;
11
+ properties: Record<string, unknown>;
12
+ }
13
+ export interface RelayEventStorage {
14
+ events: RelayEventRecord[];
15
+ nextId: number;
16
+ }
17
+ export interface RelayRequest {
18
+ type: RelayMessageType;
19
+ requestId: string;
20
+ apiKey: string;
21
+ web_exp_id_v2: string;
22
+ payload?: unknown;
23
+ }
24
+ export interface RelayResponse {
25
+ requestId: string;
26
+ ok: boolean;
27
+ payload?: unknown;
28
+ error?: string;
29
+ }
30
+ export interface MigratePayload {
31
+ sourceOrigin: string;
32
+ store: RelayEventStorage;
33
+ }
34
+ export interface WriteEventPayload {
35
+ event: RelayEventRecord;
36
+ }
@@ -0,0 +1,10 @@
1
+ /** Outcome of non-blocking relay iframe init + relay merge. */
2
+ export type RelaySyncResult = {
3
+ status: 'behaviors_changed';
4
+ } | {
5
+ status: 'unchanged';
6
+ } | {
7
+ status: 'unavailable';
8
+ } | {
9
+ status: 'sync_failed';
10
+ };
@@ -1,27 +1,57 @@
1
1
  /**
2
- * Manages browser session ID using sessionStorage.
3
- * Session ID is unique per browser tab and cleared when tab closes.
2
+ * Default rolling inactivity window before a session rotates, mirroring
3
+ * Amplitude Analytics' 30-minute session timeout.
4
+ */
5
+ export declare const DEFAULT_SESSION_TIMEOUT_MS: number;
6
+ /**
7
+ * Manages the RTBT session ID.
8
+ *
9
+ * Unlike the previous per-tab `sessionStorage` implementation, the session is
10
+ * persisted in a root-domain cookie so it is shared across subdomains, and it
11
+ * rotates on a rolling inactivity timeout (the same model Amplitude Analytics
12
+ * uses). When cookies are unavailable (private browsing, ITP, blocked I/O) the
13
+ * session degrades gracefully to an in-memory, per-page session.
14
+ *
15
+ * Cookie I/O + the cookie→memory two-tier fallback are delegated to
16
+ * {@link SyncJsonCookie}; this class owns the session lifecycle (rotation on
17
+ * inactivity, validation) on top of it.
4
18
  */
5
19
  export declare class SessionManager {
6
- private storageKey;
7
- private sessionId?;
8
- private sessionStartTime?;
9
- constructor(apiKey: string);
20
+ private sessionTimeoutMs;
21
+ private store;
22
+ /** Lazily resolved leading-dot domain (e.g. `.example.com`) or `''`. */
23
+ private resolvedDomain?;
24
+ constructor(apiKey: string, sessionTimeoutMs?: number);
25
+ /**
26
+ * Returns the current session ID, rotating it when the inactivity timeout
27
+ * has elapsed and creating one when none exists. This is a read: it does not
28
+ * extend the session (use {@link recordActivity} for that).
29
+ */
30
+ getCurrentSessionId(): string;
10
31
  /**
11
- * Gets the current session ID, creating one if it doesn't exist.
12
- * Uses sessionStorage (cleared when tab closes).
32
+ * Backwards-compatible alias for {@link getCurrentSessionId}.
13
33
  */
14
34
  getOrCreateSessionId(): string;
35
+ /**
36
+ * Records activity for the current page event: extends the active session
37
+ * (bumping `lastEventTime`) or rotates to a new session when the inactivity
38
+ * timeout has elapsed. Call this for every observed Amplitude event so that
39
+ * any activity keeps the session alive.
40
+ */
41
+ recordActivity(): void;
15
42
  /**
16
43
  * Gets the session start time in milliseconds since epoch.
17
44
  */
18
45
  getSessionStartTime(): number | undefined;
19
46
  /**
20
- * Generates a unique session ID.
47
+ * Clears the current session from memory and cookie storage.
21
48
  */
22
- private generateSessionId;
49
+ clearSession(): void;
23
50
  /**
24
- * Clears the current session (for testing).
51
+ * Resolves the active session: returns the persisted session when it is
52
+ * still within the inactivity window, otherwise creates, persists and
53
+ * returns a fresh one. Does not extend an already-active session.
25
54
  */
26
- clearSession(): void;
55
+ private resolve;
56
+ private domain;
27
57
  }
@@ -31,6 +31,7 @@ export declare class DefaultWebExperimentClient implements WebExperimentClient {
31
31
  private readonly localFlagKeys;
32
32
  private remoteFlagKeys;
33
33
  private isRemoteBlocking;
34
+ isRedirecting: boolean;
34
35
  private customRedirectHandler;
35
36
  isRunning: boolean;
36
37
  private readonly messageBus;
@@ -38,11 +39,13 @@ export declare class DefaultWebExperimentClient implements WebExperimentClient {
38
39
  private activePages;
39
40
  private readonly behavioralTargetingRules;
40
41
  readonly behavioralTargetingManager: BehavioralTargetingManager | undefined;
42
+ private relayClient;
41
43
  private subscriptionManager;
42
44
  private isVisualEditorMode;
43
45
  private isDebugActive;
44
46
  isPreviewMode: boolean;
45
47
  previewFlags: Record<string, string>;
48
+ private rootDomain;
46
49
  constructor(apiKey: string, initConfigs: InitConfigs, config?: WebExperimentConfig);
47
50
  /**
48
51
  * Start the web experiment client.
@@ -98,6 +101,26 @@ export declare class DefaultWebExperimentClient implements WebExperimentClient {
98
101
  * @returns An unsubscribe function to remove the subscriber.
99
102
  */
100
103
  addPageChangeSubscriber(callback: (event: PageChangeEvent) => void): (() => void) | undefined;
104
+ /**
105
+ * Behavioral targeting evaluates in two phases at startup:
106
+ *
107
+ * 1. start() evaluates and applies variants from this origin's own local
108
+ * event store (already done by the time we get here).
109
+ * 2. Relay sync (this method): a hidden CDN iframe pulls the shared
110
+ * cross-subdomain event store, merges it into local storage, and
111
+ * re-evaluates behavioral targeting. If matched behaviors changed,
112
+ * {@link reapplyVariantsAfterRelaySync} re-applies the affected variants.
113
+ *
114
+ * Non-blocking: the iframe init and merge run after anti-flicker is removed,
115
+ * so a relay-driven change repaints rather than delaying first paint.
116
+ */
117
+ private scheduleRelaySync;
118
+ private teardownRelay;
119
+ /**
120
+ * Re-apply variants when a relay sync changed the matched behaviors
121
+ * (phase 2 of the startup described on {@link scheduleRelaySync}).
122
+ */
123
+ private reapplyVariantsAfterRelaySync;
101
124
  /**
102
125
  * Update the user with matched behavioral targeting IDs.
103
126
  * Sets the user property `behavioral_targeting` to an array of all matched behavior IDs.
@@ -1,3 +1,4 @@
1
+ import { type GlobalScope } from '@amplitude/experiment-core';
1
2
  import { DefaultWebExperimentClient } from '../experiment';
2
3
  import { PageObjects } from '../types';
3
4
  import { MessageBus } from './message-bus';
@@ -17,7 +18,7 @@ export declare class SubscriptionManager {
17
18
  private triggerManagers;
18
19
  private pageChangeSubscribers;
19
20
  private lastNotifiedActivePages;
20
- constructor(webExperimentClient: DefaultWebExperimentClient, messageBus: MessageBus, pageObjects: PageObjects, options: initOptions, globalScope: typeof globalThis);
21
+ constructor(webExperimentClient: DefaultWebExperimentClient, messageBus: MessageBus, pageObjects: PageObjects, options: initOptions, globalScope: GlobalScope);
21
22
  setPageObjects: (pageObjects: PageObjects) => void;
22
23
  markUrlAsPublished: (url: string) => void;
23
24
  initSubscriptions: () => void;
@@ -1,3 +1,4 @@
1
+ import { type GlobalScope } from '@amplitude/experiment-core';
1
2
  import { BehavioralTargetingManager } from '../behavioral-targeting';
2
3
  import { DefaultWebExperimentClient } from '../experiment';
3
4
  import { PageObjects } from '../types';
@@ -42,7 +43,7 @@ export declare class SubscriptionManager {
42
43
  private debugDebounceTimer;
43
44
  private get contentDocument();
44
45
  private get contentWindow();
45
- constructor(webExperimentClient: DefaultWebExperimentClient, messageBus: MessageBus, pageObjects: PageObjects, behavioralTargetingManager: BehavioralTargetingManager | undefined, options: initOptions, globalScope: typeof globalThis);
46
+ constructor(webExperimentClient: DefaultWebExperimentClient, messageBus: MessageBus, pageObjects: PageObjects, behavioralTargetingManager: BehavioralTargetingManager | undefined, options: initOptions, globalScope: GlobalScope);
46
47
  setPageObjects: (pageObjects: PageObjects) => void;
47
48
  markUrlAsPublished: (url: string) => void;
48
49
  initSubscriptions: () => void;
@@ -1,3 +1,4 @@
1
+ import type { GlobalScope } from '@amplitude/experiment-core';
1
2
  import { MessageBus, MessagePayloads, MessageType } from '../subscriptions/message-bus';
2
3
  import { PageObject } from '../types';
3
4
  import { TriggerManagerOptions } from './index';
@@ -46,9 +47,9 @@ export interface TriggerManager<TPayload = any> {
46
47
  export declare abstract class BaseTriggerManager<TPayload = any> implements TriggerManager<TPayload> {
47
48
  protected readonly pageObjects: PageObject[];
48
49
  protected readonly messageBus: MessageBus;
49
- protected readonly globalScope: typeof globalThis;
50
+ protected readonly globalScope: GlobalScope;
50
51
  protected readonly options?: TriggerManagerOptions | undefined;
51
- constructor(pageObjects: PageObject[], messageBus: MessageBus, globalScope: typeof globalThis, options?: TriggerManagerOptions | undefined);
52
+ constructor(pageObjects: PageObject[], messageBus: MessageBus, globalScope: GlobalScope, options?: TriggerManagerOptions | undefined);
52
53
  abstract readonly triggerType: MessageType;
53
54
  abstract initialize(): void;
54
55
  abstract isActive(page: PageObject, payload?: TPayload): boolean;
@@ -1,3 +1,4 @@
1
+ import type { GlobalScope } from '@amplitude/experiment-core';
1
2
  import { MessageBus, MessageType } from '../subscriptions/message-bus';
2
3
  import { PageObject } from '../types';
3
4
  import { TriggerManager } from './base-trigger-manager';
@@ -17,4 +18,4 @@ type TriggerType = Exclude<MessageType, 'element_appeared_internal'>;
17
18
  * Registry of trigger managers available in this version.
18
19
  * Trigger managers will be added in subsequent PRs.
19
20
  */
20
- export declare const TRIGGER_MANAGER_REGISTRY: Partial<Record<TriggerType, new (pageObjects: PageObject[], messageBus: MessageBus, globalScope: typeof globalThis, options?: TriggerManagerOptions) => TriggerManager>>;
21
+ export declare const TRIGGER_MANAGER_REGISTRY: Partial<Record<TriggerType, new (pageObjects: PageObject[], messageBus: MessageBus, globalScope: GlobalScope, options?: TriggerManagerOptions) => TriggerManager>>;
@@ -101,6 +101,20 @@ export interface WebExperimentConfig extends ExperimentConfig {
101
101
  */
102
102
  useDefaultNavigationHandler?: boolean;
103
103
  redirectConfig?: RedirectConfig;
104
+ /**
105
+ * Rolling inactivity timeout, in milliseconds, after which the behavioral
106
+ * targeting (RTBT) session rotates. Mirrors Amplitude Analytics' session
107
+ * model. Defaults to 30 minutes when unset.
108
+ */
109
+ rtbtSessionTimeout?: number;
110
+ /**
111
+ * Overrides the origin the cross-subdomain RTBT relay iframe is loaded from.
112
+ * Provide a scheme + host (+ optional port), e.g. `https://relay.lvh.me:3036`;
113
+ * the canonical `/script/{apiKey}.relay.html` path is appended automatically.
114
+ * When unset, the relay loads from the Amplitude CDN for the configured server
115
+ * zone. Intended for local/staging testing of the relay serving path.
116
+ */
117
+ relayUrl?: string;
104
118
  }
105
119
  export declare const Defaults: WebExperimentConfig;
106
120
  /**
@@ -1,11 +1,61 @@
1
1
  import { CookieStorage } from '@amplitude/analytics-core';
2
+ /**
3
+ * Synchronous variant of {@link getTopLevelDomain}. Resolves the registrable
4
+ * (root) domain for `hostname` so callers can set a cookie shared across
5
+ * subdomains, without the async `CookieStorage.isDomainWritable` round-trip.
6
+ * Returns a leading-dot domain (e.g. `.example.com`) or `''` when no
7
+ * cross-subdomain domain is writable (single-label hosts, IPs, blocked I/O).
8
+ */
9
+ export declare function getTopLevelDomainSync(hostname: string): string;
2
10
  export declare function getTopLevelDomain(hostname: string): Promise<string>;
3
11
  /**
4
- * Resolves a cross-subdomain value using cookie storage as the authoritative
5
- * source. Falls back to a provided localStorage value (migration path), then
6
- * generates a new value if neither exists. Attempts to set the cookie when
7
- * missing; cookie I/O failures fall back to localStorage / generateNew.
8
- * Callers are responsible for syncing the returned value back to localStorage.
12
+ * Resolves several cross-subdomain fields from a single cookie, using cookie
13
+ * storage as the authoritative source. Each field falls back to its `fallback`
14
+ * value (migration path), then its generator. One read + at most one write;
15
+ * cookie I/O failures degrade to the returned value. Callers are responsible
16
+ * for mirroring values back to localStorage if needed.
17
+ */
18
+ export declare function resolveCrossSubdomainObject<T extends Record<string, string>>(cookieStorage: CookieStorage<string>, cookieKey: string, fallback: Partial<T>, generators: {
19
+ [K in keyof T]: () => string;
20
+ }): Promise<T>;
21
+ /** Reads a raw cookie value (URL-decoded) synchronously, or `undefined` if absent. */
22
+ export declare function readRawCookie(key: string): string | undefined;
23
+ /**
24
+ * Writes a cookie (`Path=/; SameSite=Lax`, `Secure` on https), then verifies it
25
+ * via read-back. Returns `false` on blocked cookie I/O (private mode, ITP, a
26
+ * wrong domain) so callers can fall back to memory. No `maxAgeSeconds` ⇒ session.
27
+ *
28
+ * The read-back compares the decoded value, not just key presence: a silently
29
+ * dropped write that leaves a stale same-key cookie (e.g. a host-only cookie
30
+ * shadowing a failed `.domain` write) reports `false` so the caller serves its
31
+ * fresh in-memory value instead of a stale payload.
32
+ */
33
+ export declare function writeRawCookie(key: string, value: string, options?: {
34
+ domain?: string;
35
+ maxAgeSeconds?: number;
36
+ }): boolean;
37
+ /** Best-effort delete (must match the domain the cookie was written with). */
38
+ export declare function deleteRawCookie(key: string, domain?: string): void;
39
+ /**
40
+ * Synchronous two-tier (cookie → in-memory) JSON store. The cookie is the
41
+ * cross-tab / cross-subdomain source of truth; if writes are blocked (detected
42
+ * via {@link writeRawCookie}'s read-back) it degrades to a per-page value. The
43
+ * domain is read lazily per write so it can be resolved after construction.
9
44
  */
10
- export declare function resolveCrossSubdomainValue(cookieStorage: CookieStorage<string>, cookieKey: string, localStorageValue: string | undefined, generateNew: () => string): Promise<string>;
45
+ export declare class SyncJsonCookie<T> {
46
+ private readonly key;
47
+ private readonly getDomain;
48
+ private readonly options;
49
+ private usable?;
50
+ private memory?;
51
+ constructor(key: string, getDomain: () => string, options?: {
52
+ maxAgeSeconds?: number;
53
+ /** Validates/normalizes a parsed payload; return undefined to reject it. */
54
+ validate?: (value: unknown) => T | undefined;
55
+ });
56
+ read(): T | undefined;
57
+ write(value: T): void;
58
+ clear(): void;
59
+ private parse;
60
+ }
11
61
  export declare function setMarketingCookie(apiKey: string, hostname: string): Promise<void>;
@@ -1,3 +1,4 @@
1
+ import type { GlobalScope } from '@amplitude/experiment-core';
1
2
  import type { DebugEvent, DebugState, FlagDebugInfo, VEMessengerState, VisualEditorDebugInfo } from '../types/debug';
2
3
  /**
3
4
  * Provides the non-event, non-timestamp parts of DebugState.
@@ -14,7 +15,7 @@ export declare const DebugRecorder: {
14
15
  * Evaluate activation signals. Must be called before any other method.
15
16
  * Checks window.__AMP_DEBUG and localStorage('amp-ve-debug').
16
17
  */
17
- init: (globalScope: typeof globalThis) => void;
18
+ init: (globalScope: GlobalScope) => void;
18
19
  isActive: () => boolean;
19
20
  /** Append a debug event. No-op when not active. */
20
21
  push: (event: string, detail?: string) => void;
@@ -1,3 +1,4 @@
1
+ import type { GlobalScope } from '@amplitude/experiment-core';
1
2
  export declare const DEVICE_IFRAME_ID = "amp-device-iframe";
2
3
  export declare function isMobileModeActive(): boolean;
3
4
  /**
@@ -10,13 +11,13 @@ export declare function getDeviceIframe(): HTMLIFrameElement | null;
10
11
  * customer site lives inside a same-origin iframe; otherwise it is the
11
12
  * top-level document.
12
13
  */
13
- export declare function getCustomerDocument(globalScope: typeof globalThis): Document;
14
+ export declare function getCustomerDocument(globalScope: GlobalScope): Document;
14
15
  /**
15
16
  * Returns the Window for the customer page. In mobile viewport mode the
16
17
  * customer site lives inside a same-origin iframe; otherwise it is the
17
18
  * top-level window.
18
19
  */
19
- export declare const getCustomerWindow: (globalScope: typeof globalThis) => Window & typeof globalThis;
20
+ export declare const getCustomerWindow: (globalScope: GlobalScope) => Window & GlobalScope;
20
21
  /**
21
22
  * Replaces the page DOM with a shell container that loads the customer site
22
23
  * in a same-origin iframe.
@@ -32,4 +33,4 @@ export declare const getCustomerWindow: (globalScope: typeof globalThis) => Wind
32
33
  * guarantee it renders into the already-built shell rather than racing with
33
34
  * DOM restructuring.
34
35
  */
35
- export declare function buildShell(globalScope: typeof globalThis): Promise<void>;
36
+ export declare function buildShell(globalScope: GlobalScope): Promise<void>;
@@ -8,5 +8,7 @@
8
8
  * In the (effectively impossible) case where `requestAnimationFrame` is
9
9
  * unavailable, the callback is invoked immediately rather than never —
10
10
  * callers that would crash on a null body should guard inside.
11
+ *
12
+ * Returns a cancel function that stops any in-flight body poll.
11
13
  */
12
- export declare const whenBodyReady: (callback: () => void) => void;
14
+ export declare const whenBodyReady: (callback: () => void) => (() => void);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amplitude/experiment-tag",
3
- "version": "0.25.0",
3
+ "version": "0.26.0",
4
4
  "description": "Amplitude Experiment Javascript Snippet",
5
5
  "author": "Amplitude",
6
6
  "homepage": "https://github.com/amplitude/experiment-js-client",
@@ -27,12 +27,14 @@
27
27
  "url": "https://github.com/amplitude/experiment-js-client/issues"
28
28
  },
29
29
  "dependencies": {
30
+ "@amplitude/analytics-connector": "^1.6.5",
30
31
  "@amplitude/analytics-core": "^2.21.0",
31
32
  "@amplitude/analytics-types": "^2.11.0",
32
- "@amplitude/experiment-core": "^0.13.1",
33
- "@amplitude/experiment-js-client": "^1.21.1",
33
+ "@amplitude/experiment-core": "^0.13.3",
34
+ "@amplitude/experiment-js-client": "^1.21.3",
34
35
  "dom-mutator": "git+ssh://git@github.com/amplitude/dom-mutator#bb5f4b52273e6a3de39dcf6db6f428d66d988a7b",
35
- "rollup-plugin-license": "^3.6.0"
36
+ "rollup-plugin-license": "^3.6.0",
37
+ "unfetch": "4.1.0"
36
38
  },
37
39
  "devDependencies": {
38
40
  "@rollup/plugin-terser": "^0.4.4",
@@ -43,5 +45,5 @@
43
45
  "files": [
44
46
  "dist"
45
47
  ],
46
- "gitHead": "59c9a47ae78137304e5b56520fd6955a103c2ffc"
48
+ "gitHead": "a40490a366c9857c542492137dc7cda04d3be816"
47
49
  }