sitepong 0.2.1 → 0.2.2

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/index.d.mts CHANGED
@@ -157,6 +157,137 @@ declare global {
157
157
  }
158
158
  }
159
159
 
160
+ interface AutocaptureEvent {
161
+ type: 'click' | 'form_submit' | 'page_view';
162
+ timestamp: string;
163
+ properties: Record<string, unknown>;
164
+ }
165
+
166
+ /**
167
+ * Watchtower Web Tap Capture (Phase P3)
168
+ *
169
+ * Captures tap/screen_view/session lifecycle events per the Watchtower wire
170
+ * contract (docs/watchtower-mobile-spec.md §1) and uploads masked screen
171
+ * templates on fingerprint miss (§1.2).
172
+ *
173
+ * - Tap events come from the EXISTING autocapture click path (no duplicate
174
+ * listeners) — the AutocaptureModule's selector/element resolution is reused.
175
+ * - Screen fingerprints are dHash'd (via @sitepong/capture-core, the reference
176
+ * implementation) over a masked rasterization of the page. Rasterization is
177
+ * done with the SVG-foreignObject trick over the replay serializer's masked
178
+ * structural snapshot, always off the hot path (idle callbacks, throttled).
179
+ * - The click handler itself only records + enqueues; batching is 50 events /
180
+ * 10 s / pagehide. Rage classification is server-side — never sent here.
181
+ */
182
+
183
+ /** Result of rasterizing the (already masked) page. */
184
+ interface RasterResult {
185
+ /** Tightly packed RGBA bytes, width*height*4. */
186
+ rgba: Uint8Array;
187
+ width: number;
188
+ height: number;
189
+ /** Base64 PNG of the same masked canvas, or null when encoding failed. */
190
+ pngBase64: string | null;
191
+ }
192
+ interface PageRasterizer {
193
+ /** Resolve null (never throw) when the page cannot be rasterized. */
194
+ rasterize(): Promise<RasterResult | null>;
195
+ }
196
+ interface TransportResponse {
197
+ ok: boolean;
198
+ status: number;
199
+ }
200
+ type TapTransport = (url: string, body: string, opts: {
201
+ headers: Record<string, string>;
202
+ keepalive?: boolean;
203
+ }) => Promise<TransportResponse>;
204
+ /** Anything exposing the AutocaptureModule secondary-listener API. */
205
+ interface AutocaptureSource {
206
+ addListener(cb: (event: AutocaptureEvent) => void): () => void;
207
+ }
208
+ interface WatchtowerCaptureConfig {
209
+ apiKey: string;
210
+ projectId: string;
211
+ /** Base endpoint — events go to `${endpoint}/api/taps`, templates to `${endpoint}/api/taps/template`. */
212
+ endpoint: string;
213
+ appVersion?: string;
214
+ /** Flush when the queue reaches this size (spec §1.3, default 50). */
215
+ maxBatchSize?: number;
216
+ /** Flush interval in ms (spec §1.3, default 10000). */
217
+ flushInterval?: number;
218
+ /** Min ms between rasterizations of the same route (default 1000). */
219
+ templateThrottleMs?: number;
220
+ /** Extra CSS selector blocked (greyed out) in the masked snapshot. */
221
+ blockSelector?: string;
222
+ /** CSS selector whose text is masked in the snapshot. */
223
+ maskSelector?: string;
224
+ debug?: boolean;
225
+ /** Injectable rasterizer (tests). Defaults to the DOM SVG-foreignObject rasterizer. */
226
+ rasterizer?: PageRasterizer;
227
+ /** Injectable transport (tests). Defaults to fetch. */
228
+ transport?: TapTransport;
229
+ }
230
+ declare class WatchtowerWebCapture {
231
+ private config;
232
+ private session;
233
+ private queue;
234
+ private flushTimer;
235
+ private flushFailures;
236
+ private disabled;
237
+ private active;
238
+ private distinctId;
239
+ private currentScreen;
240
+ private transport;
241
+ private rasterizer;
242
+ private detachAutocapture;
243
+ private ownAutocapture;
244
+ private originalPushState;
245
+ private originalReplaceState;
246
+ private popstateHandler;
247
+ private pagehideHandler;
248
+ private fpCache;
249
+ private uploadedFps;
250
+ private lastRasterAt;
251
+ private rasterInFlight;
252
+ constructor(config: WatchtowerCaptureConfig);
253
+ /**
254
+ * Start capturing. Pass the existing AutocaptureModule (via
255
+ * AnalyticsManager.getAutocaptureModule()) to reuse its click listener +
256
+ * selector resolution; when absent, a private clicks-only module is created.
257
+ */
258
+ start(source?: AutocaptureSource | null): void;
259
+ stop(): void;
260
+ isActive(): boolean;
261
+ getSessionId(): string;
262
+ /** Stamped as distinct_id on every subsequent event (identify() feeds this). */
263
+ setDistinctId(distinctId: string | null): void;
264
+ private onAutocaptureEvent;
265
+ /** Record a tap. Coordinates are viewport CSS px; normalization happens here. */
266
+ recordTap(input: {
267
+ selector: string;
268
+ label?: string;
269
+ role?: string;
270
+ clientX: number;
271
+ clientY: number;
272
+ }): void;
273
+ private setupNavigationTracking;
274
+ private handleRouteChange;
275
+ private setupPagehide;
276
+ private baseEvent;
277
+ private enqueue;
278
+ private startFlushTimer;
279
+ flush(opts?: {
280
+ keepalive?: boolean;
281
+ }): Promise<void>;
282
+ private headers;
283
+ private scheduleFingerprint;
284
+ private captureFingerprint;
285
+ private maybeUploadTemplate;
286
+ private combinedBlockSelector;
287
+ private pathname;
288
+ private log;
289
+ }
290
+
160
291
  declare class ReplayManager {
161
292
  private config;
162
293
  private recording;
@@ -999,6 +1130,7 @@ interface WebManagerFactories {
999
1130
  createReplay?: (cfg: Record<string, unknown>) => ReplayManager;
1000
1131
  createFingerprint?: (cfg: Record<string, unknown>) => FingerprintManager;
1001
1132
  createPerformance?: (cfg: Record<string, unknown>) => PerformanceManager;
1133
+ createWatchtowerCapture?: (cfg: Record<string, unknown>) => WatchtowerWebCapture;
1002
1134
  }
1003
1135
  /**
1004
1136
  * Platform-entry-only: inject web-only manager factories. Called by
@@ -1069,6 +1201,22 @@ interface SitePongInitConfig extends SitePongConfig {
1069
1201
  /** Rolling buffer duration in ms — how many seconds of replay to keep before an error (default: 20000) */
1070
1202
  bufferDuration?: number;
1071
1203
  };
1204
+ /** Watchtower tap capture (web) — tap timeline events + masked screen templates */
1205
+ watchtower?: {
1206
+ enabled?: boolean;
1207
+ /** Project ID sent as X-Project-ID on /api/taps requests (required) */
1208
+ projectId?: string;
1209
+ /** Override base endpoint for /api/taps + /api/taps/template (default: main endpoint) */
1210
+ endpoint?: string;
1211
+ /** Flush at this many buffered events (default: 50) */
1212
+ maxBatchSize?: number;
1213
+ /** Flush interval in ms (default: 10000) */
1214
+ flushInterval?: number;
1215
+ /** Extra CSS selector blocked out of the masked screen template */
1216
+ blockSelector?: string;
1217
+ /** CSS selector whose text is masked in the screen template */
1218
+ maskSelector?: string;
1219
+ };
1072
1220
  /** Cron monitoring configuration */
1073
1221
  crons?: {
1074
1222
  enabled?: boolean;
@@ -1117,6 +1265,8 @@ declare class SitePongClient {
1117
1265
  private databaseTracker;
1118
1266
  private profiler;
1119
1267
  private remoteConfigManager;
1268
+ private watchtowerCapture;
1269
+ private watchtowerOptions;
1120
1270
  private currentScreen?;
1121
1271
  private envUnsubs;
1122
1272
  private identifyHooks;
@@ -1179,6 +1329,13 @@ declare class SitePongClient {
1179
1329
  stopReplay(): void;
1180
1330
  isReplayRecording(): boolean;
1181
1331
  getReplaySessionId(): string | null;
1332
+ /**
1333
+ * Start Watchtower web tap capture. Options merge over `watchtower` from
1334
+ * init(); `projectId` is required (either here or in init config). Reuses
1335
+ * the analytics AutocaptureModule's click listener when autocapture is on.
1336
+ */
1337
+ startWatchtowerCapture(options?: SitePongInitConfig['watchtower']): boolean;
1338
+ stopWatchtowerCapture(): void;
1182
1339
  startTransaction(name: string, data?: Record<string, unknown>): string;
1183
1340
  endTransaction(id: string, status?: 'ok' | 'error'): void;
1184
1341
  startSpan(transactionId: string, name: string, data?: Record<string, unknown>): string;
@@ -1279,6 +1436,8 @@ declare const getDeviceSignals: () => Promise<DeviceSignals>;
1279
1436
  declare const getFraudCheck: () => Promise<FraudCheckResult>;
1280
1437
  declare const startReplay: () => boolean;
1281
1438
  declare const stopReplay: () => void;
1439
+ declare const startWatchtowerCapture: (options?: SitePongInitConfig["watchtower"]) => boolean;
1440
+ declare const stopWatchtowerCapture: () => void;
1282
1441
  declare const isReplayRecording: () => boolean;
1283
1442
  declare const getReplaySessionId: () => string | null;
1284
1443
  declare const startTransaction: (name: string, data?: Record<string, unknown>) => string;
@@ -1316,4 +1475,4 @@ declare const isRemoteConfigFeatureEnabled: (key: string, defaultValue?: boolean
1316
1475
  declare const onRemoteConfigChange: (listener: (config: RemoteConfig) => void) => () => void;
1317
1476
  declare const registerIdentifyHook: (hook: (userId: string) => void) => () => void;
1318
1477
 
1319
- export { type CapturedError, type CronCheckinOptions, type CronHandle, DEFAULT_SUPERLINK_ENDPOINT, type DatabaseQueryEvent, type DatabaseTrackerConfig, type DeferredDeepLinkHandler, type DeviceInfo, type DeviceSignals, type EnvironmentAdapter, type ErrorContext, type FraudCheckResult, GroupTraits, type MetricOptions, type MutableRNEnvironmentAdapter, type PerformanceConfig, type PerformanceSpan, type PerformanceTransaction, type PlatformName, type ProfileData, type ProfileFrame, type ProfilerConfig, type RemoteConfig, type RemoteConfigFeatures, type RemoteConfigSampling, ReplayConfig, type ResourceTimingBreakdown, type SitePongConfig, type SitePongInitConfig, SuperLinkClient, type SuperLinkConfig, type SuperLinkDeepLink, type SuperLinkEventType, type SuperLinkFingerprint, type SuperLinkIdentityMetadata, type SuperLinkMatchRequest, type SuperLinkMatchResponse, type SuperLinkMatchType, type SuperLinkPlatform, type TraceContext, TracePropagator, TrackProperties, UserTraits, type VisitorIdResult, type WebManagerFactories, type WebVitals, addBreadcrumb, areFlagsReady, captureError, captureMessage, captureWebDeepLink, clearAnonymousId, clearUser, sitepong as client, completeFromScan, createTraceContext, cronCheckin, cronStart, cronWrap, dbTrack, dbTrackSync, sitepong as default, endSpan, endTransaction, extractIdentityMetadata, extractTrace, flush, flushMetrics, flushProfiles, generateSpanId, generateTraceId, getAllFlags, getAnonymousId, getDbNPlusOnePatterns, getDbQueryCount, getDeepLink, getDeviceSignals, getFlag, getFraudCheck, getLatestProfile, getMatchedDeepLink, getProfiles, getRemoteConfig, getReplaySessionId, getVariant, getVariantPayload, getVisitorId, getWebVitals, group, identify, init, initRN, initSuperLink, isInitialized, isRemoteConfigFeatureEnabled, isReplayRecording, metricDistribution, metricGauge, metricHistogram, metricIncrement, metricStartTimer, metricTime, onDeferredDeepLink, onRemoteConfigChange, parseUniversalLink, profile, propagateTrace, refreshFlags, registerIdentifyHook, registerWebManagerFactories, resetAnalytics, resetDbQueryCount, setAnonymousId, setContext, setCurrentScreen, setEnvironment, setRNGetCurrentScreen, setTags, setUser, startProfileSpan, startReplay, startSpan, startTransaction, stopReplay, superlinkClient, identify$1 as superlinkIdentify, track, trackPageView, waitForFlags, writeClipboardToken };
1478
+ export { type CapturedError, type CronCheckinOptions, type CronHandle, DEFAULT_SUPERLINK_ENDPOINT, type DatabaseQueryEvent, type DatabaseTrackerConfig, type DeferredDeepLinkHandler, type DeviceInfo, type DeviceSignals, type EnvironmentAdapter, type ErrorContext, type FraudCheckResult, GroupTraits, type MetricOptions, type MutableRNEnvironmentAdapter, type PerformanceConfig, type PerformanceSpan, type PerformanceTransaction, type PlatformName, type ProfileData, type ProfileFrame, type ProfilerConfig, type RemoteConfig, type RemoteConfigFeatures, type RemoteConfigSampling, ReplayConfig, type ResourceTimingBreakdown, type SitePongConfig, type SitePongInitConfig, SuperLinkClient, type SuperLinkConfig, type SuperLinkDeepLink, type SuperLinkEventType, type SuperLinkFingerprint, type SuperLinkIdentityMetadata, type SuperLinkMatchRequest, type SuperLinkMatchResponse, type SuperLinkMatchType, type SuperLinkPlatform, type TraceContext, TracePropagator, TrackProperties, UserTraits, type VisitorIdResult, type WebManagerFactories, type WebVitals, addBreadcrumb, areFlagsReady, captureError, captureMessage, captureWebDeepLink, clearAnonymousId, clearUser, sitepong as client, completeFromScan, createTraceContext, cronCheckin, cronStart, cronWrap, dbTrack, dbTrackSync, sitepong as default, endSpan, endTransaction, extractIdentityMetadata, extractTrace, flush, flushMetrics, flushProfiles, generateSpanId, generateTraceId, getAllFlags, getAnonymousId, getDbNPlusOnePatterns, getDbQueryCount, getDeepLink, getDeviceSignals, getFlag, getFraudCheck, getLatestProfile, getMatchedDeepLink, getProfiles, getRemoteConfig, getReplaySessionId, getVariant, getVariantPayload, getVisitorId, getWebVitals, group, identify, init, initRN, initSuperLink, isInitialized, isRemoteConfigFeatureEnabled, isReplayRecording, metricDistribution, metricGauge, metricHistogram, metricIncrement, metricStartTimer, metricTime, onDeferredDeepLink, onRemoteConfigChange, parseUniversalLink, profile, propagateTrace, refreshFlags, registerIdentifyHook, registerWebManagerFactories, resetAnalytics, resetDbQueryCount, setAnonymousId, setContext, setCurrentScreen, setEnvironment, setRNGetCurrentScreen, setTags, setUser, startProfileSpan, startReplay, startSpan, startTransaction, startWatchtowerCapture, stopReplay, stopWatchtowerCapture, superlinkClient, identify$1 as superlinkIdentify, track, trackPageView, waitForFlags, writeClipboardToken };
package/dist/index.d.ts CHANGED
@@ -157,6 +157,137 @@ declare global {
157
157
  }
158
158
  }
159
159
 
160
+ interface AutocaptureEvent {
161
+ type: 'click' | 'form_submit' | 'page_view';
162
+ timestamp: string;
163
+ properties: Record<string, unknown>;
164
+ }
165
+
166
+ /**
167
+ * Watchtower Web Tap Capture (Phase P3)
168
+ *
169
+ * Captures tap/screen_view/session lifecycle events per the Watchtower wire
170
+ * contract (docs/watchtower-mobile-spec.md §1) and uploads masked screen
171
+ * templates on fingerprint miss (§1.2).
172
+ *
173
+ * - Tap events come from the EXISTING autocapture click path (no duplicate
174
+ * listeners) — the AutocaptureModule's selector/element resolution is reused.
175
+ * - Screen fingerprints are dHash'd (via @sitepong/capture-core, the reference
176
+ * implementation) over a masked rasterization of the page. Rasterization is
177
+ * done with the SVG-foreignObject trick over the replay serializer's masked
178
+ * structural snapshot, always off the hot path (idle callbacks, throttled).
179
+ * - The click handler itself only records + enqueues; batching is 50 events /
180
+ * 10 s / pagehide. Rage classification is server-side — never sent here.
181
+ */
182
+
183
+ /** Result of rasterizing the (already masked) page. */
184
+ interface RasterResult {
185
+ /** Tightly packed RGBA bytes, width*height*4. */
186
+ rgba: Uint8Array;
187
+ width: number;
188
+ height: number;
189
+ /** Base64 PNG of the same masked canvas, or null when encoding failed. */
190
+ pngBase64: string | null;
191
+ }
192
+ interface PageRasterizer {
193
+ /** Resolve null (never throw) when the page cannot be rasterized. */
194
+ rasterize(): Promise<RasterResult | null>;
195
+ }
196
+ interface TransportResponse {
197
+ ok: boolean;
198
+ status: number;
199
+ }
200
+ type TapTransport = (url: string, body: string, opts: {
201
+ headers: Record<string, string>;
202
+ keepalive?: boolean;
203
+ }) => Promise<TransportResponse>;
204
+ /** Anything exposing the AutocaptureModule secondary-listener API. */
205
+ interface AutocaptureSource {
206
+ addListener(cb: (event: AutocaptureEvent) => void): () => void;
207
+ }
208
+ interface WatchtowerCaptureConfig {
209
+ apiKey: string;
210
+ projectId: string;
211
+ /** Base endpoint — events go to `${endpoint}/api/taps`, templates to `${endpoint}/api/taps/template`. */
212
+ endpoint: string;
213
+ appVersion?: string;
214
+ /** Flush when the queue reaches this size (spec §1.3, default 50). */
215
+ maxBatchSize?: number;
216
+ /** Flush interval in ms (spec §1.3, default 10000). */
217
+ flushInterval?: number;
218
+ /** Min ms between rasterizations of the same route (default 1000). */
219
+ templateThrottleMs?: number;
220
+ /** Extra CSS selector blocked (greyed out) in the masked snapshot. */
221
+ blockSelector?: string;
222
+ /** CSS selector whose text is masked in the snapshot. */
223
+ maskSelector?: string;
224
+ debug?: boolean;
225
+ /** Injectable rasterizer (tests). Defaults to the DOM SVG-foreignObject rasterizer. */
226
+ rasterizer?: PageRasterizer;
227
+ /** Injectable transport (tests). Defaults to fetch. */
228
+ transport?: TapTransport;
229
+ }
230
+ declare class WatchtowerWebCapture {
231
+ private config;
232
+ private session;
233
+ private queue;
234
+ private flushTimer;
235
+ private flushFailures;
236
+ private disabled;
237
+ private active;
238
+ private distinctId;
239
+ private currentScreen;
240
+ private transport;
241
+ private rasterizer;
242
+ private detachAutocapture;
243
+ private ownAutocapture;
244
+ private originalPushState;
245
+ private originalReplaceState;
246
+ private popstateHandler;
247
+ private pagehideHandler;
248
+ private fpCache;
249
+ private uploadedFps;
250
+ private lastRasterAt;
251
+ private rasterInFlight;
252
+ constructor(config: WatchtowerCaptureConfig);
253
+ /**
254
+ * Start capturing. Pass the existing AutocaptureModule (via
255
+ * AnalyticsManager.getAutocaptureModule()) to reuse its click listener +
256
+ * selector resolution; when absent, a private clicks-only module is created.
257
+ */
258
+ start(source?: AutocaptureSource | null): void;
259
+ stop(): void;
260
+ isActive(): boolean;
261
+ getSessionId(): string;
262
+ /** Stamped as distinct_id on every subsequent event (identify() feeds this). */
263
+ setDistinctId(distinctId: string | null): void;
264
+ private onAutocaptureEvent;
265
+ /** Record a tap. Coordinates are viewport CSS px; normalization happens here. */
266
+ recordTap(input: {
267
+ selector: string;
268
+ label?: string;
269
+ role?: string;
270
+ clientX: number;
271
+ clientY: number;
272
+ }): void;
273
+ private setupNavigationTracking;
274
+ private handleRouteChange;
275
+ private setupPagehide;
276
+ private baseEvent;
277
+ private enqueue;
278
+ private startFlushTimer;
279
+ flush(opts?: {
280
+ keepalive?: boolean;
281
+ }): Promise<void>;
282
+ private headers;
283
+ private scheduleFingerprint;
284
+ private captureFingerprint;
285
+ private maybeUploadTemplate;
286
+ private combinedBlockSelector;
287
+ private pathname;
288
+ private log;
289
+ }
290
+
160
291
  declare class ReplayManager {
161
292
  private config;
162
293
  private recording;
@@ -999,6 +1130,7 @@ interface WebManagerFactories {
999
1130
  createReplay?: (cfg: Record<string, unknown>) => ReplayManager;
1000
1131
  createFingerprint?: (cfg: Record<string, unknown>) => FingerprintManager;
1001
1132
  createPerformance?: (cfg: Record<string, unknown>) => PerformanceManager;
1133
+ createWatchtowerCapture?: (cfg: Record<string, unknown>) => WatchtowerWebCapture;
1002
1134
  }
1003
1135
  /**
1004
1136
  * Platform-entry-only: inject web-only manager factories. Called by
@@ -1069,6 +1201,22 @@ interface SitePongInitConfig extends SitePongConfig {
1069
1201
  /** Rolling buffer duration in ms — how many seconds of replay to keep before an error (default: 20000) */
1070
1202
  bufferDuration?: number;
1071
1203
  };
1204
+ /** Watchtower tap capture (web) — tap timeline events + masked screen templates */
1205
+ watchtower?: {
1206
+ enabled?: boolean;
1207
+ /** Project ID sent as X-Project-ID on /api/taps requests (required) */
1208
+ projectId?: string;
1209
+ /** Override base endpoint for /api/taps + /api/taps/template (default: main endpoint) */
1210
+ endpoint?: string;
1211
+ /** Flush at this many buffered events (default: 50) */
1212
+ maxBatchSize?: number;
1213
+ /** Flush interval in ms (default: 10000) */
1214
+ flushInterval?: number;
1215
+ /** Extra CSS selector blocked out of the masked screen template */
1216
+ blockSelector?: string;
1217
+ /** CSS selector whose text is masked in the screen template */
1218
+ maskSelector?: string;
1219
+ };
1072
1220
  /** Cron monitoring configuration */
1073
1221
  crons?: {
1074
1222
  enabled?: boolean;
@@ -1117,6 +1265,8 @@ declare class SitePongClient {
1117
1265
  private databaseTracker;
1118
1266
  private profiler;
1119
1267
  private remoteConfigManager;
1268
+ private watchtowerCapture;
1269
+ private watchtowerOptions;
1120
1270
  private currentScreen?;
1121
1271
  private envUnsubs;
1122
1272
  private identifyHooks;
@@ -1179,6 +1329,13 @@ declare class SitePongClient {
1179
1329
  stopReplay(): void;
1180
1330
  isReplayRecording(): boolean;
1181
1331
  getReplaySessionId(): string | null;
1332
+ /**
1333
+ * Start Watchtower web tap capture. Options merge over `watchtower` from
1334
+ * init(); `projectId` is required (either here or in init config). Reuses
1335
+ * the analytics AutocaptureModule's click listener when autocapture is on.
1336
+ */
1337
+ startWatchtowerCapture(options?: SitePongInitConfig['watchtower']): boolean;
1338
+ stopWatchtowerCapture(): void;
1182
1339
  startTransaction(name: string, data?: Record<string, unknown>): string;
1183
1340
  endTransaction(id: string, status?: 'ok' | 'error'): void;
1184
1341
  startSpan(transactionId: string, name: string, data?: Record<string, unknown>): string;
@@ -1279,6 +1436,8 @@ declare const getDeviceSignals: () => Promise<DeviceSignals>;
1279
1436
  declare const getFraudCheck: () => Promise<FraudCheckResult>;
1280
1437
  declare const startReplay: () => boolean;
1281
1438
  declare const stopReplay: () => void;
1439
+ declare const startWatchtowerCapture: (options?: SitePongInitConfig["watchtower"]) => boolean;
1440
+ declare const stopWatchtowerCapture: () => void;
1282
1441
  declare const isReplayRecording: () => boolean;
1283
1442
  declare const getReplaySessionId: () => string | null;
1284
1443
  declare const startTransaction: (name: string, data?: Record<string, unknown>) => string;
@@ -1316,4 +1475,4 @@ declare const isRemoteConfigFeatureEnabled: (key: string, defaultValue?: boolean
1316
1475
  declare const onRemoteConfigChange: (listener: (config: RemoteConfig) => void) => () => void;
1317
1476
  declare const registerIdentifyHook: (hook: (userId: string) => void) => () => void;
1318
1477
 
1319
- export { type CapturedError, type CronCheckinOptions, type CronHandle, DEFAULT_SUPERLINK_ENDPOINT, type DatabaseQueryEvent, type DatabaseTrackerConfig, type DeferredDeepLinkHandler, type DeviceInfo, type DeviceSignals, type EnvironmentAdapter, type ErrorContext, type FraudCheckResult, GroupTraits, type MetricOptions, type MutableRNEnvironmentAdapter, type PerformanceConfig, type PerformanceSpan, type PerformanceTransaction, type PlatformName, type ProfileData, type ProfileFrame, type ProfilerConfig, type RemoteConfig, type RemoteConfigFeatures, type RemoteConfigSampling, ReplayConfig, type ResourceTimingBreakdown, type SitePongConfig, type SitePongInitConfig, SuperLinkClient, type SuperLinkConfig, type SuperLinkDeepLink, type SuperLinkEventType, type SuperLinkFingerprint, type SuperLinkIdentityMetadata, type SuperLinkMatchRequest, type SuperLinkMatchResponse, type SuperLinkMatchType, type SuperLinkPlatform, type TraceContext, TracePropagator, TrackProperties, UserTraits, type VisitorIdResult, type WebManagerFactories, type WebVitals, addBreadcrumb, areFlagsReady, captureError, captureMessage, captureWebDeepLink, clearAnonymousId, clearUser, sitepong as client, completeFromScan, createTraceContext, cronCheckin, cronStart, cronWrap, dbTrack, dbTrackSync, sitepong as default, endSpan, endTransaction, extractIdentityMetadata, extractTrace, flush, flushMetrics, flushProfiles, generateSpanId, generateTraceId, getAllFlags, getAnonymousId, getDbNPlusOnePatterns, getDbQueryCount, getDeepLink, getDeviceSignals, getFlag, getFraudCheck, getLatestProfile, getMatchedDeepLink, getProfiles, getRemoteConfig, getReplaySessionId, getVariant, getVariantPayload, getVisitorId, getWebVitals, group, identify, init, initRN, initSuperLink, isInitialized, isRemoteConfigFeatureEnabled, isReplayRecording, metricDistribution, metricGauge, metricHistogram, metricIncrement, metricStartTimer, metricTime, onDeferredDeepLink, onRemoteConfigChange, parseUniversalLink, profile, propagateTrace, refreshFlags, registerIdentifyHook, registerWebManagerFactories, resetAnalytics, resetDbQueryCount, setAnonymousId, setContext, setCurrentScreen, setEnvironment, setRNGetCurrentScreen, setTags, setUser, startProfileSpan, startReplay, startSpan, startTransaction, stopReplay, superlinkClient, identify$1 as superlinkIdentify, track, trackPageView, waitForFlags, writeClipboardToken };
1478
+ export { type CapturedError, type CronCheckinOptions, type CronHandle, DEFAULT_SUPERLINK_ENDPOINT, type DatabaseQueryEvent, type DatabaseTrackerConfig, type DeferredDeepLinkHandler, type DeviceInfo, type DeviceSignals, type EnvironmentAdapter, type ErrorContext, type FraudCheckResult, GroupTraits, type MetricOptions, type MutableRNEnvironmentAdapter, type PerformanceConfig, type PerformanceSpan, type PerformanceTransaction, type PlatformName, type ProfileData, type ProfileFrame, type ProfilerConfig, type RemoteConfig, type RemoteConfigFeatures, type RemoteConfigSampling, ReplayConfig, type ResourceTimingBreakdown, type SitePongConfig, type SitePongInitConfig, SuperLinkClient, type SuperLinkConfig, type SuperLinkDeepLink, type SuperLinkEventType, type SuperLinkFingerprint, type SuperLinkIdentityMetadata, type SuperLinkMatchRequest, type SuperLinkMatchResponse, type SuperLinkMatchType, type SuperLinkPlatform, type TraceContext, TracePropagator, TrackProperties, UserTraits, type VisitorIdResult, type WebManagerFactories, type WebVitals, addBreadcrumb, areFlagsReady, captureError, captureMessage, captureWebDeepLink, clearAnonymousId, clearUser, sitepong as client, completeFromScan, createTraceContext, cronCheckin, cronStart, cronWrap, dbTrack, dbTrackSync, sitepong as default, endSpan, endTransaction, extractIdentityMetadata, extractTrace, flush, flushMetrics, flushProfiles, generateSpanId, generateTraceId, getAllFlags, getAnonymousId, getDbNPlusOnePatterns, getDbQueryCount, getDeepLink, getDeviceSignals, getFlag, getFraudCheck, getLatestProfile, getMatchedDeepLink, getProfiles, getRemoteConfig, getReplaySessionId, getVariant, getVariantPayload, getVisitorId, getWebVitals, group, identify, init, initRN, initSuperLink, isInitialized, isRemoteConfigFeatureEnabled, isReplayRecording, metricDistribution, metricGauge, metricHistogram, metricIncrement, metricStartTimer, metricTime, onDeferredDeepLink, onRemoteConfigChange, parseUniversalLink, profile, propagateTrace, refreshFlags, registerIdentifyHook, registerWebManagerFactories, resetAnalytics, resetDbQueryCount, setAnonymousId, setContext, setCurrentScreen, setEnvironment, setRNGetCurrentScreen, setTags, setUser, startProfileSpan, startReplay, startSpan, startTransaction, startWatchtowerCapture, stopReplay, stopWatchtowerCapture, superlinkClient, identify$1 as superlinkIdentify, track, trackPageView, waitForFlags, writeClipboardToken };
package/dist/index.js CHANGED
@@ -2,8 +2,6 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- require('web-vitals');
6
-
7
5
  // src/flags/anonymous-id.ts
8
6
  var STORAGE_KEY = "sitepong_anonymous_id";
9
7
  function generateUUID() {
@@ -584,6 +582,7 @@ var DEFAULT_BLOCK_SELECTORS = [
584
582
  var MAX_TEXT_LENGTH = 255;
585
583
  var AutocaptureModule = class {
586
584
  constructor(config, callback) {
585
+ this.listeners = [];
587
586
  this.clickHandler = null;
588
587
  this.submitHandler = null;
589
588
  this.active = false;
@@ -598,6 +597,27 @@ var AutocaptureModule = class {
598
597
  };
599
598
  this.callback = callback;
600
599
  }
600
+ /**
601
+ * Register a secondary listener that receives the same events as the
602
+ * primary callback (e.g. Watchtower tap capture reusing the single click
603
+ * listener + selector resolution). Returns an unsubscribe function.
604
+ */
605
+ addListener(cb) {
606
+ this.listeners.push(cb);
607
+ return () => {
608
+ const idx = this.listeners.indexOf(cb);
609
+ if (idx >= 0) this.listeners.splice(idx, 1);
610
+ };
611
+ }
612
+ emit(event) {
613
+ this.callback(event);
614
+ for (const listener of this.listeners) {
615
+ try {
616
+ listener(event);
617
+ } catch {
618
+ }
619
+ }
620
+ }
601
621
  start() {
602
622
  if (this.active || typeof document === "undefined" || typeof document.addEventListener !== "function") return;
603
623
  this.active = true;
@@ -630,7 +650,7 @@ var AutocaptureModule = class {
630
650
  properties.$event_type = "click";
631
651
  properties.$x = e.clientX;
632
652
  properties.$y = e.clientY;
633
- this.callback({
653
+ this.emit({
634
654
  type: "click",
635
655
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
636
656
  properties
@@ -652,7 +672,7 @@ var AutocaptureModule = class {
652
672
  };
653
673
  const elemProps = this.getElementProperties(form);
654
674
  Object.assign(properties, elemProps);
655
- this.callback({
675
+ this.emit({
656
676
  type: "form_submit",
657
677
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
658
678
  properties
@@ -869,6 +889,14 @@ var AnalyticsManager = class {
869
889
  );
870
890
  this.autocaptureModule.start();
871
891
  }
892
+ /**
893
+ * The live AutocaptureModule (if click/form autocapture is enabled) —
894
+ * Watchtower tap capture attaches to it so there is only ONE document-level
895
+ * click listener and one selector/element resolution path.
896
+ */
897
+ getAutocaptureModule() {
898
+ return this.autocaptureModule;
899
+ }
872
900
  track(eventName, properties) {
873
901
  if (!this.config.enabled) return;
874
902
  const event = this.createEvent("track", { name: eventName, properties });
@@ -2380,6 +2408,8 @@ var SitePongClient = class {
2380
2408
  this.databaseTracker = null;
2381
2409
  this.profiler = null;
2382
2410
  this.remoteConfigManager = null;
2411
+ this.watchtowerCapture = null;
2412
+ this.watchtowerOptions = void 0;
2383
2413
  this.envUnsubs = [];
2384
2414
  this.identifyHooks = [];
2385
2415
  this.config = {
@@ -2499,6 +2529,12 @@ var SitePongClient = class {
2499
2529
  } else if (config.replay?.enabled) {
2500
2530
  this.log("Replay requested but not available on this platform (web only).");
2501
2531
  }
2532
+ this.watchtowerOptions = config.watchtower;
2533
+ if (config.watchtower?.enabled && webManagerFactories.createWatchtowerCapture) {
2534
+ this.startWatchtowerCapture();
2535
+ } else if (config.watchtower?.enabled) {
2536
+ this.log("Watchtower capture requested but not available on this platform (web only).");
2537
+ }
2502
2538
  if (config.crons?.enabled) {
2503
2539
  this.cronManager = new CronMonitorManager({
2504
2540
  apiKey: config.apiKey,
@@ -2738,6 +2774,7 @@ var SitePongClient = class {
2738
2774
  this.log("identify hook failed:", err);
2739
2775
  }
2740
2776
  }
2777
+ this.watchtowerCapture?.setDistinctId(userId);
2741
2778
  if (!this.analyticsManager) {
2742
2779
  this.log("Analytics not enabled. Set analytics.enabled: true in init()");
2743
2780
  return;
@@ -2805,6 +2842,49 @@ var SitePongClient = class {
2805
2842
  getReplaySessionId() {
2806
2843
  return this.replayManager?.getSessionId() ?? null;
2807
2844
  }
2845
+ // --- Watchtower tap capture (web) ---
2846
+ /**
2847
+ * Start Watchtower web tap capture. Options merge over `watchtower` from
2848
+ * init(); `projectId` is required (either here or in init config). Reuses
2849
+ * the analytics AutocaptureModule's click listener when autocapture is on.
2850
+ */
2851
+ startWatchtowerCapture(options) {
2852
+ if (!webManagerFactories.createWatchtowerCapture) {
2853
+ this.log("Watchtower capture not available on this platform (web only).");
2854
+ return false;
2855
+ }
2856
+ if (!this.initialized || !this.config.apiKey) {
2857
+ this.log("Watchtower capture requires init() to be called first.");
2858
+ return false;
2859
+ }
2860
+ const opts = { ...this.watchtowerOptions, ...options };
2861
+ if (!opts.projectId) {
2862
+ this.log("Watchtower capture requires watchtower.projectId.");
2863
+ return false;
2864
+ }
2865
+ if (this.watchtowerCapture) {
2866
+ this.watchtowerCapture.stop();
2867
+ this.watchtowerCapture = null;
2868
+ }
2869
+ this.watchtowerCapture = webManagerFactories.createWatchtowerCapture({
2870
+ apiKey: this.config.apiKey,
2871
+ projectId: opts.projectId,
2872
+ endpoint: opts.endpoint || this.config.endpoint || DEFAULT_ENDPOINT3,
2873
+ appVersion: this.config.release || void 0,
2874
+ maxBatchSize: opts.maxBatchSize,
2875
+ flushInterval: opts.flushInterval,
2876
+ blockSelector: opts.blockSelector,
2877
+ maskSelector: opts.maskSelector,
2878
+ debug: this.config.debug
2879
+ });
2880
+ this.watchtowerCapture.start(this.analyticsManager?.getAutocaptureModule() ?? null);
2881
+ return true;
2882
+ }
2883
+ stopWatchtowerCapture() {
2884
+ if (!this.watchtowerCapture) return;
2885
+ this.watchtowerCapture.stop();
2886
+ this.watchtowerCapture = null;
2887
+ }
2808
2888
  // --- Performance (Tier 7) ---
2809
2889
  startTransaction(name, data) {
2810
2890
  if (!this.performanceManager) {
@@ -2956,6 +3036,7 @@ var SitePongClient = class {
2956
3036
  if (this.replayManager) {
2957
3037
  this.replayManager.setUser(null);
2958
3038
  }
3039
+ this.watchtowerCapture?.setDistinctId(null);
2959
3040
  }
2960
3041
  addBreadcrumb(breadcrumb) {
2961
3042
  this.log("Breadcrumb added:", breadcrumb);
@@ -3180,6 +3261,8 @@ var getDeviceSignals = sitepong.getDeviceSignals.bind(sitepong);
3180
3261
  var getFraudCheck = sitepong.getFraudCheck.bind(sitepong);
3181
3262
  var startReplay = sitepong.startReplay.bind(sitepong);
3182
3263
  var stopReplay = sitepong.stopReplay.bind(sitepong);
3264
+ var startWatchtowerCapture = sitepong.startWatchtowerCapture.bind(sitepong);
3265
+ var stopWatchtowerCapture = sitepong.stopWatchtowerCapture.bind(sitepong);
3183
3266
  var isReplayRecording = sitepong.isReplayRecording.bind(sitepong);
3184
3267
  var getReplaySessionId = sitepong.getReplaySessionId.bind(sitepong);
3185
3268
  var startTransaction = sitepong.startTransaction.bind(sitepong);
@@ -3293,7 +3376,9 @@ exports.startProfileSpan = startProfileSpan;
3293
3376
  exports.startReplay = startReplay;
3294
3377
  exports.startSpan = startSpan;
3295
3378
  exports.startTransaction = startTransaction;
3379
+ exports.startWatchtowerCapture = startWatchtowerCapture;
3296
3380
  exports.stopReplay = stopReplay;
3381
+ exports.stopWatchtowerCapture = stopWatchtowerCapture;
3297
3382
  exports.superlinkClient = superlinkClient;
3298
3383
  exports.superlinkIdentify = identify;
3299
3384
  exports.track = track;