diff --git a/package.json b/package.json
index 888ec0c2cde5..25e310ba32de 100644
--- a/package.json
+++ b/package.json
@@ -30,6 +30,7 @@
"packages/integrations",
"packages/minimal",
"packages/nextjs",
+ "packages/next-plugin-sentry",
"packages/node",
"packages/react",
"packages/serverless",
diff --git a/packages/next-plugin-sentry/LICENSE b/packages/next-plugin-sentry/LICENSE
new file mode 100644
index 000000000000..2405b5588e48
--- /dev/null
+++ b/packages/next-plugin-sentry/LICENSE
@@ -0,0 +1,29 @@
+MIT License
+
+Copyright (c) 2021, Sentry
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+* Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/packages/next-plugin-sentry/README.md b/packages/next-plugin-sentry/README.md
new file mode 100644
index 000000000000..be8fac64345d
--- /dev/null
+++ b/packages/next-plugin-sentry/README.md
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+# Official Sentry SDK for NextJS
+
+TODO: npm version, npm dm, npm dt, typedoc
+
+## Links
+
+- [Official SDK Docs](https://docs.sentry.io/quickstart/)
+- [TypeDoc](http://getsentry.github.io/sentry-javascript/)
+
+## Usage
+
+TODO
diff --git a/packages/next-plugin-sentry/config.js b/packages/next-plugin-sentry/config.js
new file mode 100644
index 000000000000..ede9e9c40227
--- /dev/null
+++ b/packages/next-plugin-sentry/config.js
@@ -0,0 +1,2 @@
+exports.serverConfig = {};
+exports.clientConfig = {};
diff --git a/packages/next-plugin-sentry/env.js b/packages/next-plugin-sentry/env.js
new file mode 100644
index 000000000000..1c8d542dd50d
--- /dev/null
+++ b/packages/next-plugin-sentry/env.js
@@ -0,0 +1,9 @@
+export const getDsn = () =>
+ process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN;
+
+export const getRelease = () =>
+ process.env.SENTRY_RELEASE ||
+ process.env.NEXT_PUBLIC_SENTRY_RELEASE ||
+ process.env.VERCEL_GITHUB_COMMIT_SHA ||
+ process.env.VERCEL_GITLAB_COMMIT_SHA ||
+ process.env.VERCEL_BITBUCKET_COMMIT_SHA;
diff --git a/packages/next-plugin-sentry/index.js b/packages/next-plugin-sentry/index.js
new file mode 100644
index 000000000000..4ffa97645966
--- /dev/null
+++ b/packages/next-plugin-sentry/index.js
@@ -0,0 +1,10 @@
+const { serverConfig, clientConfig } = require('./config.js');
+
+const Sentry = require('@sentry/nextjs');
+Sentry.showReportDialog = (...args) => {
+ Sentry._callOnClient('showReportDialog', ...args);
+};
+
+exports.Sentry = Sentry;
+exports.serverConfig = serverConfig;
+exports.clientConfig = clientConfig;
diff --git a/packages/next-plugin-sentry/package.json b/packages/next-plugin-sentry/package.json
new file mode 100644
index 000000000000..bc1a95ae3ae6
--- /dev/null
+++ b/packages/next-plugin-sentry/package.json
@@ -0,0 +1,38 @@
+{
+ "name": "@sentry/next-plugin-sentry",
+ "version": "6.2.1",
+ "description": "Plugin for Next.js",
+ "repository": "git://github.com/getsentry/sentry-javascript.git",
+ "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/next-plugin-sentry",
+ "author": "Sentry",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "main": "index.js",
+ "publishConfig": {
+ "access": "public"
+ },
+ "dependencies": {
+ "@sentry/nextjs": "6.2.1",
+ "@sentry/integrations": "6.2.1"
+ },
+ "devDependencies": {
+ "eslint": "7.20.0",
+ "rimraf": "3.0.2"
+ },
+ "nextjs": {
+ "name": "sentry",
+ "required-env": []
+ },
+ "peerDependencies": {
+ "next": "*"
+ },
+ "scripts": {
+ "link:yarn": "yarn link",
+ "pack": "npm pack"
+ },
+ "volta": {
+ "extends": "../../package.json"
+ }
+}
diff --git a/packages/next-plugin-sentry/src/on-error-client.js b/packages/next-plugin-sentry/src/on-error-client.js
new file mode 100644
index 000000000000..4070d276c188
--- /dev/null
+++ b/packages/next-plugin-sentry/src/on-error-client.js
@@ -0,0 +1,14 @@
+import { withScope, captureException } from '@sentry/nextjs';
+
+export default async function onErrorClient({ err, errorInfo, renderErrorProps, data, version }) {
+ // TODO: Extract some useful metadata from the router and other arguments — Kamil
+
+ withScope(scope => {
+ if (typeof errorInfo?.componentStack === 'string') {
+ scope.setContext('react', {
+ componentStack: errorInfo.componentStack.trim(),
+ });
+ }
+ captureException(err);
+ });
+}
diff --git a/packages/next-plugin-sentry/src/on-error-server.js b/packages/next-plugin-sentry/src/on-error-server.js
new file mode 100644
index 000000000000..4111adccc68d
--- /dev/null
+++ b/packages/next-plugin-sentry/src/on-error-server.js
@@ -0,0 +1,23 @@
+import { captureException, flush, Handlers, withScope } from '@sentry/nextjs';
+import getConfig from 'next/config';
+
+const { parseRequest } = Handlers;
+
+export default async function onErrorServer(err) {
+ const { serverRuntimeConfig = {}, publicRuntimeConfig = {} } = getConfig() || {};
+ const sentryTimeout = serverRuntimeConfig.sentryTimeout || publicRuntimeConfig.sentryTimeout || 2000;
+
+ withScope(scope => {
+ if (typeof err.req !== 'undefined') {
+ scope.addEventProcessor(event =>
+ parseRequest(event, err.req, {
+ // 'cookies' and 'query_string' use `dynamicRequire` which has a bug in SSR envs right now — Kamil
+ request: ['data', 'headers', 'method', 'url'],
+ }),
+ );
+ }
+ captureException(err instanceof Error ? err : err.err);
+ });
+
+ await flush(sentryTimeout);
+}
diff --git a/packages/next-plugin-sentry/src/on-init-client.js b/packages/next-plugin-sentry/src/on-init-client.js
new file mode 100644
index 000000000000..c9ae987c9903
--- /dev/null
+++ b/packages/next-plugin-sentry/src/on-init-client.js
@@ -0,0 +1,17 @@
+import { init } from '@sentry/nextjs';
+import getConfig from 'next/config';
+
+import { getDsn, getRelease } from '../env';
+import { clientConfig } from '../config';
+
+export default async function initClient() {
+ const { publicRuntimeConfig = {} } = getConfig() || {};
+ const runtimeConfig = publicRuntimeConfig.sentry || {};
+
+ init({
+ dsn: getDsn(),
+ ...(getRelease() && { release: getRelease() }),
+ ...runtimeConfig,
+ ...clientConfig,
+ });
+}
diff --git a/packages/next-plugin-sentry/src/on-init-server.js b/packages/next-plugin-sentry/src/on-init-server.js
new file mode 100644
index 000000000000..92f50b79a0b2
--- /dev/null
+++ b/packages/next-plugin-sentry/src/on-init-server.js
@@ -0,0 +1,33 @@
+import { init } from '@sentry/nextjs';
+import { RewriteFrames } from '@sentry/integrations';
+import getConfig from 'next/config';
+
+import { getDsn, getRelease } from '../env';
+import { serverConfig } from '../config';
+
+export default async function initServer() {
+ const { serverRuntimeConfig = {}, publicRuntimeConfig = {} } = getConfig() || {};
+ const runtimeConfig = serverRuntimeConfig.sentry || publicRuntimeConfig.sentry || {};
+
+ init({
+ dsn: getDsn(),
+ ...(getRelease() && { release: getRelease() }),
+ ...runtimeConfig,
+ ...serverConfig,
+ integrations: [
+ new RewriteFrames({
+ iteratee: frame => {
+ try {
+ const [_, path] = frame.filename.split('.next/');
+ if (path) {
+ frame.filename = `app:///_next/${path}`;
+ }
+ } catch {}
+ return frame;
+ },
+ }),
+ ...(runtimeConfig.integrations || []),
+ ...(serverConfig.integrations || []),
+ ],
+ });
+}
diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json
index 3574a5517723..87abf2b5ff98 100644
--- a/packages/nextjs/package.json
+++ b/packages/nextjs/package.json
@@ -9,7 +9,6 @@
"engines": {
"node": ">=6"
},
- "main": "./dist/index.js",
"module": "./esm/node.js",
"browser": "./esm/browser.js",
"types": "./dist/index.d.ts",
@@ -21,6 +20,7 @@
"@sentry/minimal": "6.2.1",
"@sentry/node": "6.2.1",
"@sentry/react": "6.2.1",
+ "@sentry/next-plugin-sentry": "6.2.1",
"@sentry/wizard": "1.2.0",
"@sentry/webpack-plugin": "1.14.1"
},
diff --git a/packages/nextjs/src/browser.ts b/packages/nextjs/src/browser.ts
index 7c431144f3fd..a75cd6a1baa0 100644
--- a/packages/nextjs/src/browser.ts
+++ b/packages/nextjs/src/browser.ts
@@ -4,6 +4,8 @@ import { InitDecider } from './utils/initDecider';
import { MetadataBuilder } from './utils/metadataBuilder';
import { NextjsOptions } from './utils/nextjsOptions';
+export * from '@sentry/react';
+
/** Inits the Sentry NextJS SDK on the browser with the React SDK. */
export function init(options: NextjsOptions): any {
const metadataBuilder = new MetadataBuilder(options, ['nextjs', 'react']);
@@ -16,5 +18,3 @@ export function init(options: NextjsOptions): any {
console.log('[Sentry] Detected a non-production environment. Not initializing Sentry.');
}
}
-
-export * from '@sentry/minimal';
diff --git a/packages/nextjs/src/node.ts b/packages/nextjs/src/node.ts
index d17a6b2b5cd2..2e0528676034 100644
--- a/packages/nextjs/src/node.ts
+++ b/packages/nextjs/src/node.ts
@@ -4,6 +4,8 @@ import { InitDecider } from './utils/initDecider';
import { MetadataBuilder } from './utils/metadataBuilder';
import { NextjsOptions } from './utils/nextjsOptions';
+export * from '@sentry/node';
+
/** Inits the Sentry NextJS SDK on node. */
export function init(options: NextjsOptions): any {
const metadataBuilder = new MetadataBuilder(options, ['nextjs', 'node']);
@@ -16,5 +18,3 @@ export function init(options: NextjsOptions): any {
console.log('[Sentry] Detected a non-production environment. Not initializing Sentry.');
}
}
-
-export * from '@sentry/minimal';
diff --git a/yarn.lock b/yarn.lock
index 53d2d0b7e868..65e1f7b78a36 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3317,6 +3317,16 @@
"@sentry/utils" "6.2.1"
tslib "^1.9.3"
+"@sentry/integrations@6.2.1":
+ version "6.2.1"
+ resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-6.2.1.tgz#caa9b49de29523698668d45827633be86b2268ff"
+ integrity sha512-UBvuil/b9M5HGH6aBDzTiIVRsmpC/wqwDKy28IO05XLdalmKgJ9C1EQhoyN6xw+1lINpXXFtfq4NhfgZgWbc7Q==
+ dependencies:
+ "@sentry/types" "6.2.1"
+ "@sentry/utils" "6.2.1"
+ localforage "^1.8.1"
+ tslib "^1.9.3"
+
"@sentry/minimal@6.2.1":
version "6.2.1"
resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.2.1.tgz#8f01480e1b56bc7dd54adf925e5317f233e19384"