[Plugin] Live stream canvas via webrtc (#976)
* inline stylesheets when loaded * set empty link elements to loaded by default * Clean up stylesheet manager * Remove attribute mutation code * Update packages/rrweb/test/record.test.ts * Update packages/rrweb/test/record.test.ts * Update packages/rrweb/test/record.test.ts * Update packages/rrweb/scripts/repl.js * Update packages/rrweb/test/record.test.ts * Update packages/rrweb/src/record/index.ts * Add todo * Move require out of time sensitive assert * Add waitForRAF, its more reliable than waitForTimeout * Remove flaky tests * Add recording stylesheets in iframes * Remove variability from flaky test * Make test more robust * Fix naming * Add test cases for inlineImages * Add test cases for inlineImages * Record iframe mutations cross page * Test: should record images inside iframe with blob url after iframe was reloaded * Handle negative ids in rrdom correctly When iframes get inserted they create untracked elements, both on the dom and rrdom side. Because they are untracked they generate negative numbers when fetching the id from mirror. This creates a problem when comparing and fetching ids across mirrors. This commit tries to get away from using negative ids as much as possible in rrdom's comparisons * Update packages/rrdom/src/diff.ts Co-authored-by: Yun Feng <yun.feng@anu.edu.au> * Start unserialized nodes at -2 This way we don't accidentally think of them as mirror misses * Set unserialized id starting number at -2 * Remove duplication * Use turbo instead of lerna * Skip benchmark as it is unreliable when executed in parallel * Strip port number from serialization, it can vary * Add settimeout to virtual dom test * Remove console.log and refactor blob:url serialization * Include references in tsconfig to indicate which monorepo packages are being used * Add stream setup * Migrate project to es module * Add reference to rrweb from rrdom * Move jest config to ESM * Setup basic WebRTC canvas streaming * Cleanup and refactor WebRTC streaming * Remove ? which isn't propper javascript * Yarn lock * Remove webrtc code from rrweb * Add plugin hooks Record/Replay plugins `.getMirror` exposes the mirror to plugins Replay plugins `.onBuild` called whenever a node was added to the dom * Expose plugins with server * Use unminified version for tests * Don't include simple-peer in rrweb main project * Add canvas webrtc plugin Streams contents of canvas via webrtc * ignore tsconfig.tsbuildinfo * Cleanup unused code * type definition files are no longer committed * Devtools off by default * Extract .css into its own file * Refactor plugin apis and fix multi canvas streaming support * Add readme to rrweb canvas webrtc plugin * Reference canvas-webrtc plugin in documentation * Forbidden non-null assertion * Remove linting of each project, yarn lint:report will do this * Remove test code * Cut down line length * fix CI failure and improve the zh_CN doc * Update packages/rrweb/src/plugins/canvas-webrtc/replay/index.ts Co-authored-by: Yun Feng <yun.feng@anu.edu.au> * Cleaner styling of replay Co-authored-by: Yun Feng <yun.feng@anu.edu.au> * Clean up stream.js based on @Mark-Fenng's feedback * Remove duplicate send Co-authored-by: Yun Feng <yun.feng@anu.edu.au> Co-authored-by: Yun Feng <yun.feng0817@gmail.com>
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,6 +3,7 @@
|
||||
.idea
|
||||
node_modules
|
||||
package-lock.json
|
||||
tsconfig.tsbuildinfo
|
||||
|
||||
temp
|
||||
|
||||
|
||||
@@ -13,4 +13,4 @@ install:
|
||||
script:
|
||||
- yarn build:all
|
||||
- yarn turbo run check-types
|
||||
- xvfb-run --server-args="-screen 0 1920x1080x24" yarn lerna run test
|
||||
- xvfb-run --server-args="-screen 0 1920x1080x24" yarn test
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Canvas
|
||||
|
||||
Canvas is a special HTML element, which will not be recorded by rrweb by default. There are some options for recording and replaying Canvas.
|
||||
Canvas is a special HTML element, and will not be recorded by rrweb by default.
|
||||
There are some options for recording and replaying Canvas.
|
||||
|
||||
Enable recording Canvas:
|
||||
|
||||
@@ -33,3 +34,6 @@ replayer.play();
|
||||
```
|
||||
|
||||
**Enable replaying Canvas will remove the sandbox, which may cause a potential security issue.**
|
||||
|
||||
Alternatively you can stream canvas elements via webrtc with the canvas-webrtc plugin.
|
||||
For more information see [canvas-webrtc documentation](../../packages/rrweb/src/plugins/canvas-webrtc/Readme.md)
|
||||
|
||||
@@ -34,3 +34,6 @@ replayer.play();
|
||||
```
|
||||
|
||||
**回放 Canvas 将会关闭沙盒策略,导致一定风险**。
|
||||
|
||||
另外,您可以使用 canvas-webrtc 插件通过 WEBRTC 流式传输 Canvas 元素。
|
||||
有关更多信息,请参考[canvas-webrtc 文档](../../packages/rrweb/src/plugins/canvas-webrtc/readme.md)
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
"packages/*"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@monorepo-utils/workspaces-to-typescript-project-references": "^2.8.2",
|
||||
"@typescript-eslint/eslint-plugin": "^5.25.0",
|
||||
"@typescript-eslint/parser": "^5.25.0",
|
||||
"concurrently": "^7.1.0",
|
||||
@@ -32,11 +33,12 @@
|
||||
},
|
||||
"scripts": {
|
||||
"lerna": "lerna",
|
||||
"build:all": "yarn turbo run prepublish",
|
||||
"test": "yarn turbo run test",
|
||||
"build:all": "yarn run concurrently --success=all -r -m=1 'yarn workspaces-to-typescript-project-references' 'yarn turbo run prepublish'",
|
||||
"test": "yarn run concurrently --success=all -r -m=1 'yarn workspaces-to-typescript-project-references --check' 'yarn turbo run test'",
|
||||
"test:watch": "yarn turbo run test:watch",
|
||||
"dev": "yarn turbo run dev",
|
||||
"repl": "cd packages/rrweb && npm run repl",
|
||||
"live-stream": "cd packages/rrweb && yarn live-stream",
|
||||
"lint": "yarn run concurrently --success=all -r -m=1 'yarn run markdownlint docs' 'yarn eslint packages/*/src --ext .ts,.tsx,.js,.jsx,.svelte'",
|
||||
"lint:report": "yarn eslint --output-file eslint_report.json --format json packages/*/src --ext .ts,.tsx,.js,.jsx"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"target": "ES6",
|
||||
"module": "commonjs",
|
||||
"noImplicitAny": true,
|
||||
@@ -16,5 +17,13 @@
|
||||
},
|
||||
"compileOnSave": true,
|
||||
"exclude": ["test"],
|
||||
"include": ["src", "test.d.ts", "../rrweb/src/record/workers/workers.d.ts"]
|
||||
"include": ["src", "test.d.ts", "../rrweb/src/record/workers/workers.d.ts"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../rrdom"
|
||||
},
|
||||
{
|
||||
"path": "../rrweb-snapshot"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ function walk(node, mirror, blankSpace) {
|
||||
`;
|
||||
|
||||
describe('RRDocument for browser environment', () => {
|
||||
jest.setTimeout(60_000);
|
||||
let mirror: Mirror;
|
||||
beforeEach(() => {
|
||||
mirror = new Mirror();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"target": "ES6",
|
||||
"module": "commonjs",
|
||||
"noImplicitAny": true,
|
||||
@@ -14,6 +15,11 @@
|
||||
"declaration": true,
|
||||
"importsNotUsedAsValues": "error"
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"path": "../rrweb-snapshot"
|
||||
}
|
||||
],
|
||||
"compileOnSave": true,
|
||||
"exclude": ["test"],
|
||||
"include": ["src", "../rrweb/src/record/workers/workers.d.ts"]
|
||||
|
||||
@@ -6,5 +6,13 @@
|
||||
"__sapper__/*",
|
||||
"public/*",
|
||||
"../rrweb/src/record/workers/workers.d.ts"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"composite": true
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"path": "../rrweb"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -320,7 +320,7 @@ export function buildNodeWithSN(
|
||||
mirror: Mirror;
|
||||
skipChild?: boolean;
|
||||
hackCss: boolean;
|
||||
afterAppend?: (n: Node) => unknown;
|
||||
afterAppend?: (n: Node, id: number) => unknown;
|
||||
cache: BuildCache;
|
||||
},
|
||||
): Node | null {
|
||||
@@ -398,7 +398,7 @@ export function buildNodeWithSN(
|
||||
node.appendChild(childNode);
|
||||
}
|
||||
if (afterAppend) {
|
||||
afterAppend(childNode);
|
||||
afterAppend(childNode, childN.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -449,7 +449,7 @@ function rebuild(
|
||||
doc: Document;
|
||||
onVisit?: (node: Node) => unknown;
|
||||
hackCss?: boolean;
|
||||
afterAppend?: (n: Node) => unknown;
|
||||
afterAppend?: (n: Node, id: number) => unknown;
|
||||
cache: BuildCache;
|
||||
mirror: Mirror;
|
||||
},
|
||||
|
||||
@@ -59,7 +59,8 @@ describe('add hover class to hover selector related rules', function () {
|
||||
expect(addHoverClass(cssText, cache)).toEqual(cssText);
|
||||
});
|
||||
|
||||
it('benchmark', () => {
|
||||
// this benchmark is unreliable when run in parallel with other tests
|
||||
it.skip('benchmark', () => {
|
||||
const cssText = fs.readFileSync(
|
||||
path.resolve(__dirname, './css/benchmark.css'),
|
||||
'utf8',
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"noImplicitAny": true,
|
||||
@@ -11,5 +12,6 @@
|
||||
"lib": ["es6", "dom"]
|
||||
},
|
||||
"exclude": ["test"],
|
||||
"include": ["src"]
|
||||
"include": ["src"],
|
||||
"references": []
|
||||
}
|
||||
|
||||
1
packages/rrweb/.gitignore
vendored
1
packages/rrweb/.gitignore
vendored
@@ -3,6 +3,7 @@
|
||||
node_modules
|
||||
package-lock.json
|
||||
# yarn.lock
|
||||
tsconfig.tsbuildinfo
|
||||
build
|
||||
dist
|
||||
es
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
|
||||
module.exports = {
|
||||
export default {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
testMatch: ['**/**.test.ts'],
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"test:headless": "PUPPETEER_HEADLESS=true npm run test",
|
||||
"test:watch": "PUPPETEER_HEADLESS=true npm run test -- --watch",
|
||||
"repl": "npm run bundle:browser && node scripts/repl.js",
|
||||
"live-stream": "yarn bundle:browser && node scripts/stream.js",
|
||||
"dev": "yarn bundle:browser --watch",
|
||||
"bundle:browser": "cross-env BROWSER_ONLY=true rollup --config",
|
||||
"bundle": "rollup --config",
|
||||
@@ -18,6 +19,7 @@
|
||||
"lint": "yarn eslint src",
|
||||
"benchmark": "jest test/benchmark"
|
||||
},
|
||||
"type": "module",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+ssh://git@github.com/rrweb-io/rrweb.git"
|
||||
@@ -45,7 +47,8 @@
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-node-resolve": "^13.1.3",
|
||||
"@types/chai": "^4.1.6",
|
||||
"@types/inquirer": "0.0.43",
|
||||
"@types/dom-mediacapture-transform": "^0.1.3",
|
||||
"@types/inquirer": "^8.2.1",
|
||||
"@types/jest": "^27.4.1",
|
||||
"@types/jest-image-snapshot": "^4.3.1",
|
||||
"@types/node": "^17.0.21",
|
||||
@@ -57,7 +60,7 @@
|
||||
"fast-mhtml": "^1.1.9",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"ignore-styles": "^5.0.1",
|
||||
"inquirer": "^6.2.1",
|
||||
"inquirer": "^9.0.0",
|
||||
"jest": "^27.5.1",
|
||||
"jest-image-snapshot": "^4.5.1",
|
||||
"jest-snapshot": "^23.6.0",
|
||||
@@ -69,8 +72,9 @@
|
||||
"rollup-plugin-rename-node-modules": "^1.3.1",
|
||||
"rollup-plugin-typescript2": "^0.31.2",
|
||||
"rollup-plugin-web-worker-loader": "^1.6.1",
|
||||
"simple-peer-light": "^9.10.0",
|
||||
"ts-jest": "^27.1.3",
|
||||
"ts-node": "^10.7.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"tslib": "^2.3.1",
|
||||
"typescript": "^4.7.3"
|
||||
},
|
||||
|
||||
@@ -89,6 +89,16 @@ const baseConfigs = [
|
||||
name: 'rrwebConsoleRecord',
|
||||
pathFn: toPluginPath('console', 'record'),
|
||||
},
|
||||
{
|
||||
input: './src/plugins/canvas-webrtc/record/index.ts',
|
||||
name: 'rrwebCanvasWebRTCRecord',
|
||||
pathFn: toPluginPath('canvas-webrtc', 'record'),
|
||||
},
|
||||
{
|
||||
input: './src/plugins/canvas-webrtc/replay/index.ts',
|
||||
name: 'rrwebCanvasWebRTCReplay',
|
||||
pathFn: toPluginPath('canvas-webrtc', 'replay'),
|
||||
},
|
||||
{
|
||||
input: './src/plugins/console/replay/index.ts',
|
||||
name: 'rrwebConsoleReplay',
|
||||
@@ -121,7 +131,7 @@ function getPlugins(options = {}) {
|
||||
minify,
|
||||
}),
|
||||
postcss({
|
||||
extract: false,
|
||||
extract: true,
|
||||
inject: false,
|
||||
minimize: minify,
|
||||
sourceMap,
|
||||
@@ -209,33 +219,29 @@ if (process.env.BROWSER_ONLY) {
|
||||
name: 'rrwebConsoleRecord',
|
||||
pathFn: toPluginPath('console', 'record'),
|
||||
},
|
||||
{
|
||||
input: './src/plugins/canvas-webrtc/record/index.ts',
|
||||
name: 'rrwebCanvasWebRTCRecord',
|
||||
pathFn: toPluginPath('canvas-webrtc', 'record'),
|
||||
},
|
||||
{
|
||||
input: './src/plugins/canvas-webrtc/replay/index.ts',
|
||||
name: 'rrwebCanvasWebRTCReplay',
|
||||
pathFn: toPluginPath('canvas-webrtc', 'replay'),
|
||||
},
|
||||
];
|
||||
|
||||
configs = [];
|
||||
|
||||
// browser record + replay, unminified (for profiling and performance testing)
|
||||
configs.push({
|
||||
input: './src/index.ts',
|
||||
plugins: getPlugins(),
|
||||
output: [
|
||||
{
|
||||
name: 'rrweb',
|
||||
format: 'iife',
|
||||
file: pkg.unpkg,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
for (const c of browserOnlyBaseConfigs) {
|
||||
configs.push({
|
||||
input: c.input,
|
||||
plugins: getPlugins({ sourceMap: true, minify: true }),
|
||||
plugins: getPlugins(),
|
||||
output: [
|
||||
{
|
||||
name: c.name,
|
||||
format: 'iife',
|
||||
file: toMinPath(c.pathFn(pkg.unpkg)),
|
||||
sourcemap: true,
|
||||
file: c.pathFn(pkg.unpkg),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
/* eslint:disable: no-console */
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const EventEmitter = require('events');
|
||||
const inquirer = require('inquirer');
|
||||
const puppeteer = require('puppeteer');
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import { EventEmitter } from 'node:events';
|
||||
import inquirer from 'inquirer';
|
||||
import puppeteer from 'puppeteer';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
const emitter = new EventEmitter();
|
||||
|
||||
function getCode() {
|
||||
const bundlePath = path.resolve(__dirname, '../dist/rrweb.min.js');
|
||||
const bundlePath = path.resolve(__dirname, '../dist/rrweb.js');
|
||||
return fs.readFileSync(bundlePath, 'utf8');
|
||||
}
|
||||
|
||||
@@ -165,7 +169,7 @@ void (async () => {
|
||||
}
|
||||
|
||||
await page.addStyleTag({
|
||||
path: path.resolve(__dirname, '../dist/rrweb.min.css'),
|
||||
path: path.resolve(__dirname, '../dist/rrweb.css'),
|
||||
});
|
||||
await page.evaluate(`${code}
|
||||
const events = ${JSON.stringify(events)};
|
||||
@@ -196,10 +200,10 @@ void (async () => {
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
|
||||
<title>Record @${time}</title>
|
||||
<link rel="stylesheet" href="../dist/rrweb.min.css" />
|
||||
<link rel="stylesheet" href="../dist/rrweb.css" />
|
||||
</head>
|
||||
<body>
|
||||
<script src="../dist/rrweb.min.js"></script>
|
||||
<script src="../dist/rrweb.js"></script>
|
||||
<script>
|
||||
/*<!--*/
|
||||
const events = ${JSON.stringify(events).replace(
|
||||
|
||||
253
packages/rrweb/scripts/stream.js
Normal file
253
packages/rrweb/scripts/stream.js
Normal file
@@ -0,0 +1,253 @@
|
||||
/* eslint:disable: no-console */
|
||||
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import { EventEmitter } from 'node:events';
|
||||
import inquirer from 'inquirer';
|
||||
import puppeteer from 'puppeteer';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
import { startServer, getServerURL } from './utils.js';
|
||||
|
||||
// Turn on devtools for debugging:
|
||||
const devtools = false;
|
||||
const defaultURL = 'https://webglsamples.org/';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
const emitter = new EventEmitter();
|
||||
|
||||
async function startRecording(page, serverURL) {
|
||||
try {
|
||||
await page.addScriptTag({ url: `${serverURL}/rrweb.js` });
|
||||
await page.addScriptTag({
|
||||
url: `${serverURL}/plugins/canvas-webrtc-record.js`,
|
||||
});
|
||||
await page.evaluate((serverURL) => {
|
||||
const win = window;
|
||||
win.__IS_RECORDING__ = true;
|
||||
win.events = [];
|
||||
window.record = win.rrweb.record;
|
||||
window.plugin = new rrwebCanvasWebRTCRecord.RRWebPluginCanvasWebRTCRecord(
|
||||
{
|
||||
signalSendCallback: (msg) => {
|
||||
// [record#callback] provides canvas id, stream, and webrtc sdpOffer signal & connect message
|
||||
_signal(msg);
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
window.record({
|
||||
emit: (event) => {
|
||||
win.events.push(event);
|
||||
win._captureEvent(event);
|
||||
},
|
||||
plugins: [window.plugin.initPlugin()],
|
||||
recordCanvas: false,
|
||||
collectFonts: true,
|
||||
inlineImages: true,
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
async function startReplay(page, serverURL, recordedPage) {
|
||||
await recordedPage.exposeFunction('_signal', async (signal) => {
|
||||
await page.evaluate((signal) => {
|
||||
// [replay#signalReceive] setups up peer and starts creating counter offer
|
||||
window.plugin.signalReceive(signal);
|
||||
}, signal);
|
||||
});
|
||||
await page.exposeFunction('_signal', async (signal) => {
|
||||
await recordedPage.evaluate((signal) => {
|
||||
// [record#signalReceive] setups up webrtc connection
|
||||
window.plugin.signalReceive(signal);
|
||||
}, signal);
|
||||
});
|
||||
await page.exposeFunction('_canvas', async (id) => {
|
||||
await recordedPage.evaluate((id) => {
|
||||
// [record#setupStream] sets up the canvas stream for a given id.
|
||||
const stream = window.plugin.setupStream(id);
|
||||
console.log('stream for', id, '=>', stream);
|
||||
}, id);
|
||||
});
|
||||
|
||||
await page.addScriptTag({ url: `${serverURL}/rrweb.js` });
|
||||
await page.addScriptTag({
|
||||
url: `${serverURL}/plugins/canvas-webrtc-replay.js`,
|
||||
});
|
||||
|
||||
return page.evaluate(() => {
|
||||
window.plugin = new rrwebCanvasWebRTCReplay.RRWebPluginCanvasWebRTCReplay({
|
||||
canvasFoundCallback(canvas, context) {
|
||||
console.log('canvas', canvas, context);
|
||||
// [replay#onBuild] gets id of canvas element and sends to recorded page
|
||||
_canvas(context.id);
|
||||
},
|
||||
signalSendCallback(data) {
|
||||
_signal(JSON.stringify(data));
|
||||
},
|
||||
});
|
||||
|
||||
window.replayer = new rrweb.Replayer([], {
|
||||
UNSAFE_replayCanvas: true,
|
||||
liveMode: true,
|
||||
plugins: [window.plugin.initPlugin()],
|
||||
});
|
||||
window.replayer.startLive();
|
||||
const style = new CSSStyleSheet();
|
||||
style.replaceSync('body {margin: 0;} iframe {border: none;}');
|
||||
document.adoptedStyleSheets = [style];
|
||||
});
|
||||
}
|
||||
|
||||
async function resizeWindow(page, top, left, width, height) {
|
||||
const session = await page.target().createCDPSession();
|
||||
await page.setViewport({ height, width });
|
||||
const { windowId } = await session.send('Browser.getWindowForTarget');
|
||||
await session.send('Browser.setWindowBounds', {
|
||||
bounds: { top, left, height, width },
|
||||
windowId,
|
||||
});
|
||||
}
|
||||
|
||||
void (async () => {
|
||||
let server;
|
||||
let serverURL;
|
||||
|
||||
await start();
|
||||
|
||||
async function start() {
|
||||
server = await startServer();
|
||||
serverURL = getServerURL(server);
|
||||
|
||||
const { url } = await inquirer.prompt([
|
||||
{
|
||||
type: 'input',
|
||||
name: 'url',
|
||||
message: `Enter the url you want to record, e.g ${defaultURL}: `,
|
||||
},
|
||||
]);
|
||||
|
||||
await record(url);
|
||||
|
||||
const { shouldRecordAnother } = await inquirer.prompt([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'shouldRecordAnother',
|
||||
message: 'Record another one?',
|
||||
},
|
||||
]);
|
||||
|
||||
emitter.emit('done');
|
||||
|
||||
if (shouldRecordAnother) {
|
||||
await start();
|
||||
} else {
|
||||
process.exit();
|
||||
}
|
||||
}
|
||||
|
||||
async function record(url) {
|
||||
if (url === '') url = defaultURL;
|
||||
|
||||
const replayingBrowser = await puppeteer.launch({
|
||||
headless: false,
|
||||
devtools,
|
||||
defaultViewport: {
|
||||
width: 1600,
|
||||
height: 900,
|
||||
},
|
||||
args: [
|
||||
'--start-maximized',
|
||||
'--ignore-certificate-errors',
|
||||
'--no-sandbox',
|
||||
],
|
||||
});
|
||||
|
||||
const replayerPage = (await replayingBrowser.pages())[0];
|
||||
await replayerPage.goto('about:blank');
|
||||
|
||||
await replayerPage.addStyleTag({
|
||||
path: path.resolve(__dirname, '../dist/rrweb.css'),
|
||||
});
|
||||
|
||||
const recordingBrowser = await puppeteer.launch({
|
||||
headless: false,
|
||||
devtools,
|
||||
defaultViewport: {
|
||||
width: 1600,
|
||||
height: 900,
|
||||
},
|
||||
args: [
|
||||
'--start-maximized',
|
||||
'--ignore-certificate-errors',
|
||||
'--no-sandbox',
|
||||
],
|
||||
});
|
||||
|
||||
const recordedPage = (await recordingBrowser.pages())[0];
|
||||
if (!recordedPage) {
|
||||
throw new Error('No recorded page found');
|
||||
}
|
||||
// disables content security policy which enables us to insert rrweb as a script tag
|
||||
await recordedPage.setBypassCSP(true);
|
||||
|
||||
replayerPage.on('console', (msg) =>
|
||||
console.log('REPLAY PAGE LOG:', msg.text()),
|
||||
);
|
||||
recordedPage.on('console', (msg) =>
|
||||
console.log('RECORD PAGE LOG:', msg.text()),
|
||||
);
|
||||
await startReplay(replayerPage, serverURL, recordedPage);
|
||||
|
||||
await Promise.all([
|
||||
resizeWindow(recordedPage, 0, 0, 800, 800),
|
||||
resizeWindow(replayerPage, 0, 800, 800, 800),
|
||||
]);
|
||||
|
||||
await recordedPage.goto(url, {
|
||||
waitUntil: 'domcontentloaded',
|
||||
timeout: 300000,
|
||||
});
|
||||
|
||||
if (!replayerPage) throw new Error('No replayer page found');
|
||||
|
||||
await recordedPage.exposeFunction('_captureEvent', (event) => {
|
||||
replayerPage.evaluate((event) => {
|
||||
window.replayer.addEvent(event);
|
||||
}, event);
|
||||
});
|
||||
await startRecording(recordedPage, serverURL);
|
||||
recordedPage.on('framenavigated', async () => {
|
||||
const isRecording = await recordedPage.evaluate(
|
||||
'window.__IS_RECORDING__',
|
||||
);
|
||||
if (!isRecording) {
|
||||
await startRecording(recordedPage, serverURL);
|
||||
}
|
||||
});
|
||||
|
||||
emitter.once('done', async () => {
|
||||
const pages = [
|
||||
...(await recordingBrowser.pages()),
|
||||
...(await replayingBrowser.pages()),
|
||||
];
|
||||
await server.close();
|
||||
await Promise.all(pages.map((page) => page.close()));
|
||||
await recordingBrowser.close();
|
||||
await replayingBrowser.close();
|
||||
});
|
||||
}
|
||||
|
||||
process
|
||||
.on('uncaughtException', (error) => {
|
||||
console.error(error);
|
||||
})
|
||||
.on('unhandledRejection', (error) => {
|
||||
console.error(error);
|
||||
});
|
||||
})();
|
||||
62
packages/rrweb/scripts/utils.js
Normal file
62
packages/rrweb/scripts/utils.js
Normal file
@@ -0,0 +1,62 @@
|
||||
import * as path from 'path';
|
||||
import * as http from 'http';
|
||||
import * as url from 'url';
|
||||
import * as fs from 'fs';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
export const startServer = (defaultPort = 3030) =>
|
||||
new Promise((resolve) => {
|
||||
const mimeType = {
|
||||
'.html': 'text/html',
|
||||
'.js': 'text/javascript',
|
||||
'.css': 'text/css',
|
||||
};
|
||||
const s = http.createServer((req, res) => {
|
||||
const parsedUrl = url.parse(req.url);
|
||||
const sanitizePath = path
|
||||
.normalize(parsedUrl.pathname)
|
||||
.replace(/^(\.\.[\/\\])+/, '');
|
||||
let pathname = path.join(__dirname, sanitizePath);
|
||||
if (
|
||||
/^\/rrweb.*\.js.*/.test(sanitizePath) ||
|
||||
/^\/plugins\/.*/.test(sanitizePath)
|
||||
) {
|
||||
pathname = path.join(__dirname, `../dist`, sanitizePath);
|
||||
}
|
||||
try {
|
||||
const data = fs.readFileSync(pathname);
|
||||
const ext = path.parse(pathname).ext;
|
||||
res.setHeader('Content-type', mimeType[ext] || 'text/plain');
|
||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||
res.setHeader('Access-Control-Allow-Methods', 'GET');
|
||||
res.setHeader('Access-Control-Allow-Headers', 'Content-type');
|
||||
setTimeout(() => {
|
||||
res.end(data);
|
||||
}, 100);
|
||||
} catch (error) {
|
||||
res.end();
|
||||
}
|
||||
});
|
||||
s.listen(defaultPort)
|
||||
.on('listening', () => {
|
||||
resolve(s);
|
||||
})
|
||||
.on('error', (e) => {
|
||||
console.log('port in use, trying next one');
|
||||
s.listen().on('listening', () => {
|
||||
resolve(s);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
export function getServerURL(server) {
|
||||
const address = server.address();
|
||||
if (address && typeof address !== 'string') {
|
||||
return `http://localhost:${address.port}`;
|
||||
} else {
|
||||
return `${address}`;
|
||||
}
|
||||
}
|
||||
74
packages/rrweb/src/plugins/canvas-webrtc/Readme.md
Normal file
74
packages/rrweb/src/plugins/canvas-webrtc/Readme.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# rrweb canvas webrtc plugin
|
||||
|
||||
Plugin that live streams contents of canvas elements via webrtc
|
||||
|
||||
## Example of live streaming via `yarn live-stream`
|
||||
|
||||
https://user-images.githubusercontent.com/4106/186701616-fd71a107-5d53-423c-ba09-0395a3a0252f.mov
|
||||
|
||||
## Instructions
|
||||
|
||||
### Record side
|
||||
|
||||
```js
|
||||
// Record side
|
||||
|
||||
import rrweb from 'rrweb';
|
||||
import { RRWebPluginCanvasWebRTCRecord } from 'rrweb-plugin-canvas-webrtc-record';
|
||||
|
||||
const webRTCRecordPlugin = new RRWebPluginCanvasWebRTCRecord({
|
||||
signalSendCallback: (msg) => {
|
||||
// provides webrtc sdp offer signal & connect message
|
||||
// make sure you send this to the replayer's `webRTCReplayPlugin.signalReceive(signal)`
|
||||
sendSignalToReplayer(msg); // example of function that sends the signal to the replayer
|
||||
},
|
||||
});
|
||||
|
||||
rrweb.record({
|
||||
emit: (event) => {
|
||||
// send these events to the `replayer.addEvent(event)`, how you do that is up to you
|
||||
// you can send them to a server for example which can then send them to the replayer
|
||||
sendEventToReplayer(event); // example of function that sends the event to the replayer
|
||||
},
|
||||
plugins: [
|
||||
// add the plugin to the list of plugins, and initialize it via `.initPlugin()`
|
||||
webRTCRecordPlugin.initPlugin(),
|
||||
],
|
||||
recordCanvas: false, // we don't want canvas recording turned on, we're going to do that via the plugin
|
||||
});
|
||||
```
|
||||
|
||||
### Replay Side
|
||||
|
||||
```js
|
||||
// Replay side
|
||||
import rrweb from 'rrweb';
|
||||
import { RRWebPluginCanvasWebRTCReplay } from 'rrweb-plugin-canvas-webrtc-replay';
|
||||
|
||||
const webRTCReplayPlugin = new RRWebPluginCanvasWebRTCReplay({
|
||||
canvasFoundCallback(canvas, context) {
|
||||
console.log('canvas', canvas);
|
||||
// send the canvas id to `webRTCRecordPlugin.setupStream(id)`, how you do that is up to you
|
||||
// you can send them to a server for example which can then send them to the replayer
|
||||
sendCanvasIdToRecordScript(context.id); // example of function that sends the id to the record script
|
||||
},
|
||||
signalSendCallback(signal) {
|
||||
// provides webrtc sdp offer signal & connect message
|
||||
// make sure you send this to the record script's `webRTCRecordPlugin.signalReceive(signal)`
|
||||
sendSignalToRecordScript(signal); // example of function that sends the signal to the record script
|
||||
},
|
||||
});
|
||||
|
||||
const replayer = new rrweb.Replayer([], {
|
||||
UNSAFE_replayCanvas: true, // turn canvas replay on!
|
||||
liveMode: true, // live mode is needed to stream events to the replayer
|
||||
plugins: [webRTCReplayPlugin.initPlugin()],
|
||||
});
|
||||
replayer.startLive(); // start the replayer in live mode
|
||||
|
||||
replayer.addEvent(event); // call this whenever an event is received from the record script
|
||||
```
|
||||
|
||||
## More info
|
||||
|
||||
https://github.com/rrweb-io/rrweb/pull/976
|
||||
94
packages/rrweb/src/plugins/canvas-webrtc/record/index.ts
Normal file
94
packages/rrweb/src/plugins/canvas-webrtc/record/index.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import type { Mirror } from 'rrweb-snapshot';
|
||||
import SimplePeer from 'simple-peer-light';
|
||||
import type { RecordPlugin } from '../../../types';
|
||||
import type { WebRTCDataChannel } from '../types';
|
||||
|
||||
export const PLUGIN_NAME = 'rrweb/canvas-webrtc@1';
|
||||
|
||||
export class RRWebPluginCanvasWebRTCRecord {
|
||||
private peer: SimplePeer.Instance | null = null;
|
||||
private mirror: Mirror;
|
||||
private streamMap: Map<number, MediaStream> = new Map();
|
||||
private signalSendCallback: (msg: RTCSessionDescriptionInit) => void;
|
||||
|
||||
constructor({
|
||||
signalSendCallback,
|
||||
peer,
|
||||
}: {
|
||||
signalSendCallback: RRWebPluginCanvasWebRTCRecord['signalSendCallback'];
|
||||
peer?: SimplePeer.Instance;
|
||||
}) {
|
||||
this.signalSendCallback = signalSendCallback;
|
||||
if (peer) this.peer = peer;
|
||||
}
|
||||
|
||||
public initPlugin(): RecordPlugin {
|
||||
return {
|
||||
name: PLUGIN_NAME,
|
||||
getMirror: (mirror) => {
|
||||
this.mirror = mirror;
|
||||
},
|
||||
options: {},
|
||||
};
|
||||
}
|
||||
|
||||
public signalReceive(signal: RTCSessionDescriptionInit) {
|
||||
if (!this.peer) this.setupPeer();
|
||||
this.peer?.signal(signal);
|
||||
}
|
||||
|
||||
private startStream(id: number, stream: MediaStream) {
|
||||
if (!this.peer) return this.setupPeer();
|
||||
|
||||
const data: WebRTCDataChannel = {
|
||||
nodeId: id,
|
||||
streamId: stream.id,
|
||||
};
|
||||
this.peer?.send(JSON.stringify(data));
|
||||
this.peer?.addStream(stream);
|
||||
}
|
||||
|
||||
public setupPeer() {
|
||||
if (!this.peer) {
|
||||
this.peer = new SimplePeer({
|
||||
initiator: true,
|
||||
// trickle: false, // only create one WebRTC offer per session
|
||||
});
|
||||
|
||||
this.peer.on('error', (err: Error) => {
|
||||
this.peer = null;
|
||||
console.log('error', err);
|
||||
});
|
||||
|
||||
this.peer.on('close', () => {
|
||||
this.peer = null;
|
||||
console.log('closing');
|
||||
});
|
||||
|
||||
this.peer.on('signal', (data: RTCSessionDescriptionInit) => {
|
||||
this.signalSendCallback(data);
|
||||
});
|
||||
|
||||
this.peer.on('connect', () => {
|
||||
for (const [id, stream] of this.streamMap) {
|
||||
this.startStream(id, stream);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public setupStream(id: number): false | MediaStream {
|
||||
if (id === -1) return false;
|
||||
let stream: MediaStream | undefined = this.streamMap.get(id);
|
||||
if (stream) return stream;
|
||||
|
||||
const el = this.mirror.getNode(id) as HTMLCanvasElement | null;
|
||||
if (!el || !('captureStream' in el)) return false;
|
||||
|
||||
stream = el.captureStream();
|
||||
this.streamMap.set(id, stream);
|
||||
this.setupPeer();
|
||||
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
167
packages/rrweb/src/plugins/canvas-webrtc/replay/index.ts
Normal file
167
packages/rrweb/src/plugins/canvas-webrtc/replay/index.ts
Normal file
@@ -0,0 +1,167 @@
|
||||
import type { RRNode } from 'rrdom';
|
||||
import type { Mirror } from 'rrweb-snapshot';
|
||||
import SimplePeer from 'simple-peer-light';
|
||||
import type { Replayer } from '../../../replay';
|
||||
import type { ReplayPlugin } from '../../../types';
|
||||
import type { WebRTCDataChannel } from '../types';
|
||||
|
||||
// TODO: restrict callback to real nodes only, or make sure callback gets called when real node gets added to dom as well
|
||||
|
||||
export class RRWebPluginCanvasWebRTCReplay {
|
||||
private canvasFoundCallback: (
|
||||
node: Node | RRNode,
|
||||
context: { id: number; replayer: Replayer },
|
||||
) => void;
|
||||
private signalSendCallback: (signal: RTCSessionDescriptionInit) => void;
|
||||
private mirror: Mirror;
|
||||
|
||||
constructor({
|
||||
canvasFoundCallback,
|
||||
signalSendCallback,
|
||||
}: {
|
||||
canvasFoundCallback: RRWebPluginCanvasWebRTCReplay['canvasFoundCallback'];
|
||||
signalSendCallback: RRWebPluginCanvasWebRTCReplay['signalSendCallback'];
|
||||
}) {
|
||||
this.canvasFoundCallback = canvasFoundCallback;
|
||||
this.signalSendCallback = signalSendCallback;
|
||||
}
|
||||
|
||||
public initPlugin(): ReplayPlugin {
|
||||
return {
|
||||
onBuild: (
|
||||
node: Node | RRNode,
|
||||
context: { id: number; replayer: Replayer },
|
||||
) => {
|
||||
if (node.nodeName === 'CANVAS') {
|
||||
this.canvasFoundCallback(node, context);
|
||||
}
|
||||
},
|
||||
getMirror: (mirror: Mirror) => {
|
||||
this.mirror = mirror;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private startStream(
|
||||
target: HTMLCanvasElement | HTMLVideoElement,
|
||||
stream: MediaStream,
|
||||
) {
|
||||
if (this.runningStreams.has(stream)) return;
|
||||
|
||||
if (target.tagName === 'VIDEO') {
|
||||
const remoteVideo = target as HTMLVideoElement;
|
||||
remoteVideo.srcObject = stream;
|
||||
void remoteVideo.play();
|
||||
this.runningStreams.add(stream);
|
||||
return;
|
||||
}
|
||||
|
||||
if ('MediaStreamTrackProcessor' in window) {
|
||||
const canvas = target as HTMLCanvasElement;
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx)
|
||||
throw new Error(
|
||||
`startStream: Could not get 2d canvas context for ${canvas.outerHTML}`,
|
||||
);
|
||||
const track = stream.getVideoTracks()[0]; // MediaStream.getVideoTracks()[0]
|
||||
const processor = new MediaStreamTrackProcessor({ track: track });
|
||||
const reader = processor.readable.getReader();
|
||||
const readChunk = function () {
|
||||
void reader.read().then(({ done, value }) => {
|
||||
if (!value) return;
|
||||
// the MediaStream video can have dynamic size based on bandwidth available
|
||||
if (
|
||||
canvas.width !== value.displayWidth ||
|
||||
canvas.height !== value.displayHeight
|
||||
) {
|
||||
canvas.width = value.displayWidth;
|
||||
canvas.height = value.displayHeight;
|
||||
}
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
// value is a VideoFrame
|
||||
ctx.drawImage(value, 0, 0);
|
||||
value.close(); // close the VideoFrame when we're done with it
|
||||
if (!done) {
|
||||
readChunk();
|
||||
}
|
||||
});
|
||||
};
|
||||
readChunk();
|
||||
this.runningStreams.add(stream);
|
||||
} else {
|
||||
// Fallback for non-Chromium browsers.
|
||||
// Replaces the canvas element with a video element.
|
||||
|
||||
const remoteVideo = document.createElement('video');
|
||||
remoteVideo.setAttribute('autoplay', 'true');
|
||||
remoteVideo.setAttribute('playsinline', 'true');
|
||||
|
||||
// const { id } = mutation;
|
||||
remoteVideo.setAttribute('width', target.width.toString());
|
||||
remoteVideo.setAttribute('height', target.height.toString());
|
||||
target.replaceWith(remoteVideo);
|
||||
|
||||
this.startStream(remoteVideo, stream);
|
||||
}
|
||||
}
|
||||
|
||||
private peer: SimplePeer.Instance | null = null;
|
||||
private streamNodeMap = new Map<string, number>();
|
||||
private streams = new Set<MediaStream>();
|
||||
private runningStreams = new WeakSet<MediaStream>();
|
||||
public signalReceive(msg: RTCSessionDescriptionInit) {
|
||||
if (!this.peer) {
|
||||
this.peer = new SimplePeer({
|
||||
initiator: false,
|
||||
// trickle: false,
|
||||
});
|
||||
|
||||
this.peer.on('error', (err: Error) => {
|
||||
this.peer = null;
|
||||
console.log('error', err);
|
||||
});
|
||||
|
||||
this.peer.on('close', () => {
|
||||
this.peer = null;
|
||||
console.log('closing');
|
||||
});
|
||||
|
||||
this.peer.on('signal', (data: RTCSessionDescriptionInit) => {
|
||||
this.signalSendCallback(data);
|
||||
});
|
||||
|
||||
this.peer.on('connect', () => {
|
||||
// connected!
|
||||
});
|
||||
|
||||
this.peer.on('data', (data: SimplePeer.SimplePeerData) => {
|
||||
try {
|
||||
const json = JSON.parse(data as string) as WebRTCDataChannel;
|
||||
this.streamNodeMap.set(json.streamId, json.nodeId);
|
||||
} catch (error) {
|
||||
console.error('Could not parse data', error);
|
||||
}
|
||||
this.flushStreams();
|
||||
});
|
||||
|
||||
this.peer.on('stream', (stream: MediaStream) => {
|
||||
this.streams.add(stream);
|
||||
this.flushStreams();
|
||||
});
|
||||
}
|
||||
this.peer.signal(msg);
|
||||
}
|
||||
|
||||
private flushStreams() {
|
||||
this.streams.forEach((stream) => {
|
||||
const nodeId = this.streamNodeMap.get(stream.id);
|
||||
if (!nodeId) return;
|
||||
const target = this.mirror.getNode(nodeId) as
|
||||
| HTMLCanvasElement
|
||||
| HTMLVideoElement
|
||||
| null;
|
||||
// got remote video stream, now let's show it in a video or canvas element
|
||||
if (target) this.startStream(target, stream);
|
||||
});
|
||||
}
|
||||
}
|
||||
308
packages/rrweb/src/plugins/canvas-webrtc/simple-peer-light.d.ts
vendored
Normal file
308
packages/rrweb/src/plugins/canvas-webrtc/simple-peer-light.d.ts
vendored
Normal file
@@ -0,0 +1,308 @@
|
||||
/// <reference types="node" />
|
||||
declare module 'simple-peer-light' {
|
||||
import * as stream from 'stream';
|
||||
|
||||
const SimplePeer: SimplePeer.SimplePeer;
|
||||
|
||||
namespace SimplePeer {
|
||||
interface Options {
|
||||
/** set to `true` if this is the initiating peer */
|
||||
initiator?: boolean | undefined;
|
||||
/** custom webrtc data channel configuration (used by [`createDataChannel`](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/createDataChannel)) */
|
||||
channelConfig?: RTCDataChannelInit | undefined;
|
||||
/** custom webrtc data channel name */
|
||||
channelName?: string | undefined;
|
||||
/** custom webrtc configuration (used by [`RTCPeerConnection`](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection) constructor) */
|
||||
config?: RTCConfiguration | undefined;
|
||||
/** custom offer options (used by [`createOffer`](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/createOffer) method) */
|
||||
offerOptions?: RTCOfferOptions | undefined;
|
||||
/** custom answer options (used by [`createAnswer`](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/createAnswer) method) */
|
||||
answerOptions?: RTCAnswerOptions | undefined;
|
||||
/** function to transform the generated SDP signaling data (for advanced users) */
|
||||
sdpTransform?: ((this: Instance, sdp: string) => string) | undefined;
|
||||
/** if video/voice is desired, pass stream returned from [`getUserMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia) */
|
||||
stream?: MediaStream | undefined;
|
||||
/** an array of MediaStreams returned from [`getUserMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia) */
|
||||
streams?: MediaStream[] | undefined;
|
||||
/** set to `false` to disable [trickle ICE](http://webrtchacks.com/trickle-ice/) and get a single 'signal' event (slower) */
|
||||
trickle?: boolean | undefined;
|
||||
/** similar to `trickle`, needs to be set to `false` to disable trickling, defaults to `false` */
|
||||
allowHalfTrickle?: boolean | undefined;
|
||||
/** if `trickle` is set to `false`, determines how long to wait before providing an offer or answer; default value is 5000 milliseconds */
|
||||
iceCompleteTimeout?: number | undefined;
|
||||
/** custom webrtc implementation, mainly useful in node to specify in the [wrtc](https://npmjs.com/package/wrtc) package. */
|
||||
wrtc?:
|
||||
| {
|
||||
RTCPeerConnection: typeof RTCPeerConnection;
|
||||
RTCSessionDescription: typeof RTCSessionDescription;
|
||||
RTCIceCandidate: typeof RTCIceCandidate;
|
||||
}
|
||||
| undefined;
|
||||
/** set to true to create the stream in Object Mode. In this mode, incoming string data is not automatically converted to Buffer objects. */
|
||||
objectMode?: boolean | undefined;
|
||||
}
|
||||
interface SimplePeer {
|
||||
prototype: Instance;
|
||||
/**
|
||||
* Create a new WebRTC peer connection.
|
||||
*
|
||||
* A "data channel" for text/binary communication is always established, because it's cheap and often useful. For video/voice communication, pass the stream option.
|
||||
*
|
||||
* If opts is specified, then the default options (see <https://github.com/feross/simple-peer#peer--new-peeropts>) will be overridden.
|
||||
*/
|
||||
new (opts?: Options): Instance;
|
||||
|
||||
/** Detect native WebRTC support in the javascript environment. */
|
||||
readonly WEBRTC_SUPPORT: boolean;
|
||||
|
||||
// ********************************
|
||||
// methods which are not documented
|
||||
// ********************************
|
||||
|
||||
/**
|
||||
* Expose peer and data channel config for overriding all Peer
|
||||
* instances. Otherwise, just set opts.config or opts.channelConfig
|
||||
* when constructing a Peer.
|
||||
*/
|
||||
config: RTCConfiguration;
|
||||
/**
|
||||
* Expose peer and data channel config for overriding all Peer
|
||||
* instances. Otherwise, just set opts.config or opts.channelConfig
|
||||
* when constructing a Peer.
|
||||
*/
|
||||
channelConfig: RTCDataChannelInit;
|
||||
}
|
||||
|
||||
type TypedArray =
|
||||
| Int8Array
|
||||
| Uint8Array
|
||||
| Uint8ClampedArray
|
||||
| Int16Array
|
||||
| Uint16Array
|
||||
| Int32Array
|
||||
| Uint32Array
|
||||
| Float32Array
|
||||
| Float64Array;
|
||||
|
||||
type SimplePeerData = string | Buffer | TypedArray | ArrayBuffer | Blob;
|
||||
|
||||
type SignalData =
|
||||
| {
|
||||
type: 'transceiverRequest';
|
||||
transceiverRequest: {
|
||||
kind: string;
|
||||
init?: RTCRtpTransceiverInit | undefined;
|
||||
};
|
||||
}
|
||||
| {
|
||||
type: 'renegotiate';
|
||||
renegotiate: true;
|
||||
}
|
||||
| {
|
||||
type: 'candidate';
|
||||
candidate: RTCIceCandidate;
|
||||
}
|
||||
| RTCSessionDescriptionInit;
|
||||
|
||||
interface Instance extends stream.Duplex {
|
||||
/**
|
||||
* Call this method whenever the remote peer emits a `peer.on('signal')` event.
|
||||
*
|
||||
* The `data` will encapsulate a webrtc offer, answer, or ice candidate. These messages help
|
||||
* the peers to eventually establish a direct connection to each other. The contents of these
|
||||
* strings are an implementation detail that can be ignored by the user of this module;
|
||||
* simply pass the data from 'signal' events to the remote peer and call `peer.signal(data)`
|
||||
* to get connected.
|
||||
*/
|
||||
signal(data: string | SignalData): void;
|
||||
|
||||
/**
|
||||
* Send text/binary data to the remote peer. `data` can be any of several types: `String`,
|
||||
* `Buffer` (see [buffer](https://github.com/feross/buffer)), `ArrayBufferView` (`Uint8Array`,
|
||||
* etc.), `ArrayBuffer`, or `Blob` (in browsers that support it).
|
||||
*
|
||||
* Note: If this method is called before the `peer.on('connect')` event has fired,
|
||||
* then an exception will be thrown. Use `peer.write(data)`
|
||||
* (which is inherited from the node.js [duplex stream](https://nodejs.org/api/stream.html) interface)
|
||||
* if you want this data to be buffered instead.
|
||||
*/
|
||||
send(data: SimplePeerData): void;
|
||||
|
||||
/** Add a `MediaStream` to the connection. */
|
||||
addStream(stream: MediaStream): void;
|
||||
|
||||
/** Remove a `MediaStream` from the connection. */
|
||||
removeStream(stream: MediaStream): void;
|
||||
|
||||
/** Add a `MediaStreamTrack` to the connection. Must also pass the `MediaStream` you want to attach it to. */
|
||||
addTrack(track: MediaStreamTrack, stream: MediaStream): void;
|
||||
|
||||
/** Remove a `MediaStreamTrack` from the connection. Must also pass the `MediaStream` that it was attached to. */
|
||||
removeTrack(track: MediaStreamTrack, stream: MediaStream): void;
|
||||
|
||||
/** Replace a `MediaStreamTrack` with another track. Must also pass the `MediaStream` that the old track was attached to. */
|
||||
replaceTrack(
|
||||
oldTrack: MediaStreamTrack,
|
||||
newTrack: MediaStreamTrack,
|
||||
stream: MediaStream,
|
||||
): void;
|
||||
|
||||
/** Add a `RTCRtpTransceiver` to the connection. Can be used to add transceivers before adding tracks. Automatically called as necessary by `addTrack`. */
|
||||
addTransceiver(kind: string, init?: RTCRtpTransceiverInit): void;
|
||||
|
||||
// TODO: https://github.com/feross/simple-peer/blob/d972548299a50f836ca91c36e39304ef0f9474b7/index.js#L427
|
||||
// destroy(onclose?: () => void): void;
|
||||
/**
|
||||
* Destroy and cleanup this peer connection.
|
||||
*
|
||||
* If the optional `err` parameter is passed, then it will be emitted as an `'error'`
|
||||
* event on the stream.
|
||||
*/
|
||||
destroy(error?: Error): any;
|
||||
|
||||
// ********************************
|
||||
// methods which are not documented
|
||||
// ********************************
|
||||
|
||||
readonly bufferSize: number;
|
||||
readonly connected: boolean;
|
||||
address():
|
||||
| { port: undefined; family: undefined; address: undefined }
|
||||
| { port: number; family: 'IPv6' | 'IPv4'; address: string };
|
||||
|
||||
// used for debug logging
|
||||
_debug(message?: any, ...optionalParams: any[]): void;
|
||||
|
||||
// ******
|
||||
// events
|
||||
// ******
|
||||
addListener(
|
||||
event: 'connect' | 'close' | 'end' | 'pause' | 'readable' | 'resume',
|
||||
listener: () => void,
|
||||
): this;
|
||||
addListener(event: 'signal', listener: (data: SignalData) => void): this;
|
||||
addListener(
|
||||
event: 'stream',
|
||||
listener: (stream: MediaStream) => void,
|
||||
): this;
|
||||
addListener(
|
||||
event: 'track',
|
||||
listener: (track: MediaStreamTrack, stream: MediaStream) => void,
|
||||
): this;
|
||||
addListener(event: 'data', listener: (chunk: any) => void): this;
|
||||
addListener(event: 'error', listener: (err: Error) => void): this;
|
||||
addListener(
|
||||
event: string | symbol,
|
||||
listener: (...args: any[]) => void,
|
||||
): this;
|
||||
|
||||
emit(
|
||||
event: 'connect' | 'close' | 'end' | 'pause' | 'readable' | 'resume',
|
||||
): boolean;
|
||||
emit(event: 'signal', data: SignalData): this;
|
||||
emit(event: 'stream', stream: MediaStream): this;
|
||||
emit(event: 'track', track: MediaStreamTrack, stream: MediaStream): this;
|
||||
emit(event: 'data', chunk: any): boolean;
|
||||
emit(event: 'error', err: Error): boolean;
|
||||
emit(event: string | symbol, ...args: any[]): boolean;
|
||||
|
||||
on(
|
||||
event: 'connect' | 'close' | 'end' | 'pause' | 'readable' | 'resume',
|
||||
listener: () => void,
|
||||
): this;
|
||||
on(event: 'signal', listener: (data: SignalData) => void): this;
|
||||
on(event: 'stream', listener: (stream: MediaStream) => void): this;
|
||||
on(
|
||||
event: 'track',
|
||||
listener: (track: MediaStreamTrack, stream: MediaStream) => void,
|
||||
): this;
|
||||
on(event: 'data', listener: (chunk: any) => void): this;
|
||||
on(event: 'error', listener: (err: Error) => void): this;
|
||||
on(event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
|
||||
once(
|
||||
event: 'connect' | 'close' | 'end' | 'pause' | 'readable' | 'resume',
|
||||
listener: () => void,
|
||||
): this;
|
||||
once(event: 'signal', listener: (data: SignalData) => void): this;
|
||||
once(event: 'stream', listener: (stream: MediaStream) => void): this;
|
||||
once(
|
||||
event: 'track',
|
||||
listener: (track: MediaStreamTrack, stream: MediaStream) => void,
|
||||
): this;
|
||||
once(event: 'data', listener: (chunk: any) => void): this;
|
||||
once(event: 'error', listener: (err: Error) => void): this;
|
||||
once(event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
|
||||
prependListener(
|
||||
event: 'connect' | 'close' | 'end' | 'pause' | 'readable' | 'resume',
|
||||
listener: () => void,
|
||||
): this;
|
||||
prependListener(
|
||||
event: 'signal',
|
||||
listener: (data: SignalData) => void,
|
||||
): this;
|
||||
prependListener(
|
||||
event: 'stream',
|
||||
listener: (stream: MediaStream) => void,
|
||||
): this;
|
||||
prependListener(
|
||||
event: 'track',
|
||||
listener: (track: MediaStreamTrack, stream: MediaStream) => void,
|
||||
): this;
|
||||
prependListener(event: 'data', listener: (chunk: any) => void): this;
|
||||
prependListener(event: 'error', listener: (err: Error) => void): this;
|
||||
prependListener(
|
||||
event: string | symbol,
|
||||
listener: (...args: any[]) => void,
|
||||
): this;
|
||||
|
||||
prependOnceListener(
|
||||
event: 'connect' | 'close' | 'end' | 'pause' | 'readable' | 'resume',
|
||||
listener: () => void,
|
||||
): this;
|
||||
prependOnceListener(
|
||||
event: 'signal',
|
||||
listener: (data: SignalData) => void,
|
||||
): this;
|
||||
prependOnceListener(
|
||||
event: 'stream',
|
||||
listener: (stream: MediaStream) => void,
|
||||
): this;
|
||||
prependOnceListener(
|
||||
event: 'track',
|
||||
listener: (track: MediaStreamTrack, stream: MediaStream) => void,
|
||||
): this;
|
||||
prependOnceListener(event: 'data', listener: (chunk: any) => void): this;
|
||||
prependOnceListener(event: 'error', listener: (err: Error) => void): this;
|
||||
prependOnceListener(
|
||||
event: string | symbol,
|
||||
listener: (...args: any[]) => void,
|
||||
): this;
|
||||
|
||||
removeListener(
|
||||
event: 'connect' | 'close' | 'end' | 'pause' | 'readable' | 'resume',
|
||||
listener: () => void,
|
||||
): this;
|
||||
removeListener(
|
||||
event: 'signal',
|
||||
listener: (data: SignalData) => void,
|
||||
): this;
|
||||
removeListener(
|
||||
event: 'stream',
|
||||
listener: (stream: MediaStream) => void,
|
||||
): this;
|
||||
removeListener(
|
||||
event: 'track',
|
||||
listener: (track: MediaStreamTrack, stream: MediaStream) => void,
|
||||
): this;
|
||||
removeListener(event: 'data', listener: (chunk: any) => void): this;
|
||||
removeListener(event: 'error', listener: (err: Error) => void): this;
|
||||
removeListener(
|
||||
event: string | symbol,
|
||||
listener: (...args: any[]) => void,
|
||||
): this;
|
||||
}
|
||||
}
|
||||
export default SimplePeer;
|
||||
}
|
||||
4
packages/rrweb/src/plugins/canvas-webrtc/types.ts
Normal file
4
packages/rrweb/src/plugins/canvas-webrtc/types.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export interface WebRTCDataChannel {
|
||||
nodeId: number;
|
||||
streamId: string;
|
||||
}
|
||||
@@ -40,6 +40,7 @@ function wrapEvent(e: event): eventWithTime {
|
||||
let wrappedEmit!: (e: eventWithTime, isCheckout?: boolean) => void;
|
||||
|
||||
let takeFullSnapshot!: (isCheckout?: boolean) => void;
|
||||
let canvasManager!: CanvasManager;
|
||||
|
||||
const mirror = createMirror();
|
||||
function record<T = eventWithTime>(
|
||||
@@ -133,6 +134,14 @@ function record<T = eventWithTime>(
|
||||
|
||||
let lastFullSnapshotEvent: eventWithTime;
|
||||
let incrementalSnapshotCount = 0;
|
||||
|
||||
/**
|
||||
* Exposes mirror to the plugins
|
||||
*/
|
||||
for (const plugin of plugins || []) {
|
||||
if (plugin.getMirror) plugin.getMirror(mirror);
|
||||
}
|
||||
|
||||
const eventProcessor = (e: eventWithTime): T => {
|
||||
for (const plugin of plugins || []) {
|
||||
if (plugin.eventProcessor) {
|
||||
@@ -223,7 +232,7 @@ function record<T = eventWithTime>(
|
||||
mutationCb: wrappedMutationEmit,
|
||||
});
|
||||
|
||||
const canvasManager = new CanvasManager({
|
||||
canvasManager = new CanvasManager({
|
||||
recordCanvas,
|
||||
mutationCb: wrappedCanvasMutationEmit,
|
||||
win: window,
|
||||
|
||||
@@ -179,6 +179,13 @@ export class Replayer {
|
||||
|
||||
this.setupDom();
|
||||
|
||||
/**
|
||||
* Exposes mirror to the plugins
|
||||
*/
|
||||
for (const plugin of this.config.plugins || []) {
|
||||
if (plugin.getMirror) plugin.getMirror(this.mirror);
|
||||
}
|
||||
|
||||
this.emitter.on(ReplayerEvents.Flush, () => {
|
||||
if (this.usingVirtualDom) {
|
||||
const replayerHandler: ReplayerHandler = {
|
||||
@@ -655,7 +662,7 @@ export class Replayer {
|
||||
}
|
||||
|
||||
for (const plugin of this.config.plugins || []) {
|
||||
plugin.handler(event, isSync, { replayer: this });
|
||||
if (plugin.handler) plugin.handler(event, isSync, { replayer: this });
|
||||
}
|
||||
|
||||
this.service.send({ type: 'CAST_EVENT', payload: { event } });
|
||||
@@ -708,8 +715,15 @@ export class Replayer {
|
||||
const collected: AppendedIframe[] = [];
|
||||
rebuild(event.data.node, {
|
||||
doc: this.iframe.contentDocument,
|
||||
afterAppend: (builtNode) => {
|
||||
afterAppend: (builtNode: Node, id: number) => {
|
||||
this.collectIframeAndAttachDocument(collected, builtNode);
|
||||
for (const plugin of this.config.plugins || []) {
|
||||
if (plugin.onBuild)
|
||||
plugin.onBuild(builtNode, {
|
||||
id,
|
||||
replayer: this,
|
||||
});
|
||||
}
|
||||
},
|
||||
cache: this.cache,
|
||||
mirror: this.mirror,
|
||||
@@ -791,7 +805,7 @@ export class Replayer {
|
||||
mirror: mirror as Mirror,
|
||||
hackCss: true,
|
||||
skipChild: false,
|
||||
afterAppend: (builtNode) => {
|
||||
afterAppend: (builtNode, id: number) => {
|
||||
this.collectIframeAndAttachDocument(collected, builtNode);
|
||||
const sn = (mirror as TMirror).getMeta((builtNode as unknown) as TNode);
|
||||
if (
|
||||
@@ -804,6 +818,14 @@ export class Replayer {
|
||||
head as HTMLElement | RRElement,
|
||||
);
|
||||
}
|
||||
|
||||
for (const plugin of this.config.plugins || []) {
|
||||
if (plugin.onBuild)
|
||||
plugin.onBuild(builtNode, {
|
||||
id,
|
||||
replayer: this,
|
||||
});
|
||||
}
|
||||
},
|
||||
cache: this.cache,
|
||||
});
|
||||
@@ -1508,6 +1530,11 @@ export class Replayer {
|
||||
skipChild: true,
|
||||
hackCss: true,
|
||||
cache: this.cache,
|
||||
afterAppend: (node: Node | RRNode, id: number) => {
|
||||
for (const plugin of this.config.plugins || []) {
|
||||
if (plugin.onBuild) plugin.onBuild(node, { id, replayer: this });
|
||||
}
|
||||
},
|
||||
}) as Node | RRNode;
|
||||
|
||||
// legacy data, we should not have -1 siblings any more
|
||||
|
||||
@@ -228,6 +228,7 @@ export type RecordPlugin<TOptions = unknown> = {
|
||||
options: TOptions,
|
||||
) => listenerHandler;
|
||||
eventProcessor?: <TExtend>(event: eventWithTime) => eventWithTime & TExtend;
|
||||
getMirror?: (mirror: Mirror) => void;
|
||||
options: TOptions;
|
||||
};
|
||||
|
||||
@@ -664,11 +665,16 @@ export type listenerHandler = () => void;
|
||||
export type hookResetter = () => void;
|
||||
|
||||
export type ReplayPlugin = {
|
||||
handler: (
|
||||
handler?: (
|
||||
event: eventWithTime,
|
||||
isSync: boolean,
|
||||
context: { replayer: Replayer },
|
||||
) => void;
|
||||
onBuild?: (
|
||||
node: Node | RRNode,
|
||||
context: { id: number; replayer: Replayer },
|
||||
) => void;
|
||||
getMirror?: (mirror: Mirror) => void;
|
||||
};
|
||||
export type playerConfig = {
|
||||
speed: number;
|
||||
|
||||
@@ -9441,7 +9441,7 @@ exports[`record integration tests should record images inside iframe with blob u
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"img\\",
|
||||
\\"attributes\\": {
|
||||
\\"src\\": \\"blob:http://localhost:3030/...\\",
|
||||
\\"src\\": \\"blob:http://localhost:xxxx/...\\",
|
||||
\\"rr_dataURL\\": \\"data:image/png;base64,...\\"
|
||||
},
|
||||
\\"childNodes\\": [],
|
||||
@@ -9909,7 +9909,7 @@ exports[`record integration tests should record images inside iframe with blob u
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"img\\",
|
||||
\\"attributes\\": {
|
||||
\\"src\\": \\"blob:http://localhost:3030/...\\",
|
||||
\\"src\\": \\"blob:http://localhost:xxxx/...\\",
|
||||
\\"rr_dataURL\\": \\"data:image/png;base64,...\\"
|
||||
},
|
||||
\\"childNodes\\": [],
|
||||
@@ -10151,7 +10151,7 @@ exports[`record integration tests should record images with blob url 1`] = `
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"img\\",
|
||||
\\"attributes\\": {
|
||||
\\"src\\": \\"blob:http://localhost:3030/...\\",
|
||||
\\"src\\": \\"blob:http://localhost:xxxx/...\\",
|
||||
\\"rr_dataURL\\": \\"data:image/png;base64,...\\"
|
||||
},
|
||||
\\"childNodes\\": [],
|
||||
|
||||
@@ -26,7 +26,7 @@ describe('e2e webgl', () => {
|
||||
serverURL = getServerURL(server);
|
||||
browser = await launchPuppeteer();
|
||||
|
||||
const bundlePath = path.resolve(__dirname, '../../dist/rrweb.min.js');
|
||||
const bundlePath = path.resolve(__dirname, '../../dist/rrweb.js');
|
||||
code = fs.readFileSync(bundlePath, 'utf8');
|
||||
});
|
||||
|
||||
|
||||
@@ -52,9 +52,9 @@ describe('record integration tests', function (this: ISuite) {
|
||||
serverURL = getServerURL(server);
|
||||
browser = await launchPuppeteer();
|
||||
|
||||
const bundlePath = path.resolve(__dirname, '../dist/rrweb.min.js');
|
||||
const bundlePath = path.resolve(__dirname, '../dist/rrweb.js');
|
||||
const pluginsCode = [
|
||||
path.resolve(__dirname, '../dist/plugins/console-record.min.js'),
|
||||
path.resolve(__dirname, '../dist/plugins/console-record.js'),
|
||||
]
|
||||
.map((p) => fs.readFileSync(p, 'utf8'))
|
||||
.join();
|
||||
|
||||
@@ -37,7 +37,7 @@ const setup = function (this: ISuite, content: string): ISuite {
|
||||
devtools: true,
|
||||
});
|
||||
|
||||
const bundlePath = path.resolve(__dirname, '../dist/rrweb.min.js');
|
||||
const bundlePath = path.resolve(__dirname, '../dist/rrweb.js');
|
||||
ctx.code = fs.readFileSync(bundlePath, 'utf8');
|
||||
});
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ const setup = function (
|
||||
beforeAll(async () => {
|
||||
ctx.browser = await launchPuppeteer();
|
||||
|
||||
const bundlePath = path.resolve(__dirname, '../../dist/rrweb.min.js');
|
||||
const bundlePath = path.resolve(__dirname, '../../dist/rrweb.js');
|
||||
ctx.code = fs.readFileSync(bundlePath, 'utf8');
|
||||
});
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ describe('replayer', function () {
|
||||
beforeAll(async () => {
|
||||
browser = await launchPuppeteer();
|
||||
|
||||
const bundlePath = path.resolve(__dirname, '../../dist/rrweb.min.js');
|
||||
const bundlePath = path.resolve(__dirname, '../../dist/rrweb.js');
|
||||
code = fs.readFileSync(bundlePath, 'utf8');
|
||||
});
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ describe('replayer', function () {
|
||||
beforeAll(async () => {
|
||||
browser = await launchPuppeteer();
|
||||
|
||||
const bundlePath = path.resolve(__dirname, '../dist/rrweb.min.js');
|
||||
const bundlePath = path.resolve(__dirname, '../dist/rrweb.js');
|
||||
code = fs.readFileSync(bundlePath, 'utf8');
|
||||
});
|
||||
|
||||
|
||||
@@ -151,6 +151,9 @@ function stringifySnapshots(snapshots: eventWithTime[]): string {
|
||||
coordinatesReg.lastIndex = 0; // wow, a real wart in ECMAScript
|
||||
}
|
||||
}
|
||||
|
||||
// strip blob:urls as they are different every time
|
||||
stripBlobURLsFromAttributes(a);
|
||||
});
|
||||
s.data.adds.forEach((add) => {
|
||||
if (add.node.type === NodeType.Element) {
|
||||
@@ -167,17 +170,7 @@ function stringifySnapshots(snapshots: eventWithTime[]): string {
|
||||
coordinatesReg.lastIndex = 0; // wow, a real wart in ECMAScript
|
||||
|
||||
// strip blob:urls as they are different every time
|
||||
if (
|
||||
'src' in add.node.attributes &&
|
||||
add.node.attributes.src &&
|
||||
typeof add.node.attributes.src === 'string' &&
|
||||
add.node.attributes.src.startsWith('blob:')
|
||||
) {
|
||||
add.node.attributes.src = add.node.attributes.src.replace(
|
||||
/[\w-]+$/,
|
||||
'...',
|
||||
);
|
||||
}
|
||||
stripBlobURLsFromAttributes(add.node);
|
||||
|
||||
// strip rr_dataURL as they are not consistent
|
||||
if (
|
||||
@@ -201,6 +194,23 @@ function stringifySnapshots(snapshots: eventWithTime[]): string {
|
||||
);
|
||||
}
|
||||
|
||||
function stripBlobURLsFromAttributes(node: {
|
||||
attributes: {
|
||||
src?: string;
|
||||
};
|
||||
}) {
|
||||
if (
|
||||
'src' in node.attributes &&
|
||||
node.attributes.src &&
|
||||
typeof node.attributes.src === 'string' &&
|
||||
node.attributes.src.startsWith('blob:')
|
||||
) {
|
||||
node.attributes.src = node.attributes.src
|
||||
.replace(/[\w-]+$/, '...')
|
||||
.replace(/:[0-9]+\//, ':xxxx/');
|
||||
}
|
||||
}
|
||||
|
||||
function stringifyDomSnapshot(mhtml: string): string {
|
||||
const { Parser } = require('fast-mhtml');
|
||||
const resources: string[] = [];
|
||||
|
||||
@@ -12,12 +12,20 @@
|
||||
"lib": ["es6", "dom"],
|
||||
"downlevelIteration": true,
|
||||
"importsNotUsedAsValues": "error",
|
||||
"strictBindCallApply": true
|
||||
"strictBindCallApply": true,
|
||||
"composite": true
|
||||
},
|
||||
"exclude": ["test"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../rrdom"
|
||||
},
|
||||
{
|
||||
"path": "../rrweb-snapshot"
|
||||
}
|
||||
],
|
||||
"exclude": ["test", "scripts"],
|
||||
"include": [
|
||||
"src",
|
||||
"scripts",
|
||||
"node_modules/@types/css-font-loading-module/index.d.ts",
|
||||
"node_modules/@types/jest-image-snapshot/index.d.ts"
|
||||
]
|
||||
|
||||
@@ -1 +1,25 @@
|
||||
{}
|
||||
{
|
||||
"references": [
|
||||
{
|
||||
"path": "packages/rrdom"
|
||||
},
|
||||
{
|
||||
"path": "packages/rrdom-nodejs"
|
||||
},
|
||||
{
|
||||
"path": "packages/rrweb"
|
||||
},
|
||||
{
|
||||
"path": "packages/rrweb-player"
|
||||
},
|
||||
{
|
||||
"path": "packages/rrweb-snapshot"
|
||||
}
|
||||
],
|
||||
"files": [],
|
||||
"include": [],
|
||||
"exclude": [],
|
||||
"compilerOptions": {
|
||||
"rootDir": "."
|
||||
}
|
||||
}
|
||||
|
||||
525
yarn.lock
525
yarn.lock
@@ -490,17 +490,12 @@
|
||||
resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz"
|
||||
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
|
||||
|
||||
"@cspotcode/source-map-consumer@0.8.0":
|
||||
version "0.8.0"
|
||||
resolved "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz"
|
||||
integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==
|
||||
|
||||
"@cspotcode/source-map-support@0.7.0":
|
||||
version "0.7.0"
|
||||
resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz"
|
||||
integrity sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==
|
||||
"@cspotcode/source-map-support@^0.8.0":
|
||||
version "0.8.1"
|
||||
resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1"
|
||||
integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==
|
||||
dependencies:
|
||||
"@cspotcode/source-map-consumer" "0.8.0"
|
||||
"@jridgewell/trace-mapping" "0.3.9"
|
||||
|
||||
"@eslint/eslintrc@^1.2.3":
|
||||
version "1.2.3"
|
||||
@@ -936,6 +931,14 @@
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
|
||||
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
|
||||
|
||||
"@jridgewell/trace-mapping@0.3.9":
|
||||
version "0.3.9"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9"
|
||||
integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==
|
||||
dependencies:
|
||||
"@jridgewell/resolve-uri" "^3.0.3"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||
|
||||
"@jridgewell/trace-mapping@^0.3.9":
|
||||
version "0.3.14"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed"
|
||||
@@ -1630,6 +1633,26 @@
|
||||
resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.14.1.tgz#155ef21065427901994e765da8a0ba0eaae8b8bd"
|
||||
integrity sha512-6Wci+Tp3CgPt/B9B0a3J4s3yMgLNSku6w5TV6mN+61C71UqsRBv2FUibBf3tPGlNxebgPHMEUzKpb1ggE8KCKw==
|
||||
|
||||
"@monorepo-utils/package-utils@^2.8.1":
|
||||
version "2.8.1"
|
||||
resolved "https://registry.yarnpkg.com/@monorepo-utils/package-utils/-/package-utils-2.8.1.tgz#e345bfd2e132b4eef260db4b6e13d09f875dadc0"
|
||||
integrity sha512-D6YCDuSFOoBvJw4NvUyR1EDU7MuywV43m/kOJ+sjIVUCYmH9mxMD+JDaITHGnQ7wYR51JK/Vyp7xkI+eff+xyw==
|
||||
dependencies:
|
||||
globby "^11.0.1"
|
||||
load-json-file "^6.2.0"
|
||||
upath "^2.0.1"
|
||||
|
||||
"@monorepo-utils/workspaces-to-typescript-project-references@^2.8.2":
|
||||
version "2.8.2"
|
||||
resolved "https://registry.yarnpkg.com/@monorepo-utils/workspaces-to-typescript-project-references/-/workspaces-to-typescript-project-references-2.8.2.tgz#6768b3967822177156e62757d52cfd7fe83688c8"
|
||||
integrity sha512-ZhJX2VtTmFv/CnabQ7KhnPamV1bjGEx5I3gHm7+Flv3fOfvjFkLkWVDZWk1CvAQyQKgiaoIKAPc0SrWeneKBcw==
|
||||
dependencies:
|
||||
"@monorepo-utils/package-utils" "^2.8.1"
|
||||
comment-json "^3.0.3"
|
||||
meow "^7.1.1"
|
||||
semver-match "0.1.1"
|
||||
upath "^2.0.1"
|
||||
|
||||
"@nodelib/fs.scandir@2.1.5":
|
||||
version "2.1.5"
|
||||
resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz"
|
||||
@@ -2000,6 +2023,18 @@
|
||||
resolved "https://registry.npmjs.org/@types/cssstyle/-/cssstyle-2.2.1.tgz#fa010824006ff47af94a6b9baf9759e031815347"
|
||||
integrity sha512-CSQFKdZc3dmWoZXLAM0pPL6XiYLG8hMGzImM2MwQ9kavB5LnbeMGan94CCj4oxY65xMl5mRMwrFUfKPOWO4WpQ==
|
||||
|
||||
"@types/dom-mediacapture-transform@^0.1.3":
|
||||
version "0.1.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/dom-mediacapture-transform/-/dom-mediacapture-transform-0.1.3.tgz#ef0b5c7a3aeb0af7e35fe7f57b5700c9a479bfef"
|
||||
integrity sha512-Zi2IOA+NFqPmqFojaOskEzUOABMHEouZg8vtwMt0MbppgTu1pOVg2zWQVvfjnCIgOj//CleXHhryvRKaykSVJw==
|
||||
dependencies:
|
||||
"@types/dom-webcodecs" "*"
|
||||
|
||||
"@types/dom-webcodecs@*":
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/dom-webcodecs/-/dom-webcodecs-0.1.4.tgz#90a3dd80e5baf72baa79a74cf410e63863992516"
|
||||
integrity sha512-dc+xSUnCaCdi/hExZArnLhiavS3E1Rdpp2+zCI6TcmJvz4qgDPBbpvCM7DsQhwRXIIpVMHO6c3s+t+JyCSqYBA==
|
||||
|
||||
"@types/estree@*":
|
||||
version "0.0.50"
|
||||
resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz"
|
||||
@@ -2017,13 +2052,13 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/inquirer@0.0.43":
|
||||
version "0.0.43"
|
||||
resolved "https://registry.npmjs.org/@types/inquirer/-/inquirer-0.0.43.tgz"
|
||||
integrity sha512-xgyfKZVMFqE8aIKy1xfFVsX2MxyXUNgjgmbF6dRbR3sL+ZM5K4ka/9L4mmTwX8eTeVYtduyXu0gUVwVJa1HbNw==
|
||||
"@types/inquirer@^8.2.1":
|
||||
version "8.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-8.2.1.tgz#28a139be3105a1175e205537e8ac10830e38dbf4"
|
||||
integrity sha512-wKW3SKIUMmltbykg4I5JzCVzUhkuD9trD6efAmYgN2MrSntY0SMRQzEnD3mkyJ/rv9NLbTC7g3hKKE86YwEDLw==
|
||||
dependencies:
|
||||
"@types/rx" "*"
|
||||
"@types/through" "*"
|
||||
rxjs "^7.2.0"
|
||||
|
||||
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
|
||||
version "2.0.3"
|
||||
@@ -2176,107 +2211,6 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/rx-core-binding@*":
|
||||
version "4.0.4"
|
||||
resolved "https://registry.npmjs.org/@types/rx-core-binding/-/rx-core-binding-4.0.4.tgz"
|
||||
integrity sha512-5pkfxnC4w810LqBPUwP5bg7SFR/USwhMSaAeZQQbEHeBp57pjKXRlXmqpMrLJB4y1oglR/c2502853uN0I+DAQ==
|
||||
dependencies:
|
||||
"@types/rx-core" "*"
|
||||
|
||||
"@types/rx-core@*":
|
||||
version "4.0.3"
|
||||
resolved "https://registry.npmjs.org/@types/rx-core/-/rx-core-4.0.3.tgz"
|
||||
integrity sha1-CzNUsSOM7b4rdPYybxOdvHpZHWA=
|
||||
|
||||
"@types/rx-lite-aggregates@*":
|
||||
version "4.0.3"
|
||||
resolved "https://registry.npmjs.org/@types/rx-lite-aggregates/-/rx-lite-aggregates-4.0.3.tgz"
|
||||
integrity sha512-MAGDAHy8cRatm94FDduhJF+iNS5//jrZ/PIfm+QYw9OCeDgbymFHChM8YVIvN2zArwsRftKgE33QfRWvQk4DPg==
|
||||
dependencies:
|
||||
"@types/rx-lite" "*"
|
||||
|
||||
"@types/rx-lite-async@*":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.npmjs.org/@types/rx-lite-async/-/rx-lite-async-4.0.2.tgz"
|
||||
integrity sha512-vTEv5o8l6702ZwfAM5aOeVDfUwBSDOs+ARoGmWAKQ6LOInQ8J4/zjM7ov12fuTpktUKdMQjkeCp07Vd73mPkxw==
|
||||
dependencies:
|
||||
"@types/rx-lite" "*"
|
||||
|
||||
"@types/rx-lite-backpressure@*":
|
||||
version "4.0.3"
|
||||
resolved "https://registry.npmjs.org/@types/rx-lite-backpressure/-/rx-lite-backpressure-4.0.3.tgz"
|
||||
integrity sha512-Y6aIeQCtNban5XSAF4B8dffhIKu6aAy/TXFlScHzSxh6ivfQBQw6UjxyEJxIOt3IT49YkS+siuayM2H/Q0cmgA==
|
||||
dependencies:
|
||||
"@types/rx-lite" "*"
|
||||
|
||||
"@types/rx-lite-coincidence@*":
|
||||
version "4.0.3"
|
||||
resolved "https://registry.npmjs.org/@types/rx-lite-coincidence/-/rx-lite-coincidence-4.0.3.tgz"
|
||||
integrity sha512-1VNJqzE9gALUyMGypDXZZXzR0Tt7LC9DdAZQ3Ou/Q0MubNU35agVUNXKGHKpNTba+fr8GdIdkC26bRDqtCQBeQ==
|
||||
dependencies:
|
||||
"@types/rx-lite" "*"
|
||||
|
||||
"@types/rx-lite-experimental@*":
|
||||
version "4.0.1"
|
||||
resolved "https://registry.npmjs.org/@types/rx-lite-experimental/-/rx-lite-experimental-4.0.1.tgz"
|
||||
integrity sha1-xTL1y98/LBXaFt7Ykw0bKYQCPL0=
|
||||
dependencies:
|
||||
"@types/rx-lite" "*"
|
||||
|
||||
"@types/rx-lite-joinpatterns@*":
|
||||
version "4.0.1"
|
||||
resolved "https://registry.npmjs.org/@types/rx-lite-joinpatterns/-/rx-lite-joinpatterns-4.0.1.tgz"
|
||||
integrity sha1-9w/jcFGKhDLykVjMkv+1a05K/D4=
|
||||
dependencies:
|
||||
"@types/rx-lite" "*"
|
||||
|
||||
"@types/rx-lite-testing@*":
|
||||
version "4.0.1"
|
||||
resolved "https://registry.npmjs.org/@types/rx-lite-testing/-/rx-lite-testing-4.0.1.tgz"
|
||||
integrity sha1-IbGdEfTf1v/vWp0WSOnIh5v+Iek=
|
||||
dependencies:
|
||||
"@types/rx-lite-virtualtime" "*"
|
||||
|
||||
"@types/rx-lite-time@*":
|
||||
version "4.0.3"
|
||||
resolved "https://registry.npmjs.org/@types/rx-lite-time/-/rx-lite-time-4.0.3.tgz"
|
||||
integrity sha512-ukO5sPKDRwCGWRZRqPlaAU0SKVxmWwSjiOrLhoQDoWxZWg6vyB9XLEZViKOzIO6LnTIQBlk4UylYV0rnhJLxQw==
|
||||
dependencies:
|
||||
"@types/rx-lite" "*"
|
||||
|
||||
"@types/rx-lite-virtualtime@*":
|
||||
version "4.0.3"
|
||||
resolved "https://registry.npmjs.org/@types/rx-lite-virtualtime/-/rx-lite-virtualtime-4.0.3.tgz"
|
||||
integrity sha512-3uC6sGmjpOKatZSVHI2xB1+dedgml669ZRvqxy+WqmGJDVusOdyxcKfyzjW0P3/GrCiN4nmRkLVMhPwHCc5QLg==
|
||||
dependencies:
|
||||
"@types/rx-lite" "*"
|
||||
|
||||
"@types/rx-lite@*":
|
||||
version "4.0.6"
|
||||
resolved "https://registry.npmjs.org/@types/rx-lite/-/rx-lite-4.0.6.tgz"
|
||||
integrity sha512-oYiDrFIcor9zDm0VDUca1UbROiMYBxMLMaM6qzz4ADAfOmA9r1dYEcAFH+2fsPI5BCCjPvV9pWC3X3flbrvs7w==
|
||||
dependencies:
|
||||
"@types/rx-core" "*"
|
||||
"@types/rx-core-binding" "*"
|
||||
|
||||
"@types/rx@*":
|
||||
version "4.1.2"
|
||||
resolved "https://registry.npmjs.org/@types/rx/-/rx-4.1.2.tgz"
|
||||
integrity sha512-1r8ZaT26Nigq7o4UBGl+aXB2UMFUIdLPP/8bLIP0x3d0pZL46ybKKjhWKaJQWIkLl5QCLD0nK3qTOO1QkwdFaA==
|
||||
dependencies:
|
||||
"@types/rx-core" "*"
|
||||
"@types/rx-core-binding" "*"
|
||||
"@types/rx-lite" "*"
|
||||
"@types/rx-lite-aggregates" "*"
|
||||
"@types/rx-lite-async" "*"
|
||||
"@types/rx-lite-backpressure" "*"
|
||||
"@types/rx-lite-coincidence" "*"
|
||||
"@types/rx-lite-experimental" "*"
|
||||
"@types/rx-lite-joinpatterns" "*"
|
||||
"@types/rx-lite-testing" "*"
|
||||
"@types/rx-lite-time" "*"
|
||||
"@types/rx-lite-virtualtime" "*"
|
||||
|
||||
"@types/sass@^1.16.0":
|
||||
version "1.16.1"
|
||||
resolved "https://registry.npmjs.org/@types/sass/-/sass-1.16.1.tgz"
|
||||
@@ -2291,7 +2225,7 @@
|
||||
|
||||
"@types/through@*":
|
||||
version "0.0.30"
|
||||
resolved "https://registry.npmjs.org/@types/through/-/through-0.0.30.tgz"
|
||||
resolved "https://registry.yarnpkg.com/@types/through/-/through-0.0.30.tgz#e0e42ce77e897bd6aead6f6ea62aeb135b8a3895"
|
||||
integrity sha512-FvnCJljyxhPM3gkRgWmxmDZyAQSiBQQWLI0A0VFL0K7W1oRUrPJSqNO0NvTnLkBcotdlp3lKvaT0JrnyRDkzOg==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
@@ -2650,11 +2584,6 @@ alphanum-sort@^1.0.0:
|
||||
resolved "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz"
|
||||
integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=
|
||||
|
||||
ansi-escapes@^3.2.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz"
|
||||
integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==
|
||||
|
||||
ansi-escapes@^4.2.1:
|
||||
version "4.3.2"
|
||||
resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz"
|
||||
@@ -2662,6 +2591,13 @@ ansi-escapes@^4.2.1:
|
||||
dependencies:
|
||||
type-fest "^0.21.3"
|
||||
|
||||
ansi-escapes@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-5.0.0.tgz#b6a0caf0eef0c41af190e9a749e0c00ec04bb2a6"
|
||||
integrity sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==
|
||||
dependencies:
|
||||
type-fest "^1.0.2"
|
||||
|
||||
ansi-regex@^2.0.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz"
|
||||
@@ -2672,16 +2608,16 @@ ansi-regex@^3.0.0:
|
||||
resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz"
|
||||
integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
|
||||
|
||||
ansi-regex@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz"
|
||||
integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
|
||||
|
||||
ansi-regex@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz"
|
||||
integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
|
||||
|
||||
ansi-regex@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a"
|
||||
integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==
|
||||
|
||||
ansi-styles@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz"
|
||||
@@ -2706,6 +2642,11 @@ ansi-styles@^5.0.0:
|
||||
resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz"
|
||||
integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==
|
||||
|
||||
ansi-styles@^6.1.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.1.0.tgz#87313c102b8118abd57371afab34618bf7350ed3"
|
||||
integrity sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ==
|
||||
|
||||
anymatch@^3.0.3, anymatch@~3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz"
|
||||
@@ -3018,6 +2959,15 @@ bl@^4.0.3:
|
||||
inherits "^2.0.4"
|
||||
readable-stream "^3.4.0"
|
||||
|
||||
bl@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/bl/-/bl-5.0.0.tgz#6928804a41e9da9034868e1c50ca88f21f57aea2"
|
||||
integrity sha512-8vxFNZ0pflFfi0WXA3WQXlj6CaMEwsmh63I1CNp0q+wWv8sD0ARx1KovSQd0l2GkwrMIOyedq0EF1FxI+RCZLQ==
|
||||
dependencies:
|
||||
buffer "^6.0.3"
|
||||
inherits "^2.0.4"
|
||||
readable-stream "^3.4.0"
|
||||
|
||||
bluebird@^3.5.2:
|
||||
version "3.7.2"
|
||||
resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz"
|
||||
@@ -3150,6 +3100,14 @@ buffer@^5.2.1, buffer@^5.5.0:
|
||||
base64-js "^1.3.1"
|
||||
ieee754 "^1.1.13"
|
||||
|
||||
buffer@^6.0.3:
|
||||
version "6.0.3"
|
||||
resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6"
|
||||
integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==
|
||||
dependencies:
|
||||
base64-js "^1.3.1"
|
||||
ieee754 "^1.2.1"
|
||||
|
||||
builtin-modules@^3.1.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz"
|
||||
@@ -3290,7 +3248,7 @@ chalk@^1.1.3:
|
||||
strip-ansi "^3.0.0"
|
||||
supports-color "^2.0.0"
|
||||
|
||||
chalk@^2.0.0, chalk@^2.0.1, chalk@^2.4.1, chalk@^2.4.2:
|
||||
chalk@^2.0.0, chalk@^2.0.1, chalk@^2.4.1:
|
||||
version "2.4.2"
|
||||
resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz"
|
||||
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
|
||||
@@ -3315,6 +3273,11 @@ chalk@^4.1.0:
|
||||
ansi-styles "^4.1.0"
|
||||
supports-color "^7.1.0"
|
||||
|
||||
chalk@^5.0.0, chalk@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.0.1.tgz#ca57d71e82bb534a296df63bbacc4a1c22b2a4b6"
|
||||
integrity sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==
|
||||
|
||||
char-regex@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz"
|
||||
@@ -3399,13 +3362,6 @@ clean-stack@^2.0.0:
|
||||
resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz"
|
||||
integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
|
||||
|
||||
cli-cursor@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz"
|
||||
integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=
|
||||
dependencies:
|
||||
restore-cursor "^2.0.0"
|
||||
|
||||
cli-cursor@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz"
|
||||
@@ -3413,16 +3369,28 @@ cli-cursor@^3.1.0:
|
||||
dependencies:
|
||||
restore-cursor "^3.1.0"
|
||||
|
||||
cli-width@^2.0.0:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz"
|
||||
integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==
|
||||
cli-cursor@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-4.0.0.tgz#3cecfe3734bf4fe02a8361cbdc0f6fe28c6a57ea"
|
||||
integrity sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==
|
||||
dependencies:
|
||||
restore-cursor "^4.0.0"
|
||||
|
||||
cli-spinners@^2.6.1:
|
||||
version "2.7.0"
|
||||
resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.7.0.tgz#f815fd30b5f9eaac02db604c7a231ed7cb2f797a"
|
||||
integrity sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==
|
||||
|
||||
cli-width@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz"
|
||||
integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==
|
||||
|
||||
cli-width@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-4.0.0.tgz#a5622f6a3b0a9e3e711a25f099bf2399f608caf6"
|
||||
integrity sha512-ZksGS2xpa/bYkNzN3BAw1wEjsLV/ZKOf/CCrJ/QOBsxx6fOARIkwTutxp1XIOIohi6HKmOFjMoK/XaqDVUpEEw==
|
||||
|
||||
cliui@^7.0.2:
|
||||
version "7.0.4"
|
||||
resolved "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz"
|
||||
@@ -3547,6 +3515,16 @@ commander@~9.0.0:
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-9.0.0.tgz#86d58f24ee98126568936bd1d3574e0308a99a40"
|
||||
integrity sha512-JJfP2saEKbQqvW+FI93OYUB4ByV5cizMpFMiiJI8xDbBvQvSkIk0VvQdn1CZ8mqAO8Loq2h0gYTYtDFUZUeERw==
|
||||
|
||||
comment-json@^3.0.3:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/comment-json/-/comment-json-3.0.3.tgz#0cadacd6278602b57b8c51b1814dc5d311d228c4"
|
||||
integrity sha512-P7XwYkC3qjIK45EAa9c5Y3lR7SMXhJqwFdWg3niAIAcbk3zlpKDdajV8Hyz/Y3sGNn3l+YNMl8A2N/OubSArHg==
|
||||
dependencies:
|
||||
core-util-is "^1.0.2"
|
||||
esprima "^4.0.1"
|
||||
has-own-prop "^2.0.0"
|
||||
repeat-string "^1.6.1"
|
||||
|
||||
commondir@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz"
|
||||
@@ -3751,6 +3729,11 @@ core-util-is@1.0.2, core-util-is@~1.0.0:
|
||||
resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz"
|
||||
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
|
||||
|
||||
core-util-is@^1.0.2:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
|
||||
integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
|
||||
|
||||
cosmiconfig@^5.0.0:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz"
|
||||
@@ -4275,6 +4258,11 @@ duplexer@^0.1.1:
|
||||
resolved "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz"
|
||||
integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==
|
||||
|
||||
eastasianwidth@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb"
|
||||
integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==
|
||||
|
||||
ecc-jsbn@~0.1.1:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz"
|
||||
@@ -4313,6 +4301,11 @@ emoji-regex@^8.0.0:
|
||||
resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz"
|
||||
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
|
||||
|
||||
emoji-regex@^9.2.2:
|
||||
version "9.2.2"
|
||||
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72"
|
||||
integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
|
||||
|
||||
emojis-list@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz"
|
||||
@@ -4599,6 +4592,11 @@ escape-string-regexp@^4.0.0:
|
||||
resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz"
|
||||
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
|
||||
|
||||
escape-string-regexp@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8"
|
||||
integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==
|
||||
|
||||
escodegen@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz"
|
||||
@@ -5042,13 +5040,6 @@ fflate@^0.4.4:
|
||||
resolved "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz"
|
||||
integrity sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==
|
||||
|
||||
figures@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz"
|
||||
integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=
|
||||
dependencies:
|
||||
escape-string-regexp "^1.0.5"
|
||||
|
||||
figures@^3.0.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz"
|
||||
@@ -5056,6 +5047,14 @@ figures@^3.0.0:
|
||||
dependencies:
|
||||
escape-string-regexp "^1.0.5"
|
||||
|
||||
figures@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/figures/-/figures-4.0.1.tgz#27b26609907bc888b3e3b0ef5403643f80aa2518"
|
||||
integrity sha512-rElJwkA/xS04Vfg+CaZodpso7VqBknOYbzi6I76hI4X80RUjkSxO2oAyPmGbuXUppywjqndOrQDl817hDnI++w==
|
||||
dependencies:
|
||||
escape-string-regexp "^5.0.0"
|
||||
is-unicode-supported "^1.2.0"
|
||||
|
||||
file-entry-cache@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz"
|
||||
@@ -5498,6 +5497,18 @@ globals@^13.15.0, globals@^13.6.0, globals@^13.9.0:
|
||||
dependencies:
|
||||
type-fest "^0.20.2"
|
||||
|
||||
globby@^11.0.1, globby@^11.1.0:
|
||||
version "11.1.0"
|
||||
resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b"
|
||||
integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
|
||||
dependencies:
|
||||
array-union "^2.1.0"
|
||||
dir-glob "^3.0.1"
|
||||
fast-glob "^3.2.9"
|
||||
ignore "^5.2.0"
|
||||
merge2 "^1.4.1"
|
||||
slash "^3.0.0"
|
||||
|
||||
globby@^11.0.2, globby@^11.0.4:
|
||||
version "11.0.4"
|
||||
resolved "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz"
|
||||
@@ -5510,18 +5521,6 @@ globby@^11.0.2, globby@^11.0.4:
|
||||
merge2 "^1.3.0"
|
||||
slash "^3.0.0"
|
||||
|
||||
globby@^11.1.0:
|
||||
version "11.1.0"
|
||||
resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b"
|
||||
integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
|
||||
dependencies:
|
||||
array-union "^2.1.0"
|
||||
dir-glob "^3.0.1"
|
||||
fast-glob "^3.2.9"
|
||||
ignore "^5.2.0"
|
||||
merge2 "^1.4.1"
|
||||
slash "^3.0.0"
|
||||
|
||||
globby@^6.1.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz"
|
||||
@@ -5615,6 +5614,11 @@ has-flag@^4.0.0:
|
||||
resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz"
|
||||
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
|
||||
|
||||
has-own-prop@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/has-own-prop/-/has-own-prop-2.0.0.tgz#f0f95d58f65804f5d218db32563bb85b8e0417af"
|
||||
integrity sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==
|
||||
|
||||
has-symbols@^1.0.1, has-symbols@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz"
|
||||
@@ -5792,7 +5796,7 @@ identity-obj-proxy@^3.0.0:
|
||||
dependencies:
|
||||
harmony-reflect "^1.4.6"
|
||||
|
||||
ieee754@^1.1.13:
|
||||
ieee754@^1.1.13, ieee754@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz"
|
||||
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
|
||||
@@ -5933,25 +5937,6 @@ init-package-json@^2.0.2:
|
||||
validate-npm-package-license "^3.0.4"
|
||||
validate-npm-package-name "^3.0.0"
|
||||
|
||||
inquirer@^6.2.1:
|
||||
version "6.5.2"
|
||||
resolved "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz"
|
||||
integrity sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==
|
||||
dependencies:
|
||||
ansi-escapes "^3.2.0"
|
||||
chalk "^2.4.2"
|
||||
cli-cursor "^2.1.0"
|
||||
cli-width "^2.0.0"
|
||||
external-editor "^3.0.3"
|
||||
figures "^2.0.0"
|
||||
lodash "^4.17.12"
|
||||
mute-stream "0.0.7"
|
||||
run-async "^2.2.0"
|
||||
rxjs "^6.4.0"
|
||||
string-width "^2.1.0"
|
||||
strip-ansi "^5.1.0"
|
||||
through "^2.3.6"
|
||||
|
||||
inquirer@^7.3.3:
|
||||
version "7.3.3"
|
||||
resolved "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz"
|
||||
@@ -5971,6 +5956,27 @@ inquirer@^7.3.3:
|
||||
strip-ansi "^6.0.0"
|
||||
through "^2.3.6"
|
||||
|
||||
inquirer@^9.0.0:
|
||||
version "9.0.2"
|
||||
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-9.0.2.tgz#81d830044718528485d7b9f7d47c6d590ccd1a7f"
|
||||
integrity sha512-AqmDHmz3bIe573OiM4svTZzajBzff1xpuzYAimW8gjzW5ncuPllWB8t/GKl+NSuKRJaKyIF2bU2RCx8H1dwqyQ==
|
||||
dependencies:
|
||||
ansi-escapes "^5.0.0"
|
||||
chalk "^5.0.1"
|
||||
cli-cursor "^4.0.0"
|
||||
cli-width "^4.0.0"
|
||||
external-editor "^3.0.3"
|
||||
figures "^4.0.1"
|
||||
lodash "^4.17.21"
|
||||
mute-stream "0.0.8"
|
||||
ora "^6.1.2"
|
||||
run-async "^2.4.0"
|
||||
rxjs "^7.5.6"
|
||||
string-width "^5.1.2"
|
||||
strip-ansi "^7.0.1"
|
||||
through "^2.3.6"
|
||||
wrap-ansi "^8.0.1"
|
||||
|
||||
internal-slot@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz"
|
||||
@@ -6152,6 +6158,11 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
|
||||
dependencies:
|
||||
is-extglob "^2.1.1"
|
||||
|
||||
is-interactive@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-2.0.0.tgz#40c57614593826da1100ade6059778d597f16e90"
|
||||
integrity sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==
|
||||
|
||||
is-lambda@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz"
|
||||
@@ -6307,6 +6318,11 @@ is-typedarray@^1.0.0, is-typedarray@~1.0.0:
|
||||
resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz"
|
||||
integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
|
||||
|
||||
is-unicode-supported@^1.1.0, is-unicode-supported@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-1.2.0.tgz#f4f54f34d8ebc84a46b93559a036763b6d3e1014"
|
||||
integrity sha512-wH+U77omcRzevfIG8dDhTS0V9zZyweakfD01FULl97+0EHiJTTZtJqxPSkIIo/SDPv/i07k/C9jAPY+jwLLeUQ==
|
||||
|
||||
is-weakref@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz"
|
||||
@@ -7691,11 +7707,19 @@ lodash.uniq@^4.5.0:
|
||||
resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz"
|
||||
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
|
||||
|
||||
lodash@4.x, lodash@^4.17.12, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.17.4, lodash@^4.7.0:
|
||||
lodash@4.x, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.17.4, lodash@^4.7.0:
|
||||
version "4.17.21"
|
||||
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
|
||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||
|
||||
log-symbols@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-5.1.0.tgz#a20e3b9a5f53fac6aeb8e2bb22c07cf2c8f16d93"
|
||||
integrity sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==
|
||||
dependencies:
|
||||
chalk "^5.0.0"
|
||||
is-unicode-supported "^1.1.0"
|
||||
|
||||
lru-cache@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz"
|
||||
@@ -7854,7 +7878,7 @@ media-typer@0.3.0:
|
||||
resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz"
|
||||
integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
|
||||
|
||||
meow@^7.0.0:
|
||||
meow@^7.0.0, meow@^7.1.1:
|
||||
version "7.1.1"
|
||||
resolved "https://registry.npmjs.org/meow/-/meow-7.1.1.tgz"
|
||||
integrity sha512-GWHvA5QOcS412WCo8vwKDlTelGLsCGBVevQB5Kva961rmNfun0PCbv5+xta2kUMFJyR8/oWnn7ddeKdosbAPbA==
|
||||
@@ -7969,11 +7993,6 @@ mime@^2.0.3, mime@^2.3.1:
|
||||
resolved "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz"
|
||||
integrity sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==
|
||||
|
||||
mimic-fn@^1.0.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz"
|
||||
integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==
|
||||
|
||||
mimic-fn@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz"
|
||||
@@ -8161,11 +8180,6 @@ multimatch@^5.0.0:
|
||||
arrify "^2.0.1"
|
||||
minimatch "^3.0.4"
|
||||
|
||||
mute-stream@0.0.7:
|
||||
version "0.0.7"
|
||||
resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz"
|
||||
integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=
|
||||
|
||||
mute-stream@0.0.8, mute-stream@~0.0.4:
|
||||
version "0.0.8"
|
||||
resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz"
|
||||
@@ -8526,13 +8540,6 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0:
|
||||
dependencies:
|
||||
wrappy "1"
|
||||
|
||||
onetime@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz"
|
||||
integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=
|
||||
dependencies:
|
||||
mimic-fn "^1.0.0"
|
||||
|
||||
onetime@^5.1.0, onetime@^5.1.2:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz"
|
||||
@@ -8569,6 +8576,21 @@ optionator@^0.9.1:
|
||||
resolved "https://registry.npmjs.org/opts/-/opts-2.0.2.tgz"
|
||||
integrity sha512-k41FwbcLnlgnFh69f4qdUfvDQ+5vaSDnVPFI/y5XuhKRq97EnVVneO9F1ESVCdiVu4fCS2L8usX3mU331hB7pg==
|
||||
|
||||
ora@^6.1.2:
|
||||
version "6.1.2"
|
||||
resolved "https://registry.yarnpkg.com/ora/-/ora-6.1.2.tgz#7b3c1356b42fd90fb1dad043d5dbe649388a0bf5"
|
||||
integrity sha512-EJQ3NiP5Xo94wJXIzAyOtSb0QEIAUu7m8t6UZ9krbz0vAJqr92JpcK/lEXg91q6B9pEGqrykkd2EQplnifDSBw==
|
||||
dependencies:
|
||||
bl "^5.0.0"
|
||||
chalk "^5.0.0"
|
||||
cli-cursor "^4.0.0"
|
||||
cli-spinners "^2.6.1"
|
||||
is-interactive "^2.0.0"
|
||||
is-unicode-supported "^1.1.0"
|
||||
log-symbols "^5.1.0"
|
||||
strip-ansi "^7.0.1"
|
||||
wcwidth "^1.0.1"
|
||||
|
||||
os-homedir@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz"
|
||||
@@ -9746,7 +9768,7 @@ repeat-element@^1.1.2:
|
||||
resolved "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz"
|
||||
integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==
|
||||
|
||||
repeat-string@^1.5.2:
|
||||
repeat-string@^1.5.2, repeat-string@^1.6.1:
|
||||
version "1.6.1"
|
||||
resolved "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz"
|
||||
integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc=
|
||||
@@ -9835,14 +9857,6 @@ resolve@~1.19.0:
|
||||
is-core-module "^2.1.0"
|
||||
path-parse "^1.0.6"
|
||||
|
||||
restore-cursor@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz"
|
||||
integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368=
|
||||
dependencies:
|
||||
onetime "^2.0.0"
|
||||
signal-exit "^3.0.2"
|
||||
|
||||
restore-cursor@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz"
|
||||
@@ -9851,6 +9865,14 @@ restore-cursor@^3.1.0:
|
||||
onetime "^5.1.0"
|
||||
signal-exit "^3.0.2"
|
||||
|
||||
restore-cursor@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-4.0.0.tgz#519560a4318975096def6e609d44100edaa4ccb9"
|
||||
integrity sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==
|
||||
dependencies:
|
||||
onetime "^5.1.0"
|
||||
signal-exit "^3.0.2"
|
||||
|
||||
retry@^0.12.0:
|
||||
version "0.12.0"
|
||||
resolved "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz"
|
||||
@@ -10008,7 +10030,7 @@ rollup@^2.71.1:
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
run-async@^2.2.0, run-async@^2.4.0:
|
||||
run-async@^2.4.0:
|
||||
version "2.4.1"
|
||||
resolved "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz"
|
||||
integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==
|
||||
@@ -10030,13 +10052,20 @@ run-parallel@^1.1.9:
|
||||
dependencies:
|
||||
queue-microtask "^1.2.2"
|
||||
|
||||
rxjs@^6.4.0, rxjs@^6.6.0, rxjs@^6.6.3:
|
||||
rxjs@^6.6.0, rxjs@^6.6.3:
|
||||
version "6.6.7"
|
||||
resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz"
|
||||
integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==
|
||||
dependencies:
|
||||
tslib "^1.9.0"
|
||||
|
||||
rxjs@^7.2.0, rxjs@^7.5.6:
|
||||
version "7.5.6"
|
||||
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.6.tgz#0446577557862afd6903517ce7cae79ecb9662bc"
|
||||
integrity sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw==
|
||||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
|
||||
sade@^1.4.0, sade@^1.7.4:
|
||||
version "1.7.4"
|
||||
resolved "https://registry.npmjs.org/sade/-/sade-1.7.4.tgz"
|
||||
@@ -10076,7 +10105,14 @@ saxes@^5.0.1:
|
||||
dependencies:
|
||||
xmlchars "^2.2.0"
|
||||
|
||||
"semver@2 || 3 || 4 || 5", semver@^5.5.0, semver@^5.6.0, semver@^5.7.1:
|
||||
semver-match@0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/semver-match/-/semver-match-0.1.1.tgz#e7ccb31f83fd4a0e377d66387afd8ca3a329b5fc"
|
||||
integrity sha512-D9mpE1JeqW8YP/Y21EojbapZyIzZSBSFNTPbx9tyujCdu+4ej49ZqxASHZSK5QwB1EOAh2/5WbG/vlN+FsQ5kw==
|
||||
dependencies:
|
||||
semver "^5.1.0"
|
||||
|
||||
"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.5.0, semver@^5.6.0, semver@^5.7.1:
|
||||
version "5.7.1"
|
||||
resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz"
|
||||
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
|
||||
@@ -10191,6 +10227,11 @@ signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3:
|
||||
resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz"
|
||||
integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
|
||||
|
||||
simple-peer-light@^9.10.0:
|
||||
version "9.10.0"
|
||||
resolved "https://registry.yarnpkg.com/simple-peer-light/-/simple-peer-light-9.10.0.tgz#6f3699b80e4b6d3a9374a865e1a8e497aa623afb"
|
||||
integrity sha512-E0INlXmVy2XvVkyMallKYQlcTAD8S0ov+goSVDGD2k9vwkjBCOyFmESoUsv0Pi7P3nSh6TuMIIi+S/YRok9WLg==
|
||||
|
||||
simple-swizzle@^0.2.2:
|
||||
version "0.2.2"
|
||||
resolved "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz"
|
||||
@@ -10436,7 +10477,7 @@ string-width@^1.0.1:
|
||||
is-fullwidth-code-point "^1.0.0"
|
||||
strip-ansi "^3.0.0"
|
||||
|
||||
"string-width@^1.0.2 || 2", string-width@^2.1.0:
|
||||
"string-width@^1.0.2 || 2":
|
||||
version "2.1.1"
|
||||
resolved "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz"
|
||||
integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
|
||||
@@ -10453,6 +10494,15 @@ string-width@^4.1.0, string-width@^4.2.0:
|
||||
is-fullwidth-code-point "^3.0.0"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
string-width@^5.0.1, string-width@^5.1.2:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794"
|
||||
integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==
|
||||
dependencies:
|
||||
eastasianwidth "^0.2.0"
|
||||
emoji-regex "^9.2.2"
|
||||
strip-ansi "^7.0.1"
|
||||
|
||||
string.prototype.trimend@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz"
|
||||
@@ -10497,13 +10547,6 @@ strip-ansi@^4.0.0:
|
||||
dependencies:
|
||||
ansi-regex "^3.0.0"
|
||||
|
||||
strip-ansi@^5.1.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz"
|
||||
integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
|
||||
dependencies:
|
||||
ansi-regex "^4.1.0"
|
||||
|
||||
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
|
||||
@@ -10511,6 +10554,13 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
||||
dependencies:
|
||||
ansi-regex "^5.0.1"
|
||||
|
||||
strip-ansi@^7.0.1:
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2"
|
||||
integrity sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==
|
||||
dependencies:
|
||||
ansi-regex "^6.0.1"
|
||||
|
||||
strip-bom@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz"
|
||||
@@ -10910,12 +10960,12 @@ ts-jest@^27.1.3:
|
||||
semver "7.x"
|
||||
yargs-parser "20.x"
|
||||
|
||||
ts-node@^10.7.0:
|
||||
version "10.7.0"
|
||||
resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz"
|
||||
integrity sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==
|
||||
ts-node@^10.9.1:
|
||||
version "10.9.1"
|
||||
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b"
|
||||
integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==
|
||||
dependencies:
|
||||
"@cspotcode/source-map-support" "0.7.0"
|
||||
"@cspotcode/source-map-support" "^0.8.0"
|
||||
"@tsconfig/node10" "^1.0.7"
|
||||
"@tsconfig/node12" "^1.0.7"
|
||||
"@tsconfig/node14" "^1.0.0"
|
||||
@@ -10926,7 +10976,7 @@ ts-node@^10.7.0:
|
||||
create-require "^1.1.0"
|
||||
diff "^4.0.1"
|
||||
make-error "^1.1.1"
|
||||
v8-compile-cache-lib "^3.0.0"
|
||||
v8-compile-cache-lib "^3.0.1"
|
||||
yn "3.1.1"
|
||||
|
||||
ts-node@^7.0.1:
|
||||
@@ -10953,6 +11003,11 @@ tslib@^2.0.0, tslib@^2.2.0:
|
||||
resolved "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz"
|
||||
integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==
|
||||
|
||||
tslib@^2.1.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3"
|
||||
integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==
|
||||
|
||||
tslib@^2.3.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz"
|
||||
@@ -11115,6 +11170,11 @@ type-fest@^0.8.1:
|
||||
resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz"
|
||||
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
|
||||
|
||||
type-fest@^1.0.2:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1"
|
||||
integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==
|
||||
|
||||
type-is@~1.6.17, type-is@~1.6.18:
|
||||
version "1.6.18"
|
||||
resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz"
|
||||
@@ -11291,10 +11351,10 @@ uuid@^3.3.2:
|
||||
resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz"
|
||||
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
||||
|
||||
v8-compile-cache-lib@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz"
|
||||
integrity sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA==
|
||||
v8-compile-cache-lib@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf"
|
||||
integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==
|
||||
|
||||
v8-compile-cache@^2.0.3:
|
||||
version "2.3.0"
|
||||
@@ -11365,7 +11425,7 @@ walker@^1.0.7:
|
||||
dependencies:
|
||||
makeerror "1.0.x"
|
||||
|
||||
wcwidth@^1.0.0:
|
||||
wcwidth@^1.0.0, wcwidth@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz"
|
||||
integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=
|
||||
@@ -11467,6 +11527,15 @@ wrap-ansi@^7.0.0:
|
||||
string-width "^4.1.0"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
wrap-ansi@^8.0.1:
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.0.1.tgz#2101e861777fec527d0ea90c57c6b03aac56a5b3"
|
||||
integrity sha512-QFF+ufAqhoYHvoHdajT/Po7KoXVBPXS2bgjIam5isfWJPfIOnQZ50JtUiVvCv/sjgacf3yRrt2ZKUZ/V4itN4g==
|
||||
dependencies:
|
||||
ansi-styles "^6.1.0"
|
||||
string-width "^5.0.1"
|
||||
strip-ansi "^7.0.1"
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
|
||||
|
||||
Reference in New Issue
Block a user