@oxvo/browser 7.1.0 → 7.3.4

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.
Files changed (68) hide show
  1. package/README.md +32 -0
  2. package/dist/cjs/common/interaction.d.ts +12 -1
  3. package/dist/cjs/common/messages.gen.d.ts +4 -7
  4. package/dist/cjs/entry.js +2382 -1191
  5. package/dist/cjs/entry.js.map +1 -1
  6. package/dist/cjs/index.js +2329 -1179
  7. package/dist/cjs/index.js.map +1 -1
  8. package/dist/cjs/main/app/canvas.d.ts +13 -0
  9. package/dist/cjs/main/app/cross_domain_iframe.d.ts +44 -0
  10. package/dist/cjs/main/app/index.d.ts +63 -15
  11. package/dist/cjs/main/app/messages.gen.d.ts +2 -1
  12. package/dist/cjs/main/app/observer/observer.d.ts +16 -0
  13. package/dist/cjs/main/app/sanitizer.d.ts +5 -3
  14. package/dist/cjs/main/app/session.d.ts +1 -0
  15. package/dist/cjs/main/entry.d.ts +5 -5
  16. package/dist/cjs/main/index.d.ts +17 -1
  17. package/dist/cjs/main/modules/analytics/batcher.d.ts +6 -1
  18. package/dist/cjs/main/modules/analytics/index.d.ts +10 -0
  19. package/dist/cjs/main/modules/input.d.ts +2 -1
  20. package/dist/cjs/main/modules/markerWatcher.d.ts +4 -8
  21. package/dist/cjs/main/modules/mouse.d.ts +1 -0
  22. package/dist/cjs/main/modules/tagMatcher.d.ts +28 -0
  23. package/dist/cjs/main/singleton.d.ts +24 -0
  24. package/dist/cjs/main/utils.d.ts +2 -0
  25. package/dist/cjs/package.json +1 -0
  26. package/dist/lib/common/interaction.d.ts +12 -1
  27. package/dist/lib/common/messages.gen.d.ts +4 -7
  28. package/dist/lib/entry.js +2382 -1191
  29. package/dist/lib/entry.js.map +1 -1
  30. package/dist/lib/index.js +2329 -1179
  31. package/dist/lib/index.js.map +1 -1
  32. package/dist/lib/main/app/canvas.d.ts +13 -0
  33. package/dist/lib/main/app/cross_domain_iframe.d.ts +44 -0
  34. package/dist/lib/main/app/index.d.ts +63 -15
  35. package/dist/lib/main/app/messages.gen.d.ts +2 -1
  36. package/dist/lib/main/app/observer/observer.d.ts +16 -0
  37. package/dist/lib/main/app/sanitizer.d.ts +5 -3
  38. package/dist/lib/main/app/session.d.ts +1 -0
  39. package/dist/lib/main/entry.d.ts +5 -5
  40. package/dist/lib/main/index.d.ts +17 -1
  41. package/dist/lib/main/modules/analytics/batcher.d.ts +6 -1
  42. package/dist/lib/main/modules/analytics/index.d.ts +10 -0
  43. package/dist/lib/main/modules/input.d.ts +2 -1
  44. package/dist/lib/main/modules/markerWatcher.d.ts +4 -8
  45. package/dist/lib/main/modules/mouse.d.ts +1 -0
  46. package/dist/lib/main/modules/tagMatcher.d.ts +28 -0
  47. package/dist/lib/main/singleton.d.ts +24 -0
  48. package/dist/lib/main/utils.d.ts +2 -0
  49. package/dist/types/common/interaction.d.ts +12 -1
  50. package/dist/types/common/messages.gen.d.ts +4 -7
  51. package/dist/types/main/app/canvas.d.ts +13 -0
  52. package/dist/types/main/app/cross_domain_iframe.d.ts +44 -0
  53. package/dist/types/main/app/index.d.ts +63 -15
  54. package/dist/types/main/app/messages.gen.d.ts +2 -1
  55. package/dist/types/main/app/observer/observer.d.ts +16 -0
  56. package/dist/types/main/app/sanitizer.d.ts +5 -3
  57. package/dist/types/main/app/session.d.ts +1 -0
  58. package/dist/types/main/entry.d.ts +5 -5
  59. package/dist/types/main/index.d.ts +17 -1
  60. package/dist/types/main/modules/analytics/batcher.d.ts +6 -1
  61. package/dist/types/main/modules/analytics/index.d.ts +10 -0
  62. package/dist/types/main/modules/input.d.ts +2 -1
  63. package/dist/types/main/modules/markerWatcher.d.ts +4 -8
  64. package/dist/types/main/modules/mouse.d.ts +1 -0
  65. package/dist/types/main/modules/tagMatcher.d.ts +28 -0
  66. package/dist/types/main/singleton.d.ts +24 -0
  67. package/dist/types/main/utils.d.ts +2 -0
  68. package/package.json +14 -14
@@ -5,6 +5,8 @@ interface Options {
5
5
  isDebug?: boolean;
6
6
  fixedScaling?: boolean;
7
7
  useAnimationFrame?: boolean;
8
+ framesSupport?: boolean;
9
+ /** @deprecated webp is the default format for pipeline optimization */
8
10
  fileExt?: 'webp' | 'png' | 'jpeg' | 'avif';
9
11
  }
10
12
  declare class CanvasRecorder {
@@ -18,10 +20,18 @@ declare class CanvasRecorder {
18
20
  private uploadQueue;
19
21
  private readonly MAX_CONCURRENT_UPLOADS;
20
22
  private readonly MAX_QUEUE_SIZE;
23
+ private readonly MAX_UPLOAD_ATTEMPTS;
24
+ private readonly MAX_RETRY_DELAY_MS;
21
25
  private readonly pendingBatches;
22
26
  private isProcessingQueue;
23
27
  constructor(app: App, options: Options);
24
28
  startTracking(): void;
29
+ /**
30
+ * Reacts to a runtime sanitization change on a canvas: stop capturing if it
31
+ * just became masked, start if it just became visible. Already-sent frames
32
+ * cannot be retracted, so escalation only stops future capture.
33
+ */
34
+ resanitizeCanvas: (node: Node, id: number) => void;
25
35
  restartTracking: () => void;
26
36
  captureCanvas: (node: Node) => void;
27
37
  recordCanvas: (node: Node, id: number) => void;
@@ -31,7 +41,10 @@ declare class CanvasRecorder {
31
41
  }[], canvasId: number, createdAt: number): void;
32
42
  private processUploadQueue;
33
43
  private uploadBatch;
44
+ private isRetryableUploadStatus;
45
+ private waitBeforeUploadRetry;
34
46
  private cleanupCanvas;
47
+ flushPendingSnapshots(): void;
35
48
  clear(): void;
36
49
  }
37
50
  export default CanvasRecorder;
@@ -0,0 +1,44 @@
1
+ import type Message from './messages.gen.js';
2
+ export declare const CROSS_DOMAIN_IFRAME_PROTOCOL_VERSION: 1;
3
+ export declare const CROSS_DOMAIN_IFRAME_ALLOWED_MESSAGE_TYPES: ReadonlySet<number>;
4
+ export type CrossDomainIframeEnvelope = {
5
+ protocolVersion: typeof CROSS_DOMAIN_IFRAME_PROTOCOL_VERSION;
6
+ context: string;
7
+ nonce: string;
8
+ capability: string;
9
+ };
10
+ export type CrossDomainIframeHandshake = Omit<CrossDomainIframeEnvelope, 'capability'> & {
11
+ projectKey: string;
12
+ };
13
+ export type CrossDomainIframeSession = {
14
+ sessionID: string;
15
+ projectID?: string;
16
+ startedAt: number;
17
+ delayMs: number;
18
+ userUUID: string;
19
+ };
20
+ export type CrossDomainIframeCanvas = {
21
+ enabled: boolean;
22
+ quality?: 'low' | 'medium' | 'high';
23
+ fps?: number;
24
+ framesSupport?: boolean;
25
+ };
26
+ type ParsedIframeBatch = {
27
+ messages: Message[];
28
+ bytes: number;
29
+ } | null;
30
+ export declare function normalizeCrossDomainOrigin(value: unknown): string | null;
31
+ export declare function normalizeCrossDomainOrigins(values: unknown): Set<string>;
32
+ export declare function createCrossDomainSecret(): string | null;
33
+ export declare function parseCrossDomainHandshake(data: unknown, expectedLine: string, expectedProjectKey: string): CrossDomainIframeHandshake | null;
34
+ export declare function matchesCrossDomainEnvelope(data: unknown, expectedLine: string, expected: CrossDomainIframeEnvelope): data is Record<string, unknown> & CrossDomainIframeEnvelope;
35
+ export declare function parseCrossDomainFrameInit(data: unknown, expectedLine: string, expected: Pick<CrossDomainIframeEnvelope, 'context' | 'nonce'>): (CrossDomainIframeEnvelope & {
36
+ id: number;
37
+ frameOrderNumber: number;
38
+ frameLevel: number;
39
+ capabilityExpiresAt: number;
40
+ session: CrossDomainIframeSession;
41
+ canvas?: CrossDomainIframeCanvas;
42
+ }) | null;
43
+ export declare function parseCrossDomainIframeBatch(messages: unknown): ParsedIframeBatch;
44
+ export {};
@@ -1,13 +1,14 @@
1
1
  import type { Options as WebworkerOptions } from '../../common/interaction.js';
2
2
  import AttributeSender from '../modules/attributeSender.js';
3
3
  import type { Options as NetworkOptions } from '../modules/network.js';
4
+ import type TagMatcher from '../modules/tagMatcher.js';
4
5
  import Logger, { ILogLevel } from './logger.js';
5
6
  import Message from './messages.gen.js';
6
7
  import Nodes from './nodes/index.js';
7
8
  import type { Options as ObserverOptions } from './observer/top_observer.js';
8
9
  import Observer from './observer/top_observer.js';
9
10
  import type { Options as SanitizerOptions } from './sanitizer.js';
10
- import Sanitizer from './sanitizer.js';
11
+ import Sanitizer, { SanitizeLevel } from './sanitizer.js';
11
12
  import type { Options as SessOptions } from './session.js';
12
13
  import Session from './session.js';
13
14
  import Ticker from './ticker.js';
@@ -29,6 +30,7 @@ export interface StartOptions {
29
30
  interface OnStartInfo {
30
31
  sessionID: string;
31
32
  sessionToken: string;
33
+ assistToken?: string;
32
34
  userUUID: string;
33
35
  }
34
36
  declare const CANCELED: "canceled";
@@ -64,6 +66,7 @@ type AppOptions = {
64
66
  __is_snippet: boolean;
65
67
  __debug_report_edp: string | null;
66
68
  __debug__?: ILogLevel;
69
+ __local_debug?: boolean;
67
70
  localStorage: Storage | null;
68
71
  sessionStorage: Storage | null;
69
72
  forceSingleTab?: boolean;
@@ -95,11 +98,16 @@ type AppOptions = {
95
98
  * */
96
99
  enabled?: boolean;
97
100
  /**
98
- * used to send message up, will be '*' by default
99
- * (check your CSP settings)
100
- * @default '*'
101
+ * Exact parent origin used by a tracker running inside a child iframe.
102
+ * Wildcards are rejected.
101
103
  * */
102
104
  parentDomain?: string;
105
+ /**
106
+ * Exact child origins allowed to join the top-level recording. The
107
+ * cross-domain listener is not installed unless this list is non-empty.
108
+ * Wildcards are rejected.
109
+ * */
110
+ childOrigins?: string[];
103
111
  };
104
112
  networkCapture?: NetworkOptions;
105
113
  /**
@@ -129,6 +137,7 @@ export default class App {
129
137
  readonly ticker: Ticker;
130
138
  readonly projectKey: string;
131
139
  readonly sanitizer: Sanitizer;
140
+ private readonly resanitizeCallbacks;
132
141
  readonly debug: Logger;
133
142
  readonly notify: Logger;
134
143
  readonly session: Session;
@@ -159,29 +168,52 @@ export default class App {
159
168
  private canvasRecorder;
160
169
  private conditionsManager;
161
170
  private readonly markerWatcher;
171
+ private readonly bootstrapAttempts;
172
+ private offlineRecordingSessionToken;
173
+ get tagMatcher(): TagMatcher;
162
174
  private canStart;
163
175
  private rootId;
164
176
  private pageFrames;
165
177
  private frameOderNumber;
166
178
  private frameLevel;
167
179
  private emptyBatchCounter;
180
+ private readonly crossDomainChildOrigins;
181
+ private readonly crossDomainParentOrigin;
182
+ private readonly crossDomainFrameNonce;
183
+ private crossDomainFrameCapability;
184
+ private crossDomainFrameCapabilityExpiresAt;
185
+ private crossDomainFrameSession;
186
+ private crossDomainFrameCanvas;
187
+ private crossDomainResumeAfterHandshake;
188
+ private crossDomainConnectionRequested;
189
+ private readonly crossDomainFrames;
190
+ private readonly crossDomainEnvelopeBudgets;
191
+ private readonly pendingCrossDomainFrames;
192
+ private crossDomainAuthorizationGeneration;
193
+ private nextCrossDomainFrameOrder;
194
+ private crossDomainCanvasConfig;
168
195
  constructor(projectKey: string, sessionToken: string | undefined, options: Partial<Options>, signalError: (error: string, apis: string[]) => void, insideIframe: boolean);
169
196
  /** used by child iframes for crossdomain only */
170
197
  parentActive: boolean;
171
198
  checkStatus: () => boolean;
199
+ private postToParent;
200
+ private postHandshakeToParent;
201
+ private applyCrossDomainFrameInit;
202
+ private clearCrossDomainFrameAuthorization;
172
203
  parentCrossDomainFrameListener: (event: MessageEvent) => void;
173
- /**
174
- * context ids for iframes,
175
- * order is not so important as long as its consistent
176
- * */
177
- trackedFrames: string[];
204
+ private findCrossDomainFrame;
205
+ private revokeCrossDomainFrame;
206
+ private pruneDetachedCrossDomainFrames;
207
+ private currentCrossDomainSession;
208
+ private frameInitPayload;
209
+ private rotateCrossDomainFrameCapability;
210
+ private crossDomainFrameNeedsRotation;
211
+ private postToCrossDomainFrame;
212
+ private consumeCrossDomainEnvelopeBudget;
213
+ private establishCrossDomainFrame;
214
+ private validatedCrossDomainFrame;
215
+ private consumeCrossDomainFrameBudget;
178
216
  crossDomainIframeListener: (event: MessageEvent) => void;
179
- /**
180
- * { command : [remaining iframes] }
181
- * + order of commands
182
- **/
183
- pollingQueue: Record<string, any>;
184
- private readonly addCommand;
185
217
  bootChildrenFrames: () => Promise<void>;
186
218
  killChildrenFrames: () => void;
187
219
  signalIframeTracker: () => void;
@@ -218,6 +250,15 @@ export default class App {
218
250
  checkRequiredVersion(version: string): boolean;
219
251
  private getTrackerInfo;
220
252
  private buildStartPayload;
253
+ private getBootstrapAttemptStorageKey;
254
+ private isValidBootstrapAttempt;
255
+ private removeStoredBootstrapAttempt;
256
+ private loadBootstrapAttempt;
257
+ private getOrCreateBootstrapAttempt;
258
+ private clearBootstrapAttempt;
259
+ private buildBootstrapIntentFingerprint;
260
+ private parseBootstrapIntent;
261
+ private bootstrapIntentsMatch;
221
262
  getSessionMeta(): {
222
263
  userUUID: string | null;
223
264
  projectKey: string;
@@ -290,10 +331,17 @@ export default class App {
290
331
  * */
291
332
  uploadOfflineRecording(): Promise<void>;
292
333
  prevOpts: StartOptions;
334
+ private userStartCallback?;
335
+ private startCrossDomainFrame;
293
336
  private _start;
294
337
  restartCanvasTracking: () => void;
338
+ attachResanitizeCallback: (cb: (node: Node, id: number) => void) => void;
339
+ callResanitizeCallbacks: (node: Node, id: number) => void;
340
+ resanitize: (el?: Element) => void;
341
+ checkSanitization: (el: Node) => SanitizeLevel | undefined;
295
342
  flushBuffer: (buffer: Message[]) => Promise<unknown>;
296
343
  waitStart(): Promise<unknown>;
344
+ private waitCrossDomainStart;
297
345
  waitStarted(): Promise<unknown>;
298
346
  waitStatus(status: ActivityState): Promise<unknown>;
299
347
  /**
@@ -1,5 +1,7 @@
1
1
  import * as Messages from '../../common/messages.gen.js';
2
2
  export { default, Type } from '../../common/messages.gen.js';
3
+ export type MessageFieldType = 'number' | 'string' | 'boolean';
4
+ export declare const MESSAGE_FIELD_TYPES: Readonly<Record<number, readonly MessageFieldType[]>>;
3
5
  export declare function Timestamp(timestamp: number): Messages.Timestamp;
4
6
  export declare function SetPageLocationDeprecated(url: string, referrer: string, navigationStart: number): Messages.SetPageLocationDeprecated;
5
7
  export declare function SetViewportSize(width: number, height: number): Messages.SetViewportSize;
@@ -62,7 +64,6 @@ export declare function AdoptedSSRemoveOwner(sheetID: number, id: number): Messa
62
64
  export declare function JSException(name: string, message: string, payload: string, metadata: string): Messages.JSException;
63
65
  export declare function Zustand(mutation: string, state: string): Messages.Zustand;
64
66
  export declare function BatchMetadata(version: number, pageNo: number, firstIndex: number, timestamp: number, location: string): Messages.BatchMetadata;
65
- export declare function PartitionedMessage(partNo: number, partTotal: number): Messages.PartitionedMessage;
66
67
  export declare function NetworkRequest(type: string, method: string, url: string, request: string, response: string, status: number, timestamp: number, duration: number, transferredBodySize: number): Messages.NetworkRequest;
67
68
  export declare function WSChannel(chType: string, channelName: string, data: string, timestamp: number, dir: string, messageType: string): Messages.WSChannel;
68
69
  export declare function ResourceTiming(timestamp: number, duration: number, ttfb: number, headerSize: number, encodedBodySize: number, decodedBodySize: number, url: string, initiator: string, transferredSize: number, cached: boolean, queueing: number, dnsLookup: number, initialConnection: number, ssl: number, contentDownload: number, total: number, stalled: number): Messages.ResourceTiming;
@@ -28,6 +28,12 @@ export default abstract class Observer {
28
28
  private readonly inlineRemoteCss;
29
29
  private readonly inlinerOptions;
30
30
  private readonly domParser;
31
+ /**
32
+ * Bumped on every disconnect(). Stale async CSS-inlining callbacks from a
33
+ * previous session (e.g. agent reload → tracker restart) compare against
34
+ * this and bail instead of sending messages that reference vanished node ids.
35
+ */
36
+ private generation;
31
37
  constructor(app: App, isTopContext?: boolean, options?: Options);
32
38
  private clear;
33
39
  /**
@@ -47,6 +53,16 @@ export default abstract class Observer {
47
53
  private commitNode;
48
54
  private commitNodes;
49
55
  protected observeRoot(node: Node, beforeCommit: (id?: number) => unknown, nodeToBind?: Node): void;
56
+ /**
57
+ * Re-evaluates sanitization for every tracked node in `root`'s subtree against
58
+ * the current DOM and re-emits whatever changed. Pass the highest node you
59
+ * changed (or the document root) so inherited levels propagate correctly.
60
+ */
61
+ resanitizeSubtree(root: Node): void;
62
+ private resanitizeNode;
63
+ private recreateSubtree;
64
+ private clearSubtreeRegistration;
65
+ private reemitNode;
50
66
  disconnect(): void;
51
67
  }
52
68
  export {};
@@ -35,8 +35,7 @@ export interface Options {
35
35
  }
36
36
  export declare const stringWiper: (input: string) => string;
37
37
  export default class Sanitizer {
38
- private readonly obscured;
39
- private readonly hidden;
38
+ private readonly levels;
40
39
  private readonly options;
41
40
  readonly maskAllByDefault: boolean;
42
41
  private readonly app;
@@ -44,7 +43,10 @@ export default class Sanitizer {
44
43
  app: App;
45
44
  options?: Partial<Options>;
46
45
  });
47
- handleNode(id: number, parentID: number, node: Node): Set<number> | undefined;
46
+ computeLevel(node: Node, parentLevel: SanitizeLevel): SanitizeLevel;
47
+ getLevel(id: number): SanitizeLevel;
48
+ setLevel(id: number, level: SanitizeLevel): SanitizeLevel;
49
+ handleNode(id: number, parentID: number, node: Node): void;
48
50
  sanitize(id: number, data: string): string;
49
51
  isObscured(id: number): boolean;
50
52
  isHidden(id: number): boolean;
@@ -47,6 +47,7 @@ export default class Session {
47
47
  getSessionSecret: (projectKey?: string) => string | undefined;
48
48
  getRawSecretWithProject: () => string | null;
49
49
  setSessionSecret: (token: string, projectKey: string) => void;
50
+ clearSessionSecret: () => void;
50
51
  applySessionHash(hash: string): void;
51
52
  getSessionHash(): string | undefined;
52
53
  getTabId(): string;
@@ -1,6 +1,6 @@
1
- import TrackerClass from './index';
2
- export { default as App } from './app/index';
3
- export { default as browser, default as oxvosessions } from './singleton';
4
- export { SanitizeLevel, Messages, Options } from './index';
5
- export { default as Analytics } from './modules/analytics/index';
1
+ import TrackerClass from './index.js';
2
+ export { default as App } from './app/index.js';
3
+ export { default as browser, default as oxvosessions } from './singleton.js';
4
+ export { SanitizeLevel, Messages, Options } from './index.js';
5
+ export { default as Analytics } from './modules/analytics/index.js';
6
6
  export default TrackerClass;
@@ -1,4 +1,4 @@
1
- import App from './app/index';
1
+ import App from './app/index.js';
2
2
  export { default as App } from './app/index.js';
3
3
  import * as _Messages from './app/messages.gen.js';
4
4
  export declare const Messages: typeof _Messages;
@@ -27,6 +27,7 @@ export type Options = Partial<AppOptions & ConsoleOptions & ExceptionOptions & I
27
27
  resetTabOnWindowOpen?: boolean;
28
28
  networkCapture?: Partial<NetworkOptions>;
29
29
  mouse?: Partial<MouseHandlerOptions>;
30
+ customAttributes?: string[];
30
31
  devAllowInsecure?: boolean;
31
32
  css: CssRulesOptions;
32
33
  webAnimations?: WapOptions;
@@ -46,6 +47,21 @@ export default class API {
46
47
  checkDoNotTrack: () => boolean | undefined;
47
48
  signalStartIssue: (reason: string, missingApi: string[]) => void;
48
49
  restartCanvasTracking: () => void;
50
+ /**
51
+ * Re-evaluates sanitization against the current DOM and re-emits whatever
52
+ * changed, updating already-recorded nodes mid-session. Call after toggling
53
+ * `data-oxvosessions-*` attributes or after changing whatever your `domSanitizer`
54
+ * keys on (class/id/etc).
55
+ *
56
+ * @param el - the highest node you changed; omit to re-scan the whole document;
57
+ * scanning the entire doc is O(dom size)
58
+ * */
59
+ resanitize: (el?: Element) => void;
60
+ /**
61
+ * Returns the sanitization level the tracker currently has for a node
62
+ * (0 = Plain, 1 = Obscured, 2 = Hidden), or undefined if it isn't tracked.
63
+ * */
64
+ checkSanitization: (el: Node) => import("./app/sanitizer.js").SanitizeLevel | undefined;
49
65
  use<T>(fn: (app: App | null, options?: Partial<Options>) => T): T;
50
66
  isActive(): boolean;
51
67
  /**
@@ -15,13 +15,15 @@ declare class Batcher {
15
15
  private readonly backendUrl;
16
16
  private readonly getToken;
17
17
  private readonly init;
18
+ private readonly standalone;
18
19
  private readonly autosendInterval;
19
20
  private readonly retryTimeout;
20
21
  private readonly retryLimit;
21
22
  private readonly apiEdp;
22
23
  private batch;
23
24
  private intervalId;
24
- constructor(backendUrl: string, getToken: () => string | null, init: () => Promise<void>);
25
+ private stopped;
26
+ constructor(backendUrl: string, getToken: () => string | null, init: () => Promise<void>, standalone: boolean);
25
27
  getBatches(): {
26
28
  data: {
27
29
  user_actions: PeopleEvent[];
@@ -38,8 +40,11 @@ declare class Batcher {
38
40
  dedupePeopleEvents(): PeopleEvent[];
39
41
  private squashPeopleEvents;
40
42
  private sendBatch;
43
+ private paused;
44
+ private onVisibilityChange;
41
45
  startAutosend(): void;
42
46
  flush(): void;
43
47
  stop(): void;
48
+ restart(): void;
44
49
  }
45
50
  export default Batcher;
@@ -32,6 +32,7 @@ export default class Analytics {
32
32
  private readonly getTimestamp;
33
33
  private readonly setUserId;
34
34
  private readonly standalone;
35
+ private pendingStartAttempt;
35
36
  /**
36
37
  * @param localStorage Class or Object that implements Storage-like interface that stores
37
38
  * values persistently like window.localStorage or any other file-based storage
@@ -50,7 +51,16 @@ export default class Analytics {
50
51
  constructor(options: Options);
51
52
  _getToken: () => string | null;
52
53
  _getTimestamp: () => number;
54
+ private loadStartAttempt;
55
+ private isValidStartAttempt;
56
+ private startAttempt;
57
+ private clearStartAttempt;
53
58
  init: () => Promise<void>;
59
+ /**
60
+ * Used by tracker when running in blundled mode
61
+ */
62
+ onStart: () => void;
63
+ onStop: () => void;
54
64
  reset: () => void;
55
65
  /**
56
66
  * COMPATIBILITY LAYER
@@ -1,6 +1,6 @@
1
1
  import type App from '../app/index.js';
2
2
  type TextFieldElement = HTMLInputElement | HTMLTextAreaElement;
3
- export declare function getInputLabel(node: TextFieldElement): string;
3
+ export declare function getInputLabel(node: TextFieldElement, customAttributes?: string[]): string;
4
4
  export declare const InputMode: {
5
5
  readonly Plain: 0;
6
6
  readonly Obscured: 1;
@@ -29,6 +29,7 @@ export interface Options {
29
29
  * will override other settings.
30
30
  * */
31
31
  inputPrivacyMode: InputModeT;
32
+ customAttributes?: string[];
32
33
  }
33
34
  export default function (app: App, opts: Partial<Options>): void;
34
35
  export {};
@@ -1,10 +1,9 @@
1
+ import TagMatcher, { type Tag } from './tagMatcher.js';
1
2
  export declare const WATCHED_MARKERS_KEY = "__or__watched_markers__";
2
3
  declare class MarkerWatcher {
3
4
  interval: ReturnType<typeof setInterval> | null;
4
- tags: {
5
- id: number;
6
- selector: string;
7
- }[];
5
+ tags: Tag[];
6
+ readonly matcher: TagMatcher;
8
7
  observer: IntersectionObserver;
9
8
  private readonly sessionStorage;
10
9
  private readonly errLog;
@@ -15,10 +14,7 @@ declare class MarkerWatcher {
15
14
  onMarkerHit: (markerId: number) => void;
16
15
  });
17
16
  fetchTags(ingest: string, token: string): Promise<void>;
18
- setTags(tags: {
19
- id: number;
20
- selector: string;
21
- }[]): void;
17
+ setTags(tags: Tag[]): void;
22
18
  onMarkerRendered(markerId: number): void;
23
19
  clear(): void;
24
20
  }
@@ -8,6 +8,7 @@ export interface MouseHandlerOptions {
8
8
  * default 7 = 210ms
9
9
  * */
10
10
  trackingOffset?: number;
11
+ customAttributes?: string[];
11
12
  }
12
13
  export default function (app: App, options?: MouseHandlerOptions): void;
13
14
  export declare function getCSSPath(el: any): string | false;
@@ -0,0 +1,28 @@
1
+ export type Tag = {
2
+ id: number;
3
+ selector: string;
4
+ location?: string;
5
+ };
6
+ /**
7
+ * Two-tier tag matching:
8
+ * 1. Fast fingerprint lookup by id, data-attr,
9
+ * or class from the selector's last segment
10
+ * 2. Fallback iteration using native element.matches()
11
+ */
12
+ declare class TagMatcher {
13
+ private tags;
14
+ private byId;
15
+ private byDataAttr;
16
+ private byClass;
17
+ private fallback;
18
+ setTags(tags: Tag[]): void;
19
+ getTags(): Tag[];
20
+ /** Match element, its parent, or direct children against known tag selectors */
21
+ match(el: Element): Tag | null;
22
+ private matchExact;
23
+ clear(): void;
24
+ }
25
+ export declare function matchesLocation(tag: {
26
+ location?: string;
27
+ }): boolean;
28
+ export default TagMatcher;
@@ -97,6 +97,30 @@ declare class BrowserSingleton {
97
97
  forceFlushBatch(): void;
98
98
  getSessionMeta(): import("./app/session.js").SessionInfo | null;
99
99
  getTabId(): string | null;
100
+ /**
101
+ * Re-evaluates sanitization against the current DOM and re-emits whatever
102
+ * changed, updating already-recorded nodes mid-session. Call after toggling
103
+ * `data-oxvosessions-*` attributes or after changing whatever your `domSanitizer`
104
+ * keys on (class/id/etc).
105
+ *
106
+ * @param el - the highest node you changed; omit to re-scan the whole document.
107
+ * */
108
+ resanitize(el?: Element): void;
109
+ /**
110
+ * Returns the sanitization level the tracker currently has for a node
111
+ * (0 = Plain, 1 = Obscured, 2 = Hidden), or undefined if it isn't tracked.
112
+ * */
113
+ checkSanitization(el: Node): import("./index.js").SanitizeLevel | undefined;
114
+ incident(options: {
115
+ label?: string;
116
+ startTime: number;
117
+ endTime?: number;
118
+ }): void;
119
+ /**
120
+ * Use custom token for analytics events without session recording.
121
+ * */
122
+ setAnalyticsToken(token: string): void;
123
+ getAnalyticsToken(): string | undefined;
100
124
  }
101
125
  declare const browser: BrowserSingleton;
102
126
  export default browser;
@@ -11,6 +11,8 @@ export declare const DOCS_HOST = "https://docs.oxvo.com";
11
11
  export declare function isLoopbackHost(hostname: string): boolean;
12
12
  export declare function canUseTrackerOrigin(protocol: string, hostname: string, devAllowInsecure?: boolean): boolean;
13
13
  export declare function deprecationWarn(nameOfFeature: string, useInstead: string, docsPath?: string): void;
14
+ export declare function getCustomAttributeLabel(e: Element, customAttributes?: string[]): string;
15
+ export declare function getClassSelector(e: Element): string;
14
16
  export declare function getLabelAttribute(e: Element): string | null;
15
17
  export declare function hasOxvoSessionsAttribute(e: Element, attr: string): boolean;
16
18
  /**
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
@@ -1,4 +1,5 @@
1
1
  import Message from './messages.gen.js';
2
+ export type DataType = 'player' | 'assets' | 'devtools' | 'analytics';
2
3
  export interface Options {
3
4
  connAttemptCount?: number;
4
5
  connAttemptGap?: number;
@@ -10,18 +11,22 @@ type Start = {
10
11
  timestamp: number;
11
12
  url: string;
12
13
  tabId: string;
14
+ localDebug?: boolean;
13
15
  } & Options;
14
16
  type Auth = {
15
17
  type: 'auth';
16
18
  token: string;
17
19
  beaconSizeLimit?: number;
20
+ protocolVersion?: number;
18
21
  };
19
22
  export type ToWorkerData = null | 'stop' | Start | Auth | Array<Message> | {
20
23
  type: 'compressed';
21
24
  batch: Uint8Array;
25
+ dataType: DataType;
22
26
  } | {
23
27
  type: 'uncompressed';
24
28
  batch: Uint8Array;
29
+ dataType: DataType;
25
30
  } | 'forceFlushBatch' | 'closing' | 'check_queue';
26
31
  type Failure = {
27
32
  type: 'failure';
@@ -30,8 +35,14 @@ type Failure = {
30
35
  type QEmpty = {
31
36
  type: 'queue_empty';
32
37
  };
38
+ type LocalSave = {
39
+ type: 'local_save';
40
+ name: string;
41
+ batch: Uint8Array;
42
+ };
33
43
  export type FromWorkerData = 'a_stop' | 'a_start' | Failure | 'not_init' | {
34
44
  type: 'compress';
35
45
  batch: Uint8Array;
36
- } | QEmpty;
46
+ dataType: DataType;
47
+ } | QEmpty | LocalSave;
37
48
  export {};
@@ -61,7 +61,6 @@ export declare const enum Type {
61
61
  JSException = 78,
62
62
  Zustand = 79,
63
63
  BatchMetadata = 81,
64
- PartitionedMessage = 82,
65
64
  NetworkRequest = 83,
66
65
  WSChannel = 84,
67
66
  ResourceTiming = 85,
@@ -442,11 +441,6 @@ export type BatchMetadata = [
442
441
  number,
443
442
  string
444
443
  ];
445
- export type PartitionedMessage = [
446
- Type.PartitionedMessage,
447
- number,
448
- number
449
- ];
450
444
  export type NetworkRequest = [
451
445
  Type.NetworkRequest,
452
446
  string,
@@ -583,5 +577,8 @@ export type WebVitals = [
583
577
  string,
584
578
  string
585
579
  ];
586
- type Message = Timestamp | SetPageLocationDeprecated | SetViewportSize | SetViewportScroll | CreateDocument | CreateElementNode | CreateTextNode | MoveNode | RemoveNode | SetNodeAttribute | RemoveNodeAttribute | SetNodeData | SetNodeScroll | SetInputTarget | SetInputValue | SetInputChecked | MouseMove | NetworkRequestDeprecated | ConsoleLog | PageLoadTiming | PageRenderTiming | CustomEvent | UserID | UserAnonymousID | Metadata | StringDictGlobal | SetNodeAttributeDictGlobal | NodeAnimationResult | Profiler | OTable | StateAction | ReduxDeprecated | Vuex | MobX | NgRx | GraphQLDeprecated | PerformanceTrack | StringDictDeprecated | SetNodeAttributeDictDeprecated | StringDict | SetNodeAttributeDict | ResourceTimingDeprecatedDeprecated | ConnectionInformation | SetPageVisibility | LoadFontFace | SetNodeFocus | SetNodeAttributeURLBased | SetCSSDataURLBased | TechnicalInfo | CustomIssue | SetNodeSlot | MouseClick | MouseClickDeprecated | CreateIFrameDocument | AdoptedSSReplaceURLBased | AdoptedSSInsertRuleURLBased | AdoptedSSDeleteRule | AdoptedSSAddOwner | AdoptedSSRemoveOwner | JSException | Zustand | BatchMetadata | PartitionedMessage | NetworkRequest | WSChannel | ResourceTiming | Incident | LongAnimationTask | InputChange | SelectionChange | MouseThrashing | UnbindNodes | ResourceTimingDeprecated | TabChange | TabData | CanvasNode | TagTrigger | Redux | SetPageLocation | GraphQL | WebVitals;
580
+ export declare const ASSET_MESSAGES: ReadonlySet<number>;
581
+ export declare const DEVTOOLS_MESSAGES: ReadonlySet<number>;
582
+ export declare const ANALYTICS_MESSAGES: ReadonlySet<number>;
583
+ type Message = Timestamp | SetPageLocationDeprecated | SetViewportSize | SetViewportScroll | CreateDocument | CreateElementNode | CreateTextNode | MoveNode | RemoveNode | SetNodeAttribute | RemoveNodeAttribute | SetNodeData | SetNodeScroll | SetInputTarget | SetInputValue | SetInputChecked | MouseMove | NetworkRequestDeprecated | ConsoleLog | PageLoadTiming | PageRenderTiming | CustomEvent | UserID | UserAnonymousID | Metadata | StringDictGlobal | SetNodeAttributeDictGlobal | NodeAnimationResult | Profiler | OTable | StateAction | ReduxDeprecated | Vuex | MobX | NgRx | GraphQLDeprecated | PerformanceTrack | StringDictDeprecated | SetNodeAttributeDictDeprecated | StringDict | SetNodeAttributeDict | ResourceTimingDeprecatedDeprecated | ConnectionInformation | SetPageVisibility | LoadFontFace | SetNodeFocus | SetNodeAttributeURLBased | SetCSSDataURLBased | TechnicalInfo | CustomIssue | SetNodeSlot | MouseClick | MouseClickDeprecated | CreateIFrameDocument | AdoptedSSReplaceURLBased | AdoptedSSInsertRuleURLBased | AdoptedSSDeleteRule | AdoptedSSAddOwner | AdoptedSSRemoveOwner | JSException | Zustand | BatchMetadata | NetworkRequest | WSChannel | ResourceTiming | Incident | LongAnimationTask | InputChange | SelectionChange | MouseThrashing | UnbindNodes | ResourceTimingDeprecated | TabChange | TabData | CanvasNode | TagTrigger | Redux | SetPageLocation | GraphQL | WebVitals;
587
584
  export default Message;