@amplitude/experiment-tag 0.25.1 → 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.
- package/dist/LICENSES +28 -4
- package/dist/experiment-tag-min.js +3 -3
- package/dist/experiment-tag-min.js.gz +0 -0
- package/dist/types/src/behavioral-targeting/behavioral-targeting-manager.d.ts +21 -1
- package/dist/types/src/behavioral-targeting/event-storage.d.ts +35 -0
- package/dist/types/src/behavioral-targeting/index.d.ts +2 -0
- package/dist/types/src/behavioral-targeting/relay-client.d.ts +40 -0
- package/dist/types/src/behavioral-targeting/relay-protocol.d.ts +36 -0
- package/dist/types/src/behavioral-targeting/relay-sync-result.d.ts +10 -0
- package/dist/types/src/behavioral-targeting/session-manager.d.ts +42 -12
- package/dist/types/src/experiment.d.ts +23 -0
- package/dist/types/src/subscriptions/subscription-refactor.d.ts +2 -1
- package/dist/types/src/subscriptions/subscriptions.d.ts +2 -1
- package/dist/types/src/triggers/base-trigger-manager.d.ts +3 -2
- package/dist/types/src/triggers/index.d.ts +2 -1
- package/dist/types/src/types.d.ts +14 -0
- package/dist/types/src/util/cookie.d.ts +56 -6
- package/dist/types/src/util/debug-recorder.d.ts +2 -1
- package/dist/types/src/util/shell.d.ts +4 -3
- package/dist/types/src/util/when-body-ready.d.ts +3 -1
- package/package.json +7 -5
|
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
|
*/
|
|
@@ -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
|
+
}
|
|
@@ -1,27 +1,57 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
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
|
|
7
|
-
private
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
*
|
|
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
|
-
*
|
|
47
|
+
* Clears the current session from memory and cookie storage.
|
|
21
48
|
*/
|
|
22
|
-
|
|
49
|
+
clearSession(): void;
|
|
23
50
|
/**
|
|
24
|
-
*
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
50
|
+
protected readonly globalScope: GlobalScope;
|
|
50
51
|
protected readonly options?: TriggerManagerOptions | undefined;
|
|
51
|
-
constructor(pageObjects: PageObject[], messageBus: MessageBus, globalScope:
|
|
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:
|
|
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
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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.
|
|
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.
|
|
33
|
-
"@amplitude/experiment-js-client": "^1.21.
|
|
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": "
|
|
48
|
+
"gitHead": "a40490a366c9857c542492137dc7cda04d3be816"
|
|
47
49
|
}
|