@guidelytech/react-native 0.12.0 → 0.13.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/README.md +41 -3
- package/dist/index.cjs +586 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +235 -4
- package/dist/index.d.ts +235 -4
- package/dist/index.js +584 -8
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.d.cts
CHANGED
|
@@ -324,6 +324,194 @@ declare class Messenger {
|
|
|
324
324
|
destroy(): void;
|
|
325
325
|
}
|
|
326
326
|
|
|
327
|
+
/** One captured screen: a masked JPEG (base64) at 1 px per point, and the viewport in points. */
|
|
328
|
+
interface ReplayFrame {
|
|
329
|
+
base64: string;
|
|
330
|
+
width: number;
|
|
331
|
+
height: number;
|
|
332
|
+
/** Window position (points) of the React root view that touch coordinates are relative to. */
|
|
333
|
+
originX?: number;
|
|
334
|
+
originY?: number;
|
|
335
|
+
}
|
|
336
|
+
/** What the capturer must paint over in the next frame. */
|
|
337
|
+
interface ReplayCaptureOptions {
|
|
338
|
+
maskAllText: boolean;
|
|
339
|
+
maskAllImages: boolean;
|
|
340
|
+
/** Window rects (points) of targets whose Guidely id is in `settings.replay.blockSelectors`. */
|
|
341
|
+
blockRects: Rect[];
|
|
342
|
+
}
|
|
343
|
+
/** Captures the app's visible windows; resolves null when there is nothing to capture. */
|
|
344
|
+
type ScreenCapturer = (options: ReplayCaptureOptions) => Promise<ReplayFrame | null>;
|
|
345
|
+
type TouchPhase = "down" | "move" | "up" | "cancel";
|
|
346
|
+
/** Fixed rrweb document (ids 1–8, see the SPEC) whose single `img` (id 8) shows the current screenshot. */
|
|
347
|
+
declare const RrwebEvents: {
|
|
348
|
+
IMG_ID: number;
|
|
349
|
+
TOUCH_START: number;
|
|
350
|
+
TOUCH_END: number;
|
|
351
|
+
CLICK: number;
|
|
352
|
+
CSS: string;
|
|
353
|
+
dataUrl(base64: string): string;
|
|
354
|
+
meta(timestamp: number, href: string, width: number, height: number): string;
|
|
355
|
+
fullSnapshot(timestamp: number, dataUrl: string, width: number, height: number): string;
|
|
356
|
+
frame(timestamp: number, dataUrl: string): string;
|
|
357
|
+
/** MouseInteraction (source 2): 7 TouchStart, 9 TouchEnd, 2 Click. */
|
|
358
|
+
interaction(timestamp: number, type: number, x: number, y: number): string;
|
|
359
|
+
touchMove(timestamp: number, x: number, y: number): string;
|
|
360
|
+
custom(timestamp: number, tag: string, payload: Record<string, unknown>): string;
|
|
361
|
+
};
|
|
362
|
+
/** Per-upload metadata (`ReplayChunk` minus `sessionId` / `windowId` / `seq` / `events`). */
|
|
363
|
+
interface ReplayChunkMeta {
|
|
364
|
+
anonymousId: string;
|
|
365
|
+
userId: string | null;
|
|
366
|
+
url?: string;
|
|
367
|
+
device: {
|
|
368
|
+
type: string;
|
|
369
|
+
os: string;
|
|
370
|
+
};
|
|
371
|
+
viewport?: {
|
|
372
|
+
width: number;
|
|
373
|
+
height: number;
|
|
374
|
+
};
|
|
375
|
+
sdk: {
|
|
376
|
+
name: string;
|
|
377
|
+
version: string;
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
interface Chunk {
|
|
381
|
+
sessionId: string;
|
|
382
|
+
meta: ReplayChunkMeta;
|
|
383
|
+
events: string[];
|
|
384
|
+
bytes: number;
|
|
385
|
+
seq?: number;
|
|
386
|
+
}
|
|
387
|
+
interface ReplayUploaderOptions {
|
|
388
|
+
/** `POST /replay` URL. */
|
|
389
|
+
url: () => string;
|
|
390
|
+
fetch: () => typeof fetch | null;
|
|
391
|
+
meta: () => ReplayChunkMeta;
|
|
392
|
+
onDisabled: (sessionId: string) => void;
|
|
393
|
+
health?: ServerHealth;
|
|
394
|
+
log?: (message: string) => void;
|
|
395
|
+
flushIntervalMs?: number;
|
|
396
|
+
maxBufferBytes?: number;
|
|
397
|
+
maxQueuedBytes?: number;
|
|
398
|
+
maxAttempts?: number;
|
|
399
|
+
slowRetryMs?: number;
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Buffers rrweb events (JSON strings) and uploads them with `POST /replay`. The buffer is sealed every
|
|
403
|
+
* 10 s, above ~1 MB, on {@link flush} (stop, background) and when the session changes. Chunks go out
|
|
404
|
+
* one at a time as plain JSON (Hermes has no gzip, and base64 JPEGs barely compress); `seq` is
|
|
405
|
+
* assigned per session on a chunk's first attempt and kept for its retries. 2xx removes the chunk
|
|
406
|
+
* (`{disabled:true}` drops that session's chunks), 4xx other than 429 drops it, anything else retries
|
|
407
|
+
* with backoff, then about once a minute. The backlog is capped at ~5 MB (oldest first, never the
|
|
408
|
+
* chunk in flight).
|
|
409
|
+
*/
|
|
410
|
+
declare class ReplayUploader {
|
|
411
|
+
private readonly opts;
|
|
412
|
+
readonly windowId: string;
|
|
413
|
+
private buffer;
|
|
414
|
+
private queue;
|
|
415
|
+
private queuedBytes;
|
|
416
|
+
private seqs;
|
|
417
|
+
private inflight;
|
|
418
|
+
private flushTimer;
|
|
419
|
+
private retryTimer;
|
|
420
|
+
private attempt;
|
|
421
|
+
private destroyed;
|
|
422
|
+
private readonly offRecover;
|
|
423
|
+
constructor(opts: ReplayUploaderOptions);
|
|
424
|
+
get pendingChunks(): number;
|
|
425
|
+
get bufferedEvents(): number;
|
|
426
|
+
push(sessionId: string, json: string): void;
|
|
427
|
+
/** Seals the buffer and uploads the backlog (one chunk at a time). */
|
|
428
|
+
flush(): void;
|
|
429
|
+
/** Drops everything buffered or queued (consent withdrawn, server disabled replay). */
|
|
430
|
+
discard(): void;
|
|
431
|
+
/** Uploads what is left once; no retries afterwards. */
|
|
432
|
+
destroy(): void;
|
|
433
|
+
private clearFlushTimer;
|
|
434
|
+
private clearRetry;
|
|
435
|
+
private scheduleRetry;
|
|
436
|
+
private seal;
|
|
437
|
+
private nextSeq;
|
|
438
|
+
body(chunk: Chunk): string;
|
|
439
|
+
private sendNext;
|
|
440
|
+
private upload;
|
|
441
|
+
private onResult;
|
|
442
|
+
private remove;
|
|
443
|
+
}
|
|
444
|
+
interface SessionRecorderOptions {
|
|
445
|
+
capturer: ScreenCapturer;
|
|
446
|
+
uploader: ReplayUploader;
|
|
447
|
+
/** Time between screenshots (minimum 500 ms). */
|
|
448
|
+
intervalMs: number;
|
|
449
|
+
captureOptions: () => Promise<ReplayCaptureOptions> | ReplayCaptureOptions;
|
|
450
|
+
href: () => string;
|
|
451
|
+
now?: () => number;
|
|
452
|
+
onError?: (err: unknown) => void;
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Records one session at a time: a frame every interval while in the foreground, skipping frames
|
|
456
|
+
* identical to the previous one; keyframes (Meta + FullSnapshot) for the first frame, a viewport
|
|
457
|
+
* change, the first frame after the foreground returns and after `screen()`, mutations otherwise,
|
|
458
|
+
* plus touches and Guidely markers. No capture while a finger is down; one {@link TOUCH_SETTLE_MS}
|
|
459
|
+
* after every touch ends; after {@link IDLE_FRAMES} unchanged captures the interval stretches to
|
|
460
|
+
* `min(4 × interval, 5 s)` until a changed frame, touch, `screen()` or Guidely event.
|
|
461
|
+
*/
|
|
462
|
+
declare class SessionRecorder {
|
|
463
|
+
private readonly opts;
|
|
464
|
+
private readonly intervalMs;
|
|
465
|
+
private readonly now;
|
|
466
|
+
private sid;
|
|
467
|
+
private foreground;
|
|
468
|
+
private generation;
|
|
469
|
+
private timer;
|
|
470
|
+
private timerDue;
|
|
471
|
+
private capturing;
|
|
472
|
+
private needKeyframe;
|
|
473
|
+
private hasKeyframe;
|
|
474
|
+
private lastFrame;
|
|
475
|
+
private unchanged;
|
|
476
|
+
private captureSoon;
|
|
477
|
+
private pendingCustom;
|
|
478
|
+
private touchDown;
|
|
479
|
+
private downX;
|
|
480
|
+
private downY;
|
|
481
|
+
private downAt;
|
|
482
|
+
private maxDistance;
|
|
483
|
+
private lastMoveAt;
|
|
484
|
+
private originX;
|
|
485
|
+
private originY;
|
|
486
|
+
/** Viewport of the last frame (points), for chunk metadata. */
|
|
487
|
+
viewportWidth: number;
|
|
488
|
+
viewportHeight: number;
|
|
489
|
+
constructor(opts: SessionRecorderOptions);
|
|
490
|
+
get sessionId(): string | null;
|
|
491
|
+
get isRecording(): boolean;
|
|
492
|
+
get currentIntervalMs(): number;
|
|
493
|
+
/** Starts (or keeps) recording `sessionId`; another session stops the current one first (uploading it). */
|
|
494
|
+
start(sessionId: string): void;
|
|
495
|
+
/** Stops recording; buffered events are uploaded unless `discard`. */
|
|
496
|
+
stop(discard: boolean): void;
|
|
497
|
+
/** App backgrounded: no captures; uploads what is buffered. */
|
|
498
|
+
pause(): void;
|
|
499
|
+
/** App foregrounded: resume with a keyframe. */
|
|
500
|
+
resume(): void;
|
|
501
|
+
/** A new screen: the next frame is a keyframe with the new href. */
|
|
502
|
+
onScreen(): void;
|
|
503
|
+
private activity;
|
|
504
|
+
/** Adds the `guidely` marker for an analytics event. */
|
|
505
|
+
addGuidelyEvent(name: string, customName?: string, guideId?: string): void;
|
|
506
|
+
/** A primary-pointer touch at (x, y) points from the React root view. */
|
|
507
|
+
touch(phase: TouchPhase, rootX: number, rootY: number): void;
|
|
508
|
+
private clearTimer;
|
|
509
|
+
/** Schedules the next capture `delay` ms from now, or keeps an earlier one when `ifSooner`. */
|
|
510
|
+
private schedule;
|
|
511
|
+
private tick;
|
|
512
|
+
private onFrame;
|
|
513
|
+
}
|
|
514
|
+
|
|
327
515
|
/**
|
|
328
516
|
* AsyncStorage-compatible key/value storage (`@react-native-async-storage/async-storage`,
|
|
329
517
|
* `expo-secure-store` wrappers, MMKV adapters…). Synchronous implementations work too.
|
|
@@ -368,6 +556,12 @@ interface GuidelyOptions {
|
|
|
368
556
|
* touch-observing wrapper view.
|
|
369
557
|
*/
|
|
370
558
|
autocapture?: boolean | Partial<AutocaptureSettings>;
|
|
559
|
+
/**
|
|
560
|
+
* Session replay (off by default). Recording also needs replay enabled in the project settings and
|
|
561
|
+
* the native `@guidelytech/react-native-replay` module installed; sampling, consent and `analytics`
|
|
562
|
+
* apply too. Text inputs are always masked; wrap anything else in `<GuidelyMask>`.
|
|
563
|
+
*/
|
|
564
|
+
sessionReplay?: SessionReplayOptions;
|
|
371
565
|
/** How often to refresh the published config (default 5 minutes). */
|
|
372
566
|
configRefreshMs?: number;
|
|
373
567
|
/** Overrides for the project theme. */
|
|
@@ -397,6 +591,16 @@ interface GuidelyOptions {
|
|
|
397
591
|
*/
|
|
398
592
|
flags?: false | Partial<FlagsClientOptions>;
|
|
399
593
|
}
|
|
594
|
+
interface SessionReplayOptions {
|
|
595
|
+
/** Record sessions (when the project setting allows it and the session is sampled). */
|
|
596
|
+
enabled?: boolean;
|
|
597
|
+
/** Mask all text; also forced on by the project's "mask all text" setting. */
|
|
598
|
+
maskAllText?: boolean;
|
|
599
|
+
/** Mask all images. */
|
|
600
|
+
maskAllImages?: boolean;
|
|
601
|
+
/** Time between screenshots in ms (default 1000, minimum 500). */
|
|
602
|
+
captureIntervalMs?: number;
|
|
603
|
+
}
|
|
400
604
|
interface GuideStepInfo {
|
|
401
605
|
guide: PublishedGuide;
|
|
402
606
|
stepId: string;
|
|
@@ -478,7 +682,7 @@ interface UiState {
|
|
|
478
682
|
}
|
|
479
683
|
|
|
480
684
|
declare const SDK_NAME = "@guidelytech/react-native";
|
|
481
|
-
declare const SDK_VERSION = "0.
|
|
685
|
+
declare const SDK_VERSION = "0.13.0";
|
|
482
686
|
declare const DEFAULT_API_URL = "https://guidelytech.com";
|
|
483
687
|
/** Host-platform services the engine needs; the provider supplies React Native implementations. */
|
|
484
688
|
interface PlatformBridge {
|
|
@@ -490,6 +694,8 @@ interface PlatformBridge {
|
|
|
490
694
|
width: number;
|
|
491
695
|
height: number;
|
|
492
696
|
};
|
|
697
|
+
/** Session-replay screenshots; absent where the native replay module is not installed. */
|
|
698
|
+
capturer?: ScreenCapturer;
|
|
493
699
|
}
|
|
494
700
|
/** Mobile sessions persist across launches and expire after the configured inactivity timeout. */
|
|
495
701
|
interface MobileSession extends SessionState {
|
|
@@ -547,6 +753,10 @@ declare class GuidelyClient {
|
|
|
547
753
|
private lastAudiences;
|
|
548
754
|
private backgroundedAt;
|
|
549
755
|
private messenger;
|
|
756
|
+
private replayUploader;
|
|
757
|
+
private recorder;
|
|
758
|
+
/** Replay decision for the current session (sampled once; forced by start/stopSessionRecording). */
|
|
759
|
+
private replayDecision;
|
|
550
760
|
private ui;
|
|
551
761
|
private uiListeners;
|
|
552
762
|
/** Feature flags for this environment: `guidely.flags.isEnabled("new-checkout")`. */
|
|
@@ -619,6 +829,26 @@ declare class GuidelyClient {
|
|
|
619
829
|
/** The current screen name (last value passed to `screen()`). */
|
|
620
830
|
getScreen(): string;
|
|
621
831
|
private handleTap;
|
|
832
|
+
private replaySettings;
|
|
833
|
+
/** Reconciles recording with config, consent, readiness, the session and its sample decision. Idempotent. */
|
|
834
|
+
private syncReplay;
|
|
835
|
+
private createRecorder;
|
|
836
|
+
private replayCaptureOptions;
|
|
837
|
+
/**
|
|
838
|
+
* Records this session even when it was not sampled (still needs `sessionReplay.enabled`, replay
|
|
839
|
+
* enabled for the project, analytics consent and the native replay module). Sticks until the session ends.
|
|
840
|
+
*/
|
|
841
|
+
startSessionRecording(): void;
|
|
842
|
+
/** Stops recording for the rest of this session; what was recorded is uploaded. */
|
|
843
|
+
stopSessionRecording(): void;
|
|
844
|
+
/** True while this session is being recorded. */
|
|
845
|
+
isRecording(): boolean;
|
|
846
|
+
/** The current analytics session id (also the replay id). */
|
|
847
|
+
getSessionId(): string;
|
|
848
|
+
/** True when touches should be passed to {@link recordTouch}. */
|
|
849
|
+
isRecordingTouches(): boolean;
|
|
850
|
+
/** A primary-pointer touch on the app, in window points (the provider's touch observer calls this). */
|
|
851
|
+
recordTouch(phase: TouchPhase, x: number, y: number): void;
|
|
622
852
|
private captureAllowed;
|
|
623
853
|
/** A capability runs when the project enables it (absent on old servers → off), no option turns it off and analytics are allowed. */
|
|
624
854
|
private autocaptureOn;
|
|
@@ -892,8 +1122,9 @@ interface GuidelyMaskProps extends ViewProps {
|
|
|
892
1122
|
children?: ReactNode;
|
|
893
1123
|
}
|
|
894
1124
|
/**
|
|
895
|
-
* Keeps
|
|
896
|
-
* contains it) are captured without `text
|
|
1125
|
+
* Keeps its children out of product analytics and session replay: taps inside it (or on an element
|
|
1126
|
+
* that contains it) are captured without `text`, and recordings paint over it. Renders a plain `View`
|
|
1127
|
+
* (its `nativeID` is how the native recorder finds it).
|
|
897
1128
|
*/
|
|
898
1129
|
declare function GuidelyMask({ children, ...rest }: GuidelyMaskProps): react.JSX.Element;
|
|
899
1130
|
|
|
@@ -1050,4 +1281,4 @@ declare function useGuideState(idOrKey: string): {
|
|
|
1050
1281
|
/** The guide currently running exclusively (flow, modal, survey…), or null. */
|
|
1051
1282
|
declare function useActiveGuide(): PublishedGuide | null;
|
|
1052
1283
|
|
|
1053
|
-
export { type AutocaptureOption, type ChecklistView, DEFAULT_API_URL, type DeviceEnvironment, Feature, FeatureFlag, type FeatureProps, FeatureValue, type FeatureValueProps, FlagsProvider, type FlagsProviderProps, type GuideStepInfo, GuidelyClient, type GuidelyEventName, type GuidelyEvents, GuidelyMask, type GuidelyMaskProps, type GuidelyOptions, GuidelyOverlay, GuidelyProvider, type GuidelyProviderProps, GuidelyScreenScope, type GuidelyStorage, GuidelyTarget, type GuidelyTargetProps, HeatmapBuffer, type Insets, Messenger, type MessengerSnapshot, type MessengerTab, type MessengerThread, type MessengerView, type PlatformBridge, RageClickDetector, SDK_NAME, SDK_VERSION, type StepView, type SurveyView, type TapElement, type TapInfo, type TapProperties, TapTracker, TargetRegistry, type UiState, createSseParser, guidelyScreenLayout, htmlToText, noopClient, parseHtml, positionCard, targetIdsFor, useActiveGuide, useChecklistProgress, useFeatureValue, useFlag, useFlagDetails, useFlags, useFlagsClient, useFlagsReady, useGuideState, useGuidely, useGuidelyEvent, useGuidelyIdentify, useGuidelyNavigation, useGuidelyReady, useGuidelyScreen, useGuidelyTarget };
|
|
1284
|
+
export { type AutocaptureOption, type ChecklistView, DEFAULT_API_URL, type DeviceEnvironment, Feature, FeatureFlag, type FeatureProps, FeatureValue, type FeatureValueProps, FlagsProvider, type FlagsProviderProps, type GuideStepInfo, GuidelyClient, type GuidelyEventName, type GuidelyEvents, GuidelyMask, type GuidelyMaskProps, type GuidelyOptions, GuidelyOverlay, GuidelyProvider, type GuidelyProviderProps, GuidelyScreenScope, type GuidelyStorage, GuidelyTarget, type GuidelyTargetProps, HeatmapBuffer, type Insets, Messenger, type MessengerSnapshot, type MessengerTab, type MessengerThread, type MessengerView, type PlatformBridge, RageClickDetector, type ReplayCaptureOptions, type ReplayFrame, ReplayUploader, RrwebEvents, SDK_NAME, SDK_VERSION, type ScreenCapturer, SessionRecorder, type SessionReplayOptions, type StepView, type SurveyView, type TapElement, type TapInfo, type TapProperties, TapTracker, TargetRegistry, type TouchPhase, type UiState, createSseParser, guidelyScreenLayout, htmlToText, noopClient, parseHtml, positionCard, targetIdsFor, useActiveGuide, useChecklistProgress, useFeatureValue, useFlag, useFlagDetails, useFlags, useFlagsClient, useFlagsReady, useGuideState, useGuidely, useGuidelyEvent, useGuidelyIdentify, useGuidelyNavigation, useGuidelyReady, useGuidelyScreen, useGuidelyTarget };
|
package/dist/index.d.ts
CHANGED
|
@@ -324,6 +324,194 @@ declare class Messenger {
|
|
|
324
324
|
destroy(): void;
|
|
325
325
|
}
|
|
326
326
|
|
|
327
|
+
/** One captured screen: a masked JPEG (base64) at 1 px per point, and the viewport in points. */
|
|
328
|
+
interface ReplayFrame {
|
|
329
|
+
base64: string;
|
|
330
|
+
width: number;
|
|
331
|
+
height: number;
|
|
332
|
+
/** Window position (points) of the React root view that touch coordinates are relative to. */
|
|
333
|
+
originX?: number;
|
|
334
|
+
originY?: number;
|
|
335
|
+
}
|
|
336
|
+
/** What the capturer must paint over in the next frame. */
|
|
337
|
+
interface ReplayCaptureOptions {
|
|
338
|
+
maskAllText: boolean;
|
|
339
|
+
maskAllImages: boolean;
|
|
340
|
+
/** Window rects (points) of targets whose Guidely id is in `settings.replay.blockSelectors`. */
|
|
341
|
+
blockRects: Rect[];
|
|
342
|
+
}
|
|
343
|
+
/** Captures the app's visible windows; resolves null when there is nothing to capture. */
|
|
344
|
+
type ScreenCapturer = (options: ReplayCaptureOptions) => Promise<ReplayFrame | null>;
|
|
345
|
+
type TouchPhase = "down" | "move" | "up" | "cancel";
|
|
346
|
+
/** Fixed rrweb document (ids 1–8, see the SPEC) whose single `img` (id 8) shows the current screenshot. */
|
|
347
|
+
declare const RrwebEvents: {
|
|
348
|
+
IMG_ID: number;
|
|
349
|
+
TOUCH_START: number;
|
|
350
|
+
TOUCH_END: number;
|
|
351
|
+
CLICK: number;
|
|
352
|
+
CSS: string;
|
|
353
|
+
dataUrl(base64: string): string;
|
|
354
|
+
meta(timestamp: number, href: string, width: number, height: number): string;
|
|
355
|
+
fullSnapshot(timestamp: number, dataUrl: string, width: number, height: number): string;
|
|
356
|
+
frame(timestamp: number, dataUrl: string): string;
|
|
357
|
+
/** MouseInteraction (source 2): 7 TouchStart, 9 TouchEnd, 2 Click. */
|
|
358
|
+
interaction(timestamp: number, type: number, x: number, y: number): string;
|
|
359
|
+
touchMove(timestamp: number, x: number, y: number): string;
|
|
360
|
+
custom(timestamp: number, tag: string, payload: Record<string, unknown>): string;
|
|
361
|
+
};
|
|
362
|
+
/** Per-upload metadata (`ReplayChunk` minus `sessionId` / `windowId` / `seq` / `events`). */
|
|
363
|
+
interface ReplayChunkMeta {
|
|
364
|
+
anonymousId: string;
|
|
365
|
+
userId: string | null;
|
|
366
|
+
url?: string;
|
|
367
|
+
device: {
|
|
368
|
+
type: string;
|
|
369
|
+
os: string;
|
|
370
|
+
};
|
|
371
|
+
viewport?: {
|
|
372
|
+
width: number;
|
|
373
|
+
height: number;
|
|
374
|
+
};
|
|
375
|
+
sdk: {
|
|
376
|
+
name: string;
|
|
377
|
+
version: string;
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
interface Chunk {
|
|
381
|
+
sessionId: string;
|
|
382
|
+
meta: ReplayChunkMeta;
|
|
383
|
+
events: string[];
|
|
384
|
+
bytes: number;
|
|
385
|
+
seq?: number;
|
|
386
|
+
}
|
|
387
|
+
interface ReplayUploaderOptions {
|
|
388
|
+
/** `POST /replay` URL. */
|
|
389
|
+
url: () => string;
|
|
390
|
+
fetch: () => typeof fetch | null;
|
|
391
|
+
meta: () => ReplayChunkMeta;
|
|
392
|
+
onDisabled: (sessionId: string) => void;
|
|
393
|
+
health?: ServerHealth;
|
|
394
|
+
log?: (message: string) => void;
|
|
395
|
+
flushIntervalMs?: number;
|
|
396
|
+
maxBufferBytes?: number;
|
|
397
|
+
maxQueuedBytes?: number;
|
|
398
|
+
maxAttempts?: number;
|
|
399
|
+
slowRetryMs?: number;
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Buffers rrweb events (JSON strings) and uploads them with `POST /replay`. The buffer is sealed every
|
|
403
|
+
* 10 s, above ~1 MB, on {@link flush} (stop, background) and when the session changes. Chunks go out
|
|
404
|
+
* one at a time as plain JSON (Hermes has no gzip, and base64 JPEGs barely compress); `seq` is
|
|
405
|
+
* assigned per session on a chunk's first attempt and kept for its retries. 2xx removes the chunk
|
|
406
|
+
* (`{disabled:true}` drops that session's chunks), 4xx other than 429 drops it, anything else retries
|
|
407
|
+
* with backoff, then about once a minute. The backlog is capped at ~5 MB (oldest first, never the
|
|
408
|
+
* chunk in flight).
|
|
409
|
+
*/
|
|
410
|
+
declare class ReplayUploader {
|
|
411
|
+
private readonly opts;
|
|
412
|
+
readonly windowId: string;
|
|
413
|
+
private buffer;
|
|
414
|
+
private queue;
|
|
415
|
+
private queuedBytes;
|
|
416
|
+
private seqs;
|
|
417
|
+
private inflight;
|
|
418
|
+
private flushTimer;
|
|
419
|
+
private retryTimer;
|
|
420
|
+
private attempt;
|
|
421
|
+
private destroyed;
|
|
422
|
+
private readonly offRecover;
|
|
423
|
+
constructor(opts: ReplayUploaderOptions);
|
|
424
|
+
get pendingChunks(): number;
|
|
425
|
+
get bufferedEvents(): number;
|
|
426
|
+
push(sessionId: string, json: string): void;
|
|
427
|
+
/** Seals the buffer and uploads the backlog (one chunk at a time). */
|
|
428
|
+
flush(): void;
|
|
429
|
+
/** Drops everything buffered or queued (consent withdrawn, server disabled replay). */
|
|
430
|
+
discard(): void;
|
|
431
|
+
/** Uploads what is left once; no retries afterwards. */
|
|
432
|
+
destroy(): void;
|
|
433
|
+
private clearFlushTimer;
|
|
434
|
+
private clearRetry;
|
|
435
|
+
private scheduleRetry;
|
|
436
|
+
private seal;
|
|
437
|
+
private nextSeq;
|
|
438
|
+
body(chunk: Chunk): string;
|
|
439
|
+
private sendNext;
|
|
440
|
+
private upload;
|
|
441
|
+
private onResult;
|
|
442
|
+
private remove;
|
|
443
|
+
}
|
|
444
|
+
interface SessionRecorderOptions {
|
|
445
|
+
capturer: ScreenCapturer;
|
|
446
|
+
uploader: ReplayUploader;
|
|
447
|
+
/** Time between screenshots (minimum 500 ms). */
|
|
448
|
+
intervalMs: number;
|
|
449
|
+
captureOptions: () => Promise<ReplayCaptureOptions> | ReplayCaptureOptions;
|
|
450
|
+
href: () => string;
|
|
451
|
+
now?: () => number;
|
|
452
|
+
onError?: (err: unknown) => void;
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Records one session at a time: a frame every interval while in the foreground, skipping frames
|
|
456
|
+
* identical to the previous one; keyframes (Meta + FullSnapshot) for the first frame, a viewport
|
|
457
|
+
* change, the first frame after the foreground returns and after `screen()`, mutations otherwise,
|
|
458
|
+
* plus touches and Guidely markers. No capture while a finger is down; one {@link TOUCH_SETTLE_MS}
|
|
459
|
+
* after every touch ends; after {@link IDLE_FRAMES} unchanged captures the interval stretches to
|
|
460
|
+
* `min(4 × interval, 5 s)` until a changed frame, touch, `screen()` or Guidely event.
|
|
461
|
+
*/
|
|
462
|
+
declare class SessionRecorder {
|
|
463
|
+
private readonly opts;
|
|
464
|
+
private readonly intervalMs;
|
|
465
|
+
private readonly now;
|
|
466
|
+
private sid;
|
|
467
|
+
private foreground;
|
|
468
|
+
private generation;
|
|
469
|
+
private timer;
|
|
470
|
+
private timerDue;
|
|
471
|
+
private capturing;
|
|
472
|
+
private needKeyframe;
|
|
473
|
+
private hasKeyframe;
|
|
474
|
+
private lastFrame;
|
|
475
|
+
private unchanged;
|
|
476
|
+
private captureSoon;
|
|
477
|
+
private pendingCustom;
|
|
478
|
+
private touchDown;
|
|
479
|
+
private downX;
|
|
480
|
+
private downY;
|
|
481
|
+
private downAt;
|
|
482
|
+
private maxDistance;
|
|
483
|
+
private lastMoveAt;
|
|
484
|
+
private originX;
|
|
485
|
+
private originY;
|
|
486
|
+
/** Viewport of the last frame (points), for chunk metadata. */
|
|
487
|
+
viewportWidth: number;
|
|
488
|
+
viewportHeight: number;
|
|
489
|
+
constructor(opts: SessionRecorderOptions);
|
|
490
|
+
get sessionId(): string | null;
|
|
491
|
+
get isRecording(): boolean;
|
|
492
|
+
get currentIntervalMs(): number;
|
|
493
|
+
/** Starts (or keeps) recording `sessionId`; another session stops the current one first (uploading it). */
|
|
494
|
+
start(sessionId: string): void;
|
|
495
|
+
/** Stops recording; buffered events are uploaded unless `discard`. */
|
|
496
|
+
stop(discard: boolean): void;
|
|
497
|
+
/** App backgrounded: no captures; uploads what is buffered. */
|
|
498
|
+
pause(): void;
|
|
499
|
+
/** App foregrounded: resume with a keyframe. */
|
|
500
|
+
resume(): void;
|
|
501
|
+
/** A new screen: the next frame is a keyframe with the new href. */
|
|
502
|
+
onScreen(): void;
|
|
503
|
+
private activity;
|
|
504
|
+
/** Adds the `guidely` marker for an analytics event. */
|
|
505
|
+
addGuidelyEvent(name: string, customName?: string, guideId?: string): void;
|
|
506
|
+
/** A primary-pointer touch at (x, y) points from the React root view. */
|
|
507
|
+
touch(phase: TouchPhase, rootX: number, rootY: number): void;
|
|
508
|
+
private clearTimer;
|
|
509
|
+
/** Schedules the next capture `delay` ms from now, or keeps an earlier one when `ifSooner`. */
|
|
510
|
+
private schedule;
|
|
511
|
+
private tick;
|
|
512
|
+
private onFrame;
|
|
513
|
+
}
|
|
514
|
+
|
|
327
515
|
/**
|
|
328
516
|
* AsyncStorage-compatible key/value storage (`@react-native-async-storage/async-storage`,
|
|
329
517
|
* `expo-secure-store` wrappers, MMKV adapters…). Synchronous implementations work too.
|
|
@@ -368,6 +556,12 @@ interface GuidelyOptions {
|
|
|
368
556
|
* touch-observing wrapper view.
|
|
369
557
|
*/
|
|
370
558
|
autocapture?: boolean | Partial<AutocaptureSettings>;
|
|
559
|
+
/**
|
|
560
|
+
* Session replay (off by default). Recording also needs replay enabled in the project settings and
|
|
561
|
+
* the native `@guidelytech/react-native-replay` module installed; sampling, consent and `analytics`
|
|
562
|
+
* apply too. Text inputs are always masked; wrap anything else in `<GuidelyMask>`.
|
|
563
|
+
*/
|
|
564
|
+
sessionReplay?: SessionReplayOptions;
|
|
371
565
|
/** How often to refresh the published config (default 5 minutes). */
|
|
372
566
|
configRefreshMs?: number;
|
|
373
567
|
/** Overrides for the project theme. */
|
|
@@ -397,6 +591,16 @@ interface GuidelyOptions {
|
|
|
397
591
|
*/
|
|
398
592
|
flags?: false | Partial<FlagsClientOptions>;
|
|
399
593
|
}
|
|
594
|
+
interface SessionReplayOptions {
|
|
595
|
+
/** Record sessions (when the project setting allows it and the session is sampled). */
|
|
596
|
+
enabled?: boolean;
|
|
597
|
+
/** Mask all text; also forced on by the project's "mask all text" setting. */
|
|
598
|
+
maskAllText?: boolean;
|
|
599
|
+
/** Mask all images. */
|
|
600
|
+
maskAllImages?: boolean;
|
|
601
|
+
/** Time between screenshots in ms (default 1000, minimum 500). */
|
|
602
|
+
captureIntervalMs?: number;
|
|
603
|
+
}
|
|
400
604
|
interface GuideStepInfo {
|
|
401
605
|
guide: PublishedGuide;
|
|
402
606
|
stepId: string;
|
|
@@ -478,7 +682,7 @@ interface UiState {
|
|
|
478
682
|
}
|
|
479
683
|
|
|
480
684
|
declare const SDK_NAME = "@guidelytech/react-native";
|
|
481
|
-
declare const SDK_VERSION = "0.
|
|
685
|
+
declare const SDK_VERSION = "0.13.0";
|
|
482
686
|
declare const DEFAULT_API_URL = "https://guidelytech.com";
|
|
483
687
|
/** Host-platform services the engine needs; the provider supplies React Native implementations. */
|
|
484
688
|
interface PlatformBridge {
|
|
@@ -490,6 +694,8 @@ interface PlatformBridge {
|
|
|
490
694
|
width: number;
|
|
491
695
|
height: number;
|
|
492
696
|
};
|
|
697
|
+
/** Session-replay screenshots; absent where the native replay module is not installed. */
|
|
698
|
+
capturer?: ScreenCapturer;
|
|
493
699
|
}
|
|
494
700
|
/** Mobile sessions persist across launches and expire after the configured inactivity timeout. */
|
|
495
701
|
interface MobileSession extends SessionState {
|
|
@@ -547,6 +753,10 @@ declare class GuidelyClient {
|
|
|
547
753
|
private lastAudiences;
|
|
548
754
|
private backgroundedAt;
|
|
549
755
|
private messenger;
|
|
756
|
+
private replayUploader;
|
|
757
|
+
private recorder;
|
|
758
|
+
/** Replay decision for the current session (sampled once; forced by start/stopSessionRecording). */
|
|
759
|
+
private replayDecision;
|
|
550
760
|
private ui;
|
|
551
761
|
private uiListeners;
|
|
552
762
|
/** Feature flags for this environment: `guidely.flags.isEnabled("new-checkout")`. */
|
|
@@ -619,6 +829,26 @@ declare class GuidelyClient {
|
|
|
619
829
|
/** The current screen name (last value passed to `screen()`). */
|
|
620
830
|
getScreen(): string;
|
|
621
831
|
private handleTap;
|
|
832
|
+
private replaySettings;
|
|
833
|
+
/** Reconciles recording with config, consent, readiness, the session and its sample decision. Idempotent. */
|
|
834
|
+
private syncReplay;
|
|
835
|
+
private createRecorder;
|
|
836
|
+
private replayCaptureOptions;
|
|
837
|
+
/**
|
|
838
|
+
* Records this session even when it was not sampled (still needs `sessionReplay.enabled`, replay
|
|
839
|
+
* enabled for the project, analytics consent and the native replay module). Sticks until the session ends.
|
|
840
|
+
*/
|
|
841
|
+
startSessionRecording(): void;
|
|
842
|
+
/** Stops recording for the rest of this session; what was recorded is uploaded. */
|
|
843
|
+
stopSessionRecording(): void;
|
|
844
|
+
/** True while this session is being recorded. */
|
|
845
|
+
isRecording(): boolean;
|
|
846
|
+
/** The current analytics session id (also the replay id). */
|
|
847
|
+
getSessionId(): string;
|
|
848
|
+
/** True when touches should be passed to {@link recordTouch}. */
|
|
849
|
+
isRecordingTouches(): boolean;
|
|
850
|
+
/** A primary-pointer touch on the app, in window points (the provider's touch observer calls this). */
|
|
851
|
+
recordTouch(phase: TouchPhase, x: number, y: number): void;
|
|
622
852
|
private captureAllowed;
|
|
623
853
|
/** A capability runs when the project enables it (absent on old servers → off), no option turns it off and analytics are allowed. */
|
|
624
854
|
private autocaptureOn;
|
|
@@ -892,8 +1122,9 @@ interface GuidelyMaskProps extends ViewProps {
|
|
|
892
1122
|
children?: ReactNode;
|
|
893
1123
|
}
|
|
894
1124
|
/**
|
|
895
|
-
* Keeps
|
|
896
|
-
* contains it) are captured without `text
|
|
1125
|
+
* Keeps its children out of product analytics and session replay: taps inside it (or on an element
|
|
1126
|
+
* that contains it) are captured without `text`, and recordings paint over it. Renders a plain `View`
|
|
1127
|
+
* (its `nativeID` is how the native recorder finds it).
|
|
897
1128
|
*/
|
|
898
1129
|
declare function GuidelyMask({ children, ...rest }: GuidelyMaskProps): react.JSX.Element;
|
|
899
1130
|
|
|
@@ -1050,4 +1281,4 @@ declare function useGuideState(idOrKey: string): {
|
|
|
1050
1281
|
/** The guide currently running exclusively (flow, modal, survey…), or null. */
|
|
1051
1282
|
declare function useActiveGuide(): PublishedGuide | null;
|
|
1052
1283
|
|
|
1053
|
-
export { type AutocaptureOption, type ChecklistView, DEFAULT_API_URL, type DeviceEnvironment, Feature, FeatureFlag, type FeatureProps, FeatureValue, type FeatureValueProps, FlagsProvider, type FlagsProviderProps, type GuideStepInfo, GuidelyClient, type GuidelyEventName, type GuidelyEvents, GuidelyMask, type GuidelyMaskProps, type GuidelyOptions, GuidelyOverlay, GuidelyProvider, type GuidelyProviderProps, GuidelyScreenScope, type GuidelyStorage, GuidelyTarget, type GuidelyTargetProps, HeatmapBuffer, type Insets, Messenger, type MessengerSnapshot, type MessengerTab, type MessengerThread, type MessengerView, type PlatformBridge, RageClickDetector, SDK_NAME, SDK_VERSION, type StepView, type SurveyView, type TapElement, type TapInfo, type TapProperties, TapTracker, TargetRegistry, type UiState, createSseParser, guidelyScreenLayout, htmlToText, noopClient, parseHtml, positionCard, targetIdsFor, useActiveGuide, useChecklistProgress, useFeatureValue, useFlag, useFlagDetails, useFlags, useFlagsClient, useFlagsReady, useGuideState, useGuidely, useGuidelyEvent, useGuidelyIdentify, useGuidelyNavigation, useGuidelyReady, useGuidelyScreen, useGuidelyTarget };
|
|
1284
|
+
export { type AutocaptureOption, type ChecklistView, DEFAULT_API_URL, type DeviceEnvironment, Feature, FeatureFlag, type FeatureProps, FeatureValue, type FeatureValueProps, FlagsProvider, type FlagsProviderProps, type GuideStepInfo, GuidelyClient, type GuidelyEventName, type GuidelyEvents, GuidelyMask, type GuidelyMaskProps, type GuidelyOptions, GuidelyOverlay, GuidelyProvider, type GuidelyProviderProps, GuidelyScreenScope, type GuidelyStorage, GuidelyTarget, type GuidelyTargetProps, HeatmapBuffer, type Insets, Messenger, type MessengerSnapshot, type MessengerTab, type MessengerThread, type MessengerView, type PlatformBridge, RageClickDetector, type ReplayCaptureOptions, type ReplayFrame, ReplayUploader, RrwebEvents, SDK_NAME, SDK_VERSION, type ScreenCapturer, SessionRecorder, type SessionReplayOptions, type StepView, type SurveyView, type TapElement, type TapInfo, type TapProperties, TapTracker, TargetRegistry, type TouchPhase, type UiState, createSseParser, guidelyScreenLayout, htmlToText, noopClient, parseHtml, positionCard, targetIdsFor, useActiveGuide, useChecklistProgress, useFeatureValue, useFlag, useFlagDetails, useFlags, useFlagsClient, useFlagsReady, useGuideState, useGuidely, useGuidelyEvent, useGuidelyIdentify, useGuidelyNavigation, useGuidelyReady, useGuidelyScreen, useGuidelyTarget };
|