From 64a84af584a13e59a00a073c7dc463d69d7f21ea Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Thu, 4 Jan 2024 16:48:07 +0100 Subject: [PATCH 01/48] feat(replay): Add `ReplayCanvas` integration Adding this integration in addition to `Replay` will set up canvas recording. --- .size-limit.js | 7 +++ .../suites/replay/canvas/template.html | 9 ++++ .../canvas/withCanvasIntegrationFirst/init.js | 18 +++++++ .../canvas/withCanvasIntegrationFirst/test.ts | 28 ++++++++++ .../withCanvasIntegrationSecond/init.js | 18 +++++++ .../withCanvasIntegrationSecond/test.ts | 28 ++++++++++ .../canvas/withoutCanvasIntegration/init.js | 18 +++++++ .../canvas/withoutCanvasIntegration/test.ts | 27 ++++++++++ packages/browser/src/index.ts | 2 +- packages/replay/rollup.bundle.config.mjs | 12 ++++- packages/replay/src/canvas.ts | 54 +++++++++++++++++++ packages/replay/src/index.ts | 1 + packages/replay/src/integration.ts | 41 ++++++++++++++ packages/types/src/client.ts | 5 +- 14 files changed, 264 insertions(+), 4 deletions(-) create mode 100644 packages/browser-integration-tests/suites/replay/canvas/template.html create mode 100644 packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/init.js create mode 100644 packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts create mode 100644 packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/init.js create mode 100644 packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts create mode 100644 packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/init.js create mode 100644 packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/test.ts create mode 100644 packages/replay/src/canvas.ts diff --git a/.size-limit.js b/.size-limit.js index b29677fce51a..7fd24ce7efa1 100644 --- a/.size-limit.js +++ b/.size-limit.js @@ -14,6 +14,13 @@ module.exports = [ gzip: true, limit: '75 KB', }, + { + name: '@sentry/browser (incl. Tracing, Replay with Canvas) - Webpack (gzipped)', + path: 'packages/browser/build/npm/esm/index.js', + import: '{ init, Replay, BrowserTracing, ReplayCanvas }', + gzip: true, + limit: '90 KB', + }, { name: '@sentry/browser (incl. Tracing, Replay) - Webpack with treeshaking flags (gzipped)', path: 'packages/browser/build/npm/esm/index.js', diff --git a/packages/browser-integration-tests/suites/replay/canvas/template.html b/packages/browser-integration-tests/suites/replay/canvas/template.html new file mode 100644 index 000000000000..2b3e2f0b27b4 --- /dev/null +++ b/packages/browser-integration-tests/suites/replay/canvas/template.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/init.js b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/init.js new file mode 100644 index 000000000000..fa3248066150 --- /dev/null +++ b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/init.js @@ -0,0 +1,18 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; +window.Replay = new Sentry.Replay({ + flushMinDelay: 200, + flushMaxDelay: 200, + minReplayDuration: 0, +}); + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + sampleRate: 0, + replaysSessionSampleRate: 1.0, + replaysOnErrorSampleRate: 0.0, + debug: true, + + integrations: [new Sentry.ReplayCanvas(), window.Replay], +}); diff --git a/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts new file mode 100644 index 000000000000..7326bed95ae6 --- /dev/null +++ b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts @@ -0,0 +1,28 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getReplaySnapshot, shouldSkipReplayTest } from '../../../../utils/replayHelpers'; + +sentryTest('sets up canvas when adding ReplayCanvas integration first', async ({ getLocalTestUrl, page }) => { + if (shouldSkipReplayTest()) { + sentryTest.skip(); + } + + await page.route('https://dsn.ingest.sentry.io/**/*', route => { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ id: 'test-id' }), + }); + }); + + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.goto(url); + + const replay = await getReplaySnapshot(page); + const canvasOptions = replay._options._experiments?.canvas; + expect(canvasOptions.fps).toBe(4); + expect(canvasOptions.quality).toBe(0.6); + expect(replay._hasCanvas).toBe(true); +}); diff --git a/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/init.js b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/init.js new file mode 100644 index 000000000000..1a9d5d179c4a --- /dev/null +++ b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/init.js @@ -0,0 +1,18 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; +window.Replay = new Sentry.Replay({ + flushMinDelay: 200, + flushMaxDelay: 200, + minReplayDuration: 0, +}); + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + sampleRate: 0, + replaysSessionSampleRate: 1.0, + replaysOnErrorSampleRate: 0.0, + debug: true, + + integrations: [window.Replay, new Sentry.ReplayCanvas()], +}); diff --git a/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts new file mode 100644 index 000000000000..9168864db7e0 --- /dev/null +++ b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts @@ -0,0 +1,28 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getReplaySnapshot, shouldSkipReplayTest } from '../../../../utils/replayHelpers'; + +sentryTest('sets up canvas when adding ReplayCanvas integration after Replay', async ({ getLocalTestUrl, page }) => { + if (shouldSkipReplayTest()) { + sentryTest.skip(); + } + + await page.route('https://dsn.ingest.sentry.io/**/*', route => { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ id: 'test-id' }), + }); + }); + + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.goto(url); + + const replay = await getReplaySnapshot(page); + const canvasOptions = replay._options._experiments?.canvas; + expect(canvasOptions.fps).toBe(4); + expect(canvasOptions.quality).toBe(0.6); + expect(replay._hasCanvas).toBe(true); +}); diff --git a/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/init.js b/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/init.js new file mode 100644 index 000000000000..92a463a4bc84 --- /dev/null +++ b/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/init.js @@ -0,0 +1,18 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; +window.Replay = new Sentry.Replay({ + flushMinDelay: 200, + flushMaxDelay: 200, + minReplayDuration: 0, +}); + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + sampleRate: 0, + replaysSessionSampleRate: 1.0, + replaysOnErrorSampleRate: 0.0, + debug: true, + + integrations: [window.Replay], +}); diff --git a/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/test.ts b/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/test.ts new file mode 100644 index 000000000000..b2ce69211be0 --- /dev/null +++ b/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/test.ts @@ -0,0 +1,27 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getReplaySnapshot, shouldSkipReplayTest } from '../../../../utils/replayHelpers'; + +sentryTest('does not setup up canvas without ReplayCanvas integration', async ({ getLocalTestUrl, page }) => { + if (shouldSkipReplayTest()) { + sentryTest.skip(); + } + + await page.route('https://dsn.ingest.sentry.io/**/*', route => { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ id: 'test-id' }), + }); + }); + + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.goto(url); + + const replay = await getReplaySnapshot(page); + const canvasOptions = replay._options._experiments?.canvas; + expect(canvasOptions).toBe(undefined); + expect(replay._hasCanvas).toBe(false); +}); diff --git a/packages/browser/src/index.ts b/packages/browser/src/index.ts index 97abefea8242..857538a81139 100644 --- a/packages/browser/src/index.ts +++ b/packages/browser/src/index.ts @@ -20,7 +20,7 @@ const INTEGRATIONS = { export { INTEGRATIONS as Integrations }; -export { Replay } from '@sentry/replay'; +export { Replay, ReplayCanvas } from '@sentry/replay'; export type { ReplayEventType, ReplayEventWithTime, diff --git a/packages/replay/rollup.bundle.config.mjs b/packages/replay/rollup.bundle.config.mjs index a209b8d41af4..b254dae8d8d2 100644 --- a/packages/replay/rollup.bundle.config.mjs +++ b/packages/replay/rollup.bundle.config.mjs @@ -2,12 +2,20 @@ import { makeBaseBundleConfig, makeBundleConfigVariants } from '@sentry-internal const baseBundleConfig = makeBaseBundleConfig({ bundleType: 'addon', - entrypoints: ['src/index.ts'], + entrypoints: ['src/integration.ts'], jsVersion: 'es6', licenseTitle: '@sentry/replay', outputFileBase: () => 'bundles/replay', }); -const builds = makeBundleConfigVariants(baseBundleConfig); +const baseCanvasBundleConfig = makeBaseBundleConfig({ + bundleType: 'addon', + entrypoints: ['src/canvas.ts'], + jsVersion: 'es6', + licenseTitle: '@sentry/replaycanvas', + outputFileBase: () => 'bundles/replaycanvas', +}); + +const builds = [...makeBundleConfigVariants(baseBundleConfig), ...makeBundleConfigVariants(baseCanvasBundleConfig)]; export default builds; diff --git a/packages/replay/src/canvas.ts b/packages/replay/src/canvas.ts new file mode 100644 index 000000000000..b3fe2afa60f0 --- /dev/null +++ b/packages/replay/src/canvas.ts @@ -0,0 +1,54 @@ +import { getCanvasManager } from '@sentry-internal/rrweb'; +import type { Integration } from '@sentry/types'; +import type { ReplayConfiguration } from './types'; + +interface ReplayCanvasOptions { + fps: number; + quality: number; +} + +/** An integration to add canvas recording to replay. */ +export class ReplayCanvas implements Integration { + /** + * @inheritDoc + */ + public static id: string = 'ReplayCanvas'; + + /** + * @inheritDoc + */ + public name: string; + + private _canvasOptions: ReplayCanvasOptions; + + public constructor() { + this.name = ReplayCanvas.id; + // TODO FN: Allow to configure this + // But since we haven't finalized how to configure this, this is predefined for now + // to avoid breaking changes + this._canvasOptions = { + fps: 4, + quality: 0.6, + }; + } + + /** @inheritdoc */ + public setupOnce(): void { + // noop + } + + /** + * Get the options that should be merged into replay options. + * This is what is actually called by the Replay integration to setup canvas. + */ + public getOptions(): Partial { + return { + _experiments: { + canvas: { + ...this._canvasOptions, + manager: getCanvasManager, + }, + }, + }; + } +} diff --git a/packages/replay/src/index.ts b/packages/replay/src/index.ts index 412354f1dc54..d6ea1de76732 100644 --- a/packages/replay/src/index.ts +++ b/packages/replay/src/index.ts @@ -1,4 +1,5 @@ export { Replay } from './integration'; +export { ReplayCanvas } from './canvas'; export type { ReplayEventType, diff --git a/packages/replay/src/integration.ts b/packages/replay/src/integration.ts index 80bbeca5fdf3..26cac38b1e56 100644 --- a/packages/replay/src/integration.ts +++ b/packages/replay/src/integration.ts @@ -318,6 +318,7 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`, return this._replay.getSessionId(); } + /** * Initializes replay. */ @@ -326,6 +327,12 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`, return; } + // We have to run this in _initialize, because this runs in setTimeout + // So when this runs all integrations have been added + // Before this, we cannot access integrations on the client, + // so we need to mutate the options here + this._maybeLoadFromReplayCanvasIntegration(); + this._replay.initializeSampling(); } @@ -339,6 +346,40 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`, recordingOptions: this._recordingOptions, }); } + + /** Get canvas options from ReplayCanvas integration, if it is also added. */ + private _maybeLoadFromReplayCanvasIntegration(): void { + // If already defined, skip this... + if (this._initialOptions._experiments.canvas) { + return; + } + + // To save bundle size, we skip checking for stuff here + // and instead just try-catch everything - as generally this should all be defined + /* eslint-disable @typescript-eslint/no-non-null-assertion */ + try { + const client = getClient()!; + const canvasIntegration = client.getIntegrationById!('ReplayCanvas') as Integration & { + getOptions(): Partial; + }; + if (!canvasIntegration) { + return; + } + const additionalOptions = canvasIntegration.getOptions(); + + const mergedExperimentsOptions = { + ...this._initialOptions._experiments, + ...additionalOptions._experiments, + }; + + this._initialOptions._experiments = mergedExperimentsOptions; + + this._replay!.getOptions()._experiments = mergedExperimentsOptions; + } catch { + // ignore errors here + } + /* eslint-enable @typescript-eslint/no-non-null-assertion */ + } } /** Parse Replay-related options from SDK options */ diff --git a/packages/types/src/client.ts b/packages/types/src/client.ts index c9c37349306d..9faa21f93a26 100644 --- a/packages/types/src/client.ts +++ b/packages/types/src/client.ts @@ -138,9 +138,12 @@ export interface Client { */ getEventProcessors?(): EventProcessor[]; - /** Returns the client's instance of the given integration class, it any. */ + /** Returns the client's instance of the given integration class, if it exists. */ getIntegration(integration: IntegrationClass): T | null; + /** Returns the client's instance of the given integration name, if it exists. */ + getIntegrationById?(integrationId: string): Integration | undefined; + /** * Add an integration to the client. * This can be used to e.g. lazy load integrations. From f9507efe7c97deaa1bbe9d8ebe7e3e17d2d41b7a Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Wed, 10 Jan 2024 10:01:36 -0500 Subject: [PATCH 02/48] refactor out integrations abstraction --- .../utils/replayHelpers.ts | 11 ++- packages/replay-canvas/src/canvas.ts | 76 +++++++++++++++++++ packages/replay/src/integration.ts | 10 ++- packages/replay/src/replay.ts | 23 ++++-- packages/replay/src/types/replay.ts | 14 +++- packages/replay/src/types/rrweb.ts | 2 +- 6 files changed, 123 insertions(+), 13 deletions(-) create mode 100644 packages/replay-canvas/src/canvas.ts diff --git a/dev-packages/browser-integration-tests/utils/replayHelpers.ts b/dev-packages/browser-integration-tests/utils/replayHelpers.ts index 2a951e4a215e..4b1623ed7318 100644 --- a/dev-packages/browser-integration-tests/utils/replayHelpers.ts +++ b/dev-packages/browser-integration-tests/utils/replayHelpers.ts @@ -1,4 +1,5 @@ /* eslint-disable max-lines */ +import { ReplayCanvasIntegrationOptions } from '@sentry-internal/replay-canvas'; import type { fullSnapshotEvent, incrementalSnapshotEvent } from '@sentry-internal/rrweb'; import { EventType } from '@sentry-internal/rrweb'; import type { ReplayEventWithTime } from '@sentry/browser'; @@ -174,12 +175,17 @@ export function getReplaySnapshot(page: Page): Promise<{ _isEnabled: boolean; _context: InternalEventContext; _options: ReplayPluginOptions; + _canvas: ReplayCanvasIntegrationOptions | undefined; _hasCanvas: boolean; session: Session | undefined; recordingMode: ReplayRecordingMode; }> { return page.evaluate(() => { - const replayIntegration = (window as unknown as Window & { Replay: { _replay: ReplayContainer } }).Replay; + const replayIntegration = ( + window as unknown as Window & { + Replay: { _replay: ReplayContainer & { _canvas: ReplayCanvasIntegrationOptions | undefined } }; + } + ).Replay; const replay = replayIntegration._replay; const replaySnapshot = { @@ -187,8 +193,9 @@ export function getReplaySnapshot(page: Page): Promise<{ _isEnabled: replay.isEnabled(), _context: replay.getContext(), _options: replay.getOptions(), + _canvas: replay['_canvas'], // We cannot pass the function through as this is serialized - _hasCanvas: typeof replay.getOptions()._experiments.canvas?.manager === 'function', + _hasCanvas: typeof replay['_canvas']?.getCanvasManager === 'function', session: replay.session, recordingMode: replay.recordingMode, }; diff --git a/packages/replay-canvas/src/canvas.ts b/packages/replay-canvas/src/canvas.ts new file mode 100644 index 000000000000..6f54a109861d --- /dev/null +++ b/packages/replay-canvas/src/canvas.ts @@ -0,0 +1,76 @@ +import { CanvasManager } from '@sentry-internal/rrweb'; +import { convertIntegrationFnToClass } from '@sentry/core'; +import type { CanvasManagerInterface } from '@sentry/replay'; +import type { IntegrationFn } from '@sentry/types'; + +interface ReplayCanvasOptions { + quality: 'low' | 'medium' | 'high'; +} + +export interface ReplayCanvasIntegrationOptions { + recordCanvas: true; + getCanvasManager: (options: ConstructorParameters[0]) => CanvasManagerInterface; + sampling: { + canvas: number; + }; + dataURLOptions: { + type: string; + quality: number; + }; +} + +const CANVAS_QUALITY = { + low: { + sampling: { + canvas: 1, + }, + dataURLOptions: { + type: 'image/webp', + quality: 0.25, + }, + }, + medium: { + sampling: { + canvas: 2, + }, + dataURLOptions: { + type: 'image/webp', + quality: 0.4, + }, + }, + high: { + sampling: { + canvas: 4, + }, + dataURLOptions: { + type: 'image/webp', + quality: 0.5, + }, + }, +}; + +const INTEGRATION_NAME = 'ReplayCanvas'; + +/** + * An integration to add canvas recording to replay. + */ +const replayCanvasIntegration = ((options: Partial = {}) => { + const _canvasOptions = { + quality: options.quality || 'medium', + }; + + return { + name: INTEGRATION_NAME, + getOptions(): ReplayCanvasIntegrationOptions { + const { quality } = _canvasOptions; + + return { + recordCanvas: true, + getCanvasManager: (options: ConstructorParameters[0]) => new CanvasManager(options), + ...(CANVAS_QUALITY[quality || 'medium'] || CANVAS_QUALITY.medium), + }; + }, + }; +}) satisfies IntegrationFn; + +export const ReplayCanvas = convertIntegrationFnToClass(INTEGRATION_NAME, replayCanvasIntegration); diff --git a/packages/replay/src/integration.ts b/packages/replay/src/integration.ts index 26cac38b1e56..a8a58d46d55b 100644 --- a/packages/replay/src/integration.ts +++ b/packages/replay/src/integration.ts @@ -10,7 +10,13 @@ import { MIN_REPLAY_DURATION_LIMIT, } from './constants'; import { ReplayContainer } from './replay'; -import type { RecordingOptions, ReplayConfiguration, ReplayPluginOptions, SendBufferedReplayOptions } from './types'; +import type { + RecordingOptions, + ReplayCanvasIntegrationOptions, + ReplayConfiguration, + ReplayPluginOptions, + SendBufferedReplayOptions, +} from './types'; import { getPrivacyOptions } from './util/getPrivacyOptions'; import { maskAttribute } from './util/maskAttribute'; @@ -360,7 +366,7 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`, try { const client = getClient()!; const canvasIntegration = client.getIntegrationById!('ReplayCanvas') as Integration & { - getOptions(): Partial; + getOptions(): ReplayCanvasIntegrationOptions; }; if (!canvasIntegration) { return; diff --git a/packages/replay/src/replay.ts b/packages/replay/src/replay.ts index 27513fe5643d..748bca424784 100644 --- a/packages/replay/src/replay.ts +++ b/packages/replay/src/replay.ts @@ -39,6 +39,7 @@ import type { RecordingEvent, RecordingOptions, ReplayBreadcrumbFrame, + ReplayCanvasIntegrationOptions, ReplayContainer as ReplayContainerInterface, ReplayPerformanceEntry, ReplayPluginOptions, @@ -145,6 +146,11 @@ export class ReplayContainer implements ReplayContainerInterface { private _context: InternalEventContext; + /** + * Internal use for canvas recording options + */ + private _canvas: ReplayCanvasIntegrationOptions | undefined; + public constructor({ options, recordingOptions, @@ -338,7 +344,8 @@ export class ReplayContainer implements ReplayContainerInterface { */ public startRecording(): void { try { - const canvas = this._options._experiments.canvas; + const canvasOptions = this._canvas; + this._stopRecording = record({ ...this._recordingOptions, // When running in error sampling mode, we need to overwrite `checkoutEveryNms` @@ -347,12 +354,14 @@ export class ReplayContainer implements ReplayContainerInterface { ...(this.recordingMode === 'buffer' && { checkoutEveryNms: BUFFER_CHECKOUT_TIME }), emit: getHandleRecordingEmit(this), onMutation: this._onMutationHandler, - ...(canvas && - canvas.manager && { - recordCanvas: true, - getCanvasManager: canvas.manager, - ...(CANVAS_QUALITY[canvas.quality || 'medium'] || CANVAS_QUALITY.medium), - }), + ...(canvasOptions + ? { + recordCanvas: canvasOptions.recordCanvas, + getCanvasManager: canvasOptions.getCanvasManager, + sampling: canvasOptions.sampling, + dataURLOptions: canvasOptions.dataURLOptions, + } + : {}), }); } catch (err) { this._handleException(err); diff --git a/packages/replay/src/types/replay.ts b/packages/replay/src/types/replay.ts index 1b2b19d4d4cd..1f725d8d3d8c 100644 --- a/packages/replay/src/types/replay.ts +++ b/packages/replay/src/types/replay.ts @@ -14,7 +14,7 @@ import type { SKIPPED, THROTTLED } from '../util/throttle'; import type { AllPerformanceEntry, AllPerformanceEntryData, ReplayPerformanceEntry } from './performance'; import type { ReplayFrameEvent } from './replayFrame'; import type { ReplayNetworkRequestOrResponse } from './request'; -import type { CanvasManagerInterface, GetCanvasManagerOptions, ReplayEventWithTime, RrwebRecordOptions } from './rrweb'; +import type { CanvasManagerInterface, CanvasManagerOptions, ReplayEventWithTime, RrwebRecordOptions } from './rrweb'; export type RecordingEvent = ReplayFrameEvent | ReplayEventWithTime; export type RecordingOptions = RrwebRecordOptions; @@ -539,3 +539,15 @@ export interface SlowClickConfig { scrollTimeout: number; ignoreSelector: string; } + +export interface ReplayCanvasIntegrationOptions { + recordCanvas: true; + getCanvasManager: (options: CanvasManagerOptions) => CanvasManagerInterface; + sampling: { + canvas: number; + }; + dataURLOptions: { + type: string; + quality: number; + }; +} diff --git a/packages/replay/src/types/rrweb.ts b/packages/replay/src/types/rrweb.ts index bbef4f94903f..ae5a8ca3bac6 100644 --- a/packages/replay/src/types/rrweb.ts +++ b/packages/replay/src/types/rrweb.ts @@ -53,7 +53,7 @@ export interface CanvasManagerInterface { unlock(): void; } -export interface GetCanvasManagerOptions { +export interface CanvasManagerOptions { recordCanvas: boolean; blockClass: string | RegExp; blockSelector: string | null; From 1e919178294e12f8110ba24a35fe5cfe2bd47ea9 Mon Sep 17 00:00:00 2001 From: Catherine Lee <55311782+c298lee@users.noreply.github.com> Date: Thu, 11 Jan 2024 16:12:25 -0500 Subject: [PATCH 03/48] update --- packages/replay-canvas/src/canvas.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/replay-canvas/src/canvas.ts b/packages/replay-canvas/src/canvas.ts index 6f54a109861d..88ca7d5e8361 100644 --- a/packages/replay-canvas/src/canvas.ts +++ b/packages/replay-canvas/src/canvas.ts @@ -59,6 +59,8 @@ const replayCanvasIntegration = ((options: Partial = {}) => quality: options.quality || 'medium', }; + let _canvasManager: CanvasManager; + return { name: INTEGRATION_NAME, getOptions(): ReplayCanvasIntegrationOptions { @@ -66,10 +68,14 @@ const replayCanvasIntegration = ((options: Partial = {}) => return { recordCanvas: true, - getCanvasManager: (options: ConstructorParameters[0]) => new CanvasManager(options), + getCanvasManager: (options: CanvasManagerOptions) => _canvasManager = new CanvasManager(options), ...(CANVAS_QUALITY[quality || 'medium'] || CANVAS_QUALITY.medium), }; }, + snapshot(canvasElement?: HTMLCanvasElement):void { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + _canvasManager.snapshot(canvasElement); + } }; }) satisfies IntegrationFn; From e1ec42e77fe139bd9800b0fef822de30a8eebae2 Mon Sep 17 00:00:00 2001 From: Catherine Lee <55311782+c298lee@users.noreply.github.com> Date: Thu, 11 Jan 2024 17:09:38 -0500 Subject: [PATCH 04/48] it works --- packages/replay-canvas/src/canvas.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/replay-canvas/src/canvas.ts b/packages/replay-canvas/src/canvas.ts index 88ca7d5e8361..96dc5b4fae4f 100644 --- a/packages/replay-canvas/src/canvas.ts +++ b/packages/replay-canvas/src/canvas.ts @@ -72,7 +72,7 @@ const replayCanvasIntegration = ((options: Partial = {}) => ...(CANVAS_QUALITY[quality || 'medium'] || CANVAS_QUALITY.medium), }; }, - snapshot(canvasElement?: HTMLCanvasElement):void { + async snapshot(canvasElement?: HTMLCanvasElement) { // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access _canvasManager.snapshot(canvasElement); } From 16d99e6294f6457f32482a8e4b6ddb1e97331425 Mon Sep 17 00:00:00 2001 From: Catherine Lee <55311782+c298lee@users.noreply.github.com> Date: Fri, 12 Jan 2024 10:44:01 -0500 Subject: [PATCH 05/48] add manual snapshot option --- packages/replay/src/replay.ts | 1 + packages/replay/src/types/replay.ts | 1 + packages/replay/src/types/rrweb.ts | 1 + 3 files changed, 3 insertions(+) diff --git a/packages/replay/src/replay.ts b/packages/replay/src/replay.ts index 748bca424784..201403201622 100644 --- a/packages/replay/src/replay.ts +++ b/packages/replay/src/replay.ts @@ -356,6 +356,7 @@ export class ReplayContainer implements ReplayContainerInterface { onMutation: this._onMutationHandler, ...(canvasOptions ? { + isManualSnapshot: canvasOptions.enableManualSnapshot, recordCanvas: canvasOptions.recordCanvas, getCanvasManager: canvasOptions.getCanvasManager, sampling: canvasOptions.sampling, diff --git a/packages/replay/src/types/replay.ts b/packages/replay/src/types/replay.ts index 1f725d8d3d8c..c9a75f209f4b 100644 --- a/packages/replay/src/types/replay.ts +++ b/packages/replay/src/types/replay.ts @@ -541,6 +541,7 @@ export interface SlowClickConfig { } export interface ReplayCanvasIntegrationOptions { + enableManualSnapshot?: boolean; recordCanvas: true; getCanvasManager: (options: CanvasManagerOptions) => CanvasManagerInterface; sampling: { diff --git a/packages/replay/src/types/rrweb.ts b/packages/replay/src/types/rrweb.ts index ae5a8ca3bac6..15d5eb95f010 100644 --- a/packages/replay/src/types/rrweb.ts +++ b/packages/replay/src/types/rrweb.ts @@ -55,6 +55,7 @@ export interface CanvasManagerInterface { export interface CanvasManagerOptions { recordCanvas: boolean; + isManualSnapshot?: boolean; blockClass: string | RegExp; blockSelector: string | null; unblockSelector: string | null; From f74f12bf419497efad741f4d9419a3dd21555416 Mon Sep 17 00:00:00 2001 From: Catherine Lee <55311782+c298lee@users.noreply.github.com> Date: Fri, 12 Jan 2024 10:44:23 -0500 Subject: [PATCH 06/48] add manual snapshot option --- packages/replay-canvas/src/canvas.ts | 3 ++ packages/replay-canvas/test/canvas.test.ts | 34 ++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 packages/replay-canvas/test/canvas.test.ts diff --git a/packages/replay-canvas/src/canvas.ts b/packages/replay-canvas/src/canvas.ts index 96dc5b4fae4f..d8232471e6e3 100644 --- a/packages/replay-canvas/src/canvas.ts +++ b/packages/replay-canvas/src/canvas.ts @@ -4,10 +4,12 @@ import type { CanvasManagerInterface } from '@sentry/replay'; import type { IntegrationFn } from '@sentry/types'; interface ReplayCanvasOptions { + enableManualSnapshot?: boolean; quality: 'low' | 'medium' | 'high'; } export interface ReplayCanvasIntegrationOptions { + enableManualSnapshot?: boolean; recordCanvas: true; getCanvasManager: (options: ConstructorParameters[0]) => CanvasManagerInterface; sampling: { @@ -67,6 +69,7 @@ const replayCanvasIntegration = ((options: Partial = {}) => const { quality } = _canvasOptions; return { + enableManualSnapshot: options.enableManualSnapshot, recordCanvas: true, getCanvasManager: (options: CanvasManagerOptions) => _canvasManager = new CanvasManager(options), ...(CANVAS_QUALITY[quality || 'medium'] || CANVAS_QUALITY.medium), diff --git a/packages/replay-canvas/test/canvas.test.ts b/packages/replay-canvas/test/canvas.test.ts new file mode 100644 index 000000000000..346df7b4a89d --- /dev/null +++ b/packages/replay-canvas/test/canvas.test.ts @@ -0,0 +1,34 @@ +import { ReplayCanvas } from '../src/canvas'; + +it('initializes with default options', () => { + const rc = new ReplayCanvas(); + + expect(rc.getOptions()).toEqual({ + recordCanvas: true, + getCanvasManager: expect.any(Function), + sampling: { + canvas: 2, + }, + dataURLOptions: { + type: 'image/webp', + quality: 0.4, + }, + }); +}); + +it('initializes with quality option and manual snapshot', () => { + const rc = new ReplayCanvas({ enableManualSnapshot: true, quality: 'low' }); + + expect(rc.getOptions()).toEqual({ + enableManualSnapshot: true, + recordCanvas: true, + getCanvasManager: expect.any(Function), + sampling: { + canvas: 1, + }, + dataURLOptions: { + type: 'image/webp', + quality: 0.25, + }, + }); +}); From fd5c9e68a2ad60d01e11527822a26573edc47593 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Thu, 4 Jan 2024 16:48:07 +0100 Subject: [PATCH 07/48] feat(replay): Add `ReplayCanvas` integration Adding this integration in addition to `Replay` will set up canvas recording. --- .../suites/replay/canvas/template.html | 9 ++++ .../canvas/withCanvasIntegrationFirst/init.js | 18 +++++++ .../canvas/withCanvasIntegrationFirst/test.ts | 28 ++++++++++ .../withCanvasIntegrationSecond/init.js | 18 +++++++ .../withCanvasIntegrationSecond/test.ts | 28 ++++++++++ .../canvas/withoutCanvasIntegration/init.js | 18 +++++++ .../canvas/withoutCanvasIntegration/test.ts | 27 ++++++++++ packages/browser/src/index.ts | 2 +- packages/replay/rollup.bundle.config.mjs | 12 ++++- packages/replay/src/canvas.ts | 54 +++++++++++++++++++ packages/replay/src/index.ts | 1 + 11 files changed, 212 insertions(+), 3 deletions(-) create mode 100644 packages/browser-integration-tests/suites/replay/canvas/template.html create mode 100644 packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/init.js create mode 100644 packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts create mode 100644 packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/init.js create mode 100644 packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts create mode 100644 packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/init.js create mode 100644 packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/test.ts create mode 100644 packages/replay/src/canvas.ts diff --git a/packages/browser-integration-tests/suites/replay/canvas/template.html b/packages/browser-integration-tests/suites/replay/canvas/template.html new file mode 100644 index 000000000000..2b3e2f0b27b4 --- /dev/null +++ b/packages/browser-integration-tests/suites/replay/canvas/template.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/init.js b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/init.js new file mode 100644 index 000000000000..fa3248066150 --- /dev/null +++ b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/init.js @@ -0,0 +1,18 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; +window.Replay = new Sentry.Replay({ + flushMinDelay: 200, + flushMaxDelay: 200, + minReplayDuration: 0, +}); + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + sampleRate: 0, + replaysSessionSampleRate: 1.0, + replaysOnErrorSampleRate: 0.0, + debug: true, + + integrations: [new Sentry.ReplayCanvas(), window.Replay], +}); diff --git a/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts new file mode 100644 index 000000000000..7326bed95ae6 --- /dev/null +++ b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts @@ -0,0 +1,28 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getReplaySnapshot, shouldSkipReplayTest } from '../../../../utils/replayHelpers'; + +sentryTest('sets up canvas when adding ReplayCanvas integration first', async ({ getLocalTestUrl, page }) => { + if (shouldSkipReplayTest()) { + sentryTest.skip(); + } + + await page.route('https://dsn.ingest.sentry.io/**/*', route => { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ id: 'test-id' }), + }); + }); + + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.goto(url); + + const replay = await getReplaySnapshot(page); + const canvasOptions = replay._options._experiments?.canvas; + expect(canvasOptions.fps).toBe(4); + expect(canvasOptions.quality).toBe(0.6); + expect(replay._hasCanvas).toBe(true); +}); diff --git a/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/init.js b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/init.js new file mode 100644 index 000000000000..1a9d5d179c4a --- /dev/null +++ b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/init.js @@ -0,0 +1,18 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; +window.Replay = new Sentry.Replay({ + flushMinDelay: 200, + flushMaxDelay: 200, + minReplayDuration: 0, +}); + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + sampleRate: 0, + replaysSessionSampleRate: 1.0, + replaysOnErrorSampleRate: 0.0, + debug: true, + + integrations: [window.Replay, new Sentry.ReplayCanvas()], +}); diff --git a/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts new file mode 100644 index 000000000000..9168864db7e0 --- /dev/null +++ b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts @@ -0,0 +1,28 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getReplaySnapshot, shouldSkipReplayTest } from '../../../../utils/replayHelpers'; + +sentryTest('sets up canvas when adding ReplayCanvas integration after Replay', async ({ getLocalTestUrl, page }) => { + if (shouldSkipReplayTest()) { + sentryTest.skip(); + } + + await page.route('https://dsn.ingest.sentry.io/**/*', route => { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ id: 'test-id' }), + }); + }); + + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.goto(url); + + const replay = await getReplaySnapshot(page); + const canvasOptions = replay._options._experiments?.canvas; + expect(canvasOptions.fps).toBe(4); + expect(canvasOptions.quality).toBe(0.6); + expect(replay._hasCanvas).toBe(true); +}); diff --git a/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/init.js b/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/init.js new file mode 100644 index 000000000000..92a463a4bc84 --- /dev/null +++ b/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/init.js @@ -0,0 +1,18 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; +window.Replay = new Sentry.Replay({ + flushMinDelay: 200, + flushMaxDelay: 200, + minReplayDuration: 0, +}); + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + sampleRate: 0, + replaysSessionSampleRate: 1.0, + replaysOnErrorSampleRate: 0.0, + debug: true, + + integrations: [window.Replay], +}); diff --git a/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/test.ts b/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/test.ts new file mode 100644 index 000000000000..b2ce69211be0 --- /dev/null +++ b/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/test.ts @@ -0,0 +1,27 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getReplaySnapshot, shouldSkipReplayTest } from '../../../../utils/replayHelpers'; + +sentryTest('does not setup up canvas without ReplayCanvas integration', async ({ getLocalTestUrl, page }) => { + if (shouldSkipReplayTest()) { + sentryTest.skip(); + } + + await page.route('https://dsn.ingest.sentry.io/**/*', route => { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ id: 'test-id' }), + }); + }); + + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.goto(url); + + const replay = await getReplaySnapshot(page); + const canvasOptions = replay._options._experiments?.canvas; + expect(canvasOptions).toBe(undefined); + expect(replay._hasCanvas).toBe(false); +}); diff --git a/packages/browser/src/index.ts b/packages/browser/src/index.ts index e97b6e98b816..b8692c7aaf8e 100644 --- a/packages/browser/src/index.ts +++ b/packages/browser/src/index.ts @@ -21,7 +21,7 @@ const INTEGRATIONS = { export { INTEGRATIONS as Integrations }; -export { Replay } from '@sentry/replay'; +export { Replay, ReplayCanvas } from '@sentry/replay'; export type { ReplayEventType, ReplayEventWithTime, diff --git a/packages/replay/rollup.bundle.config.mjs b/packages/replay/rollup.bundle.config.mjs index a209b8d41af4..b254dae8d8d2 100644 --- a/packages/replay/rollup.bundle.config.mjs +++ b/packages/replay/rollup.bundle.config.mjs @@ -2,12 +2,20 @@ import { makeBaseBundleConfig, makeBundleConfigVariants } from '@sentry-internal const baseBundleConfig = makeBaseBundleConfig({ bundleType: 'addon', - entrypoints: ['src/index.ts'], + entrypoints: ['src/integration.ts'], jsVersion: 'es6', licenseTitle: '@sentry/replay', outputFileBase: () => 'bundles/replay', }); -const builds = makeBundleConfigVariants(baseBundleConfig); +const baseCanvasBundleConfig = makeBaseBundleConfig({ + bundleType: 'addon', + entrypoints: ['src/canvas.ts'], + jsVersion: 'es6', + licenseTitle: '@sentry/replaycanvas', + outputFileBase: () => 'bundles/replaycanvas', +}); + +const builds = [...makeBundleConfigVariants(baseBundleConfig), ...makeBundleConfigVariants(baseCanvasBundleConfig)]; export default builds; diff --git a/packages/replay/src/canvas.ts b/packages/replay/src/canvas.ts new file mode 100644 index 000000000000..b3fe2afa60f0 --- /dev/null +++ b/packages/replay/src/canvas.ts @@ -0,0 +1,54 @@ +import { getCanvasManager } from '@sentry-internal/rrweb'; +import type { Integration } from '@sentry/types'; +import type { ReplayConfiguration } from './types'; + +interface ReplayCanvasOptions { + fps: number; + quality: number; +} + +/** An integration to add canvas recording to replay. */ +export class ReplayCanvas implements Integration { + /** + * @inheritDoc + */ + public static id: string = 'ReplayCanvas'; + + /** + * @inheritDoc + */ + public name: string; + + private _canvasOptions: ReplayCanvasOptions; + + public constructor() { + this.name = ReplayCanvas.id; + // TODO FN: Allow to configure this + // But since we haven't finalized how to configure this, this is predefined for now + // to avoid breaking changes + this._canvasOptions = { + fps: 4, + quality: 0.6, + }; + } + + /** @inheritdoc */ + public setupOnce(): void { + // noop + } + + /** + * Get the options that should be merged into replay options. + * This is what is actually called by the Replay integration to setup canvas. + */ + public getOptions(): Partial { + return { + _experiments: { + canvas: { + ...this._canvasOptions, + manager: getCanvasManager, + }, + }, + }; + } +} diff --git a/packages/replay/src/index.ts b/packages/replay/src/index.ts index 8e8a5d55579a..60d297434924 100644 --- a/packages/replay/src/index.ts +++ b/packages/replay/src/index.ts @@ -1,4 +1,5 @@ export { Replay } from './integration'; +export { ReplayCanvas } from './canvas'; export type { ReplayConfiguration, From 1b2b67050a19b16589eb93bff65479d945086d8c Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Thu, 4 Jan 2024 14:34:51 -0500 Subject: [PATCH 08/48] new quality options --- packages/replay/src/canvas.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/replay/src/canvas.ts b/packages/replay/src/canvas.ts index b3fe2afa60f0..a35bf323b961 100644 --- a/packages/replay/src/canvas.ts +++ b/packages/replay/src/canvas.ts @@ -3,8 +3,7 @@ import type { Integration } from '@sentry/types'; import type { ReplayConfiguration } from './types'; interface ReplayCanvasOptions { - fps: number; - quality: number; + quality: 'low' | 'medium' | 'high'; } /** An integration to add canvas recording to replay. */ @@ -21,14 +20,10 @@ export class ReplayCanvas implements Integration { private _canvasOptions: ReplayCanvasOptions; - public constructor() { + public constructor(options?: Partial) { this.name = ReplayCanvas.id; - // TODO FN: Allow to configure this - // But since we haven't finalized how to configure this, this is predefined for now - // to avoid breaking changes this._canvasOptions = { - fps: 4, - quality: 0.6, + quality: options && options.quality || 'medium', }; } @@ -47,6 +42,7 @@ export class ReplayCanvas implements Integration { canvas: { ...this._canvasOptions, manager: getCanvasManager, + quality: this._canvasOptions.quality, }, }, }; From 1b21a3743b906a460f25e6c87ad897f02866b29a Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Fri, 5 Jan 2024 11:19:54 -0500 Subject: [PATCH 09/48] fix --- packages/replay/src/canvas.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/replay/src/canvas.ts b/packages/replay/src/canvas.ts index a35bf323b961..d4b869c2f024 100644 --- a/packages/replay/src/canvas.ts +++ b/packages/replay/src/canvas.ts @@ -23,7 +23,7 @@ export class ReplayCanvas implements Integration { public constructor(options?: Partial) { this.name = ReplayCanvas.id; this._canvasOptions = { - quality: options && options.quality || 'medium', + quality: (options && options.quality) || 'medium', }; } From 446aea7976a2cee11a59b4e3ce7b41f4313865b1 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Mon, 8 Jan 2024 10:19:23 -0500 Subject: [PATCH 10/48] create replay-canvas package --- packages/browser/src/index.ts | 2 +- packages/replay-canvas/MIGRATION.md | 149 +++++++++++++ packages/replay-canvas/jest.config.ts | 17 ++ packages/replay-canvas/jest.setup.ts | 269 +++++++++++++++++++++++ packages/replay-canvas/test/index.ts | 4 + packages/replay/rollup.bundle.config.mjs | 10 +- packages/replay/src/canvas.ts | 50 ----- packages/replay/src/index.ts | 1 - 8 files changed, 441 insertions(+), 61 deletions(-) create mode 100644 packages/replay-canvas/MIGRATION.md create mode 100644 packages/replay-canvas/jest.config.ts create mode 100644 packages/replay-canvas/jest.setup.ts create mode 100644 packages/replay-canvas/test/index.ts delete mode 100644 packages/replay/src/canvas.ts diff --git a/packages/browser/src/index.ts b/packages/browser/src/index.ts index b8692c7aaf8e..e97b6e98b816 100644 --- a/packages/browser/src/index.ts +++ b/packages/browser/src/index.ts @@ -21,7 +21,7 @@ const INTEGRATIONS = { export { INTEGRATIONS as Integrations }; -export { Replay, ReplayCanvas } from '@sentry/replay'; +export { Replay } from '@sentry/replay'; export type { ReplayEventType, ReplayEventWithTime, diff --git a/packages/replay-canvas/MIGRATION.md b/packages/replay-canvas/MIGRATION.md new file mode 100644 index 000000000000..ba6326939970 --- /dev/null +++ b/packages/replay-canvas/MIGRATION.md @@ -0,0 +1,149 @@ +# End of Replay Beta + +Sentry Replay is now out of Beta. This means that the usual stability guarantees apply. + +Because of experimentation and rapid iteration, during the Beta period some bugs and problems came up which have since been fixed/improved. +We **strongly** recommend anyone using Replay in a version before 7.39.0 to update to 7.39.0 or newer, in order to prevent running Replay with known problems that have since been fixed. + +Below you can find a list of relevant replay issues that have been resolved until 7.39.0: + +## New features / improvements + +- Remove `autoplay` attribute from audio/video tags ([#59](https://github.com/getsentry/rrweb/pull/59)) +- Exclude fetching scripts that use `` ([#52](https://github.com/getsentry/rrweb/pull/52)) +- With maskAllText, mask the attributes: placeholder, title, `aria-label` +- Lower the flush max delay from 15 seconds to 5 seconds (#6761) +- Stop recording when retry fails (#6765) +- Stop without retry when receiving bad API response (#6773) +- Send client_report when replay sending fails (#7093) +- Stop recording when hitting a rate limit (#7018) +- Allow Replay to be used in Electron renderers with nodeIntegration enabled (#6644) +- Do not renew session in error mode (#6948) +- Remove default sample rates for replay (#6878) +- Add `flush` method to integration (#6776) +- Improve compression worker & fallback behavior (#6988, #6936, #6827) +- Improve error handling (#7087, #7094, #7010, getsentry/rrweb#16, #6856) +- Add more default block filters (#7233) + +## Fixes + +- Fix masking inputs on change when `maskAllInputs:false` ([#61](https://github.com/getsentry/rrweb/pull/61)) +- More robust `rootShadowHost` check ([#50](https://github.com/getsentry/rrweb/pull/50)) +- Fix duplicated textarea value ([#62](https://github.com/getsentry/rrweb/pull/62)) +- Handle removed attributes ([#65](https://github.com/getsentry/rrweb/pull/65)) +- Change LCP calculation (#7187, #7225) +- Fix debounced flushes not respecting `maxWait` (#7207, #7208) +- Fix svgs not getting unblocked (#7132) +- Fix missing fetch/xhr requests (#7134) +- Fix feature detection of PerformanceObserver (#7029) +- Fix `checkoutEveryNms` (#6722) +- Fix incorrect uncompressed recording size due to encoding (#6740) +- Ensure dropping replays works (#6522) +- Envelope send should be awaited in try/catch (#6625) +- Improve handling of `maskAllText` selector (#6637) + +# Upgrading Replay from 7.34.0 to 7.35.0 - #6645 + +This release will remove the ability to change the default rrweb recording options (outside of privacy options). The following are the new configuration values all replays will use: +`slimDOMOptions: 'all'` - Removes `script`, comments, `favicon`, whitespace in `head`, and a few `meta` tags in `head` +`recordCanvas: false` - This option did not do anything as playback of recorded canvas means we would have to remove the playback sandbox (which is a security concern). +`inlineStylesheet: true` - Inlines styles into the recording itself instead of attempting to fetch it remotely. This means that styles in the replay will reflect the styles at the time of recording and not the current styles of the remote stylesheet. +`collectFonts: true` - Attempts to load custom fonts. +`inlineImages: false` - Does not inline images to recording and instead loads the asset remotely. During playback, images may not load due to CORS (add sentry.io as an origin). + +Additionally, we have streamlined the privacy options. The following table lists the deprecated value, and what it is replaced by: + +| deprecated key | replaced by | description | +| ---------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| maskInputOptions | mask | Use CSS selectors in `mask` in order to mask all inputs of a certain type. For example, `input[type="address"]` | +| blockSelector | block | The selector(s) can be moved directly in the `block` array. | +| blockClass | block | Convert the class name to a CSS selector and add to `block` array. For example, `first-name` becomes `.first-name`. Regexes can be moved as-is. | +| maskClass | mask | Convert the class name to a CSS selector and add to `mask` array. For example, `first-name` becomes `.first-name`. Regexes can be moved as-is. | +| maskSelector | mask | The selector(s) can be moved directly in the `mask` array. | +| ignoreClass | ignore | Convert the class name to a CSS selector and add to `ignore` array. For example, `first-name` becomes `.first-name`. Regexes can be moved as-is. | + +# Upgrading Replay from 7.31.0 to 7.32.0 + +In 7.32.0, we have removed the default values for the replay sample rates. +Previously, they were: + +* `replaysSessionSampleRate: 0.1` +* `replaysOnErrorSampleRate: 1.0` + +Now, you have to explicitly set the sample rates, otherwise they default to 0. + +# Upgrading Replay from 0.6.x to 7.24.0 + +The Sentry Replay integration was moved to the Sentry JavaScript SDK monorepo. Hence we're jumping from version 0.x to the monorepo's 7.x version which is shared across all JS SDK packages. + +## Replay sample rates are defined on top level (https://github.com/getsentry/sentry-javascript/issues/6351) + +Instead of defining the sample rates on the integration like this: + +```js +Sentry.init({ + dsn: '__DSN__', + integrations: [ + new Replay({ + sessionSampleRate: 0.1, + errorSampleRate: 1.0, + }) + ], + // ... +}); +``` + +They are now defined on the top level of the SDK: + +```js +Sentry.init({ + dsn: '__DSN__', + replaysSessionSampleRate: 0.1, + replaysOnErrorSampleRate: 1.0, + integrations: [ + new Replay({ + // other replay config still goes in here + }) + ], +}); +``` + +Note that the sample rate options inside of `new Replay({})` have been deprecated and will be removed in a future update. + +## Removed deprecated options (https://github.com/getsentry/sentry-javascript/pull/6370) + +Two options, which have been deprecated for some time, have been removed: + +* `replaysSamplingRate` - instead use `sessionSampleRate` +* `captureOnlyOnError` - instead use `errorSampleRate` + +## New NPM package structure (https://github.com/getsentry/sentry-javascript/issues/6280) + +The internal structure of the npm package has changed. This is unlikely to affect you, unless you have imported something from e.g.: + +```js +import something from '@sentry/replay/submodule'; +``` + +If you only imported from `@sentry/replay`, this will not affect you. + +## Changed type name from `IEventBuffer` to `EventBuffer` (https://github.com/getsentry/sentry-javascript/pull/6416) + +It is highly unlikely to affect anybody, but the type `IEventBuffer` was renamed to `EventBuffer` for consistency. +Unless you manually imported this and used it somewhere in your codebase, this will not affect you. + +## Session object is now a plain object (https://github.com/getsentry/sentry-javascript/pull/6417) + +The `Session` object exported from Replay is now a plain object, instead of a class. +This should not affect you unless you specifically accessed this class & did custom things with it. + +## Reduce public API of Replay integration (https://github.com/getsentry/sentry-javascript/pull/6407) + +The result of `new Replay()` now has a much more limited public API. Only the following methods are exposed: + +```js +const replay = new Replay(); + +replay.start(); +replay.stop(); +``` diff --git a/packages/replay-canvas/jest.config.ts b/packages/replay-canvas/jest.config.ts new file mode 100644 index 000000000000..90a3cf471f8d --- /dev/null +++ b/packages/replay-canvas/jest.config.ts @@ -0,0 +1,17 @@ +import type { Config } from '@jest/types'; +import { jsWithTs as jsWithTsPreset } from 'ts-jest/presets'; + +export default async (): Promise => { + return { + ...jsWithTsPreset, + globals: { + 'ts-jest': { + tsconfig: '/tsconfig.test.json', + }, + __DEBUG_BUILD__: true, + }, + setupFilesAfterEnv: ['./jest.setup.ts'], + testEnvironment: 'jsdom', + testMatch: ['/test/**/*(*.)@(spec|test).ts'], + }; +}; diff --git a/packages/replay-canvas/jest.setup.ts b/packages/replay-canvas/jest.setup.ts new file mode 100644 index 000000000000..09e6c68a4483 --- /dev/null +++ b/packages/replay-canvas/jest.setup.ts @@ -0,0 +1,269 @@ +import { TextEncoder } from 'util'; +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +import { getCurrentHub } from '@sentry/core'; +import type { ReplayRecordingData, Transport } from '@sentry/types'; +import * as SentryUtils from '@sentry/utils'; + +import type { ReplayContainer, Session } from './src/types'; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +(global as any).TextEncoder = TextEncoder; + +type MockTransport = jest.MockedFunction; + +jest.spyOn(SentryUtils, 'isBrowser').mockImplementation(() => true); + +type EnvelopeHeader = { + event_id: string; + sent_at: string; + sdk: { + name: string; + version?: string; + }; +}; + +type ReplayEventHeader = { type: 'replay_event' }; +type ReplayEventPayload = Record; +type RecordingHeader = { type: 'replay_recording'; length: number }; +type RecordingPayloadHeader = Record; +type SentReplayExpected = { + envelopeHeader?: EnvelopeHeader; + replayEventHeader?: ReplayEventHeader; + replayEventPayload?: ReplayEventPayload; + recordingHeader?: RecordingHeader; + recordingPayloadHeader?: RecordingPayloadHeader; + recordingData?: ReplayRecordingData; +}; + +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type +const toHaveSameSession = function (received: jest.Mocked, expected: undefined | Session) { + const pass = this.equals(received.session?.id, expected?.id) as boolean; + + const options = { + isNot: this.isNot, + promise: this.promise, + }; + + return { + pass, + message: () => + `${this.utils.matcherHint( + 'toHaveSameSession', + undefined, + undefined, + options, + )}\n\n${this.utils.printDiffOrStringify(expected, received.session, 'Expected', 'Received')}`, + }; +}; + +type Result = { + passed: boolean; + key: string; + expectedVal: SentReplayExpected[keyof SentReplayExpected]; + actualVal: SentReplayExpected[keyof SentReplayExpected]; +}; +type Call = [ + EnvelopeHeader, + [ + [ReplayEventHeader | undefined, ReplayEventPayload | undefined], + [RecordingHeader | undefined, RecordingPayloadHeader | undefined], + ], +]; +type CheckCallForSentReplayResult = { pass: boolean; call: Call | undefined; results: Result[] }; + +function checkCallForSentReplay( + call: Call | undefined, + expected?: SentReplayExpected | { sample: SentReplayExpected; inverse: boolean }, +): CheckCallForSentReplayResult { + const envelopeHeader = call?.[0]; + const envelopeItems = call?.[1] || [[], []]; + const [[replayEventHeader, replayEventPayload], [recordingHeader, recordingPayload] = []] = envelopeItems; + + // @ts-expect-error recordingPayload is always a string in our tests + const [recordingPayloadHeader, recordingData] = recordingPayload?.split('\n') || []; + + const actualObj: Required = { + // @ts-expect-error Custom envelope + envelopeHeader: envelopeHeader, + // @ts-expect-error Custom envelope + replayEventHeader: replayEventHeader, + // @ts-expect-error Custom envelope + replayEventPayload: replayEventPayload, + // @ts-expect-error Custom envelope + recordingHeader: recordingHeader, + recordingPayloadHeader: recordingPayloadHeader && JSON.parse(recordingPayloadHeader), + recordingData, + }; + + const isObjectContaining = expected && 'sample' in expected && 'inverse' in expected; + const expectedObj = isObjectContaining + ? (expected as { sample: SentReplayExpected }).sample + : (expected as SentReplayExpected); + + if (isObjectContaining) { + console.warn('`expect.objectContaining` is unnecessary when using the `toHaveSentReplay` matcher'); + } + + const results = expected + ? Object.keys(expectedObj) + .map(key => { + const actualVal = actualObj[key as keyof SentReplayExpected]; + const expectedVal = expectedObj[key as keyof SentReplayExpected]; + const passed = !expectedVal || this.equals(actualVal, expectedVal); + + return { passed, key, expectedVal, actualVal }; + }) + .filter(({ passed }) => !passed) + : []; + + const pass = Boolean(call && (!expected || results.length === 0)); + + return { + pass, + call, + results, + }; +} + +/** + * Only want calls that send replay events, i.e. ignore error events + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function getReplayCalls(calls: any[][][]): any[][][] { + return calls + .map(call => { + const arg = call[0]; + if (arg.length !== 2) { + return []; + } + + if (!arg[1][0].find(({ type }: { type: string }) => ['replay_event', 'replay_recording'].includes(type))) { + return []; + } + + return [arg]; + }) + .filter(Boolean); +} + +/** + * Checks all calls to `fetch` and ensures a replay was uploaded by + * checking the `fetch()` request's body. + */ +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type +const toHaveSentReplay = function ( + _received: jest.Mocked, + expected?: SentReplayExpected | { sample: SentReplayExpected; inverse: boolean }, +) { + const { calls } = (getCurrentHub().getClient()?.getTransport()?.send as MockTransport).mock; + + let result: CheckCallForSentReplayResult; + + const expectedKeysLength = expected + ? ('sample' in expected ? Object.keys(expected.sample) : Object.keys(expected)).length + : 0; + + const replayCalls = getReplayCalls(calls); + + for (const currentCall of replayCalls) { + result = checkCallForSentReplay.call(this, currentCall[0], expected); + if (result.pass) { + break; + } + + // stop on the first call where any of the expected obj passes + if (result.results.length < expectedKeysLength) { + break; + } + } + + // @ts-expect-error use before assigned + const { results, call, pass } = result; + + const options = { + isNot: this.isNot, + promise: this.promise, + }; + + return { + pass, + message: () => + !call + ? pass + ? 'Expected Replay to not have been sent, but a request was attempted' + : 'Expected Replay to have been sent, but a request was not attempted' + : `${this.utils.matcherHint('toHaveSentReplay', undefined, undefined, options)}\n\n${results + .map(({ key, expectedVal, actualVal }: Result) => + this.utils.printDiffOrStringify( + expectedVal, + actualVal, + `Expected (key: ${key})`, + `Received (key: ${key})`, + ), + ) + .join('\n')}`, + }; +}; + +/** + * Checks the last call to `fetch` and ensures a replay was uploaded by + * checking the `fetch()` request's body. + */ +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type +const toHaveLastSentReplay = function ( + _received: jest.Mocked, + expected?: SentReplayExpected | { sample: SentReplayExpected; inverse: boolean }, +) { + const { calls } = (getCurrentHub().getClient()?.getTransport()?.send as MockTransport).mock; + const replayCalls = getReplayCalls(calls); + + const lastCall = replayCalls[calls.length - 1]?.[0]; + + const { results, call, pass } = checkCallForSentReplay.call(this, lastCall, expected); + + const options = { + isNot: this.isNot, + promise: this.promise, + }; + + return { + pass, + message: () => + !call + ? pass + ? 'Expected Replay to not have been sent, but a request was attempted' + : 'Expected Replay to have last been sent, but a request was not attempted' + : `${this.utils.matcherHint('toHaveSentReplay', undefined, undefined, options)}\n\n${results + .map(({ key, expectedVal, actualVal }: Result) => + this.utils.printDiffOrStringify( + expectedVal, + actualVal, + `Expected (key: ${key})`, + `Received (key: ${key})`, + ), + ) + .join('\n')}`, + }; +}; + +expect.extend({ + toHaveSameSession, + toHaveSentReplay, + toHaveLastSentReplay, +}); + +declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace jest { + interface AsymmetricMatchers { + toHaveSentReplay(expected?: SentReplayExpected): void; + toHaveLastSentReplay(expected?: SentReplayExpected): void; + toHaveSameSession(expected: undefined | Session): void; + } + interface Matchers { + toHaveSentReplay(expected?: SentReplayExpected): R; + toHaveLastSentReplay(expected?: SentReplayExpected): R; + toHaveSameSession(expected: undefined | Session): R; + } + } +} diff --git a/packages/replay-canvas/test/index.ts b/packages/replay-canvas/test/index.ts new file mode 100644 index 000000000000..ed4b82a6c780 --- /dev/null +++ b/packages/replay-canvas/test/index.ts @@ -0,0 +1,4 @@ +export * from './mocks/mockRrweb'; // XXX: Needs to happen before `mockSdk` or importing Replay! +export * from './mocks/mockSdk'; + +export const BASE_TIMESTAMP = new Date('2020-02-02 00:00:00').getTime(); // 1580619600000 diff --git a/packages/replay/rollup.bundle.config.mjs b/packages/replay/rollup.bundle.config.mjs index b254dae8d8d2..bc81b0cb46a4 100644 --- a/packages/replay/rollup.bundle.config.mjs +++ b/packages/replay/rollup.bundle.config.mjs @@ -8,14 +8,6 @@ const baseBundleConfig = makeBaseBundleConfig({ outputFileBase: () => 'bundles/replay', }); -const baseCanvasBundleConfig = makeBaseBundleConfig({ - bundleType: 'addon', - entrypoints: ['src/canvas.ts'], - jsVersion: 'es6', - licenseTitle: '@sentry/replaycanvas', - outputFileBase: () => 'bundles/replaycanvas', -}); - -const builds = [...makeBundleConfigVariants(baseBundleConfig), ...makeBundleConfigVariants(baseCanvasBundleConfig)]; +const builds = makeBundleConfigVariants(baseBundleConfig); export default builds; diff --git a/packages/replay/src/canvas.ts b/packages/replay/src/canvas.ts deleted file mode 100644 index d4b869c2f024..000000000000 --- a/packages/replay/src/canvas.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { getCanvasManager } from '@sentry-internal/rrweb'; -import type { Integration } from '@sentry/types'; -import type { ReplayConfiguration } from './types'; - -interface ReplayCanvasOptions { - quality: 'low' | 'medium' | 'high'; -} - -/** An integration to add canvas recording to replay. */ -export class ReplayCanvas implements Integration { - /** - * @inheritDoc - */ - public static id: string = 'ReplayCanvas'; - - /** - * @inheritDoc - */ - public name: string; - - private _canvasOptions: ReplayCanvasOptions; - - public constructor(options?: Partial) { - this.name = ReplayCanvas.id; - this._canvasOptions = { - quality: (options && options.quality) || 'medium', - }; - } - - /** @inheritdoc */ - public setupOnce(): void { - // noop - } - - /** - * Get the options that should be merged into replay options. - * This is what is actually called by the Replay integration to setup canvas. - */ - public getOptions(): Partial { - return { - _experiments: { - canvas: { - ...this._canvasOptions, - manager: getCanvasManager, - quality: this._canvasOptions.quality, - }, - }, - }; - } -} diff --git a/packages/replay/src/index.ts b/packages/replay/src/index.ts index 60d297434924..8e8a5d55579a 100644 --- a/packages/replay/src/index.ts +++ b/packages/replay/src/index.ts @@ -1,5 +1,4 @@ export { Replay } from './integration'; -export { ReplayCanvas } from './canvas'; export type { ReplayConfiguration, From f9a887dd6de7b539312425aa89bb94c374ee6676 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Tue, 9 Jan 2024 12:34:49 -0500 Subject: [PATCH 11/48] cleanup repo --- packages/replay-canvas/MIGRATION.md | 149 -------- packages/replay-canvas/jest.config.ts | 17 - packages/replay-canvas/jest.setup.ts | 269 --------------- packages/replay-canvas/test/index.ts | 4 - packages/replay-canvas/yarn.lock | 469 ++++++++++++++++++++++++++ 5 files changed, 469 insertions(+), 439 deletions(-) delete mode 100644 packages/replay-canvas/MIGRATION.md delete mode 100644 packages/replay-canvas/jest.config.ts delete mode 100644 packages/replay-canvas/jest.setup.ts delete mode 100644 packages/replay-canvas/test/index.ts create mode 100644 packages/replay-canvas/yarn.lock diff --git a/packages/replay-canvas/MIGRATION.md b/packages/replay-canvas/MIGRATION.md deleted file mode 100644 index ba6326939970..000000000000 --- a/packages/replay-canvas/MIGRATION.md +++ /dev/null @@ -1,149 +0,0 @@ -# End of Replay Beta - -Sentry Replay is now out of Beta. This means that the usual stability guarantees apply. - -Because of experimentation and rapid iteration, during the Beta period some bugs and problems came up which have since been fixed/improved. -We **strongly** recommend anyone using Replay in a version before 7.39.0 to update to 7.39.0 or newer, in order to prevent running Replay with known problems that have since been fixed. - -Below you can find a list of relevant replay issues that have been resolved until 7.39.0: - -## New features / improvements - -- Remove `autoplay` attribute from audio/video tags ([#59](https://github.com/getsentry/rrweb/pull/59)) -- Exclude fetching scripts that use `` ([#52](https://github.com/getsentry/rrweb/pull/52)) -- With maskAllText, mask the attributes: placeholder, title, `aria-label` -- Lower the flush max delay from 15 seconds to 5 seconds (#6761) -- Stop recording when retry fails (#6765) -- Stop without retry when receiving bad API response (#6773) -- Send client_report when replay sending fails (#7093) -- Stop recording when hitting a rate limit (#7018) -- Allow Replay to be used in Electron renderers with nodeIntegration enabled (#6644) -- Do not renew session in error mode (#6948) -- Remove default sample rates for replay (#6878) -- Add `flush` method to integration (#6776) -- Improve compression worker & fallback behavior (#6988, #6936, #6827) -- Improve error handling (#7087, #7094, #7010, getsentry/rrweb#16, #6856) -- Add more default block filters (#7233) - -## Fixes - -- Fix masking inputs on change when `maskAllInputs:false` ([#61](https://github.com/getsentry/rrweb/pull/61)) -- More robust `rootShadowHost` check ([#50](https://github.com/getsentry/rrweb/pull/50)) -- Fix duplicated textarea value ([#62](https://github.com/getsentry/rrweb/pull/62)) -- Handle removed attributes ([#65](https://github.com/getsentry/rrweb/pull/65)) -- Change LCP calculation (#7187, #7225) -- Fix debounced flushes not respecting `maxWait` (#7207, #7208) -- Fix svgs not getting unblocked (#7132) -- Fix missing fetch/xhr requests (#7134) -- Fix feature detection of PerformanceObserver (#7029) -- Fix `checkoutEveryNms` (#6722) -- Fix incorrect uncompressed recording size due to encoding (#6740) -- Ensure dropping replays works (#6522) -- Envelope send should be awaited in try/catch (#6625) -- Improve handling of `maskAllText` selector (#6637) - -# Upgrading Replay from 7.34.0 to 7.35.0 - #6645 - -This release will remove the ability to change the default rrweb recording options (outside of privacy options). The following are the new configuration values all replays will use: -`slimDOMOptions: 'all'` - Removes `script`, comments, `favicon`, whitespace in `head`, and a few `meta` tags in `head` -`recordCanvas: false` - This option did not do anything as playback of recorded canvas means we would have to remove the playback sandbox (which is a security concern). -`inlineStylesheet: true` - Inlines styles into the recording itself instead of attempting to fetch it remotely. This means that styles in the replay will reflect the styles at the time of recording and not the current styles of the remote stylesheet. -`collectFonts: true` - Attempts to load custom fonts. -`inlineImages: false` - Does not inline images to recording and instead loads the asset remotely. During playback, images may not load due to CORS (add sentry.io as an origin). - -Additionally, we have streamlined the privacy options. The following table lists the deprecated value, and what it is replaced by: - -| deprecated key | replaced by | description | -| ---------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | -| maskInputOptions | mask | Use CSS selectors in `mask` in order to mask all inputs of a certain type. For example, `input[type="address"]` | -| blockSelector | block | The selector(s) can be moved directly in the `block` array. | -| blockClass | block | Convert the class name to a CSS selector and add to `block` array. For example, `first-name` becomes `.first-name`. Regexes can be moved as-is. | -| maskClass | mask | Convert the class name to a CSS selector and add to `mask` array. For example, `first-name` becomes `.first-name`. Regexes can be moved as-is. | -| maskSelector | mask | The selector(s) can be moved directly in the `mask` array. | -| ignoreClass | ignore | Convert the class name to a CSS selector and add to `ignore` array. For example, `first-name` becomes `.first-name`. Regexes can be moved as-is. | - -# Upgrading Replay from 7.31.0 to 7.32.0 - -In 7.32.0, we have removed the default values for the replay sample rates. -Previously, they were: - -* `replaysSessionSampleRate: 0.1` -* `replaysOnErrorSampleRate: 1.0` - -Now, you have to explicitly set the sample rates, otherwise they default to 0. - -# Upgrading Replay from 0.6.x to 7.24.0 - -The Sentry Replay integration was moved to the Sentry JavaScript SDK monorepo. Hence we're jumping from version 0.x to the monorepo's 7.x version which is shared across all JS SDK packages. - -## Replay sample rates are defined on top level (https://github.com/getsentry/sentry-javascript/issues/6351) - -Instead of defining the sample rates on the integration like this: - -```js -Sentry.init({ - dsn: '__DSN__', - integrations: [ - new Replay({ - sessionSampleRate: 0.1, - errorSampleRate: 1.0, - }) - ], - // ... -}); -``` - -They are now defined on the top level of the SDK: - -```js -Sentry.init({ - dsn: '__DSN__', - replaysSessionSampleRate: 0.1, - replaysOnErrorSampleRate: 1.0, - integrations: [ - new Replay({ - // other replay config still goes in here - }) - ], -}); -``` - -Note that the sample rate options inside of `new Replay({})` have been deprecated and will be removed in a future update. - -## Removed deprecated options (https://github.com/getsentry/sentry-javascript/pull/6370) - -Two options, which have been deprecated for some time, have been removed: - -* `replaysSamplingRate` - instead use `sessionSampleRate` -* `captureOnlyOnError` - instead use `errorSampleRate` - -## New NPM package structure (https://github.com/getsentry/sentry-javascript/issues/6280) - -The internal structure of the npm package has changed. This is unlikely to affect you, unless you have imported something from e.g.: - -```js -import something from '@sentry/replay/submodule'; -``` - -If you only imported from `@sentry/replay`, this will not affect you. - -## Changed type name from `IEventBuffer` to `EventBuffer` (https://github.com/getsentry/sentry-javascript/pull/6416) - -It is highly unlikely to affect anybody, but the type `IEventBuffer` was renamed to `EventBuffer` for consistency. -Unless you manually imported this and used it somewhere in your codebase, this will not affect you. - -## Session object is now a plain object (https://github.com/getsentry/sentry-javascript/pull/6417) - -The `Session` object exported from Replay is now a plain object, instead of a class. -This should not affect you unless you specifically accessed this class & did custom things with it. - -## Reduce public API of Replay integration (https://github.com/getsentry/sentry-javascript/pull/6407) - -The result of `new Replay()` now has a much more limited public API. Only the following methods are exposed: - -```js -const replay = new Replay(); - -replay.start(); -replay.stop(); -``` diff --git a/packages/replay-canvas/jest.config.ts b/packages/replay-canvas/jest.config.ts deleted file mode 100644 index 90a3cf471f8d..000000000000 --- a/packages/replay-canvas/jest.config.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { Config } from '@jest/types'; -import { jsWithTs as jsWithTsPreset } from 'ts-jest/presets'; - -export default async (): Promise => { - return { - ...jsWithTsPreset, - globals: { - 'ts-jest': { - tsconfig: '/tsconfig.test.json', - }, - __DEBUG_BUILD__: true, - }, - setupFilesAfterEnv: ['./jest.setup.ts'], - testEnvironment: 'jsdom', - testMatch: ['/test/**/*(*.)@(spec|test).ts'], - }; -}; diff --git a/packages/replay-canvas/jest.setup.ts b/packages/replay-canvas/jest.setup.ts deleted file mode 100644 index 09e6c68a4483..000000000000 --- a/packages/replay-canvas/jest.setup.ts +++ /dev/null @@ -1,269 +0,0 @@ -import { TextEncoder } from 'util'; -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -import { getCurrentHub } from '@sentry/core'; -import type { ReplayRecordingData, Transport } from '@sentry/types'; -import * as SentryUtils from '@sentry/utils'; - -import type { ReplayContainer, Session } from './src/types'; - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -(global as any).TextEncoder = TextEncoder; - -type MockTransport = jest.MockedFunction; - -jest.spyOn(SentryUtils, 'isBrowser').mockImplementation(() => true); - -type EnvelopeHeader = { - event_id: string; - sent_at: string; - sdk: { - name: string; - version?: string; - }; -}; - -type ReplayEventHeader = { type: 'replay_event' }; -type ReplayEventPayload = Record; -type RecordingHeader = { type: 'replay_recording'; length: number }; -type RecordingPayloadHeader = Record; -type SentReplayExpected = { - envelopeHeader?: EnvelopeHeader; - replayEventHeader?: ReplayEventHeader; - replayEventPayload?: ReplayEventPayload; - recordingHeader?: RecordingHeader; - recordingPayloadHeader?: RecordingPayloadHeader; - recordingData?: ReplayRecordingData; -}; - -// eslint-disable-next-line @typescript-eslint/explicit-function-return-type -const toHaveSameSession = function (received: jest.Mocked, expected: undefined | Session) { - const pass = this.equals(received.session?.id, expected?.id) as boolean; - - const options = { - isNot: this.isNot, - promise: this.promise, - }; - - return { - pass, - message: () => - `${this.utils.matcherHint( - 'toHaveSameSession', - undefined, - undefined, - options, - )}\n\n${this.utils.printDiffOrStringify(expected, received.session, 'Expected', 'Received')}`, - }; -}; - -type Result = { - passed: boolean; - key: string; - expectedVal: SentReplayExpected[keyof SentReplayExpected]; - actualVal: SentReplayExpected[keyof SentReplayExpected]; -}; -type Call = [ - EnvelopeHeader, - [ - [ReplayEventHeader | undefined, ReplayEventPayload | undefined], - [RecordingHeader | undefined, RecordingPayloadHeader | undefined], - ], -]; -type CheckCallForSentReplayResult = { pass: boolean; call: Call | undefined; results: Result[] }; - -function checkCallForSentReplay( - call: Call | undefined, - expected?: SentReplayExpected | { sample: SentReplayExpected; inverse: boolean }, -): CheckCallForSentReplayResult { - const envelopeHeader = call?.[0]; - const envelopeItems = call?.[1] || [[], []]; - const [[replayEventHeader, replayEventPayload], [recordingHeader, recordingPayload] = []] = envelopeItems; - - // @ts-expect-error recordingPayload is always a string in our tests - const [recordingPayloadHeader, recordingData] = recordingPayload?.split('\n') || []; - - const actualObj: Required = { - // @ts-expect-error Custom envelope - envelopeHeader: envelopeHeader, - // @ts-expect-error Custom envelope - replayEventHeader: replayEventHeader, - // @ts-expect-error Custom envelope - replayEventPayload: replayEventPayload, - // @ts-expect-error Custom envelope - recordingHeader: recordingHeader, - recordingPayloadHeader: recordingPayloadHeader && JSON.parse(recordingPayloadHeader), - recordingData, - }; - - const isObjectContaining = expected && 'sample' in expected && 'inverse' in expected; - const expectedObj = isObjectContaining - ? (expected as { sample: SentReplayExpected }).sample - : (expected as SentReplayExpected); - - if (isObjectContaining) { - console.warn('`expect.objectContaining` is unnecessary when using the `toHaveSentReplay` matcher'); - } - - const results = expected - ? Object.keys(expectedObj) - .map(key => { - const actualVal = actualObj[key as keyof SentReplayExpected]; - const expectedVal = expectedObj[key as keyof SentReplayExpected]; - const passed = !expectedVal || this.equals(actualVal, expectedVal); - - return { passed, key, expectedVal, actualVal }; - }) - .filter(({ passed }) => !passed) - : []; - - const pass = Boolean(call && (!expected || results.length === 0)); - - return { - pass, - call, - results, - }; -} - -/** - * Only want calls that send replay events, i.e. ignore error events - */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function getReplayCalls(calls: any[][][]): any[][][] { - return calls - .map(call => { - const arg = call[0]; - if (arg.length !== 2) { - return []; - } - - if (!arg[1][0].find(({ type }: { type: string }) => ['replay_event', 'replay_recording'].includes(type))) { - return []; - } - - return [arg]; - }) - .filter(Boolean); -} - -/** - * Checks all calls to `fetch` and ensures a replay was uploaded by - * checking the `fetch()` request's body. - */ -// eslint-disable-next-line @typescript-eslint/explicit-function-return-type -const toHaveSentReplay = function ( - _received: jest.Mocked, - expected?: SentReplayExpected | { sample: SentReplayExpected; inverse: boolean }, -) { - const { calls } = (getCurrentHub().getClient()?.getTransport()?.send as MockTransport).mock; - - let result: CheckCallForSentReplayResult; - - const expectedKeysLength = expected - ? ('sample' in expected ? Object.keys(expected.sample) : Object.keys(expected)).length - : 0; - - const replayCalls = getReplayCalls(calls); - - for (const currentCall of replayCalls) { - result = checkCallForSentReplay.call(this, currentCall[0], expected); - if (result.pass) { - break; - } - - // stop on the first call where any of the expected obj passes - if (result.results.length < expectedKeysLength) { - break; - } - } - - // @ts-expect-error use before assigned - const { results, call, pass } = result; - - const options = { - isNot: this.isNot, - promise: this.promise, - }; - - return { - pass, - message: () => - !call - ? pass - ? 'Expected Replay to not have been sent, but a request was attempted' - : 'Expected Replay to have been sent, but a request was not attempted' - : `${this.utils.matcherHint('toHaveSentReplay', undefined, undefined, options)}\n\n${results - .map(({ key, expectedVal, actualVal }: Result) => - this.utils.printDiffOrStringify( - expectedVal, - actualVal, - `Expected (key: ${key})`, - `Received (key: ${key})`, - ), - ) - .join('\n')}`, - }; -}; - -/** - * Checks the last call to `fetch` and ensures a replay was uploaded by - * checking the `fetch()` request's body. - */ -// eslint-disable-next-line @typescript-eslint/explicit-function-return-type -const toHaveLastSentReplay = function ( - _received: jest.Mocked, - expected?: SentReplayExpected | { sample: SentReplayExpected; inverse: boolean }, -) { - const { calls } = (getCurrentHub().getClient()?.getTransport()?.send as MockTransport).mock; - const replayCalls = getReplayCalls(calls); - - const lastCall = replayCalls[calls.length - 1]?.[0]; - - const { results, call, pass } = checkCallForSentReplay.call(this, lastCall, expected); - - const options = { - isNot: this.isNot, - promise: this.promise, - }; - - return { - pass, - message: () => - !call - ? pass - ? 'Expected Replay to not have been sent, but a request was attempted' - : 'Expected Replay to have last been sent, but a request was not attempted' - : `${this.utils.matcherHint('toHaveSentReplay', undefined, undefined, options)}\n\n${results - .map(({ key, expectedVal, actualVal }: Result) => - this.utils.printDiffOrStringify( - expectedVal, - actualVal, - `Expected (key: ${key})`, - `Received (key: ${key})`, - ), - ) - .join('\n')}`, - }; -}; - -expect.extend({ - toHaveSameSession, - toHaveSentReplay, - toHaveLastSentReplay, -}); - -declare global { - // eslint-disable-next-line @typescript-eslint/no-namespace - namespace jest { - interface AsymmetricMatchers { - toHaveSentReplay(expected?: SentReplayExpected): void; - toHaveLastSentReplay(expected?: SentReplayExpected): void; - toHaveSameSession(expected: undefined | Session): void; - } - interface Matchers { - toHaveSentReplay(expected?: SentReplayExpected): R; - toHaveLastSentReplay(expected?: SentReplayExpected): R; - toHaveSameSession(expected: undefined | Session): R; - } - } -} diff --git a/packages/replay-canvas/test/index.ts b/packages/replay-canvas/test/index.ts deleted file mode 100644 index ed4b82a6c780..000000000000 --- a/packages/replay-canvas/test/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './mocks/mockRrweb'; // XXX: Needs to happen before `mockSdk` or importing Replay! -export * from './mocks/mockSdk'; - -export const BASE_TIMESTAMP = new Date('2020-02-02 00:00:00').getTime(); // 1580619600000 diff --git a/packages/replay-canvas/yarn.lock b/packages/replay-canvas/yarn.lock new file mode 100644 index 000000000000..08c8645d6c10 --- /dev/null +++ b/packages/replay-canvas/yarn.lock @@ -0,0 +1,469 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.2.0": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" + integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@babel/code-frame@^7.22.13", "@babel/code-frame@^7.23.5": + version "7.23.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244" + integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA== + dependencies: + "@babel/highlight" "^7.23.4" + chalk "^2.4.2" + +"@babel/compat-data@^7.23.5": + version "7.23.5" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.5.tgz#ffb878728bb6bdcb6f4510aa51b1be9afb8cfd98" + integrity sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw== + +"@babel/core@^7.17.5": + version "7.23.7" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.7.tgz#4d8016e06a14b5f92530a13ed0561730b5c6483f" + integrity sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.23.5" + "@babel/generator" "^7.23.6" + "@babel/helper-compilation-targets" "^7.23.6" + "@babel/helper-module-transforms" "^7.23.3" + "@babel/helpers" "^7.23.7" + "@babel/parser" "^7.23.6" + "@babel/template" "^7.22.15" + "@babel/traverse" "^7.23.7" + "@babel/types" "^7.23.6" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.6.tgz#9e1fca4811c77a10580d17d26b57b036133f3c2e" + integrity sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw== + dependencies: + "@babel/types" "^7.23.6" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" + +"@babel/helper-compilation-targets@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz#4d79069b16cbcf1461289eccfbbd81501ae39991" + integrity sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ== + dependencies: + "@babel/compat-data" "^7.23.5" + "@babel/helper-validator-option" "^7.23.5" + browserslist "^4.22.2" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-environment-visitor@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" + integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== + +"@babel/helper-function-name@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" + integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== + dependencies: + "@babel/template" "^7.22.15" + "@babel/types" "^7.23.0" + +"@babel/helper-hoist-variables@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-module-imports@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0" + integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== + dependencies: + "@babel/types" "^7.22.15" + +"@babel/helper-module-transforms@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz#d7d12c3c5d30af5b3c0fcab2a6d5217773e2d0f1" + integrity sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ== + dependencies: + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-module-imports" "^7.22.15" + "@babel/helper-simple-access" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/helper-validator-identifier" "^7.22.20" + +"@babel/helper-simple-access@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" + integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-split-export-declaration@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" + integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-string-parser@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83" + integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== + +"@babel/helper-validator-identifier@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" + integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== + +"@babel/helper-validator-option@^7.23.5": + version "7.23.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307" + integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== + +"@babel/helpers@^7.23.7": + version "7.23.8" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.8.tgz#fc6b2d65b16847fd50adddbd4232c76378959e34" + integrity sha512-KDqYz4PiOWvDFrdHLPhKtCThtIcKVy6avWD2oG4GEvyQ+XDZwHD4YQd+H2vNMnq2rkdxsDkU82T+Vk8U/WXHRQ== + dependencies: + "@babel/template" "^7.22.15" + "@babel/traverse" "^7.23.7" + "@babel/types" "^7.23.6" + +"@babel/highlight@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b" + integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A== + dependencies: + "@babel/helper-validator-identifier" "^7.22.20" + chalk "^2.4.2" + js-tokens "^4.0.0" + +"@babel/parser@^7.22.15", "@babel/parser@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.6.tgz#ba1c9e512bda72a47e285ae42aff9d2a635a9e3b" + integrity sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ== + +"@babel/template@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" + integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== + dependencies: + "@babel/code-frame" "^7.22.13" + "@babel/parser" "^7.22.15" + "@babel/types" "^7.22.15" + +"@babel/traverse@^7.23.7": + version "7.23.7" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.7.tgz#9a7bf285c928cb99b5ead19c3b1ce5b310c9c305" + integrity sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg== + dependencies: + "@babel/code-frame" "^7.23.5" + "@babel/generator" "^7.23.6" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.23.0" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.23.6" + "@babel/types" "^7.23.6" + debug "^4.3.1" + globals "^11.1.0" + +"@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.6.tgz#be33fdb151e1f5a56877d704492c240fc71c7ccd" + integrity sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg== + dependencies: + "@babel/helper-string-parser" "^7.23.4" + "@babel/helper-validator-identifier" "^7.22.20" + to-fast-properties "^2.0.0" + +"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" + integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" + integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== + +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.20" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz#72e45707cf240fa6b081d0366f8265b0cd10197f" + integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@sentry-internal/rrdom@2.7.3": + version "2.7.3" + resolved "https://registry.yarnpkg.com/@sentry-internal/rrdom/-/rrdom-2.7.3.tgz#2efe68a9cf23de9a8970acf4303748cdd7866b20" + integrity sha512-XD14G4Lv3ppvJlR7VkkCgHTKu1ylh7yvXdSsN5/FyGTH+IAXQIKL5nINIgWZTN3noNBWV9R0vcHDufXG/WktWA== + dependencies: + "@sentry-internal/rrweb-snapshot" "2.7.3" + +"@sentry-internal/rrweb-snapshot@2.7.3": + version "2.7.3" + resolved "https://registry.yarnpkg.com/@sentry-internal/rrweb-snapshot/-/rrweb-snapshot-2.7.3.tgz#9a7173825a31c07ccf27a5956f154400e11fdd97" + integrity sha512-mSZuBPmWia3x9wCuaJiZMD9ZVDnFv7TSG1Nz9X4ZqWb3DdaxB2MogGUU/2aTVqmRj6F91nl+GHb5NpmNYojUsw== + +"@sentry-internal/rrweb-types@2.7.3": + version "2.7.3" + resolved "https://registry.yarnpkg.com/@sentry-internal/rrweb-types/-/rrweb-types-2.7.3.tgz#e38737bc5c31aa9dfb8ce8faf46af374c2aa7cbb" + integrity sha512-EqALxhZtvH0rimYfj7J48DRC+fj+AGsZ/VDdOPKh3MQXptTyHncoWBj4ZtB1AaH7foYUr+2wkyxl3HqMVwe+6g== + dependencies: + "@sentry-internal/rrweb-snapshot" "2.7.3" + +"@sentry-internal/rrweb@file:.yalc/@sentry-internal/rrweb": + version "2.7.3" + dependencies: + "@sentry-internal/rrdom" "2.7.3" + "@sentry-internal/rrweb-snapshot" "2.7.3" + "@sentry-internal/rrweb-types" "2.7.3" + "@types/css-font-loading-module" "0.0.7" + "@xstate/fsm" "^1.4.0" + base64-arraybuffer "^1.0.1" + fflate "^0.4.4" + mitt "^3.0.0" + +"@sentry-internal/tracing@7.92.0": + version "7.92.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.92.0.tgz#505d94a93b5df965ec6bfb35da43389988259d4d" + integrity sha512-ur55vPcUUUWFUX4eVLNP71ohswK7ZZpleNZw9Y1GfLqyI+0ILQUwjtzqItJrdClvVsdRZJMRmDV40Hp9Lbb9mA== + dependencies: + "@sentry/core" "7.92.0" + "@sentry/types" "7.92.0" + "@sentry/utils" "7.92.0" + +"@sentry/core@7.92.0": + version "7.92.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.92.0.tgz#4e74c1959348b698226c49ead7a24e165502b55c" + integrity sha512-1Tly7YB2I1byI5xb0Cwrxs56Rhww+6mQ7m9P7rTmdC3/ijOzbEoohtYIUPwcooCEarpbEJe/tAayRx6BrH2UbQ== + dependencies: + "@sentry/types" "7.92.0" + "@sentry/utils" "7.92.0" + +"@sentry/replay@7.92.0": + version "7.92.0" + resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.92.0.tgz#d94e9f6b72e540e73378a74ca1190068edd447f2" + integrity sha512-G1t9Uvc9cR8VpNkElwvHIMGzykjIKikb10n0tfVd3e+rBPMCCjCPWOduwG6jZYxcvCjTpqmJh6NSLXxL/Mt4JA== + dependencies: + "@sentry-internal/tracing" "7.92.0" + "@sentry/core" "7.92.0" + "@sentry/types" "7.92.0" + "@sentry/utils" "7.92.0" + +"@sentry/types@7.92.0": + version "7.92.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.92.0.tgz#4c308fdb316c0272f55f0816230fe87e7b9b551a" + integrity sha512-APmSOuZuoRGpbPpPeYIbMSplPjiWNLZRQa73QiXuTflW4Tu/ItDlU8hOa2+A6JKVkJCuD2EN6yUrxDGSMyNXeg== + +"@sentry/utils@7.92.0": + version "7.92.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.92.0.tgz#20ed29742594eab007f9ff72e008b5262456a319" + integrity sha512-3nEfrQ1z28b/2zgFGANPh5yMVtgwXmrasZxTvKbrAj+KWJpjrJHrIR84r9W277J44NMeZ5RhRW2uoDmuBslPnA== + dependencies: + "@sentry/types" "7.92.0" + +"@types/css-font-loading-module@0.0.7": + version "0.0.7" + resolved "https://registry.yarnpkg.com/@types/css-font-loading-module/-/css-font-loading-module-0.0.7.tgz#2f98ede46acc0975de85c0b7b0ebe06041d24601" + integrity sha512-nl09VhutdjINdWyXxHWN/w9zlNCfr60JUqJbd24YXUuCwgeL0TpFSdElCwb6cxfB6ybE19Gjj4g0jsgkXxKv1Q== + +"@xstate/fsm@^1.4.0": + version "1.6.5" + resolved "https://registry.yarnpkg.com/@xstate/fsm/-/fsm-1.6.5.tgz#f599e301997ad7e3c572a0b1ff0696898081bea5" + integrity sha512-b5o1I6aLNeYlU/3CPlj/Z91ybk1gUsKT+5NAJI+2W4UjvS5KLG28K9v5UvNoFVjHV8PajVZ00RH3vnjyQO7ZAw== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +base64-arraybuffer@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz#1c37589a7c4b0746e34bd1feb951da2df01c1bdc" + integrity sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ== + +browserslist@^4.22.2: + version "4.22.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.2.tgz#704c4943072bd81ea18997f3bd2180e89c77874b" + integrity sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A== + dependencies: + caniuse-lite "^1.0.30001565" + electron-to-chromium "^1.4.601" + node-releases "^2.0.14" + update-browserslist-db "^1.0.13" + +caniuse-lite@^1.0.30001565: + version "1.0.30001576" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001576.tgz#893be772cf8ee6056d6c1e2d07df365b9ec0a5c4" + integrity sha512-ff5BdakGe2P3SQsMsiqmt1Lc8221NR1VzHj5jXN5vBny9A6fpze94HiVV/n7XRosOlsShJcvMv5mdnpjOGCEgg== + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +debug@^4.1.0, debug@^4.3.1: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +electron-to-chromium@^1.4.601: + version "1.4.624" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.624.tgz#ff40ac0afeaeda0c2c7b8cfc19d93c49adb1245b" + integrity sha512-w9niWuheXjz23vezH3w90n9KKcHe0UkhTfJ+rXJkuGGogHyQbQ7KS1x0a8ER4LbI3ljFS/gqxKh1TidNXDMHOg== + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +fflate@^0.4.4: + version "0.4.8" + resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.4.8.tgz#f90b82aefbd8ac174213abb338bd7ef848f0f5ae" + integrity sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +mitt@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mitt/-/mitt-3.0.1.tgz#ea36cf0cc30403601ae074c8f77b7092cdab36d1" + integrity sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +node-releases@^2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" + integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +update-browserslist-db@^1.0.13: + version "1.0.13" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" + integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== From 32b4ccdfd96603211d37228bca4540c7c6908287 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Tue, 9 Jan 2024 16:21:04 -0500 Subject: [PATCH 12/48] change to not use `_experiments` for canvas --- packages/replay/src/replay.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/replay/src/replay.ts b/packages/replay/src/replay.ts index 30ccda422544..4db8fb2b46ab 100644 --- a/packages/replay/src/replay.ts +++ b/packages/replay/src/replay.ts @@ -168,6 +168,7 @@ export class ReplayContainer implements ReplayContainerInterface { this._lastActivity = Date.now(); this._isEnabled = false; this._isPaused = false; + this._integrations = {}; this._hasInitializedCoreListeners = false; this._context = { errorIds: new Set(), @@ -732,6 +733,13 @@ export class ReplayContainer implements ReplayContainerInterface { return spanToJSON(lastTransaction).description; } + /** + * Internal integration use only, should not be public + */ + public addIntegration(name: string, options: Record): void { + this._integrations[name] = options; + } + /** * Initialize and start all listeners to varying events (DOM, * Performance Observer, Recording, Sentry SDK, etc) From 255fa862d5ef0f45fd0de328fe6fef14d1847681 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Tue, 9 Jan 2024 16:26:48 -0500 Subject: [PATCH 13/48] revert entrypoint change --- packages/replay/rollup.bundle.config.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/replay/rollup.bundle.config.mjs b/packages/replay/rollup.bundle.config.mjs index bc81b0cb46a4..a209b8d41af4 100644 --- a/packages/replay/rollup.bundle.config.mjs +++ b/packages/replay/rollup.bundle.config.mjs @@ -2,7 +2,7 @@ import { makeBaseBundleConfig, makeBundleConfigVariants } from '@sentry-internal const baseBundleConfig = makeBaseBundleConfig({ bundleType: 'addon', - entrypoints: ['src/integration.ts'], + entrypoints: ['src/index.ts'], jsVersion: 'es6', licenseTitle: '@sentry/replay', outputFileBase: () => 'bundles/replay', From 425f1ab1bf9cee73f997598c045ef5fcd60daf8a Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Tue, 9 Jan 2024 17:57:03 -0500 Subject: [PATCH 14/48] move tests to dev-packages --- .../canvas/withCanvasIntegrationFirst/init.js | 18 ------------ .../canvas/withCanvasIntegrationFirst/test.ts | 28 ------------------- .../withCanvasIntegrationSecond/init.js | 18 ------------ .../withCanvasIntegrationSecond/test.ts | 28 ------------------- .../canvas/withoutCanvasIntegration/init.js | 18 ------------ .../canvas/withoutCanvasIntegration/test.ts | 27 ------------------ 6 files changed, 137 deletions(-) delete mode 100644 packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/init.js delete mode 100644 packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts delete mode 100644 packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/init.js delete mode 100644 packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts delete mode 100644 packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/init.js delete mode 100644 packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/test.ts diff --git a/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/init.js b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/init.js deleted file mode 100644 index fa3248066150..000000000000 --- a/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/init.js +++ /dev/null @@ -1,18 +0,0 @@ -import * as Sentry from '@sentry/browser'; - -window.Sentry = Sentry; -window.Replay = new Sentry.Replay({ - flushMinDelay: 200, - flushMaxDelay: 200, - minReplayDuration: 0, -}); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - sampleRate: 0, - replaysSessionSampleRate: 1.0, - replaysOnErrorSampleRate: 0.0, - debug: true, - - integrations: [new Sentry.ReplayCanvas(), window.Replay], -}); diff --git a/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts deleted file mode 100644 index 7326bed95ae6..000000000000 --- a/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { expect } from '@playwright/test'; - -import { sentryTest } from '../../../../utils/fixtures'; -import { getReplaySnapshot, shouldSkipReplayTest } from '../../../../utils/replayHelpers'; - -sentryTest('sets up canvas when adding ReplayCanvas integration first', async ({ getLocalTestUrl, page }) => { - if (shouldSkipReplayTest()) { - sentryTest.skip(); - } - - await page.route('https://dsn.ingest.sentry.io/**/*', route => { - return route.fulfill({ - status: 200, - contentType: 'application/json', - body: JSON.stringify({ id: 'test-id' }), - }); - }); - - const url = await getLocalTestUrl({ testDir: __dirname }); - - await page.goto(url); - - const replay = await getReplaySnapshot(page); - const canvasOptions = replay._options._experiments?.canvas; - expect(canvasOptions.fps).toBe(4); - expect(canvasOptions.quality).toBe(0.6); - expect(replay._hasCanvas).toBe(true); -}); diff --git a/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/init.js b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/init.js deleted file mode 100644 index 1a9d5d179c4a..000000000000 --- a/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/init.js +++ /dev/null @@ -1,18 +0,0 @@ -import * as Sentry from '@sentry/browser'; - -window.Sentry = Sentry; -window.Replay = new Sentry.Replay({ - flushMinDelay: 200, - flushMaxDelay: 200, - minReplayDuration: 0, -}); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - sampleRate: 0, - replaysSessionSampleRate: 1.0, - replaysOnErrorSampleRate: 0.0, - debug: true, - - integrations: [window.Replay, new Sentry.ReplayCanvas()], -}); diff --git a/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts deleted file mode 100644 index 9168864db7e0..000000000000 --- a/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { expect } from '@playwright/test'; - -import { sentryTest } from '../../../../utils/fixtures'; -import { getReplaySnapshot, shouldSkipReplayTest } from '../../../../utils/replayHelpers'; - -sentryTest('sets up canvas when adding ReplayCanvas integration after Replay', async ({ getLocalTestUrl, page }) => { - if (shouldSkipReplayTest()) { - sentryTest.skip(); - } - - await page.route('https://dsn.ingest.sentry.io/**/*', route => { - return route.fulfill({ - status: 200, - contentType: 'application/json', - body: JSON.stringify({ id: 'test-id' }), - }); - }); - - const url = await getLocalTestUrl({ testDir: __dirname }); - - await page.goto(url); - - const replay = await getReplaySnapshot(page); - const canvasOptions = replay._options._experiments?.canvas; - expect(canvasOptions.fps).toBe(4); - expect(canvasOptions.quality).toBe(0.6); - expect(replay._hasCanvas).toBe(true); -}); diff --git a/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/init.js b/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/init.js deleted file mode 100644 index 92a463a4bc84..000000000000 --- a/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/init.js +++ /dev/null @@ -1,18 +0,0 @@ -import * as Sentry from '@sentry/browser'; - -window.Sentry = Sentry; -window.Replay = new Sentry.Replay({ - flushMinDelay: 200, - flushMaxDelay: 200, - minReplayDuration: 0, -}); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - sampleRate: 0, - replaysSessionSampleRate: 1.0, - replaysOnErrorSampleRate: 0.0, - debug: true, - - integrations: [window.Replay], -}); diff --git a/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/test.ts b/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/test.ts deleted file mode 100644 index b2ce69211be0..000000000000 --- a/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/test.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { expect } from '@playwright/test'; - -import { sentryTest } from '../../../../utils/fixtures'; -import { getReplaySnapshot, shouldSkipReplayTest } from '../../../../utils/replayHelpers'; - -sentryTest('does not setup up canvas without ReplayCanvas integration', async ({ getLocalTestUrl, page }) => { - if (shouldSkipReplayTest()) { - sentryTest.skip(); - } - - await page.route('https://dsn.ingest.sentry.io/**/*', route => { - return route.fulfill({ - status: 200, - contentType: 'application/json', - body: JSON.stringify({ id: 'test-id' }), - }); - }); - - const url = await getLocalTestUrl({ testDir: __dirname }); - - await page.goto(url); - - const replay = await getReplaySnapshot(page); - const canvasOptions = replay._options._experiments?.canvas; - expect(canvasOptions).toBe(undefined); - expect(replay._hasCanvas).toBe(false); -}); From 97fa4e761181cee3470e09dd0f08832efb2defee Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Tue, 9 Jan 2024 18:05:02 -0500 Subject: [PATCH 15/48] update tests --- .../suites/replay/canvas/withCanvasIntegrationFirst/test.ts | 1 + .../suites/replay/canvas/withCanvasIntegrationSecond/test.ts | 1 + packages/replay/src/replay.ts | 5 +++++ packages/replay/src/types/replay.ts | 1 + 4 files changed, 8 insertions(+) diff --git a/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts b/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts index 104098eed2cf..e24b3415e7a7 100644 --- a/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts +++ b/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts @@ -1,4 +1,5 @@ import { expect } from '@playwright/test'; +import type { ReplayCanvasIntegrationOptions } from '@sentry-internal/replay-canvas'; import { sentryTest } from '../../../../utils/fixtures'; import { getReplaySnapshot, shouldSkipReplayTest, waitForReplayRequest } from '../../../../utils/replayHelpers'; diff --git a/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts b/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts index d25066dc065b..0e9414978ce9 100644 --- a/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts +++ b/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts @@ -1,4 +1,5 @@ import { expect } from '@playwright/test'; +import type { ReplayCanvasIntegrationOptions } from '@sentry-internal/replay-canvas'; import { sentryTest } from '../../../../utils/fixtures'; import { getReplaySnapshot, shouldSkipReplayTest, waitForReplayRequest } from '../../../../utils/replayHelpers'; diff --git a/packages/replay/src/replay.ts b/packages/replay/src/replay.ts index 4db8fb2b46ab..6d0f79258dc7 100644 --- a/packages/replay/src/replay.ts +++ b/packages/replay/src/replay.ts @@ -236,6 +236,11 @@ export class ReplayContainer implements ReplayContainerInterface { return this._options; } + /** Get the replay integrations. [test only] */ + public getIntegrations(): Record> { + return { ...this._integrations }; + } + /** * Initializes the plugin based on sampling configuration. Should not be * called outside of constructor. diff --git a/packages/replay/src/types/replay.ts b/packages/replay/src/types/replay.ts index 93fd60a868f3..e21e102c8db6 100644 --- a/packages/replay/src/types/replay.ts +++ b/packages/replay/src/types/replay.ts @@ -503,6 +503,7 @@ export interface ReplayContainer { updateUserActivity(): void; addUpdate(cb: AddUpdateCallback): void; getOptions(): ReplayPluginOptions; + getIntegrations(): Record>; getSessionId(): string | undefined; checkAndHandleExpiredSession(): boolean | void; setInitialState(): void; From cd8f1599ff20c452e6ee71d40786ba964a498fb8 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Wed, 10 Jan 2024 08:44:54 -0500 Subject: [PATCH 16/48] remove old template --- .../suites/replay/canvas/template.html | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 packages/browser-integration-tests/suites/replay/canvas/template.html diff --git a/packages/browser-integration-tests/suites/replay/canvas/template.html b/packages/browser-integration-tests/suites/replay/canvas/template.html deleted file mode 100644 index 2b3e2f0b27b4..000000000000 --- a/packages/browser-integration-tests/suites/replay/canvas/template.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - From eedcf21227c67680402b959cb67c4c1f63f5b469 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Wed, 10 Jan 2024 08:48:01 -0500 Subject: [PATCH 17/48] do not publish as separate package --- .craft.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.craft.yml b/.craft.yml index 7c09cb4ddd4c..1a4b07c18874 100644 --- a/.craft.yml +++ b/.craft.yml @@ -32,10 +32,6 @@ targets: - name: npm id: '@sentry-internal/feedback' includeNames: /^sentry-internal-feedback-\d.*\.tgz$/ - ## 1.8 ReplayCanvas package (browser only) - - name: npm - id: '@sentry-internal/replay-canvas' - includeNames: /^sentry-internal-replay-canvas-\d.*\.tgz$/ ## 2. Browser & Node SDKs - name: npm From f1039837d90303d7fe18a506688b86f896b61d52 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Wed, 10 Jan 2024 09:18:21 -0500 Subject: [PATCH 18/48] remove yarn lockfile --- packages/replay-canvas/yarn.lock | 469 ------------------------------- 1 file changed, 469 deletions(-) delete mode 100644 packages/replay-canvas/yarn.lock diff --git a/packages/replay-canvas/yarn.lock b/packages/replay-canvas/yarn.lock deleted file mode 100644 index 08c8645d6c10..000000000000 --- a/packages/replay-canvas/yarn.lock +++ /dev/null @@ -1,469 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@ampproject/remapping@^2.2.0": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" - integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== - dependencies: - "@jridgewell/gen-mapping" "^0.3.0" - "@jridgewell/trace-mapping" "^0.3.9" - -"@babel/code-frame@^7.22.13", "@babel/code-frame@^7.23.5": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244" - integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA== - dependencies: - "@babel/highlight" "^7.23.4" - chalk "^2.4.2" - -"@babel/compat-data@^7.23.5": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.5.tgz#ffb878728bb6bdcb6f4510aa51b1be9afb8cfd98" - integrity sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw== - -"@babel/core@^7.17.5": - version "7.23.7" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.7.tgz#4d8016e06a14b5f92530a13ed0561730b5c6483f" - integrity sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw== - dependencies: - "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.23.5" - "@babel/generator" "^7.23.6" - "@babel/helper-compilation-targets" "^7.23.6" - "@babel/helper-module-transforms" "^7.23.3" - "@babel/helpers" "^7.23.7" - "@babel/parser" "^7.23.6" - "@babel/template" "^7.22.15" - "@babel/traverse" "^7.23.7" - "@babel/types" "^7.23.6" - convert-source-map "^2.0.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.3" - semver "^6.3.1" - -"@babel/generator@^7.23.6": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.6.tgz#9e1fca4811c77a10580d17d26b57b036133f3c2e" - integrity sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw== - dependencies: - "@babel/types" "^7.23.6" - "@jridgewell/gen-mapping" "^0.3.2" - "@jridgewell/trace-mapping" "^0.3.17" - jsesc "^2.5.1" - -"@babel/helper-compilation-targets@^7.23.6": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz#4d79069b16cbcf1461289eccfbbd81501ae39991" - integrity sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ== - dependencies: - "@babel/compat-data" "^7.23.5" - "@babel/helper-validator-option" "^7.23.5" - browserslist "^4.22.2" - lru-cache "^5.1.1" - semver "^6.3.1" - -"@babel/helper-environment-visitor@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" - integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== - -"@babel/helper-function-name@^7.23.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" - integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== - dependencies: - "@babel/template" "^7.22.15" - "@babel/types" "^7.23.0" - -"@babel/helper-hoist-variables@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" - integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-module-imports@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0" - integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== - dependencies: - "@babel/types" "^7.22.15" - -"@babel/helper-module-transforms@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz#d7d12c3c5d30af5b3c0fcab2a6d5217773e2d0f1" - integrity sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ== - dependencies: - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-module-imports" "^7.22.15" - "@babel/helper-simple-access" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/helper-validator-identifier" "^7.22.20" - -"@babel/helper-simple-access@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" - integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-split-export-declaration@^7.22.6": - version "7.22.6" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" - integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-string-parser@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83" - integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== - -"@babel/helper-validator-identifier@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" - integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== - -"@babel/helper-validator-option@^7.23.5": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307" - integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== - -"@babel/helpers@^7.23.7": - version "7.23.8" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.8.tgz#fc6b2d65b16847fd50adddbd4232c76378959e34" - integrity sha512-KDqYz4PiOWvDFrdHLPhKtCThtIcKVy6avWD2oG4GEvyQ+XDZwHD4YQd+H2vNMnq2rkdxsDkU82T+Vk8U/WXHRQ== - dependencies: - "@babel/template" "^7.22.15" - "@babel/traverse" "^7.23.7" - "@babel/types" "^7.23.6" - -"@babel/highlight@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b" - integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A== - dependencies: - "@babel/helper-validator-identifier" "^7.22.20" - chalk "^2.4.2" - js-tokens "^4.0.0" - -"@babel/parser@^7.22.15", "@babel/parser@^7.23.6": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.6.tgz#ba1c9e512bda72a47e285ae42aff9d2a635a9e3b" - integrity sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ== - -"@babel/template@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" - integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== - dependencies: - "@babel/code-frame" "^7.22.13" - "@babel/parser" "^7.22.15" - "@babel/types" "^7.22.15" - -"@babel/traverse@^7.23.7": - version "7.23.7" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.7.tgz#9a7bf285c928cb99b5ead19c3b1ce5b310c9c305" - integrity sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg== - dependencies: - "@babel/code-frame" "^7.23.5" - "@babel/generator" "^7.23.6" - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-function-name" "^7.23.0" - "@babel/helper-hoist-variables" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/parser" "^7.23.6" - "@babel/types" "^7.23.6" - debug "^4.3.1" - globals "^11.1.0" - -"@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.6": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.6.tgz#be33fdb151e1f5a56877d704492c240fc71c7ccd" - integrity sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg== - dependencies: - "@babel/helper-string-parser" "^7.23.4" - "@babel/helper-validator-identifier" "^7.22.20" - to-fast-properties "^2.0.0" - -"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" - integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== - dependencies: - "@jridgewell/set-array" "^1.0.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.9" - -"@jridgewell/resolve-uri@^3.1.0": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" - integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== - -"@jridgewell/set-array@^1.0.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" - integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== - -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": - version "1.4.15" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" - integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== - -"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.20" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz#72e45707cf240fa6b081d0366f8265b0cd10197f" - integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" - -"@sentry-internal/rrdom@2.7.3": - version "2.7.3" - resolved "https://registry.yarnpkg.com/@sentry-internal/rrdom/-/rrdom-2.7.3.tgz#2efe68a9cf23de9a8970acf4303748cdd7866b20" - integrity sha512-XD14G4Lv3ppvJlR7VkkCgHTKu1ylh7yvXdSsN5/FyGTH+IAXQIKL5nINIgWZTN3noNBWV9R0vcHDufXG/WktWA== - dependencies: - "@sentry-internal/rrweb-snapshot" "2.7.3" - -"@sentry-internal/rrweb-snapshot@2.7.3": - version "2.7.3" - resolved "https://registry.yarnpkg.com/@sentry-internal/rrweb-snapshot/-/rrweb-snapshot-2.7.3.tgz#9a7173825a31c07ccf27a5956f154400e11fdd97" - integrity sha512-mSZuBPmWia3x9wCuaJiZMD9ZVDnFv7TSG1Nz9X4ZqWb3DdaxB2MogGUU/2aTVqmRj6F91nl+GHb5NpmNYojUsw== - -"@sentry-internal/rrweb-types@2.7.3": - version "2.7.3" - resolved "https://registry.yarnpkg.com/@sentry-internal/rrweb-types/-/rrweb-types-2.7.3.tgz#e38737bc5c31aa9dfb8ce8faf46af374c2aa7cbb" - integrity sha512-EqALxhZtvH0rimYfj7J48DRC+fj+AGsZ/VDdOPKh3MQXptTyHncoWBj4ZtB1AaH7foYUr+2wkyxl3HqMVwe+6g== - dependencies: - "@sentry-internal/rrweb-snapshot" "2.7.3" - -"@sentry-internal/rrweb@file:.yalc/@sentry-internal/rrweb": - version "2.7.3" - dependencies: - "@sentry-internal/rrdom" "2.7.3" - "@sentry-internal/rrweb-snapshot" "2.7.3" - "@sentry-internal/rrweb-types" "2.7.3" - "@types/css-font-loading-module" "0.0.7" - "@xstate/fsm" "^1.4.0" - base64-arraybuffer "^1.0.1" - fflate "^0.4.4" - mitt "^3.0.0" - -"@sentry-internal/tracing@7.92.0": - version "7.92.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.92.0.tgz#505d94a93b5df965ec6bfb35da43389988259d4d" - integrity sha512-ur55vPcUUUWFUX4eVLNP71ohswK7ZZpleNZw9Y1GfLqyI+0ILQUwjtzqItJrdClvVsdRZJMRmDV40Hp9Lbb9mA== - dependencies: - "@sentry/core" "7.92.0" - "@sentry/types" "7.92.0" - "@sentry/utils" "7.92.0" - -"@sentry/core@7.92.0": - version "7.92.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.92.0.tgz#4e74c1959348b698226c49ead7a24e165502b55c" - integrity sha512-1Tly7YB2I1byI5xb0Cwrxs56Rhww+6mQ7m9P7rTmdC3/ijOzbEoohtYIUPwcooCEarpbEJe/tAayRx6BrH2UbQ== - dependencies: - "@sentry/types" "7.92.0" - "@sentry/utils" "7.92.0" - -"@sentry/replay@7.92.0": - version "7.92.0" - resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.92.0.tgz#d94e9f6b72e540e73378a74ca1190068edd447f2" - integrity sha512-G1t9Uvc9cR8VpNkElwvHIMGzykjIKikb10n0tfVd3e+rBPMCCjCPWOduwG6jZYxcvCjTpqmJh6NSLXxL/Mt4JA== - dependencies: - "@sentry-internal/tracing" "7.92.0" - "@sentry/core" "7.92.0" - "@sentry/types" "7.92.0" - "@sentry/utils" "7.92.0" - -"@sentry/types@7.92.0": - version "7.92.0" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.92.0.tgz#4c308fdb316c0272f55f0816230fe87e7b9b551a" - integrity sha512-APmSOuZuoRGpbPpPeYIbMSplPjiWNLZRQa73QiXuTflW4Tu/ItDlU8hOa2+A6JKVkJCuD2EN6yUrxDGSMyNXeg== - -"@sentry/utils@7.92.0": - version "7.92.0" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.92.0.tgz#20ed29742594eab007f9ff72e008b5262456a319" - integrity sha512-3nEfrQ1z28b/2zgFGANPh5yMVtgwXmrasZxTvKbrAj+KWJpjrJHrIR84r9W277J44NMeZ5RhRW2uoDmuBslPnA== - dependencies: - "@sentry/types" "7.92.0" - -"@types/css-font-loading-module@0.0.7": - version "0.0.7" - resolved "https://registry.yarnpkg.com/@types/css-font-loading-module/-/css-font-loading-module-0.0.7.tgz#2f98ede46acc0975de85c0b7b0ebe06041d24601" - integrity sha512-nl09VhutdjINdWyXxHWN/w9zlNCfr60JUqJbd24YXUuCwgeL0TpFSdElCwb6cxfB6ybE19Gjj4g0jsgkXxKv1Q== - -"@xstate/fsm@^1.4.0": - version "1.6.5" - resolved "https://registry.yarnpkg.com/@xstate/fsm/-/fsm-1.6.5.tgz#f599e301997ad7e3c572a0b1ff0696898081bea5" - integrity sha512-b5o1I6aLNeYlU/3CPlj/Z91ybk1gUsKT+5NAJI+2W4UjvS5KLG28K9v5UvNoFVjHV8PajVZ00RH3vnjyQO7ZAw== - -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -base64-arraybuffer@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz#1c37589a7c4b0746e34bd1feb951da2df01c1bdc" - integrity sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ== - -browserslist@^4.22.2: - version "4.22.2" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.2.tgz#704c4943072bd81ea18997f3bd2180e89c77874b" - integrity sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A== - dependencies: - caniuse-lite "^1.0.30001565" - electron-to-chromium "^1.4.601" - node-releases "^2.0.14" - update-browserslist-db "^1.0.13" - -caniuse-lite@^1.0.30001565: - version "1.0.30001576" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001576.tgz#893be772cf8ee6056d6c1e2d07df365b9ec0a5c4" - integrity sha512-ff5BdakGe2P3SQsMsiqmt1Lc8221NR1VzHj5jXN5vBny9A6fpze94HiVV/n7XRosOlsShJcvMv5mdnpjOGCEgg== - -chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - -convert-source-map@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" - integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== - -debug@^4.1.0, debug@^4.3.1: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - -electron-to-chromium@^1.4.601: - version "1.4.624" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.624.tgz#ff40ac0afeaeda0c2c7b8cfc19d93c49adb1245b" - integrity sha512-w9niWuheXjz23vezH3w90n9KKcHe0UkhTfJ+rXJkuGGogHyQbQ7KS1x0a8ER4LbI3ljFS/gqxKh1TidNXDMHOg== - -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== - -fflate@^0.4.4: - version "0.4.8" - resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.4.8.tgz#f90b82aefbd8ac174213abb338bd7ef848f0f5ae" - integrity sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA== - -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== - -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -json5@^2.2.3: - version "2.2.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" - integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== - -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - dependencies: - yallist "^3.0.2" - -mitt@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/mitt/-/mitt-3.0.1.tgz#ea36cf0cc30403601ae074c8f77b7092cdab36d1" - integrity sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw== - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -node-releases@^2.0.14: - version "2.0.14" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" - integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== - -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== - -semver@^6.3.1: - version "6.3.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== - -update-browserslist-db@^1.0.13: - version "1.0.13" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" - integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== - dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" - -yallist@^3.0.2: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== From c4e957fb373c2095092c2f9d0e317b148475dc3b Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Wed, 10 Jan 2024 10:01:36 -0500 Subject: [PATCH 19/48] refactor out integrations abstraction --- .../canvas/withCanvasIntegrationFirst/test.ts | 1 - .../canvas/withCanvasIntegrationSecond/test.ts | 1 - packages/replay/src/replay.ts | 13 ------------- packages/replay/src/types/replay.ts | 1 - 4 files changed, 16 deletions(-) diff --git a/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts b/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts index e24b3415e7a7..104098eed2cf 100644 --- a/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts +++ b/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts @@ -1,5 +1,4 @@ import { expect } from '@playwright/test'; -import type { ReplayCanvasIntegrationOptions } from '@sentry-internal/replay-canvas'; import { sentryTest } from '../../../../utils/fixtures'; import { getReplaySnapshot, shouldSkipReplayTest, waitForReplayRequest } from '../../../../utils/replayHelpers'; diff --git a/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts b/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts index 0e9414978ce9..d25066dc065b 100644 --- a/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts +++ b/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts @@ -1,5 +1,4 @@ import { expect } from '@playwright/test'; -import type { ReplayCanvasIntegrationOptions } from '@sentry-internal/replay-canvas'; import { sentryTest } from '../../../../utils/fixtures'; import { getReplaySnapshot, shouldSkipReplayTest, waitForReplayRequest } from '../../../../utils/replayHelpers'; diff --git a/packages/replay/src/replay.ts b/packages/replay/src/replay.ts index 6d0f79258dc7..30ccda422544 100644 --- a/packages/replay/src/replay.ts +++ b/packages/replay/src/replay.ts @@ -168,7 +168,6 @@ export class ReplayContainer implements ReplayContainerInterface { this._lastActivity = Date.now(); this._isEnabled = false; this._isPaused = false; - this._integrations = {}; this._hasInitializedCoreListeners = false; this._context = { errorIds: new Set(), @@ -236,11 +235,6 @@ export class ReplayContainer implements ReplayContainerInterface { return this._options; } - /** Get the replay integrations. [test only] */ - public getIntegrations(): Record> { - return { ...this._integrations }; - } - /** * Initializes the plugin based on sampling configuration. Should not be * called outside of constructor. @@ -738,13 +732,6 @@ export class ReplayContainer implements ReplayContainerInterface { return spanToJSON(lastTransaction).description; } - /** - * Internal integration use only, should not be public - */ - public addIntegration(name: string, options: Record): void { - this._integrations[name] = options; - } - /** * Initialize and start all listeners to varying events (DOM, * Performance Observer, Recording, Sentry SDK, etc) diff --git a/packages/replay/src/types/replay.ts b/packages/replay/src/types/replay.ts index e21e102c8db6..93fd60a868f3 100644 --- a/packages/replay/src/types/replay.ts +++ b/packages/replay/src/types/replay.ts @@ -503,7 +503,6 @@ export interface ReplayContainer { updateUserActivity(): void; addUpdate(cb: AddUpdateCallback): void; getOptions(): ReplayPluginOptions; - getIntegrations(): Record>; getSessionId(): string | undefined; checkAndHandleExpiredSession(): boolean | void; setInitialState(): void; From fbe85d5d0f66a17540cb90cb9225f5fddc2a09b4 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Wed, 10 Jan 2024 16:54:43 -0500 Subject: [PATCH 20/48] add replaycanvas to replay bundles --- packages/browser/src/index.bundle.feedback.ts | 4 ++-- packages/browser/src/index.bundle.replay.ts | 3 ++- .../src/index.bundle.tracing.replay.feedback.ts | 3 ++- packages/browser/src/index.bundle.tracing.replay.ts | 3 ++- packages/browser/src/index.bundle.tracing.ts | 4 ++-- packages/browser/src/index.bundle.ts | 10 ++++++++-- .../browser/test/unit/index.bundle.feedback.test.ts | 7 ++++++- packages/browser/test/unit/index.bundle.replay.test.ts | 2 ++ packages/browser/test/unit/index.bundle.test.ts | 2 ++ .../unit/index.bundle.tracing.replay.feedback.test.ts | 3 ++- .../test/unit/index.bundle.tracing.replay.test.ts | 2 ++ .../browser/test/unit/index.bundle.tracing.test.ts | 7 ++++++- packages/integration-shims/src/index.ts | 1 + 13 files changed, 39 insertions(+), 12 deletions(-) diff --git a/packages/browser/src/index.bundle.feedback.ts b/packages/browser/src/index.bundle.feedback.ts index 7aab6485d254..48d7b4aecf13 100644 --- a/packages/browser/src/index.bundle.feedback.ts +++ b/packages/browser/src/index.bundle.feedback.ts @@ -1,6 +1,6 @@ // This is exported so the loader does not fail when switching off Replay/Tracing import { Feedback } from '@sentry-internal/feedback'; -import { BrowserTracing, Replay, addTracingExtensions } from '@sentry-internal/integration-shims'; +import { BrowserTracing, Replay, ReplayCanvas, addTracingExtensions } from '@sentry-internal/integration-shims'; import * as Sentry from './index.bundle.base'; @@ -10,5 +10,5 @@ Sentry.Integrations.Replay = Replay; Sentry.Integrations.BrowserTracing = BrowserTracing; export * from './index.bundle.base'; -export { BrowserTracing, addTracingExtensions, Replay, Feedback }; +export { BrowserTracing, addTracingExtensions, Replay, ReplayCanvas, Feedback }; // Note: We do not export a shim for `Span` here, as that is quite complex and would blow up the bundle diff --git a/packages/browser/src/index.bundle.replay.ts b/packages/browser/src/index.bundle.replay.ts index 0b556bc71b8e..e1fe19cda06c 100644 --- a/packages/browser/src/index.bundle.replay.ts +++ b/packages/browser/src/index.bundle.replay.ts @@ -1,5 +1,6 @@ // This is exported so the loader does not fail when switching off Replay/Tracing import { BrowserTracing, Feedback, addTracingExtensions } from '@sentry-internal/integration-shims'; +import { ReplayCanvas } from '@sentry-internal/replay-canvas'; import { Replay } from '@sentry/replay'; import * as Sentry from './index.bundle.base'; @@ -10,5 +11,5 @@ Sentry.Integrations.Replay = Replay; Sentry.Integrations.BrowserTracing = BrowserTracing; export * from './index.bundle.base'; -export { BrowserTracing, addTracingExtensions, Replay, Feedback }; +export { BrowserTracing, addTracingExtensions, Replay, ReplayCanvas, Feedback }; // Note: We do not export a shim for `Span` here, as that is quite complex and would blow up the bundle diff --git a/packages/browser/src/index.bundle.tracing.replay.feedback.ts b/packages/browser/src/index.bundle.tracing.replay.feedback.ts index 5558703f7703..04dc02a8e946 100644 --- a/packages/browser/src/index.bundle.tracing.replay.feedback.ts +++ b/packages/browser/src/index.bundle.tracing.replay.feedback.ts @@ -1,4 +1,5 @@ import { Feedback } from '@sentry-internal/feedback'; +import { ReplayCanvas } from '@sentry-internal/replay-canvas'; import { BrowserTracing, Span, addExtensionMethods } from '@sentry-internal/tracing'; import { Replay } from '@sentry/replay'; @@ -14,5 +15,5 @@ Sentry.Integrations.BrowserTracing = BrowserTracing; // We are patching the global object with our hub extension methods addExtensionMethods(); -export { Feedback, Replay, BrowserTracing, Span, addExtensionMethods }; +export { Feedback, Replay, ReplayCanvas, BrowserTracing, Span, addExtensionMethods }; export * from './index.bundle.base'; diff --git a/packages/browser/src/index.bundle.tracing.replay.ts b/packages/browser/src/index.bundle.tracing.replay.ts index 0e7aa1ec19bc..683d1509f9d8 100644 --- a/packages/browser/src/index.bundle.tracing.replay.ts +++ b/packages/browser/src/index.bundle.tracing.replay.ts @@ -1,4 +1,5 @@ import { Feedback } from '@sentry-internal/integration-shims'; +import { ReplayCanvas } from '@sentry-internal/replay-canvas'; import { BrowserTracing, Span, addExtensionMethods } from '@sentry-internal/tracing'; import { Replay } from '@sentry/replay'; @@ -14,5 +15,5 @@ Sentry.Integrations.BrowserTracing = BrowserTracing; // We are patching the global object with our hub extension methods addExtensionMethods(); -export { Feedback, Replay, BrowserTracing, Span, addExtensionMethods }; +export { Feedback, Replay, ReplayCanvas, BrowserTracing, Span, addExtensionMethods }; export * from './index.bundle.base'; diff --git a/packages/browser/src/index.bundle.tracing.ts b/packages/browser/src/index.bundle.tracing.ts index 22b33962e860..0a958c634974 100644 --- a/packages/browser/src/index.bundle.tracing.ts +++ b/packages/browser/src/index.bundle.tracing.ts @@ -1,5 +1,5 @@ // This is exported so the loader does not fail when switching off Replay -import { Feedback, Replay } from '@sentry-internal/integration-shims'; +import { Feedback, Replay, ReplayCanvas } from '@sentry-internal/integration-shims'; import { BrowserTracing, Span, addExtensionMethods } from '@sentry-internal/tracing'; import * as Sentry from './index.bundle.base'; @@ -14,5 +14,5 @@ Sentry.Integrations.BrowserTracing = BrowserTracing; // We are patching the global object with our hub extension methods addExtensionMethods(); -export { Feedback, Replay, BrowserTracing, Span, addExtensionMethods }; +export { Feedback, Replay, ReplayCanvas, BrowserTracing, Span, addExtensionMethods }; export * from './index.bundle.base'; diff --git a/packages/browser/src/index.bundle.ts b/packages/browser/src/index.bundle.ts index a2541ceadda1..f479757db105 100644 --- a/packages/browser/src/index.bundle.ts +++ b/packages/browser/src/index.bundle.ts @@ -1,5 +1,11 @@ // This is exported so the loader does not fail when switching off Replay/Tracing -import { BrowserTracing, Feedback, Replay, addTracingExtensions } from '@sentry-internal/integration-shims'; +import { + BrowserTracing, + Feedback, + Replay, + ReplayCanvas, + addTracingExtensions, +} from '@sentry-internal/integration-shims'; import * as Sentry from './index.bundle.base'; @@ -9,5 +15,5 @@ Sentry.Integrations.Replay = Replay; Sentry.Integrations.BrowserTracing = BrowserTracing; export * from './index.bundle.base'; -export { BrowserTracing, addTracingExtensions, Replay, Feedback }; +export { BrowserTracing, addTracingExtensions, Replay, ReplayCanvas, Feedback }; // Note: We do not export a shim for `Span` here, as that is quite complex and would blow up the bundle diff --git a/packages/browser/test/unit/index.bundle.feedback.test.ts b/packages/browser/test/unit/index.bundle.feedback.test.ts index 4c5f26e5f313..03bb93047a5c 100644 --- a/packages/browser/test/unit/index.bundle.feedback.test.ts +++ b/packages/browser/test/unit/index.bundle.feedback.test.ts @@ -1,4 +1,8 @@ -import { BrowserTracing as BrowserTracingShim, Replay as ReplayShim } from '@sentry-internal/integration-shims'; +import { + BrowserTracing as BrowserTracingShim, + Replay as ReplayShim, + ReplayCanvas as ReplayCanvasShim, +} from '@sentry-internal/integration-shims'; import { Feedback } from '@sentry/browser'; import * as TracingReplayBundle from '../../src/index.bundle.feedback'; @@ -16,6 +20,7 @@ describe('index.bundle.feedback', () => { expect(TracingReplayBundle.Integrations.Replay).toBe(ReplayShim); expect(TracingReplayBundle.Replay).toBe(ReplayShim); + expect(TracingReplayBundle.ReplayCanvas).toBe(ReplayCanvasShim); expect(TracingReplayBundle.Integrations.BrowserTracing).toBe(BrowserTracingShim); expect(TracingReplayBundle.BrowserTracing).toBe(BrowserTracingShim); diff --git a/packages/browser/test/unit/index.bundle.replay.test.ts b/packages/browser/test/unit/index.bundle.replay.test.ts index b14eb70f6330..30eb69ee27cd 100644 --- a/packages/browser/test/unit/index.bundle.replay.test.ts +++ b/packages/browser/test/unit/index.bundle.replay.test.ts @@ -1,5 +1,6 @@ import { BrowserTracing as BrowserTracingShim, Feedback as FeedbackShim } from '@sentry-internal/integration-shims'; import { Replay } from '@sentry/browser'; +import { ReplayCanvas } from '@sentry/browser'; import * as TracingReplayBundle from '../../src/index.bundle.replay'; @@ -16,6 +17,7 @@ describe('index.bundle.replay', () => { expect(TracingReplayBundle.Integrations.Replay).toBe(Replay); expect(TracingReplayBundle.Replay).toBe(Replay); + expect(TracingReplayBundle.ReplayCanvas).toBe(ReplayCanvas); expect(TracingReplayBundle.Integrations.BrowserTracing).toBe(BrowserTracingShim); expect(TracingReplayBundle.BrowserTracing).toBe(BrowserTracingShim); diff --git a/packages/browser/test/unit/index.bundle.test.ts b/packages/browser/test/unit/index.bundle.test.ts index f61987732858..08cbd86145a4 100644 --- a/packages/browser/test/unit/index.bundle.test.ts +++ b/packages/browser/test/unit/index.bundle.test.ts @@ -2,6 +2,7 @@ import { BrowserTracing as BrowserTracingShim, Feedback as FeedbackShim, Replay as ReplayShim, + ReplayCanvas as ReplayCanvasShim, } from '@sentry-internal/integration-shims'; import * as TracingBundle from '../../src/index.bundle'; @@ -19,6 +20,7 @@ describe('index.bundle', () => { expect(TracingBundle.Integrations.Replay).toBe(ReplayShim); expect(TracingBundle.Replay).toBe(ReplayShim); + expect(TracingBundle.ReplayCanvas).toBe(ReplayCanvasShim); expect(TracingBundle.Integrations.BrowserTracing).toBe(BrowserTracingShim); expect(TracingBundle.BrowserTracing).toBe(BrowserTracingShim); diff --git a/packages/browser/test/unit/index.bundle.tracing.replay.feedback.test.ts b/packages/browser/test/unit/index.bundle.tracing.replay.feedback.test.ts index 0bd50453da43..9f9076374b1e 100644 --- a/packages/browser/test/unit/index.bundle.tracing.replay.feedback.test.ts +++ b/packages/browser/test/unit/index.bundle.tracing.replay.feedback.test.ts @@ -1,5 +1,5 @@ import { BrowserTracing } from '@sentry-internal/tracing'; -import { Feedback, Replay } from '@sentry/browser'; +import { Feedback, Replay, ReplayCanvas } from '@sentry/browser'; import * as TracingReplayFeedbackBundle from '../../src/index.bundle.tracing.replay.feedback'; @@ -16,6 +16,7 @@ describe('index.bundle.tracing.replay.feedback', () => { expect(TracingReplayFeedbackBundle.Integrations.Replay).toBe(Replay); expect(TracingReplayFeedbackBundle.Replay).toBe(Replay); + expect(TracingReplayFeedbackBundle.ReplayCanvas).toBe(ReplayCanvas); expect(TracingReplayFeedbackBundle.Integrations.BrowserTracing).toBe(BrowserTracing); expect(TracingReplayFeedbackBundle.BrowserTracing).toBe(BrowserTracing); diff --git a/packages/browser/test/unit/index.bundle.tracing.replay.test.ts b/packages/browser/test/unit/index.bundle.tracing.replay.test.ts index 4c8af2130a3b..c016367f2bf6 100644 --- a/packages/browser/test/unit/index.bundle.tracing.replay.test.ts +++ b/packages/browser/test/unit/index.bundle.tracing.replay.test.ts @@ -1,6 +1,7 @@ import { Feedback as FeedbackShim } from '@sentry-internal/integration-shims'; import { BrowserTracing } from '@sentry-internal/tracing'; import { Replay } from '@sentry/browser'; +import { ReplayCanvas } from '@sentry/browser'; import * as TracingReplayBundle from '../../src/index.bundle.tracing.replay'; @@ -17,6 +18,7 @@ describe('index.bundle.tracing.replay', () => { expect(TracingReplayBundle.Integrations.Replay).toBe(Replay); expect(TracingReplayBundle.Replay).toBe(Replay); + expect(TracingReplayBundle.ReplayCanvas).toBe(ReplayCanvas); expect(TracingReplayBundle.Integrations.BrowserTracing).toBe(BrowserTracing); expect(TracingReplayBundle.BrowserTracing).toBe(BrowserTracing); diff --git a/packages/browser/test/unit/index.bundle.tracing.test.ts b/packages/browser/test/unit/index.bundle.tracing.test.ts index b439dece8c6f..bce177ce0d72 100644 --- a/packages/browser/test/unit/index.bundle.tracing.test.ts +++ b/packages/browser/test/unit/index.bundle.tracing.test.ts @@ -1,4 +1,8 @@ -import { Feedback as FeedbackShim, Replay as ReplayShim } from '@sentry-internal/integration-shims'; +import { + Feedback as FeedbackShim, + Replay as ReplayShim, + ReplayCanvas as ReplayCanvasShim, +} from '@sentry-internal/integration-shims'; import { BrowserTracing } from '@sentry-internal/tracing'; import * as TracingBundle from '../../src/index.bundle.tracing'; @@ -16,6 +20,7 @@ describe('index.bundle.tracing', () => { expect(TracingBundle.Integrations.Replay).toBe(ReplayShim); expect(TracingBundle.Replay).toBe(ReplayShim); + expect(TracingBundle.ReplayCanvas).toBe(ReplayCanvasShim); expect(TracingBundle.Integrations.BrowserTracing).toBe(BrowserTracing); expect(TracingBundle.BrowserTracing).toBe(BrowserTracing); diff --git a/packages/integration-shims/src/index.ts b/packages/integration-shims/src/index.ts index 410a4a31d9c8..31958781ac44 100644 --- a/packages/integration-shims/src/index.ts +++ b/packages/integration-shims/src/index.ts @@ -1,3 +1,4 @@ export { Feedback } from './Feedback'; export { Replay } from './Replay'; +export { ReplayCanvas } from './ReplayCanvas'; export { BrowserTracing, addTracingExtensions } from './BrowserTracing'; From 20e61fd5f6895094a6e86d156ffb57cc7f4a1b8a Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Wed, 10 Jan 2024 18:03:25 -0500 Subject: [PATCH 21/48] forgot shims --- .../integration-shims/src/ReplayCanvas.ts | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 packages/integration-shims/src/ReplayCanvas.ts diff --git a/packages/integration-shims/src/ReplayCanvas.ts b/packages/integration-shims/src/ReplayCanvas.ts new file mode 100644 index 000000000000..1bff93359342 --- /dev/null +++ b/packages/integration-shims/src/ReplayCanvas.ts @@ -0,0 +1,41 @@ +import type { Integration } from '@sentry/types'; +import { consoleSandbox } from '@sentry/utils'; + +/** + * This is a shim for the Replay integration. + * It is needed in order for the CDN bundles to continue working when users add/remove replay + * from it, without changing their config. This is necessary for the loader mechanism. + */ +class ReplayCanvasShim implements Integration { + /** + * @inheritDoc + */ + public static id: string = 'ReplayCanvas'; + + /** + * @inheritDoc + */ + public name: string; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public constructor(_options: any) { + this.name = ReplayCanvasShim.id; + + consoleSandbox(() => { + // eslint-disable-next-line no-console + console.error('You are using new ReplayCanvas() even though this bundle does not include replay canvas.'); + }); + } + + /** jsdoc */ + public setupOnce(): void { + // noop + } + + /** jsdoc */ + public getOptions(): void { + // noop + } +} + +export { ReplayCanvasShim as ReplayCanvas }; From 645bbbbb06089cf0b34bbea2e261950219f471b1 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Wed, 10 Jan 2024 18:53:42 -0500 Subject: [PATCH 22/48] debug playwright test --- .../suites/replay/canvas/withCanvasIntegrationFirst/test.ts | 3 +++ .../suites/replay/canvas/withCanvasIntegrationSecond/test.ts | 3 +++ packages/replay-canvas/src/canvas.ts | 1 + packages/replay/src/integration.ts | 3 +++ 4 files changed, 10 insertions(+) diff --git a/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts b/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts index 104098eed2cf..792411ea783f 100644 --- a/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts +++ b/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts @@ -23,6 +23,9 @@ sentryTest('sets up canvas when adding ReplayCanvas integration first', async ({ await page.goto(url); await reqPromise0; + page.on('console', (m) => { + console.log(m); + }); const replay = await getReplaySnapshot(page); const canvasOptions = replay._canvas; expect(canvasOptions?.sampling.canvas).toBe(2); diff --git a/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts b/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts index d25066dc065b..2fe25a295b0d 100644 --- a/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts +++ b/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts @@ -23,6 +23,9 @@ sentryTest('sets up canvas when adding ReplayCanvas integration after Replay', a await page.goto(url); await reqPromise0; + page.on('console', (m) => { + console.log(m); + }); const replay = await getReplaySnapshot(page); const canvasOptions = replay._canvas; expect(canvasOptions?.sampling.canvas).toBe(2); diff --git a/packages/replay-canvas/src/canvas.ts b/packages/replay-canvas/src/canvas.ts index 90b65e5ccd35..b2d3c689ffbb 100644 --- a/packages/replay-canvas/src/canvas.ts +++ b/packages/replay-canvas/src/canvas.ts @@ -67,6 +67,7 @@ const replayCanvasIntegration = ((options: Partial = {}) => getOptions(): ReplayCanvasIntegrationOptions { const { quality } = _canvasOptions; + console.log('getoptions'); return { recordCanvas: true, getCanvasManager: (options: CanvasManagerOptions) => new CanvasManager(options), diff --git a/packages/replay/src/integration.ts b/packages/replay/src/integration.ts index c73da03c1b85..56f928cfb011 100644 --- a/packages/replay/src/integration.ts +++ b/packages/replay/src/integration.ts @@ -357,6 +357,7 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`, private _maybeLoadFromReplayCanvasIntegration(): void { // To save bundle size, we skip checking for stuff here // and instead just try-catch everything - as generally this should all be defined + console.log("maybeload") /* eslint-disable @typescript-eslint/no-non-null-assertion */ try { const client = getClient()!; @@ -364,10 +365,12 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`, getOptions(): ReplayCanvasIntegrationOptions; }; if (!canvasIntegration) { + console.log('no canvas integration'); return; } this._replay!['_canvas'] = canvasIntegration.getOptions(); + console.log(this._replay!['_canvas']) } catch { // ignore errors here } From 6e51bff26b4d0d40bce9c88f05a5475f27ba42e5 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Wed, 10 Jan 2024 22:52:54 -0500 Subject: [PATCH 23/48] Revert "debug playwright test" This reverts commit 7cf7b73a66bcd0a6ff485243e8662fe5344637e9. --- .../suites/replay/canvas/withCanvasIntegrationFirst/test.ts | 3 --- .../suites/replay/canvas/withCanvasIntegrationSecond/test.ts | 3 --- packages/replay-canvas/src/canvas.ts | 1 - packages/replay/src/integration.ts | 3 --- 4 files changed, 10 deletions(-) diff --git a/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts b/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts index 792411ea783f..104098eed2cf 100644 --- a/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts +++ b/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts @@ -23,9 +23,6 @@ sentryTest('sets up canvas when adding ReplayCanvas integration first', async ({ await page.goto(url); await reqPromise0; - page.on('console', (m) => { - console.log(m); - }); const replay = await getReplaySnapshot(page); const canvasOptions = replay._canvas; expect(canvasOptions?.sampling.canvas).toBe(2); diff --git a/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts b/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts index 2fe25a295b0d..d25066dc065b 100644 --- a/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts +++ b/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts @@ -23,9 +23,6 @@ sentryTest('sets up canvas when adding ReplayCanvas integration after Replay', a await page.goto(url); await reqPromise0; - page.on('console', (m) => { - console.log(m); - }); const replay = await getReplaySnapshot(page); const canvasOptions = replay._canvas; expect(canvasOptions?.sampling.canvas).toBe(2); diff --git a/packages/replay-canvas/src/canvas.ts b/packages/replay-canvas/src/canvas.ts index b2d3c689ffbb..90b65e5ccd35 100644 --- a/packages/replay-canvas/src/canvas.ts +++ b/packages/replay-canvas/src/canvas.ts @@ -67,7 +67,6 @@ const replayCanvasIntegration = ((options: Partial = {}) => getOptions(): ReplayCanvasIntegrationOptions { const { quality } = _canvasOptions; - console.log('getoptions'); return { recordCanvas: true, getCanvasManager: (options: CanvasManagerOptions) => new CanvasManager(options), diff --git a/packages/replay/src/integration.ts b/packages/replay/src/integration.ts index 56f928cfb011..c73da03c1b85 100644 --- a/packages/replay/src/integration.ts +++ b/packages/replay/src/integration.ts @@ -357,7 +357,6 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`, private _maybeLoadFromReplayCanvasIntegration(): void { // To save bundle size, we skip checking for stuff here // and instead just try-catch everything - as generally this should all be defined - console.log("maybeload") /* eslint-disable @typescript-eslint/no-non-null-assertion */ try { const client = getClient()!; @@ -365,12 +364,10 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`, getOptions(): ReplayCanvasIntegrationOptions; }; if (!canvasIntegration) { - console.log('no canvas integration'); return; } this._replay!['_canvas'] = canvasIntegration.getOptions(); - console.log(this._replay!['_canvas']) } catch { // ignore errors here } From 26d834e3931118dc6c03d24926a9826d18707dbb Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Thu, 11 Jan 2024 11:59:59 -0500 Subject: [PATCH 24/48] fix types --- packages/replay-canvas/src/canvas.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/replay-canvas/src/canvas.ts b/packages/replay-canvas/src/canvas.ts index 90b65e5ccd35..b3d64ffcf000 100644 --- a/packages/replay-canvas/src/canvas.ts +++ b/packages/replay-canvas/src/canvas.ts @@ -1,4 +1,3 @@ -import { CanvasManager } from '@sentry-internal/rrweb'; import { convertIntegrationFnToClass } from '@sentry/core'; import type { CanvasManagerInterface, CanvasManagerOptions } from '@sentry/replay'; import type { Integration, IntegrationClass, IntegrationFn } from '@sentry/types'; From fed7da29c1f932dc39c31b9e204bbd0758548ed3 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Thu, 11 Jan 2024 12:24:32 -0500 Subject: [PATCH 25/48] lint --- packages/replay-canvas/src/canvas.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/replay-canvas/src/canvas.ts b/packages/replay-canvas/src/canvas.ts index b3d64ffcf000..90b65e5ccd35 100644 --- a/packages/replay-canvas/src/canvas.ts +++ b/packages/replay-canvas/src/canvas.ts @@ -1,3 +1,4 @@ +import { CanvasManager } from '@sentry-internal/rrweb'; import { convertIntegrationFnToClass } from '@sentry/core'; import type { CanvasManagerInterface, CanvasManagerOptions } from '@sentry/replay'; import type { Integration, IntegrationClass, IntegrationFn } from '@sentry/types'; From 5aa96e331426145a950a8beec59090730c946d5a Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Mon, 15 Jan 2024 14:54:39 -0500 Subject: [PATCH 26/48] Revert "add replaycanvas to replay bundles" This reverts commit ab2d746f1365532695c53fda4263d48351752a8f. --- packages/browser/src/index.bundle.feedback.ts | 4 ++-- packages/browser/src/index.bundle.replay.ts | 3 +-- .../src/index.bundle.tracing.replay.feedback.ts | 3 +-- packages/browser/src/index.bundle.tracing.replay.ts | 3 +-- packages/browser/src/index.bundle.tracing.ts | 4 ++-- packages/browser/src/index.bundle.ts | 10 ++-------- .../browser/test/unit/index.bundle.feedback.test.ts | 7 +------ packages/browser/test/unit/index.bundle.replay.test.ts | 2 -- packages/browser/test/unit/index.bundle.test.ts | 2 -- .../unit/index.bundle.tracing.replay.feedback.test.ts | 3 +-- .../test/unit/index.bundle.tracing.replay.test.ts | 2 -- .../browser/test/unit/index.bundle.tracing.test.ts | 7 +------ packages/integration-shims/src/index.ts | 1 - 13 files changed, 12 insertions(+), 39 deletions(-) diff --git a/packages/browser/src/index.bundle.feedback.ts b/packages/browser/src/index.bundle.feedback.ts index 48d7b4aecf13..7aab6485d254 100644 --- a/packages/browser/src/index.bundle.feedback.ts +++ b/packages/browser/src/index.bundle.feedback.ts @@ -1,6 +1,6 @@ // This is exported so the loader does not fail when switching off Replay/Tracing import { Feedback } from '@sentry-internal/feedback'; -import { BrowserTracing, Replay, ReplayCanvas, addTracingExtensions } from '@sentry-internal/integration-shims'; +import { BrowserTracing, Replay, addTracingExtensions } from '@sentry-internal/integration-shims'; import * as Sentry from './index.bundle.base'; @@ -10,5 +10,5 @@ Sentry.Integrations.Replay = Replay; Sentry.Integrations.BrowserTracing = BrowserTracing; export * from './index.bundle.base'; -export { BrowserTracing, addTracingExtensions, Replay, ReplayCanvas, Feedback }; +export { BrowserTracing, addTracingExtensions, Replay, Feedback }; // Note: We do not export a shim for `Span` here, as that is quite complex and would blow up the bundle diff --git a/packages/browser/src/index.bundle.replay.ts b/packages/browser/src/index.bundle.replay.ts index e1fe19cda06c..0b556bc71b8e 100644 --- a/packages/browser/src/index.bundle.replay.ts +++ b/packages/browser/src/index.bundle.replay.ts @@ -1,6 +1,5 @@ // This is exported so the loader does not fail when switching off Replay/Tracing import { BrowserTracing, Feedback, addTracingExtensions } from '@sentry-internal/integration-shims'; -import { ReplayCanvas } from '@sentry-internal/replay-canvas'; import { Replay } from '@sentry/replay'; import * as Sentry from './index.bundle.base'; @@ -11,5 +10,5 @@ Sentry.Integrations.Replay = Replay; Sentry.Integrations.BrowserTracing = BrowserTracing; export * from './index.bundle.base'; -export { BrowserTracing, addTracingExtensions, Replay, ReplayCanvas, Feedback }; +export { BrowserTracing, addTracingExtensions, Replay, Feedback }; // Note: We do not export a shim for `Span` here, as that is quite complex and would blow up the bundle diff --git a/packages/browser/src/index.bundle.tracing.replay.feedback.ts b/packages/browser/src/index.bundle.tracing.replay.feedback.ts index 04dc02a8e946..5558703f7703 100644 --- a/packages/browser/src/index.bundle.tracing.replay.feedback.ts +++ b/packages/browser/src/index.bundle.tracing.replay.feedback.ts @@ -1,5 +1,4 @@ import { Feedback } from '@sentry-internal/feedback'; -import { ReplayCanvas } from '@sentry-internal/replay-canvas'; import { BrowserTracing, Span, addExtensionMethods } from '@sentry-internal/tracing'; import { Replay } from '@sentry/replay'; @@ -15,5 +14,5 @@ Sentry.Integrations.BrowserTracing = BrowserTracing; // We are patching the global object with our hub extension methods addExtensionMethods(); -export { Feedback, Replay, ReplayCanvas, BrowserTracing, Span, addExtensionMethods }; +export { Feedback, Replay, BrowserTracing, Span, addExtensionMethods }; export * from './index.bundle.base'; diff --git a/packages/browser/src/index.bundle.tracing.replay.ts b/packages/browser/src/index.bundle.tracing.replay.ts index 683d1509f9d8..0e7aa1ec19bc 100644 --- a/packages/browser/src/index.bundle.tracing.replay.ts +++ b/packages/browser/src/index.bundle.tracing.replay.ts @@ -1,5 +1,4 @@ import { Feedback } from '@sentry-internal/integration-shims'; -import { ReplayCanvas } from '@sentry-internal/replay-canvas'; import { BrowserTracing, Span, addExtensionMethods } from '@sentry-internal/tracing'; import { Replay } from '@sentry/replay'; @@ -15,5 +14,5 @@ Sentry.Integrations.BrowserTracing = BrowserTracing; // We are patching the global object with our hub extension methods addExtensionMethods(); -export { Feedback, Replay, ReplayCanvas, BrowserTracing, Span, addExtensionMethods }; +export { Feedback, Replay, BrowserTracing, Span, addExtensionMethods }; export * from './index.bundle.base'; diff --git a/packages/browser/src/index.bundle.tracing.ts b/packages/browser/src/index.bundle.tracing.ts index 0a958c634974..22b33962e860 100644 --- a/packages/browser/src/index.bundle.tracing.ts +++ b/packages/browser/src/index.bundle.tracing.ts @@ -1,5 +1,5 @@ // This is exported so the loader does not fail when switching off Replay -import { Feedback, Replay, ReplayCanvas } from '@sentry-internal/integration-shims'; +import { Feedback, Replay } from '@sentry-internal/integration-shims'; import { BrowserTracing, Span, addExtensionMethods } from '@sentry-internal/tracing'; import * as Sentry from './index.bundle.base'; @@ -14,5 +14,5 @@ Sentry.Integrations.BrowserTracing = BrowserTracing; // We are patching the global object with our hub extension methods addExtensionMethods(); -export { Feedback, Replay, ReplayCanvas, BrowserTracing, Span, addExtensionMethods }; +export { Feedback, Replay, BrowserTracing, Span, addExtensionMethods }; export * from './index.bundle.base'; diff --git a/packages/browser/src/index.bundle.ts b/packages/browser/src/index.bundle.ts index f479757db105..a2541ceadda1 100644 --- a/packages/browser/src/index.bundle.ts +++ b/packages/browser/src/index.bundle.ts @@ -1,11 +1,5 @@ // This is exported so the loader does not fail when switching off Replay/Tracing -import { - BrowserTracing, - Feedback, - Replay, - ReplayCanvas, - addTracingExtensions, -} from '@sentry-internal/integration-shims'; +import { BrowserTracing, Feedback, Replay, addTracingExtensions } from '@sentry-internal/integration-shims'; import * as Sentry from './index.bundle.base'; @@ -15,5 +9,5 @@ Sentry.Integrations.Replay = Replay; Sentry.Integrations.BrowserTracing = BrowserTracing; export * from './index.bundle.base'; -export { BrowserTracing, addTracingExtensions, Replay, ReplayCanvas, Feedback }; +export { BrowserTracing, addTracingExtensions, Replay, Feedback }; // Note: We do not export a shim for `Span` here, as that is quite complex and would blow up the bundle diff --git a/packages/browser/test/unit/index.bundle.feedback.test.ts b/packages/browser/test/unit/index.bundle.feedback.test.ts index 03bb93047a5c..4c5f26e5f313 100644 --- a/packages/browser/test/unit/index.bundle.feedback.test.ts +++ b/packages/browser/test/unit/index.bundle.feedback.test.ts @@ -1,8 +1,4 @@ -import { - BrowserTracing as BrowserTracingShim, - Replay as ReplayShim, - ReplayCanvas as ReplayCanvasShim, -} from '@sentry-internal/integration-shims'; +import { BrowserTracing as BrowserTracingShim, Replay as ReplayShim } from '@sentry-internal/integration-shims'; import { Feedback } from '@sentry/browser'; import * as TracingReplayBundle from '../../src/index.bundle.feedback'; @@ -20,7 +16,6 @@ describe('index.bundle.feedback', () => { expect(TracingReplayBundle.Integrations.Replay).toBe(ReplayShim); expect(TracingReplayBundle.Replay).toBe(ReplayShim); - expect(TracingReplayBundle.ReplayCanvas).toBe(ReplayCanvasShim); expect(TracingReplayBundle.Integrations.BrowserTracing).toBe(BrowserTracingShim); expect(TracingReplayBundle.BrowserTracing).toBe(BrowserTracingShim); diff --git a/packages/browser/test/unit/index.bundle.replay.test.ts b/packages/browser/test/unit/index.bundle.replay.test.ts index 30eb69ee27cd..b14eb70f6330 100644 --- a/packages/browser/test/unit/index.bundle.replay.test.ts +++ b/packages/browser/test/unit/index.bundle.replay.test.ts @@ -1,6 +1,5 @@ import { BrowserTracing as BrowserTracingShim, Feedback as FeedbackShim } from '@sentry-internal/integration-shims'; import { Replay } from '@sentry/browser'; -import { ReplayCanvas } from '@sentry/browser'; import * as TracingReplayBundle from '../../src/index.bundle.replay'; @@ -17,7 +16,6 @@ describe('index.bundle.replay', () => { expect(TracingReplayBundle.Integrations.Replay).toBe(Replay); expect(TracingReplayBundle.Replay).toBe(Replay); - expect(TracingReplayBundle.ReplayCanvas).toBe(ReplayCanvas); expect(TracingReplayBundle.Integrations.BrowserTracing).toBe(BrowserTracingShim); expect(TracingReplayBundle.BrowserTracing).toBe(BrowserTracingShim); diff --git a/packages/browser/test/unit/index.bundle.test.ts b/packages/browser/test/unit/index.bundle.test.ts index 08cbd86145a4..f61987732858 100644 --- a/packages/browser/test/unit/index.bundle.test.ts +++ b/packages/browser/test/unit/index.bundle.test.ts @@ -2,7 +2,6 @@ import { BrowserTracing as BrowserTracingShim, Feedback as FeedbackShim, Replay as ReplayShim, - ReplayCanvas as ReplayCanvasShim, } from '@sentry-internal/integration-shims'; import * as TracingBundle from '../../src/index.bundle'; @@ -20,7 +19,6 @@ describe('index.bundle', () => { expect(TracingBundle.Integrations.Replay).toBe(ReplayShim); expect(TracingBundle.Replay).toBe(ReplayShim); - expect(TracingBundle.ReplayCanvas).toBe(ReplayCanvasShim); expect(TracingBundle.Integrations.BrowserTracing).toBe(BrowserTracingShim); expect(TracingBundle.BrowserTracing).toBe(BrowserTracingShim); diff --git a/packages/browser/test/unit/index.bundle.tracing.replay.feedback.test.ts b/packages/browser/test/unit/index.bundle.tracing.replay.feedback.test.ts index 9f9076374b1e..0bd50453da43 100644 --- a/packages/browser/test/unit/index.bundle.tracing.replay.feedback.test.ts +++ b/packages/browser/test/unit/index.bundle.tracing.replay.feedback.test.ts @@ -1,5 +1,5 @@ import { BrowserTracing } from '@sentry-internal/tracing'; -import { Feedback, Replay, ReplayCanvas } from '@sentry/browser'; +import { Feedback, Replay } from '@sentry/browser'; import * as TracingReplayFeedbackBundle from '../../src/index.bundle.tracing.replay.feedback'; @@ -16,7 +16,6 @@ describe('index.bundle.tracing.replay.feedback', () => { expect(TracingReplayFeedbackBundle.Integrations.Replay).toBe(Replay); expect(TracingReplayFeedbackBundle.Replay).toBe(Replay); - expect(TracingReplayFeedbackBundle.ReplayCanvas).toBe(ReplayCanvas); expect(TracingReplayFeedbackBundle.Integrations.BrowserTracing).toBe(BrowserTracing); expect(TracingReplayFeedbackBundle.BrowserTracing).toBe(BrowserTracing); diff --git a/packages/browser/test/unit/index.bundle.tracing.replay.test.ts b/packages/browser/test/unit/index.bundle.tracing.replay.test.ts index c016367f2bf6..4c8af2130a3b 100644 --- a/packages/browser/test/unit/index.bundle.tracing.replay.test.ts +++ b/packages/browser/test/unit/index.bundle.tracing.replay.test.ts @@ -1,7 +1,6 @@ import { Feedback as FeedbackShim } from '@sentry-internal/integration-shims'; import { BrowserTracing } from '@sentry-internal/tracing'; import { Replay } from '@sentry/browser'; -import { ReplayCanvas } from '@sentry/browser'; import * as TracingReplayBundle from '../../src/index.bundle.tracing.replay'; @@ -18,7 +17,6 @@ describe('index.bundle.tracing.replay', () => { expect(TracingReplayBundle.Integrations.Replay).toBe(Replay); expect(TracingReplayBundle.Replay).toBe(Replay); - expect(TracingReplayBundle.ReplayCanvas).toBe(ReplayCanvas); expect(TracingReplayBundle.Integrations.BrowserTracing).toBe(BrowserTracing); expect(TracingReplayBundle.BrowserTracing).toBe(BrowserTracing); diff --git a/packages/browser/test/unit/index.bundle.tracing.test.ts b/packages/browser/test/unit/index.bundle.tracing.test.ts index bce177ce0d72..b439dece8c6f 100644 --- a/packages/browser/test/unit/index.bundle.tracing.test.ts +++ b/packages/browser/test/unit/index.bundle.tracing.test.ts @@ -1,8 +1,4 @@ -import { - Feedback as FeedbackShim, - Replay as ReplayShim, - ReplayCanvas as ReplayCanvasShim, -} from '@sentry-internal/integration-shims'; +import { Feedback as FeedbackShim, Replay as ReplayShim } from '@sentry-internal/integration-shims'; import { BrowserTracing } from '@sentry-internal/tracing'; import * as TracingBundle from '../../src/index.bundle.tracing'; @@ -20,7 +16,6 @@ describe('index.bundle.tracing', () => { expect(TracingBundle.Integrations.Replay).toBe(ReplayShim); expect(TracingBundle.Replay).toBe(ReplayShim); - expect(TracingBundle.ReplayCanvas).toBe(ReplayCanvasShim); expect(TracingBundle.Integrations.BrowserTracing).toBe(BrowserTracing); expect(TracingBundle.BrowserTracing).toBe(BrowserTracing); diff --git a/packages/integration-shims/src/index.ts b/packages/integration-shims/src/index.ts index 31958781ac44..410a4a31d9c8 100644 --- a/packages/integration-shims/src/index.ts +++ b/packages/integration-shims/src/index.ts @@ -1,4 +1,3 @@ export { Feedback } from './Feedback'; export { Replay } from './Replay'; -export { ReplayCanvas } from './ReplayCanvas'; export { BrowserTracing, addTracingExtensions } from './BrowserTracing'; From 6d5a0f25b48e66bc12a2abbba50991f874895405 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Mon, 15 Jan 2024 14:55:00 -0500 Subject: [PATCH 27/48] Revert "forgot shims" This reverts commit 9dd87585ac01e33cd6134030d6c40cc91db14291. --- .../integration-shims/src/ReplayCanvas.ts | 41 ------------------- 1 file changed, 41 deletions(-) delete mode 100644 packages/integration-shims/src/ReplayCanvas.ts diff --git a/packages/integration-shims/src/ReplayCanvas.ts b/packages/integration-shims/src/ReplayCanvas.ts deleted file mode 100644 index 1bff93359342..000000000000 --- a/packages/integration-shims/src/ReplayCanvas.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type { Integration } from '@sentry/types'; -import { consoleSandbox } from '@sentry/utils'; - -/** - * This is a shim for the Replay integration. - * It is needed in order for the CDN bundles to continue working when users add/remove replay - * from it, without changing their config. This is necessary for the loader mechanism. - */ -class ReplayCanvasShim implements Integration { - /** - * @inheritDoc - */ - public static id: string = 'ReplayCanvas'; - - /** - * @inheritDoc - */ - public name: string; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public constructor(_options: any) { - this.name = ReplayCanvasShim.id; - - consoleSandbox(() => { - // eslint-disable-next-line no-console - console.error('You are using new ReplayCanvas() even though this bundle does not include replay canvas.'); - }); - } - - /** jsdoc */ - public setupOnce(): void { - // noop - } - - /** jsdoc */ - public getOptions(): void { - // noop - } -} - -export { ReplayCanvasShim as ReplayCanvas }; From 833ee6f1f82f700da69243fcbb86973b77a7300e Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Mon, 15 Jan 2024 19:35:08 -0500 Subject: [PATCH 28/48] add `canvas` to options event --- packages/replay/src/types/replayFrame.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/replay/src/types/replayFrame.ts b/packages/replay/src/types/replayFrame.ts index 3a595e47a4cf..68ffed20d714 100644 --- a/packages/replay/src/types/replayFrame.ts +++ b/packages/replay/src/types/replayFrame.ts @@ -114,6 +114,7 @@ export interface ReplayMultiClickFrame extends ReplayBaseBreadcrumbFrame { interface ReplayOptionFrame { blockAllMedia: boolean; + canvas: boolean; errorSampleRate: number; maskAllInputs: boolean; maskAllText: boolean; From 1f790e207879bdb18acfe85dd3d9ecd9b7942b65 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Tue, 16 Jan 2024 12:01:11 -0500 Subject: [PATCH 29/48] move replay-canvas to devDeps --- packages/browser/package.json | 2 +- packages/replay-canvas/package.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/browser/package.json b/packages/browser/package.json index d367f603d701..1311053ffdee 100644 --- a/packages/browser/package.json +++ b/packages/browser/package.json @@ -30,7 +30,6 @@ }, "dependencies": { "@sentry-internal/feedback": "7.93.0", - "@sentry-internal/replay-canvas": "7.93.0", "@sentry-internal/tracing": "7.93.0", "@sentry/core": "7.93.0", "@sentry/replay": "7.93.0", @@ -38,6 +37,7 @@ "@sentry/utils": "7.93.0" }, "devDependencies": { + "@sentry-internal/replay-canvas": "7.93.0", "@sentry-internal/integration-shims": "7.93.0", "@types/md5": "2.1.33", "btoa": "^1.2.1", diff --git a/packages/replay-canvas/package.json b/packages/replay-canvas/package.json index 81a70f18c20d..fbae2055482d 100644 --- a/packages/replay-canvas/package.json +++ b/packages/replay-canvas/package.json @@ -19,6 +19,7 @@ "types-ts3.8" ], "sideEffects": false, + "private": true, "scripts": { "build": "run-p build:transpile build:types build:bundle", "build:transpile": "rollup -c rollup.npm.config.mjs", From 1121e89e7df92a592b50c030983670b708f5f316 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Tue, 16 Jan 2024 12:53:15 -0500 Subject: [PATCH 30/48] canvas --> shouldRecordCanvas --- packages/replay/src/types/replayFrame.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/replay/src/types/replayFrame.ts b/packages/replay/src/types/replayFrame.ts index 68ffed20d714..3a595e47a4cf 100644 --- a/packages/replay/src/types/replayFrame.ts +++ b/packages/replay/src/types/replayFrame.ts @@ -114,7 +114,6 @@ export interface ReplayMultiClickFrame extends ReplayBaseBreadcrumbFrame { interface ReplayOptionFrame { blockAllMedia: boolean; - canvas: boolean; errorSampleRate: number; maskAllInputs: boolean; maskAllText: boolean; From e805e6c560f040d218d68f5f5c2e12fcf13aeeaa Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Tue, 16 Jan 2024 13:09:02 -0500 Subject: [PATCH 31/48] move back to deps --- packages/browser/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/browser/package.json b/packages/browser/package.json index 1311053ffdee..d367f603d701 100644 --- a/packages/browser/package.json +++ b/packages/browser/package.json @@ -30,6 +30,7 @@ }, "dependencies": { "@sentry-internal/feedback": "7.93.0", + "@sentry-internal/replay-canvas": "7.93.0", "@sentry-internal/tracing": "7.93.0", "@sentry/core": "7.93.0", "@sentry/replay": "7.93.0", @@ -37,7 +38,6 @@ "@sentry/utils": "7.93.0" }, "devDependencies": { - "@sentry-internal/replay-canvas": "7.93.0", "@sentry-internal/integration-shims": "7.93.0", "@types/md5": "2.1.33", "btoa": "^1.2.1", From ec1bbe986a9cdbced429eebd6c820699d5449098 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Tue, 16 Jan 2024 13:29:07 -0500 Subject: [PATCH 32/48] remove private: true, fails the e2e tests --- packages/replay-canvas/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/replay-canvas/package.json b/packages/replay-canvas/package.json index fbae2055482d..81a70f18c20d 100644 --- a/packages/replay-canvas/package.json +++ b/packages/replay-canvas/package.json @@ -19,7 +19,6 @@ "types-ts3.8" ], "sideEffects": false, - "private": true, "scripts": { "build": "run-p build:transpile build:types build:bundle", "build:transpile": "rollup -c rollup.npm.config.mjs", From 7ee6be032447c8fe05bcdb0df26643119e403bd8 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Thu, 4 Jan 2024 16:48:07 +0100 Subject: [PATCH 33/48] feat(replay): Add `ReplayCanvas` integration Adding this integration in addition to `Replay` will set up canvas recording. --- .../suites/replay/canvas/template.html | 9 ++++ .../canvas/withCanvasIntegrationFirst/init.js | 18 +++++++ .../canvas/withCanvasIntegrationFirst/test.ts | 28 ++++++++++ .../withCanvasIntegrationSecond/init.js | 18 +++++++ .../withCanvasIntegrationSecond/test.ts | 28 ++++++++++ .../canvas/withoutCanvasIntegration/init.js | 18 +++++++ .../canvas/withoutCanvasIntegration/test.ts | 27 ++++++++++ packages/browser/src/index.ts | 2 +- packages/replay/rollup.bundle.config.mjs | 12 ++++- packages/replay/src/canvas.ts | 54 +++++++++++++++++++ packages/replay/src/index.ts | 1 + packages/types/src/client.ts | 9 ++-- 12 files changed, 215 insertions(+), 9 deletions(-) create mode 100644 packages/browser-integration-tests/suites/replay/canvas/template.html create mode 100644 packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/init.js create mode 100644 packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts create mode 100644 packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/init.js create mode 100644 packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts create mode 100644 packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/init.js create mode 100644 packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/test.ts create mode 100644 packages/replay/src/canvas.ts diff --git a/packages/browser-integration-tests/suites/replay/canvas/template.html b/packages/browser-integration-tests/suites/replay/canvas/template.html new file mode 100644 index 000000000000..2b3e2f0b27b4 --- /dev/null +++ b/packages/browser-integration-tests/suites/replay/canvas/template.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/init.js b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/init.js new file mode 100644 index 000000000000..fa3248066150 --- /dev/null +++ b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/init.js @@ -0,0 +1,18 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; +window.Replay = new Sentry.Replay({ + flushMinDelay: 200, + flushMaxDelay: 200, + minReplayDuration: 0, +}); + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + sampleRate: 0, + replaysSessionSampleRate: 1.0, + replaysOnErrorSampleRate: 0.0, + debug: true, + + integrations: [new Sentry.ReplayCanvas(), window.Replay], +}); diff --git a/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts new file mode 100644 index 000000000000..7326bed95ae6 --- /dev/null +++ b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts @@ -0,0 +1,28 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getReplaySnapshot, shouldSkipReplayTest } from '../../../../utils/replayHelpers'; + +sentryTest('sets up canvas when adding ReplayCanvas integration first', async ({ getLocalTestUrl, page }) => { + if (shouldSkipReplayTest()) { + sentryTest.skip(); + } + + await page.route('https://dsn.ingest.sentry.io/**/*', route => { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ id: 'test-id' }), + }); + }); + + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.goto(url); + + const replay = await getReplaySnapshot(page); + const canvasOptions = replay._options._experiments?.canvas; + expect(canvasOptions.fps).toBe(4); + expect(canvasOptions.quality).toBe(0.6); + expect(replay._hasCanvas).toBe(true); +}); diff --git a/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/init.js b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/init.js new file mode 100644 index 000000000000..1a9d5d179c4a --- /dev/null +++ b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/init.js @@ -0,0 +1,18 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; +window.Replay = new Sentry.Replay({ + flushMinDelay: 200, + flushMaxDelay: 200, + minReplayDuration: 0, +}); + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + sampleRate: 0, + replaysSessionSampleRate: 1.0, + replaysOnErrorSampleRate: 0.0, + debug: true, + + integrations: [window.Replay, new Sentry.ReplayCanvas()], +}); diff --git a/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts new file mode 100644 index 000000000000..9168864db7e0 --- /dev/null +++ b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts @@ -0,0 +1,28 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getReplaySnapshot, shouldSkipReplayTest } from '../../../../utils/replayHelpers'; + +sentryTest('sets up canvas when adding ReplayCanvas integration after Replay', async ({ getLocalTestUrl, page }) => { + if (shouldSkipReplayTest()) { + sentryTest.skip(); + } + + await page.route('https://dsn.ingest.sentry.io/**/*', route => { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ id: 'test-id' }), + }); + }); + + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.goto(url); + + const replay = await getReplaySnapshot(page); + const canvasOptions = replay._options._experiments?.canvas; + expect(canvasOptions.fps).toBe(4); + expect(canvasOptions.quality).toBe(0.6); + expect(replay._hasCanvas).toBe(true); +}); diff --git a/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/init.js b/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/init.js new file mode 100644 index 000000000000..92a463a4bc84 --- /dev/null +++ b/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/init.js @@ -0,0 +1,18 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; +window.Replay = new Sentry.Replay({ + flushMinDelay: 200, + flushMaxDelay: 200, + minReplayDuration: 0, +}); + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + sampleRate: 0, + replaysSessionSampleRate: 1.0, + replaysOnErrorSampleRate: 0.0, + debug: true, + + integrations: [window.Replay], +}); diff --git a/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/test.ts b/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/test.ts new file mode 100644 index 000000000000..b2ce69211be0 --- /dev/null +++ b/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/test.ts @@ -0,0 +1,27 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getReplaySnapshot, shouldSkipReplayTest } from '../../../../utils/replayHelpers'; + +sentryTest('does not setup up canvas without ReplayCanvas integration', async ({ getLocalTestUrl, page }) => { + if (shouldSkipReplayTest()) { + sentryTest.skip(); + } + + await page.route('https://dsn.ingest.sentry.io/**/*', route => { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ id: 'test-id' }), + }); + }); + + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.goto(url); + + const replay = await getReplaySnapshot(page); + const canvasOptions = replay._options._experiments?.canvas; + expect(canvasOptions).toBe(undefined); + expect(replay._hasCanvas).toBe(false); +}); diff --git a/packages/browser/src/index.ts b/packages/browser/src/index.ts index e97b6e98b816..b8692c7aaf8e 100644 --- a/packages/browser/src/index.ts +++ b/packages/browser/src/index.ts @@ -21,7 +21,7 @@ const INTEGRATIONS = { export { INTEGRATIONS as Integrations }; -export { Replay } from '@sentry/replay'; +export { Replay, ReplayCanvas } from '@sentry/replay'; export type { ReplayEventType, ReplayEventWithTime, diff --git a/packages/replay/rollup.bundle.config.mjs b/packages/replay/rollup.bundle.config.mjs index a209b8d41af4..b254dae8d8d2 100644 --- a/packages/replay/rollup.bundle.config.mjs +++ b/packages/replay/rollup.bundle.config.mjs @@ -2,12 +2,20 @@ import { makeBaseBundleConfig, makeBundleConfigVariants } from '@sentry-internal const baseBundleConfig = makeBaseBundleConfig({ bundleType: 'addon', - entrypoints: ['src/index.ts'], + entrypoints: ['src/integration.ts'], jsVersion: 'es6', licenseTitle: '@sentry/replay', outputFileBase: () => 'bundles/replay', }); -const builds = makeBundleConfigVariants(baseBundleConfig); +const baseCanvasBundleConfig = makeBaseBundleConfig({ + bundleType: 'addon', + entrypoints: ['src/canvas.ts'], + jsVersion: 'es6', + licenseTitle: '@sentry/replaycanvas', + outputFileBase: () => 'bundles/replaycanvas', +}); + +const builds = [...makeBundleConfigVariants(baseBundleConfig), ...makeBundleConfigVariants(baseCanvasBundleConfig)]; export default builds; diff --git a/packages/replay/src/canvas.ts b/packages/replay/src/canvas.ts new file mode 100644 index 000000000000..b3fe2afa60f0 --- /dev/null +++ b/packages/replay/src/canvas.ts @@ -0,0 +1,54 @@ +import { getCanvasManager } from '@sentry-internal/rrweb'; +import type { Integration } from '@sentry/types'; +import type { ReplayConfiguration } from './types'; + +interface ReplayCanvasOptions { + fps: number; + quality: number; +} + +/** An integration to add canvas recording to replay. */ +export class ReplayCanvas implements Integration { + /** + * @inheritDoc + */ + public static id: string = 'ReplayCanvas'; + + /** + * @inheritDoc + */ + public name: string; + + private _canvasOptions: ReplayCanvasOptions; + + public constructor() { + this.name = ReplayCanvas.id; + // TODO FN: Allow to configure this + // But since we haven't finalized how to configure this, this is predefined for now + // to avoid breaking changes + this._canvasOptions = { + fps: 4, + quality: 0.6, + }; + } + + /** @inheritdoc */ + public setupOnce(): void { + // noop + } + + /** + * Get the options that should be merged into replay options. + * This is what is actually called by the Replay integration to setup canvas. + */ + public getOptions(): Partial { + return { + _experiments: { + canvas: { + ...this._canvasOptions, + manager: getCanvasManager, + }, + }, + }; + } +} diff --git a/packages/replay/src/index.ts b/packages/replay/src/index.ts index 8e8a5d55579a..60d297434924 100644 --- a/packages/replay/src/index.ts +++ b/packages/replay/src/index.ts @@ -1,4 +1,5 @@ export { Replay } from './integration'; +export { ReplayCanvas } from './canvas'; export type { ReplayConfiguration, diff --git a/packages/types/src/client.ts b/packages/types/src/client.ts index d8d09ec1431b..f780277942b5 100644 --- a/packages/types/src/client.ts +++ b/packages/types/src/client.ts @@ -138,14 +138,11 @@ export interface Client { */ getEventProcessors?(): EventProcessor[]; - /** - * Returns the client's instance of the given integration class, it any. - * @deprecated Use `getIntegrationByName()` instead. - */ + /** Returns the client's instance of the given integration class, if it exists. */ getIntegration(integration: IntegrationClass): T | null; - /** Get the instance of the integration with the given name on the client, if it was added. */ - getIntegrationByName?(name: string): T | undefined; + /** Returns the client's instance of the given integration name, if it exists. */ + getIntegrationById?(integrationId: string): Integration | undefined; /** * Add an integration to the client. From 0f32f8a3f8054d16db0b7e529fb44296cb86f23b Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Wed, 10 Jan 2024 10:01:36 -0500 Subject: [PATCH 34/48] refactor out integrations abstraction --- dev-packages/browser-integration-tests/utils/replayHelpers.ts | 2 +- packages/replay/src/integration.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dev-packages/browser-integration-tests/utils/replayHelpers.ts b/dev-packages/browser-integration-tests/utils/replayHelpers.ts index 295ae82e0fa3..4b1623ed7318 100644 --- a/dev-packages/browser-integration-tests/utils/replayHelpers.ts +++ b/dev-packages/browser-integration-tests/utils/replayHelpers.ts @@ -1,5 +1,5 @@ /* eslint-disable max-lines */ -import type { ReplayCanvasIntegrationOptions } from '@sentry-internal/replay-canvas'; +import { ReplayCanvasIntegrationOptions } from '@sentry-internal/replay-canvas'; import type { fullSnapshotEvent, incrementalSnapshotEvent } from '@sentry-internal/rrweb'; import { EventType } from '@sentry-internal/rrweb'; import type { ReplayEventWithTime } from '@sentry/browser'; diff --git a/packages/replay/src/integration.ts b/packages/replay/src/integration.ts index c73da03c1b85..9bebfe011b47 100644 --- a/packages/replay/src/integration.ts +++ b/packages/replay/src/integration.ts @@ -360,8 +360,8 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`, /* eslint-disable @typescript-eslint/no-non-null-assertion */ try { const client = getClient()!; - const canvasIntegration = client.getIntegrationByName!('ReplayCanvas') as Integration & { - getOptions(): ReplayCanvasIntegrationOptions; + const canvasIntegration = client.getIntegrationById!('ReplayCanvas') as Integration & { + getOptions(): Partial; }; if (!canvasIntegration) { return; From 9a09eff2be53e3d82ecaf0b0f64b346292af7f4a Mon Sep 17 00:00:00 2001 From: Catherine Lee <55311782+c298lee@users.noreply.github.com> Date: Fri, 12 Jan 2024 11:07:13 -0500 Subject: [PATCH 35/48] add snapshot to shim --- .../integration-shims/src/ReplayCanvas.ts | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 packages/integration-shims/src/ReplayCanvas.ts diff --git a/packages/integration-shims/src/ReplayCanvas.ts b/packages/integration-shims/src/ReplayCanvas.ts new file mode 100644 index 000000000000..6e2ebc6f7179 --- /dev/null +++ b/packages/integration-shims/src/ReplayCanvas.ts @@ -0,0 +1,46 @@ +import type { Integration } from '@sentry/types'; +import { consoleSandbox } from '@sentry/utils'; + +/** + * This is a shim for the Replay integration. + * It is needed in order for the CDN bundles to continue working when users add/remove replay + * from it, without changing their config. This is necessary for the loader mechanism. + */ +class ReplayCanvasShim implements Integration { + /** + * @inheritDoc + */ + public static id: string = 'ReplayCanvas'; + + /** + * @inheritDoc + */ + public name: string; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public constructor(_options: any) { + this.name = ReplayCanvasShim.id; + + consoleSandbox(() => { + // eslint-disable-next-line no-console + console.error('You are using new ReplayCanvas() even though this bundle does not include replay canvas.'); + }); + } + + /** jsdoc */ + public setupOnce(): void { + // noop + } + + /** jsdoc */ + public getOptions(): void { + // noop + } + + /** jsdoc */ + public async snapshot(): Promise { + // noop + } +} + +export { ReplayCanvasShim as ReplayCanvas }; From d3f23cc678cdef678d3f6112328bb47ed8fd104c Mon Sep 17 00:00:00 2001 From: Catherine Lee <55311782+c298lee@users.noreply.github.com> Date: Fri, 12 Jan 2024 11:21:34 -0500 Subject: [PATCH 36/48] lint --- packages/replay-canvas/src/canvas.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/replay-canvas/src/canvas.ts b/packages/replay-canvas/src/canvas.ts index d8232471e6e3..9fcd3555fee7 100644 --- a/packages/replay-canvas/src/canvas.ts +++ b/packages/replay-canvas/src/canvas.ts @@ -71,14 +71,14 @@ const replayCanvasIntegration = ((options: Partial = {}) => return { enableManualSnapshot: options.enableManualSnapshot, recordCanvas: true, - getCanvasManager: (options: CanvasManagerOptions) => _canvasManager = new CanvasManager(options), + getCanvasManager: (options: CanvasManagerOptions) => (_canvasManager = new CanvasManager(options)), ...(CANVAS_QUALITY[quality || 'medium'] || CANVAS_QUALITY.medium), }; }, async snapshot(canvasElement?: HTMLCanvasElement) { // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access _canvasManager.snapshot(canvasElement); - } + }, }; }) satisfies IntegrationFn; From 43daae2146893792c7c65762711f734952cb4e28 Mon Sep 17 00:00:00 2001 From: Catherine Lee <55311782+c298lee@users.noreply.github.com> Date: Mon, 15 Jan 2024 18:29:27 -0500 Subject: [PATCH 37/48] test and snapshot --- .../suites/replay/canvas/snapshots/init.js | 18 +++++ .../replay/canvas/snapshots/template.html | 26 ++++++ .../suites/replay/canvas/snapshots/test.ts | 79 +++++++++++++++++++ packages/replay-canvas/src/canvas.ts | 13 +-- packages/replay/src/replay.ts | 1 - 5 files changed, 130 insertions(+), 7 deletions(-) create mode 100644 dev-packages/browser-integration-tests/suites/replay/canvas/snapshots/init.js create mode 100644 dev-packages/browser-integration-tests/suites/replay/canvas/snapshots/template.html create mode 100644 dev-packages/browser-integration-tests/suites/replay/canvas/snapshots/test.ts diff --git a/dev-packages/browser-integration-tests/suites/replay/canvas/snapshots/init.js b/dev-packages/browser-integration-tests/suites/replay/canvas/snapshots/init.js new file mode 100644 index 000000000000..244f951588c6 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/replay/canvas/snapshots/init.js @@ -0,0 +1,18 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; +window.Replay = new Sentry.Replay({ + flushMinDelay: 50, + flushMaxDelay: 50, + minReplayDuration: 0, +}); + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + sampleRate: 0, + replaysSessionSampleRate: 1.0, + replaysOnErrorSampleRate: 0.0, + debug: true, + + integrations: [window.Replay, new Sentry.ReplayCanvas({ enableManualSnapshot: true })], +}); diff --git a/dev-packages/browser-integration-tests/suites/replay/canvas/snapshots/template.html b/dev-packages/browser-integration-tests/suites/replay/canvas/snapshots/template.html new file mode 100644 index 000000000000..5f23d569fcc2 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/replay/canvas/snapshots/template.html @@ -0,0 +1,26 @@ + + + + + + + + + + + + + diff --git a/dev-packages/browser-integration-tests/suites/replay/canvas/snapshots/test.ts b/dev-packages/browser-integration-tests/suites/replay/canvas/snapshots/test.ts new file mode 100644 index 000000000000..40d2dbf0e538 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/replay/canvas/snapshots/test.ts @@ -0,0 +1,79 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getReplayRecordingContent, shouldSkipReplayTest, waitForReplayRequest } from '../../../../utils/replayHelpers'; + +sentryTest('can manually snapshot canvas', async ({ getLocalTestUrl, page, browserName }) => { + if (shouldSkipReplayTest() || browserName === 'webkit') { + sentryTest.skip(); + } + + const reqPromise0 = waitForReplayRequest(page, 0); + const reqPromise1 = waitForReplayRequest(page, 1); + const reqPromise2 = waitForReplayRequest(page, 2); + const reqPromise3 = waitForReplayRequest(page, 3); + + await page.route('https://dsn.ingest.sentry.io/**/*', route => { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ id: 'test-id' }), + }); + }); + + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.goto(url); + await reqPromise0; + await Promise.all([page.click('#draw'), reqPromise1]); + + const { incrementalSnapshots } = getReplayRecordingContent(await reqPromise2); + expect(incrementalSnapshots).toEqual([]); + + await page.evaluate(() => { + (window as any).Sentry.getClient().getIntegrationById('ReplayCanvas').snapshot(); + }); + + const { incrementalSnapshots:incrementalSnapshotsManual } = getReplayRecordingContent(await reqPromise3); + expect(incrementalSnapshotsManual).toEqual( + expect.arrayContaining([ + { + data: { + commands: [ + { + args: [0, 0, 150, 150], + property: 'clearRect', + }, + { + args: [ + { + args: [ + { + data: [ + { + base64: expect.any(String), + rr_type: 'ArrayBuffer', + }, + ], + rr_type: 'Blob', + type: 'image/webp', + }, + ], + rr_type: 'ImageBitmap', + }, + 0, + 0, + ], + property: 'drawImage', + }, + ], + id: 9, + source: 9, + type: 0, + }, + timestamp: 0, + type: 3, + }, + ]), + ); +}); diff --git a/packages/replay-canvas/src/canvas.ts b/packages/replay-canvas/src/canvas.ts index 9fcd3555fee7..c592a3cd980a 100644 --- a/packages/replay-canvas/src/canvas.ts +++ b/packages/replay-canvas/src/canvas.ts @@ -59,25 +59,26 @@ const INTEGRATION_NAME = 'ReplayCanvas'; const replayCanvasIntegration = ((options: Partial = {}) => { const _canvasOptions = { quality: options.quality || 'medium', + enableManualSnapshot: options.enableManualSnapshot, }; - let _canvasManager: CanvasManager; + let canvasManagerResolve: (value: CanvasManager) => void; + const _canvasManager: Promise = new Promise((resolve) => canvasManagerResolve = resolve); return { name: INTEGRATION_NAME, getOptions(): ReplayCanvasIntegrationOptions { - const { quality } = _canvasOptions; + const { quality, enableManualSnapshot } = _canvasOptions; return { - enableManualSnapshot: options.enableManualSnapshot, recordCanvas: true, - getCanvasManager: (options: CanvasManagerOptions) => (_canvasManager = new CanvasManager(options)), + getCanvasManager: (options: CanvasManagerOptions) => (canvasManagerResolve(new CanvasManager({ ...options, isManualSnapshot: enableManualSnapshot } ))), ...(CANVAS_QUALITY[quality || 'medium'] || CANVAS_QUALITY.medium), }; }, async snapshot(canvasElement?: HTMLCanvasElement) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - _canvasManager.snapshot(canvasElement); + const canvasManager = await _canvasManager; + canvasManager.snapshot(canvasElement); }, }; }) satisfies IntegrationFn; diff --git a/packages/replay/src/replay.ts b/packages/replay/src/replay.ts index 587ba6bb08e0..8302bbb0c8b6 100644 --- a/packages/replay/src/replay.ts +++ b/packages/replay/src/replay.ts @@ -355,7 +355,6 @@ export class ReplayContainer implements ReplayContainerInterface { onMutation: this._onMutationHandler, ...(canvasOptions ? { - isManualSnapshot: canvasOptions.enableManualSnapshot, recordCanvas: canvasOptions.recordCanvas, getCanvasManager: canvasOptions.getCanvasManager, sampling: canvasOptions.sampling, From 0a1350c9fdea6ceb9463dde8f3c5b4ef6041860e Mon Sep 17 00:00:00 2001 From: Catherine Lee <55311782+c298lee@users.noreply.github.com> Date: Mon, 15 Jan 2024 18:55:19 -0500 Subject: [PATCH 38/48] fix --- .../suites/replay/canvas/template.html | 9 ---- .../canvas/withCanvasIntegrationFirst/init.js | 18 ------- .../canvas/withCanvasIntegrationFirst/test.ts | 31 ----------- .../withCanvasIntegrationSecond/init.js | 18 ------- .../withCanvasIntegrationSecond/test.ts | 31 ----------- .../canvas/withoutCanvasIntegration/init.js | 18 ------- .../canvas/withoutCanvasIntegration/test.ts | 27 ---------- .../utils/replayHelpers.ts | 2 +- packages/browser/src/index.ts | 2 +- .../integration-shims/src/ReplayCanvas.ts | 46 ---------------- packages/replay/rollup.bundle.config.mjs | 12 +---- packages/replay/src/canvas.ts | 54 ------------------- packages/replay/src/index.ts | 1 - packages/replay/src/integration.ts | 2 +- packages/types/src/client.ts | 11 ++-- 15 files changed, 12 insertions(+), 270 deletions(-) delete mode 100644 dev-packages/browser-integration-tests/suites/replay/canvas/template.html delete mode 100644 dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/init.js delete mode 100644 dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts delete mode 100644 dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/init.js delete mode 100644 dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts delete mode 100644 dev-packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/init.js delete mode 100644 dev-packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/test.ts delete mode 100644 packages/integration-shims/src/ReplayCanvas.ts delete mode 100644 packages/replay/src/canvas.ts diff --git a/dev-packages/browser-integration-tests/suites/replay/canvas/template.html b/dev-packages/browser-integration-tests/suites/replay/canvas/template.html deleted file mode 100644 index 2b3e2f0b27b4..000000000000 --- a/dev-packages/browser-integration-tests/suites/replay/canvas/template.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/init.js b/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/init.js deleted file mode 100644 index fa3248066150..000000000000 --- a/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/init.js +++ /dev/null @@ -1,18 +0,0 @@ -import * as Sentry from '@sentry/browser'; - -window.Sentry = Sentry; -window.Replay = new Sentry.Replay({ - flushMinDelay: 200, - flushMaxDelay: 200, - minReplayDuration: 0, -}); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - sampleRate: 0, - replaysSessionSampleRate: 1.0, - replaysOnErrorSampleRate: 0.0, - debug: true, - - integrations: [new Sentry.ReplayCanvas(), window.Replay], -}); diff --git a/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts b/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts deleted file mode 100644 index 104098eed2cf..000000000000 --- a/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { expect } from '@playwright/test'; - -import { sentryTest } from '../../../../utils/fixtures'; -import { getReplaySnapshot, shouldSkipReplayTest, waitForReplayRequest } from '../../../../utils/replayHelpers'; - -sentryTest('sets up canvas when adding ReplayCanvas integration first', async ({ getLocalTestUrl, page }) => { - if (shouldSkipReplayTest() || (process.env.PW_BUNDLE || '').startsWith('bundle')) { - sentryTest.skip(); - } - - const reqPromise0 = waitForReplayRequest(page, 0); - - await page.route('https://dsn.ingest.sentry.io/**/*', route => { - return route.fulfill({ - status: 200, - contentType: 'application/json', - body: JSON.stringify({ id: 'test-id' }), - }); - }); - - const url = await getLocalTestUrl({ testDir: __dirname }); - - await page.goto(url); - await reqPromise0; - - const replay = await getReplaySnapshot(page); - const canvasOptions = replay._canvas; - expect(canvasOptions?.sampling.canvas).toBe(2); - expect(canvasOptions?.dataURLOptions.quality).toBe(0.4); - expect(replay._hasCanvas).toBe(true); -}); diff --git a/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/init.js b/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/init.js deleted file mode 100644 index 1a9d5d179c4a..000000000000 --- a/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/init.js +++ /dev/null @@ -1,18 +0,0 @@ -import * as Sentry from '@sentry/browser'; - -window.Sentry = Sentry; -window.Replay = new Sentry.Replay({ - flushMinDelay: 200, - flushMaxDelay: 200, - minReplayDuration: 0, -}); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - sampleRate: 0, - replaysSessionSampleRate: 1.0, - replaysOnErrorSampleRate: 0.0, - debug: true, - - integrations: [window.Replay, new Sentry.ReplayCanvas()], -}); diff --git a/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts b/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts deleted file mode 100644 index d25066dc065b..000000000000 --- a/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { expect } from '@playwright/test'; - -import { sentryTest } from '../../../../utils/fixtures'; -import { getReplaySnapshot, shouldSkipReplayTest, waitForReplayRequest } from '../../../../utils/replayHelpers'; - -sentryTest('sets up canvas when adding ReplayCanvas integration after Replay', async ({ getLocalTestUrl, page }) => { - if (shouldSkipReplayTest() || (process.env.PW_BUNDLE || '').startsWith('bundle')) { - sentryTest.skip(); - } - - const reqPromise0 = waitForReplayRequest(page, 0); - - await page.route('https://dsn.ingest.sentry.io/**/*', route => { - return route.fulfill({ - status: 200, - contentType: 'application/json', - body: JSON.stringify({ id: 'test-id' }), - }); - }); - - const url = await getLocalTestUrl({ testDir: __dirname }); - - await page.goto(url); - await reqPromise0; - - const replay = await getReplaySnapshot(page); - const canvasOptions = replay._canvas; - expect(canvasOptions?.sampling.canvas).toBe(2); - expect(canvasOptions?.dataURLOptions.quality).toBe(0.4); - expect(replay._hasCanvas).toBe(true); -}); diff --git a/dev-packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/init.js b/dev-packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/init.js deleted file mode 100644 index 92a463a4bc84..000000000000 --- a/dev-packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/init.js +++ /dev/null @@ -1,18 +0,0 @@ -import * as Sentry from '@sentry/browser'; - -window.Sentry = Sentry; -window.Replay = new Sentry.Replay({ - flushMinDelay: 200, - flushMaxDelay: 200, - minReplayDuration: 0, -}); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - sampleRate: 0, - replaysSessionSampleRate: 1.0, - replaysOnErrorSampleRate: 0.0, - debug: true, - - integrations: [window.Replay], -}); diff --git a/dev-packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/test.ts b/dev-packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/test.ts deleted file mode 100644 index af3ec4a4bc97..000000000000 --- a/dev-packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/test.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { expect } from '@playwright/test'; - -import { sentryTest } from '../../../../utils/fixtures'; -import { getReplaySnapshot, shouldSkipReplayTest } from '../../../../utils/replayHelpers'; - -sentryTest('does not setup up canvas without ReplayCanvas integration', async ({ getLocalTestUrl, page }) => { - if (shouldSkipReplayTest()) { - sentryTest.skip(); - } - - await page.route('https://dsn.ingest.sentry.io/**/*', route => { - return route.fulfill({ - status: 200, - contentType: 'application/json', - body: JSON.stringify({ id: 'test-id' }), - }); - }); - - const url = await getLocalTestUrl({ testDir: __dirname }); - - await page.goto(url); - - const replay = await getReplaySnapshot(page); - const canvasOptions = replay._canvas; - expect(canvasOptions).toBe(undefined); - expect(replay._hasCanvas).toBe(false); -}); diff --git a/dev-packages/browser-integration-tests/utils/replayHelpers.ts b/dev-packages/browser-integration-tests/utils/replayHelpers.ts index 4b1623ed7318..295ae82e0fa3 100644 --- a/dev-packages/browser-integration-tests/utils/replayHelpers.ts +++ b/dev-packages/browser-integration-tests/utils/replayHelpers.ts @@ -1,5 +1,5 @@ /* eslint-disable max-lines */ -import { ReplayCanvasIntegrationOptions } from '@sentry-internal/replay-canvas'; +import type { ReplayCanvasIntegrationOptions } from '@sentry-internal/replay-canvas'; import type { fullSnapshotEvent, incrementalSnapshotEvent } from '@sentry-internal/rrweb'; import { EventType } from '@sentry-internal/rrweb'; import type { ReplayEventWithTime } from '@sentry/browser'; diff --git a/packages/browser/src/index.ts b/packages/browser/src/index.ts index b8692c7aaf8e..e97b6e98b816 100644 --- a/packages/browser/src/index.ts +++ b/packages/browser/src/index.ts @@ -21,7 +21,7 @@ const INTEGRATIONS = { export { INTEGRATIONS as Integrations }; -export { Replay, ReplayCanvas } from '@sentry/replay'; +export { Replay } from '@sentry/replay'; export type { ReplayEventType, ReplayEventWithTime, diff --git a/packages/integration-shims/src/ReplayCanvas.ts b/packages/integration-shims/src/ReplayCanvas.ts deleted file mode 100644 index 6e2ebc6f7179..000000000000 --- a/packages/integration-shims/src/ReplayCanvas.ts +++ /dev/null @@ -1,46 +0,0 @@ -import type { Integration } from '@sentry/types'; -import { consoleSandbox } from '@sentry/utils'; - -/** - * This is a shim for the Replay integration. - * It is needed in order for the CDN bundles to continue working when users add/remove replay - * from it, without changing their config. This is necessary for the loader mechanism. - */ -class ReplayCanvasShim implements Integration { - /** - * @inheritDoc - */ - public static id: string = 'ReplayCanvas'; - - /** - * @inheritDoc - */ - public name: string; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public constructor(_options: any) { - this.name = ReplayCanvasShim.id; - - consoleSandbox(() => { - // eslint-disable-next-line no-console - console.error('You are using new ReplayCanvas() even though this bundle does not include replay canvas.'); - }); - } - - /** jsdoc */ - public setupOnce(): void { - // noop - } - - /** jsdoc */ - public getOptions(): void { - // noop - } - - /** jsdoc */ - public async snapshot(): Promise { - // noop - } -} - -export { ReplayCanvasShim as ReplayCanvas }; diff --git a/packages/replay/rollup.bundle.config.mjs b/packages/replay/rollup.bundle.config.mjs index b254dae8d8d2..a209b8d41af4 100644 --- a/packages/replay/rollup.bundle.config.mjs +++ b/packages/replay/rollup.bundle.config.mjs @@ -2,20 +2,12 @@ import { makeBaseBundleConfig, makeBundleConfigVariants } from '@sentry-internal const baseBundleConfig = makeBaseBundleConfig({ bundleType: 'addon', - entrypoints: ['src/integration.ts'], + entrypoints: ['src/index.ts'], jsVersion: 'es6', licenseTitle: '@sentry/replay', outputFileBase: () => 'bundles/replay', }); -const baseCanvasBundleConfig = makeBaseBundleConfig({ - bundleType: 'addon', - entrypoints: ['src/canvas.ts'], - jsVersion: 'es6', - licenseTitle: '@sentry/replaycanvas', - outputFileBase: () => 'bundles/replaycanvas', -}); - -const builds = [...makeBundleConfigVariants(baseBundleConfig), ...makeBundleConfigVariants(baseCanvasBundleConfig)]; +const builds = makeBundleConfigVariants(baseBundleConfig); export default builds; diff --git a/packages/replay/src/canvas.ts b/packages/replay/src/canvas.ts deleted file mode 100644 index b3fe2afa60f0..000000000000 --- a/packages/replay/src/canvas.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { getCanvasManager } from '@sentry-internal/rrweb'; -import type { Integration } from '@sentry/types'; -import type { ReplayConfiguration } from './types'; - -interface ReplayCanvasOptions { - fps: number; - quality: number; -} - -/** An integration to add canvas recording to replay. */ -export class ReplayCanvas implements Integration { - /** - * @inheritDoc - */ - public static id: string = 'ReplayCanvas'; - - /** - * @inheritDoc - */ - public name: string; - - private _canvasOptions: ReplayCanvasOptions; - - public constructor() { - this.name = ReplayCanvas.id; - // TODO FN: Allow to configure this - // But since we haven't finalized how to configure this, this is predefined for now - // to avoid breaking changes - this._canvasOptions = { - fps: 4, - quality: 0.6, - }; - } - - /** @inheritdoc */ - public setupOnce(): void { - // noop - } - - /** - * Get the options that should be merged into replay options. - * This is what is actually called by the Replay integration to setup canvas. - */ - public getOptions(): Partial { - return { - _experiments: { - canvas: { - ...this._canvasOptions, - manager: getCanvasManager, - }, - }, - }; - } -} diff --git a/packages/replay/src/index.ts b/packages/replay/src/index.ts index 60d297434924..8e8a5d55579a 100644 --- a/packages/replay/src/index.ts +++ b/packages/replay/src/index.ts @@ -1,5 +1,4 @@ export { Replay } from './integration'; -export { ReplayCanvas } from './canvas'; export type { ReplayConfiguration, diff --git a/packages/replay/src/integration.ts b/packages/replay/src/integration.ts index a8a58d46d55b..baf0839660c8 100644 --- a/packages/replay/src/integration.ts +++ b/packages/replay/src/integration.ts @@ -365,7 +365,7 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`, /* eslint-disable @typescript-eslint/no-non-null-assertion */ try { const client = getClient()!; - const canvasIntegration = client.getIntegrationById!('ReplayCanvas') as Integration & { + const canvasIntegration = client.getIntegrationByName!('ReplayCanvas') as Integration & { getOptions(): ReplayCanvasIntegrationOptions; }; if (!canvasIntegration) { diff --git a/packages/types/src/client.ts b/packages/types/src/client.ts index f780277942b5..135c361c64c6 100644 --- a/packages/types/src/client.ts +++ b/packages/types/src/client.ts @@ -138,11 +138,14 @@ export interface Client { */ getEventProcessors?(): EventProcessor[]; - /** Returns the client's instance of the given integration class, if it exists. */ - getIntegration(integration: IntegrationClass): T | null; + /** + * Returns the client's instance of the given integration class, it any. + * @deprecated Use `getIntegrationByName()` instead. + */ + getIntegration(integration: IntegrationClass): T | null; - /** Returns the client's instance of the given integration name, if it exists. */ - getIntegrationById?(integrationId: string): Integration | undefined; + /** Get the instance of the integration with the given name on the client, if it was added. */ + getIntegrationByName?(name: string): T | undefined; /** * Add an integration to the client. From 8db7bde0eebc573e1d801d7f2d0beaf675623f21 Mon Sep 17 00:00:00 2001 From: Catherine Lee <55311782+c298lee@users.noreply.github.com> Date: Mon, 15 Jan 2024 19:03:27 -0500 Subject: [PATCH 39/48] fix again --- .../canvas/withCanvasIntegrationFirst/test.ts | 13 ++++++++----- .../canvas/withCanvasIntegrationSecond/test.ts | 13 ++++++++----- .../replay/canvas/withoutCanvasIntegration/test.ts | 2 +- packages/types/src/client.ts | 6 +++--- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts index 7326bed95ae6..104098eed2cf 100644 --- a/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts +++ b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts @@ -1,13 +1,15 @@ import { expect } from '@playwright/test'; import { sentryTest } from '../../../../utils/fixtures'; -import { getReplaySnapshot, shouldSkipReplayTest } from '../../../../utils/replayHelpers'; +import { getReplaySnapshot, shouldSkipReplayTest, waitForReplayRequest } from '../../../../utils/replayHelpers'; sentryTest('sets up canvas when adding ReplayCanvas integration first', async ({ getLocalTestUrl, page }) => { - if (shouldSkipReplayTest()) { + if (shouldSkipReplayTest() || (process.env.PW_BUNDLE || '').startsWith('bundle')) { sentryTest.skip(); } + const reqPromise0 = waitForReplayRequest(page, 0); + await page.route('https://dsn.ingest.sentry.io/**/*', route => { return route.fulfill({ status: 200, @@ -19,10 +21,11 @@ sentryTest('sets up canvas when adding ReplayCanvas integration first', async ({ const url = await getLocalTestUrl({ testDir: __dirname }); await page.goto(url); + await reqPromise0; const replay = await getReplaySnapshot(page); - const canvasOptions = replay._options._experiments?.canvas; - expect(canvasOptions.fps).toBe(4); - expect(canvasOptions.quality).toBe(0.6); + const canvasOptions = replay._canvas; + expect(canvasOptions?.sampling.canvas).toBe(2); + expect(canvasOptions?.dataURLOptions.quality).toBe(0.4); expect(replay._hasCanvas).toBe(true); }); diff --git a/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts index 9168864db7e0..d25066dc065b 100644 --- a/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts +++ b/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts @@ -1,13 +1,15 @@ import { expect } from '@playwright/test'; import { sentryTest } from '../../../../utils/fixtures'; -import { getReplaySnapshot, shouldSkipReplayTest } from '../../../../utils/replayHelpers'; +import { getReplaySnapshot, shouldSkipReplayTest, waitForReplayRequest } from '../../../../utils/replayHelpers'; sentryTest('sets up canvas when adding ReplayCanvas integration after Replay', async ({ getLocalTestUrl, page }) => { - if (shouldSkipReplayTest()) { + if (shouldSkipReplayTest() || (process.env.PW_BUNDLE || '').startsWith('bundle')) { sentryTest.skip(); } + const reqPromise0 = waitForReplayRequest(page, 0); + await page.route('https://dsn.ingest.sentry.io/**/*', route => { return route.fulfill({ status: 200, @@ -19,10 +21,11 @@ sentryTest('sets up canvas when adding ReplayCanvas integration after Replay', a const url = await getLocalTestUrl({ testDir: __dirname }); await page.goto(url); + await reqPromise0; const replay = await getReplaySnapshot(page); - const canvasOptions = replay._options._experiments?.canvas; - expect(canvasOptions.fps).toBe(4); - expect(canvasOptions.quality).toBe(0.6); + const canvasOptions = replay._canvas; + expect(canvasOptions?.sampling.canvas).toBe(2); + expect(canvasOptions?.dataURLOptions.quality).toBe(0.4); expect(replay._hasCanvas).toBe(true); }); diff --git a/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/test.ts b/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/test.ts index b2ce69211be0..af3ec4a4bc97 100644 --- a/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/test.ts +++ b/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/test.ts @@ -21,7 +21,7 @@ sentryTest('does not setup up canvas without ReplayCanvas integration', async ({ await page.goto(url); const replay = await getReplaySnapshot(page); - const canvasOptions = replay._options._experiments?.canvas; + const canvasOptions = replay._canvas; expect(canvasOptions).toBe(undefined); expect(replay._hasCanvas).toBe(false); }); diff --git a/packages/types/src/client.ts b/packages/types/src/client.ts index 135c361c64c6..d8d09ec1431b 100644 --- a/packages/types/src/client.ts +++ b/packages/types/src/client.ts @@ -138,13 +138,13 @@ export interface Client { */ getEventProcessors?(): EventProcessor[]; - /** + /** * Returns the client's instance of the given integration class, it any. * @deprecated Use `getIntegrationByName()` instead. */ - getIntegration(integration: IntegrationClass): T | null; + getIntegration(integration: IntegrationClass): T | null; - /** Get the instance of the integration with the given name on the client, if it was added. */ + /** Get the instance of the integration with the given name on the client, if it was added. */ getIntegrationByName?(name: string): T | undefined; /** From 6324d180ba8008b540d50d1e53d09f5b2c5d0fce Mon Sep 17 00:00:00 2001 From: Catherine Lee <55311782+c298lee@users.noreply.github.com> Date: Mon, 15 Jan 2024 19:08:03 -0500 Subject: [PATCH 40/48] done fix hopefully --- .../browser-integration-tests/suites/replay/canvas/template.html | 0 .../suites/replay/canvas/withCanvasIntegrationFirst/init.js | 0 .../suites/replay/canvas/withCanvasIntegrationFirst/test.ts | 0 .../suites/replay/canvas/withCanvasIntegrationSecond/init.js | 0 .../suites/replay/canvas/withCanvasIntegrationSecond/test.ts | 0 .../suites/replay/canvas/withoutCanvasIntegration/init.js | 0 .../suites/replay/canvas/withoutCanvasIntegration/test.ts | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename {packages => dev-packages}/browser-integration-tests/suites/replay/canvas/template.html (100%) rename {packages => dev-packages}/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/init.js (100%) rename {packages => dev-packages}/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts (100%) rename {packages => dev-packages}/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/init.js (100%) rename {packages => dev-packages}/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts (100%) rename {packages => dev-packages}/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/init.js (100%) rename {packages => dev-packages}/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/test.ts (100%) diff --git a/packages/browser-integration-tests/suites/replay/canvas/template.html b/dev-packages/browser-integration-tests/suites/replay/canvas/template.html similarity index 100% rename from packages/browser-integration-tests/suites/replay/canvas/template.html rename to dev-packages/browser-integration-tests/suites/replay/canvas/template.html diff --git a/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/init.js b/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/init.js similarity index 100% rename from packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/init.js rename to dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/init.js diff --git a/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts b/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts similarity index 100% rename from packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts rename to dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationFirst/test.ts diff --git a/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/init.js b/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/init.js similarity index 100% rename from packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/init.js rename to dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/init.js diff --git a/packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts b/dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts similarity index 100% rename from packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts rename to dev-packages/browser-integration-tests/suites/replay/canvas/withCanvasIntegrationSecond/test.ts diff --git a/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/init.js b/dev-packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/init.js similarity index 100% rename from packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/init.js rename to dev-packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/init.js diff --git a/packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/test.ts b/dev-packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/test.ts similarity index 100% rename from packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/test.ts rename to dev-packages/browser-integration-tests/suites/replay/canvas/withoutCanvasIntegration/test.ts From b8a8a3aacd10aeca8e2af3deb7a23b1d9a474174 Mon Sep 17 00:00:00 2001 From: Catherine Lee <55311782+c298lee@users.noreply.github.com> Date: Mon, 15 Jan 2024 19:49:27 -0500 Subject: [PATCH 41/48] comments and update test --- .../replay/canvas/{snapshots => manualSnapshots}/init.js | 0 .../canvas/{snapshots => manualSnapshots}/template.html | 0 .../replay/canvas/{snapshots => manualSnapshots}/test.ts | 2 +- packages/replay-canvas/src/canvas.ts | 8 ++++++-- packages/replay-canvas/test/canvas.test.ts | 3 +-- 5 files changed, 8 insertions(+), 5 deletions(-) rename dev-packages/browser-integration-tests/suites/replay/canvas/{snapshots => manualSnapshots}/init.js (100%) rename dev-packages/browser-integration-tests/suites/replay/canvas/{snapshots => manualSnapshots}/template.html (100%) rename dev-packages/browser-integration-tests/suites/replay/canvas/{snapshots => manualSnapshots}/test.ts (95%) diff --git a/dev-packages/browser-integration-tests/suites/replay/canvas/snapshots/init.js b/dev-packages/browser-integration-tests/suites/replay/canvas/manualSnapshots/init.js similarity index 100% rename from dev-packages/browser-integration-tests/suites/replay/canvas/snapshots/init.js rename to dev-packages/browser-integration-tests/suites/replay/canvas/manualSnapshots/init.js diff --git a/dev-packages/browser-integration-tests/suites/replay/canvas/snapshots/template.html b/dev-packages/browser-integration-tests/suites/replay/canvas/manualSnapshots/template.html similarity index 100% rename from dev-packages/browser-integration-tests/suites/replay/canvas/snapshots/template.html rename to dev-packages/browser-integration-tests/suites/replay/canvas/manualSnapshots/template.html diff --git a/dev-packages/browser-integration-tests/suites/replay/canvas/snapshots/test.ts b/dev-packages/browser-integration-tests/suites/replay/canvas/manualSnapshots/test.ts similarity index 95% rename from dev-packages/browser-integration-tests/suites/replay/canvas/snapshots/test.ts rename to dev-packages/browser-integration-tests/suites/replay/canvas/manualSnapshots/test.ts index 40d2dbf0e538..ccea521651e8 100644 --- a/dev-packages/browser-integration-tests/suites/replay/canvas/snapshots/test.ts +++ b/dev-packages/browser-integration-tests/suites/replay/canvas/manualSnapshots/test.ts @@ -34,7 +34,7 @@ sentryTest('can manually snapshot canvas', async ({ getLocalTestUrl, page, brows (window as any).Sentry.getClient().getIntegrationById('ReplayCanvas').snapshot(); }); - const { incrementalSnapshots:incrementalSnapshotsManual } = getReplayRecordingContent(await reqPromise3); + const { incrementalSnapshots: incrementalSnapshotsManual } = getReplayRecordingContent(await reqPromise3); expect(incrementalSnapshotsManual).toEqual( expect.arrayContaining([ { diff --git a/packages/replay-canvas/src/canvas.ts b/packages/replay-canvas/src/canvas.ts index c592a3cd980a..19ad24adb0e0 100644 --- a/packages/replay-canvas/src/canvas.ts +++ b/packages/replay-canvas/src/canvas.ts @@ -63,7 +63,7 @@ const replayCanvasIntegration = ((options: Partial = {}) => }; let canvasManagerResolve: (value: CanvasManager) => void; - const _canvasManager: Promise = new Promise((resolve) => canvasManagerResolve = resolve); + const _canvasManager: Promise = new Promise(resolve => (canvasManagerResolve = resolve)); return { name: INTEGRATION_NAME, @@ -72,7 +72,11 @@ const replayCanvasIntegration = ((options: Partial = {}) => return { recordCanvas: true, - getCanvasManager: (options: CanvasManagerOptions) => (canvasManagerResolve(new CanvasManager({ ...options, isManualSnapshot: enableManualSnapshot } ))), + getCanvasManager: (options: CanvasManagerOptions) => { + const manager = new CanvasManager({ ...options, isManualSnapshot: enableManualSnapshot }); + canvasManagerResolve(manager); + return manager; + }, ...(CANVAS_QUALITY[quality || 'medium'] || CANVAS_QUALITY.medium), }; }, diff --git a/packages/replay-canvas/test/canvas.test.ts b/packages/replay-canvas/test/canvas.test.ts index 346df7b4a89d..131903db297c 100644 --- a/packages/replay-canvas/test/canvas.test.ts +++ b/packages/replay-canvas/test/canvas.test.ts @@ -17,10 +17,9 @@ it('initializes with default options', () => { }); it('initializes with quality option and manual snapshot', () => { - const rc = new ReplayCanvas({ enableManualSnapshot: true, quality: 'low' }); + const rc = new ReplayCanvas({ quality: 'low' }); expect(rc.getOptions()).toEqual({ - enableManualSnapshot: true, recordCanvas: true, getCanvasManager: expect.any(Function), sampling: { From 8807086e758651708afd2ba0fefe47e67187067f Mon Sep 17 00:00:00 2001 From: Catherine Lee <55311782+c298lee@users.noreply.github.com> Date: Tue, 16 Jan 2024 10:46:20 -0500 Subject: [PATCH 42/48] typo --- packages/replay-canvas/src/canvas.ts | 1 + packages/replay-canvas/test/canvas.test.ts | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/replay-canvas/src/canvas.ts b/packages/replay-canvas/src/canvas.ts index 19ad24adb0e0..91f16f9ac01a 100644 --- a/packages/replay-canvas/src/canvas.ts +++ b/packages/replay-canvas/src/canvas.ts @@ -71,6 +71,7 @@ const replayCanvasIntegration = ((options: Partial = {}) => const { quality, enableManualSnapshot } = _canvasOptions; return { + enableManualSnapshot, recordCanvas: true, getCanvasManager: (options: CanvasManagerOptions) => { const manager = new CanvasManager({ ...options, isManualSnapshot: enableManualSnapshot }); diff --git a/packages/replay-canvas/test/canvas.test.ts b/packages/replay-canvas/test/canvas.test.ts index 131903db297c..242700a722a2 100644 --- a/packages/replay-canvas/test/canvas.test.ts +++ b/packages/replay-canvas/test/canvas.test.ts @@ -17,9 +17,10 @@ it('initializes with default options', () => { }); it('initializes with quality option and manual snapshot', () => { - const rc = new ReplayCanvas({ quality: 'low' }); + const rc = new ReplayCanvas({ enableManualSnapshot: true , quality: 'low' }); expect(rc.getOptions()).toEqual({ + enableManualSnapshot: true, recordCanvas: true, getCanvasManager: expect.any(Function), sampling: { From b3f5889b9bd0774e3d8a060e8ffc1bb0d7cd6a63 Mon Sep 17 00:00:00 2001 From: Catherine Lee <55311782+c298lee@users.noreply.github.com> Date: Tue, 16 Jan 2024 10:46:46 -0500 Subject: [PATCH 43/48] typo --- .../replay/canvas/{manualSnapshots => manualSnapshot}/init.js | 0 .../canvas/{manualSnapshots => manualSnapshot}/template.html | 0 .../replay/canvas/{manualSnapshots => manualSnapshot}/test.ts | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename dev-packages/browser-integration-tests/suites/replay/canvas/{manualSnapshots => manualSnapshot}/init.js (100%) rename dev-packages/browser-integration-tests/suites/replay/canvas/{manualSnapshots => manualSnapshot}/template.html (100%) rename dev-packages/browser-integration-tests/suites/replay/canvas/{manualSnapshots => manualSnapshot}/test.ts (100%) diff --git a/dev-packages/browser-integration-tests/suites/replay/canvas/manualSnapshots/init.js b/dev-packages/browser-integration-tests/suites/replay/canvas/manualSnapshot/init.js similarity index 100% rename from dev-packages/browser-integration-tests/suites/replay/canvas/manualSnapshots/init.js rename to dev-packages/browser-integration-tests/suites/replay/canvas/manualSnapshot/init.js diff --git a/dev-packages/browser-integration-tests/suites/replay/canvas/manualSnapshots/template.html b/dev-packages/browser-integration-tests/suites/replay/canvas/manualSnapshot/template.html similarity index 100% rename from dev-packages/browser-integration-tests/suites/replay/canvas/manualSnapshots/template.html rename to dev-packages/browser-integration-tests/suites/replay/canvas/manualSnapshot/template.html diff --git a/dev-packages/browser-integration-tests/suites/replay/canvas/manualSnapshots/test.ts b/dev-packages/browser-integration-tests/suites/replay/canvas/manualSnapshot/test.ts similarity index 100% rename from dev-packages/browser-integration-tests/suites/replay/canvas/manualSnapshots/test.ts rename to dev-packages/browser-integration-tests/suites/replay/canvas/manualSnapshot/test.ts From 64e0a5b6d09651256b7527570669c2ffa622ab90 Mon Sep 17 00:00:00 2001 From: Catherine Lee <55311782+c298lee@users.noreply.github.com> Date: Tue, 16 Jan 2024 11:07:45 -0500 Subject: [PATCH 44/48] lint --- packages/replay-canvas/test/canvas.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/replay-canvas/test/canvas.test.ts b/packages/replay-canvas/test/canvas.test.ts index 242700a722a2..346df7b4a89d 100644 --- a/packages/replay-canvas/test/canvas.test.ts +++ b/packages/replay-canvas/test/canvas.test.ts @@ -17,7 +17,7 @@ it('initializes with default options', () => { }); it('initializes with quality option and manual snapshot', () => { - const rc = new ReplayCanvas({ enableManualSnapshot: true , quality: 'low' }); + const rc = new ReplayCanvas({ enableManualSnapshot: true, quality: 'low' }); expect(rc.getOptions()).toEqual({ enableManualSnapshot: true, From 9f769b470e2e9399f4e854b7d6768324838bca45 Mon Sep 17 00:00:00 2001 From: Catherine Lee <55311782+c298lee@users.noreply.github.com> Date: Tue, 16 Jan 2024 14:07:46 -0500 Subject: [PATCH 45/48] update enableManualSnapshot --- packages/replay-canvas/src/canvas.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/replay-canvas/src/canvas.ts b/packages/replay-canvas/src/canvas.ts index 91f16f9ac01a..23fae53d9640 100644 --- a/packages/replay-canvas/src/canvas.ts +++ b/packages/replay-canvas/src/canvas.ts @@ -74,7 +74,7 @@ const replayCanvasIntegration = ((options: Partial = {}) => enableManualSnapshot, recordCanvas: true, getCanvasManager: (options: CanvasManagerOptions) => { - const manager = new CanvasManager({ ...options, isManualSnapshot: enableManualSnapshot }); + const manager = new CanvasManager({ ...options, enableManualSnapshot }); canvasManagerResolve(manager); return manager; }, From bdb58a480d1736a630ebc55380a30d6e80bcabfb Mon Sep 17 00:00:00 2001 From: Catherine Lee <55311782+c298lee@users.noreply.github.com> Date: Tue, 16 Jan 2024 14:25:04 -0500 Subject: [PATCH 46/48] fix merge --- packages/replay/src/replay.ts | 7 +++++++ packages/replay/src/types/rrweb.ts | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/replay/src/replay.ts b/packages/replay/src/replay.ts index 8302bbb0c8b6..30ccda422544 100644 --- a/packages/replay/src/replay.ts +++ b/packages/replay/src/replay.ts @@ -223,6 +223,13 @@ export class ReplayContainer implements ReplayContainerInterface { return this._isPaused; } + /** + * Determine if canvas recording is enabled + */ + public isRecordingCanvas(): boolean { + return Boolean(this._canvas); + } + /** Get the replay integration options. */ public getOptions(): ReplayPluginOptions { return this._options; diff --git a/packages/replay/src/types/rrweb.ts b/packages/replay/src/types/rrweb.ts index 3fc8417cd563..a490a6e46c1b 100644 --- a/packages/replay/src/types/rrweb.ts +++ b/packages/replay/src/types/rrweb.ts @@ -56,7 +56,7 @@ export interface CanvasManagerInterface { export interface CanvasManagerOptions { recordCanvas: boolean; - isManualSnapshot?: boolean; + enableManualSnapshot?: boolean; blockClass: string | RegExp; blockSelector: string | null; unblockSelector: string | null; From 7382f9726b026eff18b276e8f7d48be2e60babbf Mon Sep 17 00:00:00 2001 From: Catherine Lee <55311782+c298lee@users.noreply.github.com> Date: Wed, 17 Jan 2024 11:24:37 -0500 Subject: [PATCH 47/48] fix merge and change rrweb to 2.9.0 --- .craft.yml | 4 ++++ .../browser-integration-tests/package.json | 2 +- .../suites/replay/canvas/manualSnapshot/test.ts | 2 +- packages/replay-canvas/package.json | 2 +- packages/replay-canvas/src/canvas.ts | 17 +++++++++++++---- packages/replay/package.json | 4 ++-- packages/replay/src/integration.ts | 15 +-------------- 7 files changed, 23 insertions(+), 23 deletions(-) diff --git a/.craft.yml b/.craft.yml index 1a4b07c18874..fcecff7a807b 100644 --- a/.craft.yml +++ b/.craft.yml @@ -32,6 +32,10 @@ targets: - name: npm id: '@sentry-internal/feedback' includeNames: /^sentry-internal-feedback-\d.*\.tgz$/ + ## 1.8 ReplayCanvas package (browser only) + - name: npm + id: '@sentry-internal/replay-canvas' + includeNames: /^sentry-internal-replay-canvas-\d.*\.tgz$/ ## 2. Browser & Node SDKs - name: npm diff --git a/dev-packages/browser-integration-tests/package.json b/dev-packages/browser-integration-tests/package.json index 8fb2ce61b0ea..e090e9e788bf 100644 --- a/dev-packages/browser-integration-tests/package.json +++ b/dev-packages/browser-integration-tests/package.json @@ -45,7 +45,7 @@ "dependencies": { "@babel/preset-typescript": "^7.16.7", "@playwright/test": "^1.31.1", - "@sentry-internal/rrweb": "2.8.0", + "@sentry-internal/rrweb": "2.9.0", "@sentry/browser": "7.93.0", "@sentry/tracing": "7.93.0", "axios": "1.6.0", diff --git a/dev-packages/browser-integration-tests/suites/replay/canvas/manualSnapshot/test.ts b/dev-packages/browser-integration-tests/suites/replay/canvas/manualSnapshot/test.ts index ccea521651e8..583ff672e590 100644 --- a/dev-packages/browser-integration-tests/suites/replay/canvas/manualSnapshot/test.ts +++ b/dev-packages/browser-integration-tests/suites/replay/canvas/manualSnapshot/test.ts @@ -4,7 +4,7 @@ import { sentryTest } from '../../../../utils/fixtures'; import { getReplayRecordingContent, shouldSkipReplayTest, waitForReplayRequest } from '../../../../utils/replayHelpers'; sentryTest('can manually snapshot canvas', async ({ getLocalTestUrl, page, browserName }) => { - if (shouldSkipReplayTest() || browserName === 'webkit') { + if (shouldSkipReplayTest() || browserName === 'webkit' || (process.env.PW_BUNDLE || '').startsWith('bundle')) { sentryTest.skip(); } diff --git a/packages/replay-canvas/package.json b/packages/replay-canvas/package.json index 81a70f18c20d..0a495945f2d1 100644 --- a/packages/replay-canvas/package.json +++ b/packages/replay-canvas/package.json @@ -53,7 +53,7 @@ "homepage": "https://docs.sentry.io/platforms/javascript/session-replay/", "devDependencies": { "@babel/core": "^7.17.5", - "@sentry-internal/rrweb": "2.8.0" + "@sentry-internal/rrweb": "2.9.0" }, "dependencies": { "@sentry/core": "7.93.0", diff --git a/packages/replay-canvas/src/canvas.ts b/packages/replay-canvas/src/canvas.ts index 23fae53d9640..ba3ec85ebcfb 100644 --- a/packages/replay-canvas/src/canvas.ts +++ b/packages/replay-canvas/src/canvas.ts @@ -1,17 +1,18 @@ import { CanvasManager } from '@sentry-internal/rrweb'; import { convertIntegrationFnToClass } from '@sentry/core'; -import type { CanvasManagerInterface } from '@sentry/replay'; -import type { IntegrationFn } from '@sentry/types'; +import type { CanvasManagerInterface, CanvasManagerOptions } from '@sentry/replay'; +import type { Integration, IntegrationClass, IntegrationFn } from '@sentry/types'; interface ReplayCanvasOptions { enableManualSnapshot?: boolean; quality: 'low' | 'medium' | 'high'; } +type GetCanvasManager = (options: CanvasManagerOptions) => CanvasManagerInterface; export interface ReplayCanvasIntegrationOptions { enableManualSnapshot?: boolean; recordCanvas: true; - getCanvasManager: (options: ConstructorParameters[0]) => CanvasManagerInterface; + getCanvasManager: GetCanvasManager; sampling: { canvas: number; }; @@ -67,6 +68,8 @@ const replayCanvasIntegration = ((options: Partial = {}) => return { name: INTEGRATION_NAME, + // eslint-disable-next-line @typescript-eslint/no-empty-function + setupOnce() {}, getOptions(): ReplayCanvasIntegrationOptions { const { quality, enableManualSnapshot } = _canvasOptions; @@ -88,4 +91,10 @@ const replayCanvasIntegration = ((options: Partial = {}) => }; }) satisfies IntegrationFn; -export const ReplayCanvas = convertIntegrationFnToClass(INTEGRATION_NAME, replayCanvasIntegration); +// TODO(v8) +// eslint-disable-next-line deprecation/deprecation +export const ReplayCanvas = convertIntegrationFnToClass(INTEGRATION_NAME, replayCanvasIntegration) as IntegrationClass< + Integration & { + getOptions: () => ReplayCanvasIntegrationOptions; + } +>; diff --git a/packages/replay/package.json b/packages/replay/package.json index 936b861a7f17..0b44a611a270 100644 --- a/packages/replay/package.json +++ b/packages/replay/package.json @@ -54,8 +54,8 @@ "devDependencies": { "@babel/core": "^7.17.5", "@sentry-internal/replay-worker": "7.93.0", - "@sentry-internal/rrweb": "2.8.0", - "@sentry-internal/rrweb-snapshot": "2.8.0", + "@sentry-internal/rrweb": "2.9.0", + "@sentry-internal/rrweb-snapshot": "2.9.0", "fflate": "^0.8.1", "jsdom-worker": "^0.2.1" }, diff --git a/packages/replay/src/integration.ts b/packages/replay/src/integration.ts index baf0839660c8..c73da03c1b85 100644 --- a/packages/replay/src/integration.ts +++ b/packages/replay/src/integration.ts @@ -355,11 +355,6 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`, /** Get canvas options from ReplayCanvas integration, if it is also added. */ private _maybeLoadFromReplayCanvasIntegration(): void { - // If already defined, skip this... - if (this._initialOptions._experiments.canvas) { - return; - } - // To save bundle size, we skip checking for stuff here // and instead just try-catch everything - as generally this should all be defined /* eslint-disable @typescript-eslint/no-non-null-assertion */ @@ -371,16 +366,8 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`, if (!canvasIntegration) { return; } - const additionalOptions = canvasIntegration.getOptions(); - - const mergedExperimentsOptions = { - ...this._initialOptions._experiments, - ...additionalOptions._experiments, - }; - - this._initialOptions._experiments = mergedExperimentsOptions; - this._replay!.getOptions()._experiments = mergedExperimentsOptions; + this._replay!['_canvas'] = canvasIntegration.getOptions(); } catch { // ignore errors here } From 3d6df9225cdab1d6f344506dce006b08783fd61b Mon Sep 17 00:00:00 2001 From: Catherine Lee <55311782+c298lee@users.noreply.github.com> Date: Wed, 17 Jan 2024 11:28:28 -0500 Subject: [PATCH 48/48] lint --- .craft.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.craft.yml b/.craft.yml index fcecff7a807b..7c09cb4ddd4c 100644 --- a/.craft.yml +++ b/.craft.yml @@ -32,7 +32,7 @@ targets: - name: npm id: '@sentry-internal/feedback' includeNames: /^sentry-internal-feedback-\d.*\.tgz$/ - ## 1.8 ReplayCanvas package (browser only) + ## 1.8 ReplayCanvas package (browser only) - name: npm id: '@sentry-internal/replay-canvas' includeNames: /^sentry-internal-replay-canvas-\d.*\.tgz$/