From 4bff5a9aafe973506bd76884f51e1084f79e1afc Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Tue, 14 Mar 2023 10:29:33 +0100 Subject: [PATCH] feat(bundles): Ensure CDN bundles always have a `Replay` export (#7414) --- package.json | 2 + packages/browser/package.json | 1 + packages/browser/rollup.bundle.config.js | 1 + packages/integration-shims/.eslintrc.js | 8 ++ packages/integration-shims/LICENSE | 14 +++ packages/integration-shims/README.md | 9 ++ packages/integration-shims/package.json | 46 +++++++++ .../integration-shims/rollup.npm.config.js | 7 ++ packages/integration-shims/src/Replay.ts | 46 +++++++++ packages/integration-shims/src/index.ts | 1 + packages/integration-shims/tsconfig.json | 11 +++ .../integration-shims/tsconfig.types.json | 10 ++ .../suites/replay/replayShim/init.js | 22 +++++ .../suites/replay/replayShim/template.html | 9 ++ .../suites/replay/replayShim/test.ts | 37 ++++++++ packages/tracing/package.json | 1 + packages/tracing/rollup.bundle.config.js | 1 + packages/tracing/src/index.bundle.base.ts | 92 ++++++++++++++++++ packages/tracing/src/index.bundle.replay.ts | 2 +- packages/tracing/src/index.bundle.ts | 94 +------------------ rollup/bundleHelpers.js | 9 ++ rollup/plugins/bundlePlugins.js | 14 +++ yarn.lock | 22 +++++ 23 files changed, 367 insertions(+), 92 deletions(-) create mode 100644 packages/integration-shims/.eslintrc.js create mode 100644 packages/integration-shims/LICENSE create mode 100644 packages/integration-shims/README.md create mode 100644 packages/integration-shims/package.json create mode 100644 packages/integration-shims/rollup.npm.config.js create mode 100644 packages/integration-shims/src/Replay.ts create mode 100644 packages/integration-shims/src/index.ts create mode 100644 packages/integration-shims/tsconfig.json create mode 100644 packages/integration-shims/tsconfig.types.json create mode 100644 packages/integration-tests/suites/replay/replayShim/init.js create mode 100644 packages/integration-tests/suites/replay/replayShim/template.html create mode 100644 packages/integration-tests/suites/replay/replayShim/test.ts create mode 100644 packages/tracing/src/index.bundle.base.ts diff --git a/package.json b/package.json index dda4cf8e57e2..3fb01dada5ed 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "packages/hub", "packages/integration-tests", "packages/integrations", + "packages/integration-shims", "packages/overhead-metrics", "packages/nextjs", "packages/node", @@ -105,6 +106,7 @@ "rollup": "^2.67.1", "rollup-plugin-cleanup": "3.2.1", "rollup-plugin-license": "^2.6.1", + "rollup-plugin-modify": "^3.0.0", "rollup-plugin-terser": "^7.0.2", "rollup-plugin-typescript2": "^0.31.2", "sinon": "^7.3.2", diff --git a/packages/browser/package.json b/packages/browser/package.json index 20dc64aad29e..fb2a3ccd2a54 100644 --- a/packages/browser/package.json +++ b/packages/browser/package.json @@ -23,6 +23,7 @@ "tslib": "^1.9.3" }, "devDependencies": { + "@sentry-internal/integration-shims": "7.43.0", "@types/md5": "2.1.33", "btoa": "^1.2.1", "chai": "^4.1.2", diff --git a/packages/browser/rollup.bundle.config.js b/packages/browser/rollup.bundle.config.js index e063a9bd4ab0..380ca59eed95 100644 --- a/packages/browser/rollup.bundle.config.js +++ b/packages/browser/rollup.bundle.config.js @@ -8,6 +8,7 @@ const builds = []; entrypoints: ['src/index.ts'], jsVersion, licenseTitle: '@sentry/browser', + includeReplay: 'shim', outputFileBase: () => `bundles/bundle${jsVersion === 'es5' ? '.es5' : ''}`, }); diff --git a/packages/integration-shims/.eslintrc.js b/packages/integration-shims/.eslintrc.js new file mode 100644 index 000000000000..0c83f7d0ff9d --- /dev/null +++ b/packages/integration-shims/.eslintrc.js @@ -0,0 +1,8 @@ +// Note: All paths are relative to the directory in which eslint is being run, rather than the directory where this file +// lives + +// ESLint config docs: https://eslint.org/docs/user-guide/configuring/ + +module.exports = { + extends: ['../../.eslintrc.js'], +}; diff --git a/packages/integration-shims/LICENSE b/packages/integration-shims/LICENSE new file mode 100644 index 000000000000..d11896ba1181 --- /dev/null +++ b/packages/integration-shims/LICENSE @@ -0,0 +1,14 @@ +Copyright (c) 2023 Sentry (https://sentry.io) and individual contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/integration-shims/README.md b/packages/integration-shims/README.md new file mode 100644 index 000000000000..523e3e4fd85f --- /dev/null +++ b/packages/integration-shims/README.md @@ -0,0 +1,9 @@ +

+ + Sentry + +

+ +# Sentry Integration Shims + +This internal package exports shims for Integrations, which are used in order to guarantee a consistent CDN bundle output. diff --git a/packages/integration-shims/package.json b/packages/integration-shims/package.json new file mode 100644 index 000000000000..e986841e3129 --- /dev/null +++ b/packages/integration-shims/package.json @@ -0,0 +1,46 @@ +{ + "name": "@sentry-internal/integration-shims", + "version": "7.43.0", + "description": "Shims for integrations in Sentry SDK.", + "main": "build/cjs/index.js", + "module": "build/esm/index.js", + "types": "build/types/index.d.ts", + "sideEffects": false, + "private": true, + "scripts": { + "build": "run-p build:transpile build:types", + "build:transpile": "rollup -c rollup.npm.config.js", + "build:types": "tsc -p tsconfig.types.json", + "build:dev": "yarn build", + "build:watch": "run-p build:transpile:watch build:types:watch", + "build:dev:watch": "run-p build:watch", + "build:transpile:watch": "yarn build:rollup --watch", + "build:types:watch": "yarn build:types --watch", + "clean": "rimraf build", + "fix": "run-s fix:eslint fix:prettier", + "fix:eslint": "eslint . --format stylish --fix", + "fix:prettier": "prettier --write \"{src,test}/**/*.ts\"", + "lint": "run-s lint:prettier lint:eslint", + "lint:eslint": "eslint . --format stylish", + "lint:prettier": "prettier --check \"{src,test}/**/*.ts\"" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/getsentry/sentry-javascript.git" + }, + "author": "Sentry", + "license": "MIT", + "bugs": { + "url": "https://github.com/getsentry/sentry-javascript/issues" + }, + "devDependencies": {}, + "dependencies": { + "@sentry/types": "7.43.0" + }, + "engines": { + "node": ">=12" + }, + "volta": { + "extends": "../../package.json" + } +} diff --git a/packages/integration-shims/rollup.npm.config.js b/packages/integration-shims/rollup.npm.config.js new file mode 100644 index 000000000000..2928d05abeed --- /dev/null +++ b/packages/integration-shims/rollup.npm.config.js @@ -0,0 +1,7 @@ +import { makeBaseNPMConfig, makeNPMConfigVariants } from '../../rollup/index.js'; + +export default makeNPMConfigVariants( + makeBaseNPMConfig({ + entrypoints: ['src/index.ts'], + }), +); diff --git a/packages/integration-shims/src/Replay.ts b/packages/integration-shims/src/Replay.ts new file mode 100644 index 000000000000..c89bbd415d5f --- /dev/null +++ b/packages/integration-shims/src/Replay.ts @@ -0,0 +1,46 @@ +import type { Integration } from '@sentry/types'; + +/** + * This is a shim for the Replay integration. + * It is needed in order for the CDN bundles to continue working when users add/remove replay + * from it, without changing their config. This is necessary for the loader mechanism. + */ +class ReplayShim implements Integration { + /** + * @inheritDoc + */ + public static id: string = 'Replay'; + + /** + * @inheritDoc + */ + public name: string = ReplayShim.id; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public constructor(_options: any) { + // eslint-disable-next-line no-console + console.error('You are using new Replay() even though this bundle does not include the replay integration.'); + } + + /** jsdoc */ + public setupOnce(): void { + // noop + } + + /** jsdoc */ + public start(): void { + // noop + } + + /** jsdoc */ + public stop(): void { + // noop + } + + /** jsdoc */ + public flush(): void { + // noop + } +} + +export { ReplayShim as Replay }; diff --git a/packages/integration-shims/src/index.ts b/packages/integration-shims/src/index.ts new file mode 100644 index 000000000000..a55c52bcb483 --- /dev/null +++ b/packages/integration-shims/src/index.ts @@ -0,0 +1 @@ +export * from './Replay'; diff --git a/packages/integration-shims/tsconfig.json b/packages/integration-shims/tsconfig.json new file mode 100644 index 000000000000..dd48230408ab --- /dev/null +++ b/packages/integration-shims/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "module": "esnext", + "lib": ["ES6"], + "esModuleInterop": true, + "target": "es6", + "strictPropertyInitialization": false + }, + "include": ["src/**/*.ts"] +} diff --git a/packages/integration-shims/tsconfig.types.json b/packages/integration-shims/tsconfig.types.json new file mode 100644 index 000000000000..16be672259fb --- /dev/null +++ b/packages/integration-shims/tsconfig.types.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "include": ["src/index.ts"], + "compilerOptions": { + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "build/types" + } +} diff --git a/packages/integration-tests/suites/replay/replayShim/init.js b/packages/integration-tests/suites/replay/replayShim/init.js new file mode 100644 index 000000000000..b53ada8b5e7c --- /dev/null +++ b/packages/integration-tests/suites/replay/replayShim/init.js @@ -0,0 +1,22 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +// Replay should not actually work, but still not error out +window.Replay = new Sentry.Replay({ + flushMinDelay: 200, + flushMaxDelay: 200, +}); + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + sampleRate: 1, + replaysSessionSampleRate: 1.0, + replaysOnErrorSampleRate: 0.0, + integrations: [window.Replay], +}); + +// Ensure none of these break +window.Replay.start(); +window.Replay.stop(); +window.Replay.flush(); diff --git a/packages/integration-tests/suites/replay/replayShim/template.html b/packages/integration-tests/suites/replay/replayShim/template.html new file mode 100644 index 000000000000..2b3e2f0b27b4 --- /dev/null +++ b/packages/integration-tests/suites/replay/replayShim/template.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/packages/integration-tests/suites/replay/replayShim/test.ts b/packages/integration-tests/suites/replay/replayShim/test.ts new file mode 100644 index 000000000000..ca11e1c431f2 --- /dev/null +++ b/packages/integration-tests/suites/replay/replayShim/test.ts @@ -0,0 +1,37 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../utils/fixtures'; + +sentryTest( + 'exports a shim Replay integration for non-replay bundles', + async ({ getLocalTestPath, page, forceFlushReplay }) => { + const bundle = process.env.PW_BUNDLE; + + if (!bundle || !bundle.startsWith('bundle_') || bundle.includes('replay')) { + sentryTest.skip(); + } + + const consoleMessages: string[] = []; + page.on('console', msg => consoleMessages.push(msg.text())); + + let requestCount = 0; + await page.route('https://dsn.ingest.sentry.io/**/*', route => { + requestCount++; + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ id: 'test-id' }), + }); + }); + + const url = await getLocalTestPath({ testDir: __dirname }); + + await page.goto(url); + await forceFlushReplay(); + + expect(requestCount).toBe(0); + expect(consoleMessages).toEqual([ + 'You are using new Replay() even though this bundle does not include the replay integration.', + ]); + }, +); diff --git a/packages/tracing/package.json b/packages/tracing/package.json index 8ecb03f572e8..5ac7ac899983 100644 --- a/packages/tracing/package.json +++ b/packages/tracing/package.json @@ -23,6 +23,7 @@ }, "devDependencies": { "@sentry/browser": "7.43.0", + "@sentry-internal/integration-shims": "7.43.0", "@types/express": "^4.17.14" }, "scripts": { diff --git a/packages/tracing/rollup.bundle.config.js b/packages/tracing/rollup.bundle.config.js index a0c5bc6cd421..52aa6396a370 100644 --- a/packages/tracing/rollup.bundle.config.js +++ b/packages/tracing/rollup.bundle.config.js @@ -8,6 +8,7 @@ const builds = []; entrypoints: ['src/index.bundle.ts'], jsVersion, licenseTitle: '@sentry/tracing & @sentry/browser', + includeReplay: false, outputFileBase: () => `bundles/bundle.tracing${jsVersion === 'es5' ? '.es5' : ''}`, }); diff --git a/packages/tracing/src/index.bundle.base.ts b/packages/tracing/src/index.bundle.base.ts new file mode 100644 index 000000000000..a753bab932d4 --- /dev/null +++ b/packages/tracing/src/index.bundle.base.ts @@ -0,0 +1,92 @@ +export type { + Breadcrumb, + Request, + SdkInfo, + Event, + Exception, + // eslint-disable-next-line deprecation/deprecation + Severity, + SeverityLevel, + StackFrame, + Stacktrace, + Thread, + User, +} from '@sentry/types'; + +export type { BrowserOptions, ReportDialogOptions } from '@sentry/browser'; + +export { + addGlobalEventProcessor, + addBreadcrumb, + captureException, + captureEvent, + captureMessage, + configureScope, + getHubFromCarrier, + getCurrentHub, + Hub, + Scope, + setContext, + setExtra, + setExtras, + setTag, + setTags, + setUser, + startTransaction, + makeFetchTransport, + makeXHRTransport, + withScope, +} from '@sentry/browser'; + +export { BrowserClient } from '@sentry/browser'; +export { + defaultIntegrations, + defaultStackParser, + forceLoad, + init, + lastEventId, + onLoad, + showReportDialog, + flush, + close, + wrap, +} from '@sentry/browser'; +export { SDK_VERSION } from '@sentry/browser'; + +import { Integrations as BrowserIntegrations } from '@sentry/browser'; +import type { Integration } from '@sentry/types'; +import { GLOBAL_OBJ } from '@sentry/utils'; + +import { BrowserTracing } from './browser'; +import { addExtensionMethods } from './extensions'; + +export { Span } from '@sentry/core'; + +let windowIntegrations = {}; + +// This block is needed to add compatibility with the integrations packages when used with a CDN +if (GLOBAL_OBJ.Sentry && GLOBAL_OBJ.Sentry.Integrations) { + windowIntegrations = GLOBAL_OBJ.Sentry.Integrations; +} + +// For whatever reason, it does not recognize BrowserTracing or some of the BrowserIntegrations as Integration +const INTEGRATIONS: Record< + string, + Integration | typeof BrowserTracing | typeof BrowserIntegrations[keyof typeof BrowserIntegrations] +> = { + ...windowIntegrations, + ...BrowserIntegrations, + BrowserTracing, +}; + +export { INTEGRATIONS as Integrations }; +// Though in this case exporting `BrowserTracing` separately (in addition to exporting it as part of +// `Sentry.Integrations`) doesn't gain us any bundle size advantage (we're making the bundle here, not the user, and we +// can't leave anything out of ours), it does bring the API for using the integration in line with that recommended for +// users bundling Sentry themselves. +export { BrowserTracing }; + +// We are patching the global object with our hub extension methods +addExtensionMethods(); + +export { addExtensionMethods }; diff --git a/packages/tracing/src/index.bundle.replay.ts b/packages/tracing/src/index.bundle.replay.ts index 403cc6342b65..fe503b961461 100644 --- a/packages/tracing/src/index.bundle.replay.ts +++ b/packages/tracing/src/index.bundle.replay.ts @@ -9,4 +9,4 @@ Sentry.Integrations.Replay = Replay; export { Replay }; -export * from './index.bundle'; +export * from './index.bundle.base'; diff --git a/packages/tracing/src/index.bundle.ts b/packages/tracing/src/index.bundle.ts index a753bab932d4..ac897b145298 100644 --- a/packages/tracing/src/index.bundle.ts +++ b/packages/tracing/src/index.bundle.ts @@ -1,92 +1,4 @@ -export type { - Breadcrumb, - Request, - SdkInfo, - Event, - Exception, - // eslint-disable-next-line deprecation/deprecation - Severity, - SeverityLevel, - StackFrame, - Stacktrace, - Thread, - User, -} from '@sentry/types'; +// This is exported so the loader does not fail when switching off Replay +export { Replay } from '@sentry-internal/integration-shims'; -export type { BrowserOptions, ReportDialogOptions } from '@sentry/browser'; - -export { - addGlobalEventProcessor, - addBreadcrumb, - captureException, - captureEvent, - captureMessage, - configureScope, - getHubFromCarrier, - getCurrentHub, - Hub, - Scope, - setContext, - setExtra, - setExtras, - setTag, - setTags, - setUser, - startTransaction, - makeFetchTransport, - makeXHRTransport, - withScope, -} from '@sentry/browser'; - -export { BrowserClient } from '@sentry/browser'; -export { - defaultIntegrations, - defaultStackParser, - forceLoad, - init, - lastEventId, - onLoad, - showReportDialog, - flush, - close, - wrap, -} from '@sentry/browser'; -export { SDK_VERSION } from '@sentry/browser'; - -import { Integrations as BrowserIntegrations } from '@sentry/browser'; -import type { Integration } from '@sentry/types'; -import { GLOBAL_OBJ } from '@sentry/utils'; - -import { BrowserTracing } from './browser'; -import { addExtensionMethods } from './extensions'; - -export { Span } from '@sentry/core'; - -let windowIntegrations = {}; - -// This block is needed to add compatibility with the integrations packages when used with a CDN -if (GLOBAL_OBJ.Sentry && GLOBAL_OBJ.Sentry.Integrations) { - windowIntegrations = GLOBAL_OBJ.Sentry.Integrations; -} - -// For whatever reason, it does not recognize BrowserTracing or some of the BrowserIntegrations as Integration -const INTEGRATIONS: Record< - string, - Integration | typeof BrowserTracing | typeof BrowserIntegrations[keyof typeof BrowserIntegrations] -> = { - ...windowIntegrations, - ...BrowserIntegrations, - BrowserTracing, -}; - -export { INTEGRATIONS as Integrations }; -// Though in this case exporting `BrowserTracing` separately (in addition to exporting it as part of -// `Sentry.Integrations`) doesn't gain us any bundle size advantage (we're making the bundle here, not the user, and we -// can't leave anything out of ours), it does bring the API for using the integration in line with that recommended for -// users bundling Sentry themselves. -export { BrowserTracing }; - -// We are patching the global object with our hub extension methods -addExtensionMethods(); - -export { addExtensionMethods }; +export * from './index.bundle.base'; diff --git a/rollup/bundleHelpers.js b/rollup/bundleHelpers.js index 56ef80d12415..e81069990fa4 100644 --- a/rollup/bundleHelpers.js +++ b/rollup/bundleHelpers.js @@ -18,6 +18,7 @@ import { makeTSPlugin, makeExcludeBlockPlugin, makeSetSDKSourcePlugin, + makeReplayShimPlugin, } from './plugins/index.js'; import { mergePlugins } from './utils'; @@ -43,8 +44,10 @@ export function makeBaseBundleConfig(options) { const licensePlugin = makeLicensePlugin(licenseTitle); const tsPlugin = makeTSPlugin(jsVersion.toLowerCase()); const excludeReplayPlugin = makeExcludeBlockPlugin('REPLAY'); + const excludeReplayShimPlugin = makeExcludeBlockPlugin('REPLAY_SHIM'); const excludeOfflineTransport = makeExcludeBlockPlugin('OFFLINE'); const excludeBrowserProfiling = makeExcludeBlockPlugin('BROWSER_PROFILING'); + const replayShimPlugin = makeReplayShimPlugin(); // The `commonjs` plugin is the `esModuleInterop` of the bundling world. When used with `transformMixedEsModules`, it // will include all dependencies, imported or required, in the final bundle. (Without it, CJS modules aren't included @@ -61,6 +64,12 @@ export function makeBaseBundleConfig(options) { plugins: [markAsBrowserBuildPlugin], }; + if (includeReplay === 'shim') { + standAloneBundleConfig.plugins.push(replayShimPlugin); + } else { + standAloneBundleConfig.plugins.push(excludeReplayShimPlugin); + } + if (!includeReplay) { standAloneBundleConfig.plugins.push(excludeReplayPlugin); } diff --git a/rollup/plugins/bundlePlugins.js b/rollup/plugins/bundlePlugins.js index 49dcaefbdf73..f00e090c740c 100644 --- a/rollup/plugins/bundlePlugins.js +++ b/rollup/plugins/bundlePlugins.js @@ -18,6 +18,7 @@ import replace from '@rollup/plugin-replace'; import { terser } from 'rollup-plugin-terser'; import typescript from 'rollup-plugin-typescript2'; import MagicString from 'magic-string'; +import modify from 'rollup-plugin-modify'; /** * Create a plugin to add an identification banner to the top of stand-alone bundles. @@ -215,6 +216,19 @@ export function makeExcludeBlockPlugin(type) { return plugin; } +export function makeReplayShimPlugin() { + // This is designed to replace the re-export in browser/index.ts to export the shim + const plugin = modify({ + find: '@sentry/replay', + replace: '@sentry-internal/integration-shims', + }); + + // give it a nicer name for later, when we'll need to sort the plugins + plugin.name = 'replayShim'; + + return plugin; +} + // We don't pass these plugins any options which need to be calculated or changed by us, so no need to wrap them in // another factory function, as they are themselves already factory functions. export { resolve as makeNodeResolvePlugin }; diff --git a/yarn.lock b/yarn.lock index 2568164fa859..d39f972d5311 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17812,6 +17812,13 @@ madge@4.0.2: typescript "^3.9.5" walkdir "^0.4.1" +magic-string@0.25.2: + version "0.25.2" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.2.tgz#139c3a729515ec55e96e69e82a11fe890a293ad9" + integrity sha512-iLs9mPjh9IuTtRsqqhNGYcZXGei0Nh/A4xirrsqW7c+QhKVFL2vm7U09ru6cHRD22azaP/wMDgI+HCqbETMTtg== + dependencies: + sourcemap-codec "^1.4.4" + magic-string@0.25.7: version "0.25.7" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" @@ -20002,6 +20009,13 @@ osenv@^0.1.3, osenv@^0.1.5: os-homedir "^1.0.0" os-tmpdir "^1.0.0" +ospec@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/ospec/-/ospec-3.1.0.tgz#d36b8e10110f58f63a463df2390a7a73fe9579a8" + integrity sha512-+nGtjV3vlADp+UGfL51miAh/hB4awPBkQrArhcgG4trAaoA2gKt5bf9w0m9ch9zOr555cHWaCHZEDiBOkNZSxw== + dependencies: + glob "^7.1.3" + p-cancelable@^0.4.0: version "0.4.1" resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0" @@ -23416,6 +23430,14 @@ rollup-plugin-license@^2.6.1: spdx-expression-validate "2.0.0" spdx-satisfies "5.0.1" +rollup-plugin-modify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/rollup-plugin-modify/-/rollup-plugin-modify-3.0.0.tgz#5326e11dfec247e8bbdd9507f3da1da1e5c7818b" + integrity sha512-p/ffs0Y2jz2dEnWjq1oVC7SY37tuS+aP7whoNaQz1EAAOPg+k3vKJo8cMMWx6xpdd0NzhX4y2YF9o/NPu5YR0Q== + dependencies: + magic-string "0.25.2" + ospec "3.1.0" + rollup-plugin-sourcemaps@^0.6.0, rollup-plugin-sourcemaps@^0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/rollup-plugin-sourcemaps/-/rollup-plugin-sourcemaps-0.6.3.tgz#bf93913ffe056e414419607f1d02780d7ece84ed"