Skip to content

feat(replay): Add "maxCanvasSize" option for replay canvases #11617

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ sentryTest('can manually snapshot canvas', async ({ getLocalTestUrl, page, brows
},
0,
0,
150,
150,
],
property: 'drawImage',
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ sentryTest('can record canvas', async ({ getLocalTestUrl, page, browserName }) =
},
0,
0,
150,
150,
],
property: 'drawImage',
},
Expand Down
2 changes: 1 addition & 1 deletion packages/replay-canvas/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
"homepage": "https://docs.sentry.io/platforms/javascript/session-replay/",
"devDependencies": {
"@babel/core": "^7.17.5",
"@sentry-internal/rrweb": "2.12.0"
"@sentry-internal/rrweb": "2.13.0"
},
"dependencies": {
"@sentry-internal/replay": "8.0.0-beta.3",
Expand Down
15 changes: 12 additions & 3 deletions packages/replay-canvas/src/canvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import type { IntegrationFn } from '@sentry/types';

interface ReplayCanvasOptions {
enableManualSnapshot?: boolean;
maxCanvasSize?: [width: number, height: number];
quality: 'low' | 'medium' | 'high';
}

type GetCanvasManager = (options: CanvasManagerOptions) => CanvasManagerInterface;
export interface ReplayCanvasIntegrationOptions {
enableManualSnapshot?: boolean;
maxCanvasSize?: number;
recordCanvas: true;
getCanvasManager: GetCanvasManager;
sampling: {
Expand Down Expand Up @@ -53,12 +55,18 @@ const CANVAS_QUALITY = {
};

const INTEGRATION_NAME = 'ReplayCanvas';
const DEFAULT_MAX_CANVAS_SIZE = 1280;

/** Exported only for type safe tests. */
export const _replayCanvasIntegration = ((options: Partial<ReplayCanvasOptions> = {}) => {
const [maxCanvasWidth, maxCanvasHeight] = options.maxCanvasSize || [];
const _canvasOptions = {
quality: options.quality || 'medium',
enableManualSnapshot: options.enableManualSnapshot,
maxCanvasSize: [
maxCanvasWidth ? Math.min(maxCanvasWidth, DEFAULT_MAX_CANVAS_SIZE) : DEFAULT_MAX_CANVAS_SIZE,
maxCanvasHeight ? Math.min(maxCanvasHeight, DEFAULT_MAX_CANVAS_SIZE) : DEFAULT_MAX_CANVAS_SIZE,
] as [number, number],
};

let canvasManagerResolve: (value: CanvasManager) => void;
Expand All @@ -67,15 +75,16 @@ export const _replayCanvasIntegration = ((options: Partial<ReplayCanvasOptions>
return {
name: INTEGRATION_NAME,
getOptions(): ReplayCanvasIntegrationOptions {
const { quality, enableManualSnapshot } = _canvasOptions;
const { quality, enableManualSnapshot, maxCanvasSize } = _canvasOptions;

return {
enableManualSnapshot,
recordCanvas: true,
getCanvasManager: (options: CanvasManagerOptions) => {
getCanvasManager: (getCanvasManagerOptions: CanvasManagerOptions) => {
const manager = new CanvasManager({
...options,
...getCanvasManagerOptions,
enableManualSnapshot,
maxCanvasSize,
errorHandler: (err: unknown) => {
try {
if (typeof err === 'object') {
Expand Down
58 changes: 56 additions & 2 deletions packages/replay-canvas/test/canvas.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import { CanvasManager } from '@sentry-internal/rrweb';
import { _replayCanvasIntegration } from '../src/canvas';

jest.mock('@sentry-internal/rrweb');

beforeEach(() => {
jest.clearAllMocks();
});

it('initializes with default options', () => {
const rc = _replayCanvasIntegration();
const options = rc.getOptions();

expect(rc.getOptions()).toEqual({
expect(options).toEqual({
recordCanvas: true,
getCanvasManager: expect.any(Function),
sampling: {
Expand All @@ -14,12 +22,22 @@ it('initializes with default options', () => {
quality: 0.4,
},
});

// @ts-expect-error don't care about the normal options we need to call this with, just want to test maxCanvasSize
options.getCanvasManager({});

expect(CanvasManager).toHaveBeenCalledWith(
expect.objectContaining({
maxCanvasSize: [1280, 1280],
}),
);
});

it('initializes with quality option and manual snapshot', () => {
const rc = _replayCanvasIntegration({ enableManualSnapshot: true, quality: 'low' });
const options = rc.getOptions();

expect(rc.getOptions()).toEqual({
expect(options).toEqual({
enableManualSnapshot: true,
recordCanvas: true,
getCanvasManager: expect.any(Function),
Expand All @@ -31,4 +49,40 @@ it('initializes with quality option and manual snapshot', () => {
quality: 0.25,
},
});

// @ts-expect-error don't care about the normal options we need to call this with, just want to test maxCanvasSize
options.getCanvasManager({});

expect(CanvasManager).toHaveBeenCalledWith(
expect.objectContaining({
maxCanvasSize: [1280, 1280],
}),
);
});

it('enforces a max canvas size', () => {
const rc = _replayCanvasIntegration({ enableManualSnapshot: true, quality: 'low', maxCanvasSize: [2000, 2000] });
const options = rc.getOptions();

expect(options).toEqual({
enableManualSnapshot: true,
recordCanvas: true,
getCanvasManager: expect.any(Function),
sampling: {
canvas: 1,
},
dataURLOptions: {
type: 'image/webp',
quality: 0.25,
},
});

// @ts-expect-error don't care about the normal options we need to call this with, just want to test maxCanvasSize
options.getCanvasManager({});

expect(CanvasManager).toHaveBeenCalledWith(
expect.objectContaining({
maxCanvasSize: [1280, 1280],
}),
);
});
4 changes: 2 additions & 2 deletions packages/replay-internal/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@
"devDependencies": {
"@babel/core": "^7.17.5",
"@sentry-internal/replay-worker": "8.0.0-beta.3",
"@sentry-internal/rrweb": "2.12.0",
"@sentry-internal/rrweb-snapshot": "2.12.0",
"@sentry-internal/rrweb": "2.13.0",
"@sentry-internal/rrweb-snapshot": "2.13.0",
"fflate": "^0.8.1",
"jsdom-worker": "^0.2.1"
},
Expand Down
42 changes: 21 additions & 21 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5665,22 +5665,22 @@
dependencies:
"@sentry-internal/rrweb-snapshot" "2.11.0"

"@sentry-internal/rrdom@2.12.0":
version "2.12.0"
resolved "https://registry.yarnpkg.com/@sentry-internal/rrdom/-/rrdom-2.12.0.tgz#d3ca32b1e4b8c5d8cc9bdb44f933fe4b059573a0"
integrity sha512-EQ9vmhkTREdtzKp6SmD4GEkwr+RJcaEnbVcDZjbnQnxagskOpqvXjoPMONPf9hZhkULwnrnyFGGp0VpQOGBS0w==
"@sentry-internal/rrdom@2.13.0":
version "2.13.0"
resolved "https://registry.yarnpkg.com/@sentry-internal/rrdom/-/rrdom-2.13.0.tgz#3bb77fd67e72f743d33699431d8f66efb193e951"
integrity sha512-Idm+phUohY74mu9KxFX+lhBqHAN7qTMB6TZGf1hKBn8CusGm91jdEoBe4xqwesnthe8a37svkf8D3CIsiblZPA==
dependencies:
"@sentry-internal/rrweb-snapshot" "2.12.0"
"@sentry-internal/rrweb-snapshot" "2.13.0"

"@sentry-internal/[email protected]":
version "2.11.0"
resolved "https://registry.yarnpkg.com/@sentry-internal/rrweb-snapshot/-/rrweb-snapshot-2.11.0.tgz#1af79130604afea989d325465b209ac015b27c9a"
integrity sha512-1nP22QlplMNooSNvTh+L30NSZ+E3UcfaJyxXSMLxUjQHTGPyM1VkndxZMmxlKhyR5X+rLbxi/+RvuAcpM43VoA==

"@sentry-internal/rrweb-snapshot@2.12.0":
version "2.12.0"
resolved "https://registry.yarnpkg.com/@sentry-internal/rrweb-snapshot/-/rrweb-snapshot-2.12.0.tgz#2f1f6d4867a07ab757475fb4fa337d7f1aaa6b2d"
integrity sha512-AYo8CeDA7qDOKFG75E+bnxrS/qm7l5Ad0ftClA3VzoGV58bNNgv/aKiECtUPk0UPs4EqTQ8z8W/MZ9EYDF6vvA==
"@sentry-internal/rrweb-snapshot@2.13.0":
version "2.13.0"
resolved "https://registry.yarnpkg.com/@sentry-internal/rrweb-snapshot/-/rrweb-snapshot-2.13.0.tgz#47fb017b2031075cdd4f1b54c098c0bd8eb75e16"
integrity sha512-ftSybKlmddX9QsLXq02gMiWfuXEfyjysSJe0tvKxGMP2r1y4rS5h2qjJeKx+GYPhcGi1s48KkjphLNwHehqf4g==

"@sentry-internal/[email protected]":
version "2.11.0"
Expand All @@ -5689,12 +5689,12 @@
dependencies:
"@sentry-internal/rrweb-snapshot" "2.11.0"

"@sentry-internal/rrweb-types@2.12.0":
version "2.12.0"
resolved "https://registry.yarnpkg.com/@sentry-internal/rrweb-types/-/rrweb-types-2.12.0.tgz#f7c57eda7610882c71860437657ffbbcb788184d"
integrity sha512-W0iLlTx3HeapBTGjg/uLoKQr1/DGPbkANqwjf4mW0IS4jHAVcxFX/e769aHHKEmd68Lm3+A8b08xdA9UDBXW5w==
"@sentry-internal/rrweb-types@2.13.0":
version "2.13.0"
resolved "https://registry.yarnpkg.com/@sentry-internal/rrweb-types/-/rrweb-types-2.13.0.tgz#b68b9cf03c51626051bed9f8c41a40f1cf362991"
integrity sha512-noG66TvuN5xJuQAPfxHECW84XUsjYR95fytH6tSvPQQh7a0JUC+i5H76YSWdGhbu5eCMcrypzgATfw/GEN7bPA==
dependencies:
"@sentry-internal/rrweb-snapshot" "2.12.0"
"@sentry-internal/rrweb-snapshot" "2.13.0"

"@sentry-internal/[email protected]":
version "2.11.0"
Expand All @@ -5710,14 +5710,14 @@
fflate "^0.4.4"
mitt "^3.0.0"

"@sentry-internal/rrweb@2.12.0":
version "2.12.0"
resolved "https://registry.yarnpkg.com/@sentry-internal/rrweb/-/rrweb-2.12.0.tgz#4becbedf7315f4b4e0ebc35319a848ec6f082dce"
integrity sha512-NosAF5f8dXdj6linXpI+e38/eKVtwy3R2rzmMohBCwdhPXgTkTV/Laj/9OsRxARNRyz81mIEGcn/Ivp/De7RaA==
"@sentry-internal/rrweb@2.13.0":
version "2.13.0"
resolved "https://registry.yarnpkg.com/@sentry-internal/rrweb/-/rrweb-2.13.0.tgz#27f997a5922fa4af5990198b62a149bbf4c18833"
integrity sha512-Xi+Sg7T8+1UbIaW5l5zKNb+X7FlD7O0l8TZwZjMXVGQtfQcJTkPkrALspqZfUeaAtX+rQHQArcfpNhQWiDYezQ==
dependencies:
"@sentry-internal/rrdom" "2.12.0"
"@sentry-internal/rrweb-snapshot" "2.12.0"
"@sentry-internal/rrweb-types" "2.12.0"
"@sentry-internal/rrdom" "2.13.0"
"@sentry-internal/rrweb-snapshot" "2.13.0"
"@sentry-internal/rrweb-types" "2.13.0"
"@types/css-font-loading-module" "0.0.7"
"@xstate/fsm" "^1.4.0"
base64-arraybuffer "^1.0.1"
Expand Down