@sentry/wizard 6.9.0 → 6.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -1
- package/dist/e2e-tests/tests/nextjs-14.test.js +6 -6
- package/dist/e2e-tests/tests/nextjs-14.test.js.map +1 -1
- package/dist/e2e-tests/tests/nextjs-15.test.js +6 -6
- package/dist/e2e-tests/tests/nextjs-15.test.js.map +1 -1
- package/dist/e2e-tests/tests/nextjs-16.test.d.ts +1 -0
- package/dist/e2e-tests/tests/nextjs-16.test.js +120 -0
- package/dist/e2e-tests/tests/nextjs-16.test.js.map +1 -0
- package/dist/e2e-tests/utils/index.d.ts +6 -0
- package/dist/e2e-tests/utils/index.js +16 -1
- package/dist/e2e-tests/utils/index.js.map +1 -1
- package/dist/src/nextjs/nextjs-wizard.js +46 -8
- package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
- package/dist/src/nextjs/templates.d.ts +6 -3
- package/dist/src/nextjs/templates.js +144 -93
- package/dist/src/nextjs/templates.js.map +1 -1
- package/dist/src/react-router/codemods/client.entry.js +4 -1
- package/dist/src/react-router/codemods/client.entry.js.map +1 -1
- package/dist/src/react-router/sdk-example.js +5 -2
- package/dist/src/react-router/sdk-example.js.map +1 -1
- package/dist/src/sourcemaps/tools/sentry-cli.js +1 -1
- package/dist/src/sourcemaps/tools/sentry-cli.js.map +1 -1
- package/dist/src/sourcemaps/tools/wrangler.js +1 -1
- package/dist/src/sourcemaps/tools/wrangler.js.map +1 -1
- package/dist/src/sveltekit/sveltekit-wizard.js +2 -2
- package/dist/src/sveltekit/sveltekit-wizard.js.map +1 -1
- package/dist/src/telemetry.d.ts +1 -1
- package/dist/src/telemetry.js +52 -31
- package/dist/src/telemetry.js.map +1 -1
- package/dist/src/utils/clack/index.d.ts +17 -0
- package/dist/src/utils/clack/index.js +174 -12
- package/dist/src/utils/clack/index.js.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/version.js.map +1 -1
- package/dist/test/apple/cocoapod.test.js +7 -3
- package/dist/test/apple/cocoapod.test.js.map +1 -1
- package/dist/test/apple/code-tools.test.js +8 -2
- package/dist/test/apple/code-tools.test.js.map +1 -1
- package/dist/test/nextjs/templates.test.js +156 -87
- package/dist/test/nextjs/templates.test.js.map +1 -1
- package/dist/test/nextjs/wizard-double-wrap-prevention.test.js +12 -7
- package/dist/test/nextjs/wizard-double-wrap-prevention.test.js.map +1 -1
- package/dist/test/utils/clack/index.test.js +37 -29
- package/dist/test/utils/clack/index.test.js.map +1 -1
- package/package.json +2 -2
|
@@ -8,36 +8,41 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
8
8
|
const clack_1 = require("../utils/clack");
|
|
9
9
|
function getWithSentryConfigOptionsTemplate({ orgSlug, projectSlug, selfHosted, tunnelRoute, sentryUrl, }) {
|
|
10
10
|
return `{
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
// For all available options, see:
|
|
12
|
+
// https://www.npmjs.com/package/@sentry/webpack-plugin#options
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
org: "${orgSlug}",
|
|
15
|
+
project: "${projectSlug}",${selfHosted ? `\n sentryUrl: "${sentryUrl}",` : ''}
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
// Only print logs for uploading source maps in CI
|
|
18
|
+
silent: !process.env.CI,
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
// For all available options, see:
|
|
21
|
+
// https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
// Upload a larger set of source maps for prettier stack traces (increases build time)
|
|
24
|
+
widenClientFileUpload: true,
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
// Automatically tree-shake Sentry logger statements to reduce bundle size
|
|
33
|
-
disableLogger: true,
|
|
26
|
+
// ${tunnelRoute ? 'Route' : 'Uncomment to route'} browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers.
|
|
27
|
+
// This can increase your server load as well as your hosting bill.
|
|
28
|
+
// Note: Check that the configured route will not match with your Next.js middleware, otherwise reporting of client-
|
|
29
|
+
// side errors will fail.
|
|
30
|
+
${tunnelRoute ? '' : '// '}tunnelRoute: "/monitoring",
|
|
34
31
|
|
|
32
|
+
webpack: {
|
|
35
33
|
// Enables automatic instrumentation of Vercel Cron Monitors. (Does not yet work with App Router route handlers.)
|
|
36
34
|
// See the following for more information:
|
|
37
35
|
// https://docs.sentry.io/product/crons/
|
|
38
36
|
// https://vercel.com/docs/cron-jobs
|
|
39
37
|
automaticVercelMonitors: true,
|
|
40
|
-
|
|
38
|
+
|
|
39
|
+
// Tree-shaking options for reducing bundle size
|
|
40
|
+
treeshake: {
|
|
41
|
+
// Automatically tree-shake Sentry logger statements to reduce bundle size
|
|
42
|
+
removeDebugLogging: true,
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
}`;
|
|
41
46
|
}
|
|
42
47
|
exports.getWithSentryConfigOptionsTemplate = getWithSentryConfigOptionsTemplate;
|
|
43
48
|
function getNextjsConfigCjsTemplate(withSentryConfigOptionsTemplate) {
|
|
@@ -46,10 +51,7 @@ function getNextjsConfigCjsTemplate(withSentryConfigOptionsTemplate) {
|
|
|
46
51
|
/** @type {import('next').NextConfig} */
|
|
47
52
|
const nextConfig = {};
|
|
48
53
|
|
|
49
|
-
module.exports = withSentryConfig(
|
|
50
|
-
nextConfig,
|
|
51
|
-
${withSentryConfigOptionsTemplate}
|
|
52
|
-
);
|
|
54
|
+
module.exports = withSentryConfig(nextConfig, ${withSentryConfigOptionsTemplate});
|
|
53
55
|
`;
|
|
54
56
|
}
|
|
55
57
|
exports.getNextjsConfigCjsTemplate = getNextjsConfigCjsTemplate;
|
|
@@ -59,10 +61,7 @@ function getNextjsConfigMjsTemplate(withSentryConfigOptionsTemplate) {
|
|
|
59
61
|
/** @type {import('next').NextConfig} */
|
|
60
62
|
const nextConfig = {};
|
|
61
63
|
|
|
62
|
-
export default withSentryConfig(
|
|
63
|
-
nextConfig,
|
|
64
|
-
${withSentryConfigOptionsTemplate}
|
|
65
|
-
);
|
|
64
|
+
export default withSentryConfig(nextConfig, ${withSentryConfigOptionsTemplate});
|
|
66
65
|
`;
|
|
67
66
|
}
|
|
68
67
|
exports.getNextjsConfigMjsTemplate = getNextjsConfigMjsTemplate;
|
|
@@ -73,10 +72,7 @@ function getNextjsConfigCjsAppendix(withSentryConfigOptionsTemplate) {
|
|
|
73
72
|
|
|
74
73
|
const { withSentryConfig } = require("@sentry/nextjs");
|
|
75
74
|
|
|
76
|
-
module.exports = withSentryConfig(
|
|
77
|
-
module.exports,
|
|
78
|
-
${withSentryConfigOptionsTemplate}
|
|
79
|
-
);
|
|
75
|
+
module.exports = withSentryConfig(module.exports, ${withSentryConfigOptionsTemplate});
|
|
80
76
|
`;
|
|
81
77
|
}
|
|
82
78
|
exports.getNextjsConfigCjsAppendix = getNextjsConfigCjsAppendix;
|
|
@@ -86,10 +82,7 @@ function getNextjsConfigEsmCopyPasteSnippet(withSentryConfigOptionsTemplate) {
|
|
|
86
82
|
// next.config.mjs
|
|
87
83
|
import { withSentryConfig } from "@sentry/nextjs";
|
|
88
84
|
|
|
89
|
-
export default withSentryConfig(
|
|
90
|
-
yourNextConfig,
|
|
91
|
-
${withSentryConfigOptionsTemplate}
|
|
92
|
-
);
|
|
85
|
+
export default withSentryConfig(yourNextConfig, ${withSentryConfigOptionsTemplate});
|
|
93
86
|
`;
|
|
94
87
|
}
|
|
95
88
|
exports.getNextjsConfigEsmCopyPasteSnippet = getNextjsConfigEsmCopyPasteSnippet;
|
|
@@ -98,9 +91,7 @@ function getClientIntegrationsSnippet(features) {
|
|
|
98
91
|
return `
|
|
99
92
|
|
|
100
93
|
// Add optional integrations for additional features
|
|
101
|
-
integrations: [
|
|
102
|
-
Sentry.replayIntegration(),
|
|
103
|
-
],`;
|
|
94
|
+
integrations: [Sentry.replayIntegration()],`;
|
|
104
95
|
}
|
|
105
96
|
return '';
|
|
106
97
|
}
|
|
@@ -200,16 +191,25 @@ Sentry.init({
|
|
|
200
191
|
sendDefaultPii: true,${spotlightOptions}
|
|
201
192
|
});
|
|
202
193
|
|
|
203
|
-
export const onRouterTransitionStart = Sentry.captureRouterTransitionStart
|
|
194
|
+
export const onRouterTransitionStart = Sentry.captureRouterTransitionStart;
|
|
195
|
+
`;
|
|
204
196
|
}
|
|
205
197
|
exports.getInstrumentationClientFileContents = getInstrumentationClientFileContents;
|
|
206
198
|
function getSentryExamplePageContents(options) {
|
|
207
199
|
const issuesPageLink = options.selfHosted
|
|
208
200
|
? `${options.sentryUrl}organizations/${options.orgSlug}/issues/?project=${options.projectId}`
|
|
209
201
|
: `https://${options.orgSlug}.sentry.io/issues/?project=${options.projectId}`;
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
202
|
+
const loggerPageLoad = options.logsEnabled
|
|
203
|
+
? `
|
|
204
|
+
Sentry.logger.info("Sentry example page loaded");`
|
|
205
|
+
: '';
|
|
206
|
+
const loggerUserAction = options.logsEnabled
|
|
207
|
+
? `
|
|
208
|
+
Sentry.logger.info("User clicked the button, throwing a sample error");`
|
|
209
|
+
: '';
|
|
210
|
+
return `${options.useClient ? '"use client";\n\n' : ''}import * as Sentry from "@sentry/nextjs";
|
|
211
|
+
import Head from "next/head";
|
|
212
|
+
import { useEffect, useState } from "react";
|
|
213
213
|
|
|
214
214
|
class SentryExampleFrontendError extends Error {
|
|
215
215
|
constructor(message${options.isTypeScript ? ': string | undefined' : ''}) {
|
|
@@ -221,11 +221,11 @@ class SentryExampleFrontendError extends Error {
|
|
|
221
221
|
export default function Page() {
|
|
222
222
|
const [hasSentError, setHasSentError] = useState(false);
|
|
223
223
|
const [isConnected, setIsConnected] = useState(true);
|
|
224
|
-
|
|
225
|
-
useEffect(() => {
|
|
224
|
+
|
|
225
|
+
useEffect(() => {${loggerPageLoad}
|
|
226
226
|
async function checkConnectivity() {
|
|
227
227
|
const result = await Sentry.diagnoseSdkConnectivity();
|
|
228
|
-
setIsConnected(result !==
|
|
228
|
+
setIsConnected(result !== "sentry-unreachable");
|
|
229
229
|
}
|
|
230
230
|
checkConnectivity();
|
|
231
231
|
}, []);
|
|
@@ -239,54 +239,80 @@ export default function Page() {
|
|
|
239
239
|
|
|
240
240
|
<main>
|
|
241
241
|
<div className="flex-spacer" />
|
|
242
|
-
<svg
|
|
243
|
-
|
|
242
|
+
<svg
|
|
243
|
+
height="40"
|
|
244
|
+
width="40"
|
|
245
|
+
fill="none"
|
|
246
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
247
|
+
role="img"
|
|
248
|
+
aria-label="Sentry logo"
|
|
249
|
+
>
|
|
250
|
+
<path
|
|
251
|
+
d="M21.85 2.995a3.698 3.698 0 0 1 1.353 1.354l16.303 28.278a3.703 3.703 0 0 1-1.354 5.053 3.694 3.694 0 0 1-1.848.496h-3.828a31.149 31.149 0 0 0 0-3.09h3.815a.61.61 0 0 0 .537-.917L20.523 5.893a.61.61 0 0 0-1.057 0l-3.739 6.494a28.948 28.948 0 0 1 9.63 10.453 28.988 28.988 0 0 1 3.499 13.78v1.542h-9.852v-1.544a19.106 19.106 0 0 0-2.182-8.85 19.08 19.08 0 0 0-6.032-6.829l-1.85 3.208a15.377 15.377 0 0 1 6.382 12.484v1.542H3.696A3.694 3.694 0 0 1 0 34.473c0-.648.17-1.286.494-1.849l2.33-4.074a8.562 8.562 0 0 1 2.689 1.536L3.158 34.17a.611.611 0 0 0 .538.917h8.448a12.481 12.481 0 0 0-6.037-9.09l-1.344-.772 4.908-8.545 1.344.77a22.16 22.16 0 0 1 7.705 7.444 22.193 22.193 0 0 1 3.316 10.193h3.699a25.892 25.892 0 0 0-3.811-12.033 25.856 25.856 0 0 0-9.046-8.796l-1.344-.772 5.269-9.136a3.698 3.698 0 0 1 3.2-1.849c.648 0 1.285.17 1.847.495Z"
|
|
252
|
+
fill="currentcolor"
|
|
253
|
+
/>
|
|
244
254
|
</svg>
|
|
245
|
-
<h1>
|
|
246
|
-
sentry-example-page
|
|
247
|
-
</h1>
|
|
255
|
+
<h1>sentry-example-page</h1>
|
|
248
256
|
|
|
249
257
|
<p className="description">
|
|
250
|
-
Click the button below, and view the sample error on the Sentry
|
|
251
|
-
|
|
252
|
-
|
|
258
|
+
Click the button below, and view the sample error on the Sentry{" "}
|
|
259
|
+
<a
|
|
260
|
+
target="_blank"
|
|
261
|
+
rel="noopener"
|
|
262
|
+
href="${issuesPageLink}"
|
|
263
|
+
>
|
|
264
|
+
Issues Page
|
|
265
|
+
</a>
|
|
266
|
+
. For more details about setting up Sentry,{" "}
|
|
267
|
+
<a
|
|
268
|
+
target="_blank"
|
|
269
|
+
rel="noopener"
|
|
270
|
+
href="https://docs.sentry.io/platforms/javascript/guides/nextjs/"
|
|
271
|
+
>
|
|
272
|
+
read our docs
|
|
273
|
+
</a>
|
|
274
|
+
.
|
|
253
275
|
</p>
|
|
254
276
|
|
|
255
277
|
<button
|
|
256
278
|
type="button"
|
|
257
|
-
onClick={async () => {
|
|
258
|
-
await Sentry.startSpan(
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
279
|
+
onClick={async () => {${loggerUserAction}
|
|
280
|
+
await Sentry.startSpan(
|
|
281
|
+
{
|
|
282
|
+
name: "Example Frontend/Backend Span",
|
|
283
|
+
op: "test",
|
|
284
|
+
},
|
|
285
|
+
async () => {
|
|
286
|
+
const res = await fetch("/api/sentry-example-api");
|
|
287
|
+
if (!res.ok) {
|
|
288
|
+
setHasSentError(true);
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
);
|
|
292
|
+
throw new SentryExampleFrontendError(
|
|
293
|
+
"This error is raised on the frontend of the example page.",
|
|
294
|
+
);
|
|
268
295
|
}}
|
|
269
296
|
disabled={!isConnected}
|
|
270
297
|
>
|
|
271
|
-
<span>
|
|
272
|
-
Throw Sample Error
|
|
273
|
-
</span>
|
|
298
|
+
<span>Throw Sample Error</span>
|
|
274
299
|
</button>
|
|
275
300
|
|
|
276
301
|
{hasSentError ? (
|
|
277
|
-
<p className="success">
|
|
278
|
-
Error sent to Sentry.
|
|
279
|
-
</p>
|
|
302
|
+
<p className="success">Error sent to Sentry.</p>
|
|
280
303
|
) : !isConnected ? (
|
|
281
304
|
<div className="connectivity-error">
|
|
282
|
-
<p>
|
|
305
|
+
<p>
|
|
306
|
+
It looks like network requests to Sentry are being blocked, which
|
|
307
|
+
will prevent errors from being captured. Try disabling your
|
|
308
|
+
ad-blocker to complete the test.
|
|
309
|
+
</p>
|
|
283
310
|
</div>
|
|
284
311
|
) : (
|
|
285
312
|
<div className="success_placeholder" />
|
|
286
313
|
)}
|
|
287
314
|
|
|
288
315
|
<div className="flex-spacer" />
|
|
289
|
-
|
|
290
316
|
</main>
|
|
291
317
|
|
|
292
318
|
<style>{\`
|
|
@@ -357,7 +383,7 @@ export default function Page() {
|
|
|
357
383
|
&:disabled {
|
|
358
384
|
cursor: not-allowed;
|
|
359
385
|
opacity: 0.6;
|
|
360
|
-
|
|
386
|
+
|
|
361
387
|
& > span {
|
|
362
388
|
transform: translateY(0);
|
|
363
389
|
border: none
|
|
@@ -405,7 +431,7 @@ export default function Page() {
|
|
|
405
431
|
text-align: center;
|
|
406
432
|
margin: 0;
|
|
407
433
|
}
|
|
408
|
-
|
|
434
|
+
|
|
409
435
|
.connectivity-error a {
|
|
410
436
|
color: #FFFFFF;
|
|
411
437
|
text-decoration: underline;
|
|
@@ -417,8 +443,17 @@ export default function Page() {
|
|
|
417
443
|
`;
|
|
418
444
|
}
|
|
419
445
|
exports.getSentryExamplePageContents = getSentryExamplePageContents;
|
|
420
|
-
function getSentryExamplePagesDirApiRoute({ isTypeScript, }) {
|
|
421
|
-
|
|
446
|
+
function getSentryExamplePagesDirApiRoute({ isTypeScript, logsEnabled, }) {
|
|
447
|
+
const sentryImport = logsEnabled
|
|
448
|
+
? `import * as Sentry from "@sentry/nextjs";
|
|
449
|
+
|
|
450
|
+
`
|
|
451
|
+
: '';
|
|
452
|
+
const loggerCall = logsEnabled
|
|
453
|
+
? ` Sentry.logger.info("Sentry example API called");
|
|
454
|
+
`
|
|
455
|
+
: '';
|
|
456
|
+
return `${sentryImport}// Custom error class for Sentry testing
|
|
422
457
|
class SentryExampleAPIError extends Error {
|
|
423
458
|
constructor(message${isTypeScript ? ': string | undefined' : ''}) {
|
|
424
459
|
super(message);
|
|
@@ -427,26 +462,37 @@ class SentryExampleAPIError extends Error {
|
|
|
427
462
|
}
|
|
428
463
|
// A faulty API route to test Sentry's error monitoring
|
|
429
464
|
export default function handler(_req, res) {
|
|
430
|
-
throw new SentryExampleAPIError("This error is raised on the backend called by the example page.");
|
|
465
|
+
${loggerCall}throw new SentryExampleAPIError("This error is raised on the backend called by the example page.");
|
|
431
466
|
res.status(200).json({ name: "John Doe" });
|
|
432
467
|
}
|
|
433
468
|
`;
|
|
434
469
|
}
|
|
435
470
|
exports.getSentryExamplePagesDirApiRoute = getSentryExamplePagesDirApiRoute;
|
|
436
|
-
function getSentryExampleAppDirApiRoute({ isTypeScript, }) {
|
|
437
|
-
|
|
471
|
+
function getSentryExampleAppDirApiRoute({ isTypeScript, logsEnabled, }) {
|
|
472
|
+
const sentryImport = logsEnabled
|
|
473
|
+
? `import * as Sentry from "@sentry/nextjs";
|
|
474
|
+
`
|
|
475
|
+
: '';
|
|
476
|
+
const loggerCall = logsEnabled
|
|
477
|
+
? `
|
|
478
|
+
Sentry.logger.info("Sentry example API called");`
|
|
479
|
+
: '';
|
|
480
|
+
// Note: We intentionally don't have a return statement after throw - it would be unreachable code
|
|
481
|
+
// We also don't import NextResponse since we don't use it (Biome noUnusedImports rule)
|
|
482
|
+
return `${sentryImport}export const dynamic = "force-dynamic";
|
|
438
483
|
|
|
439
|
-
export const dynamic = "force-dynamic";
|
|
440
484
|
class SentryExampleAPIError extends Error {
|
|
441
485
|
constructor(message${isTypeScript ? ': string | undefined' : ''}) {
|
|
442
486
|
super(message);
|
|
443
487
|
this.name = "SentryExampleAPIError";
|
|
444
488
|
}
|
|
445
489
|
}
|
|
490
|
+
|
|
446
491
|
// A faulty API route to test Sentry's error monitoring
|
|
447
|
-
export function GET() {
|
|
448
|
-
throw new SentryExampleAPIError(
|
|
449
|
-
|
|
492
|
+
export function GET() {${loggerCall}
|
|
493
|
+
throw new SentryExampleAPIError(
|
|
494
|
+
"This error is raised on the backend called by the example page.",
|
|
495
|
+
);
|
|
450
496
|
}
|
|
451
497
|
`;
|
|
452
498
|
}
|
|
@@ -522,15 +568,15 @@ YourCustomErrorComponent.getInitialProps = async (contextData${isTs ? ': NextPag
|
|
|
522
568
|
}
|
|
523
569
|
exports.getFullUnderscoreErrorCopyPasteSnippet = getFullUnderscoreErrorCopyPasteSnippet;
|
|
524
570
|
function getInstrumentationHookContent(instrumentationHookLocation) {
|
|
525
|
-
return `import * as Sentry from
|
|
571
|
+
return `import * as Sentry from "@sentry/nextjs";
|
|
526
572
|
|
|
527
573
|
export async function register() {
|
|
528
|
-
if (process.env.NEXT_RUNTIME ===
|
|
529
|
-
await import(
|
|
574
|
+
if (process.env.NEXT_RUNTIME === "nodejs") {
|
|
575
|
+
await import("${instrumentationHookLocation === 'root' ? '.' : '..'}/sentry.server.config");
|
|
530
576
|
}
|
|
531
577
|
|
|
532
|
-
if (process.env.NEXT_RUNTIME ===
|
|
533
|
-
await import(
|
|
578
|
+
if (process.env.NEXT_RUNTIME === "edge") {
|
|
579
|
+
await import("${instrumentationHookLocation === 'root' ? '.' : '..'}/sentry.edge.config");
|
|
534
580
|
}
|
|
535
581
|
}
|
|
536
582
|
|
|
@@ -558,7 +604,7 @@ ${plus('export const onRequestError = Sentry.captureRequestError;')}
|
|
|
558
604
|
}
|
|
559
605
|
exports.getInstrumentationHookCopyPasteSnippet = getInstrumentationHookCopyPasteSnippet;
|
|
560
606
|
function getInstrumentationClientHookCopyPasteSnippet(dsn, selectedFeaturesMap, spotlight = false) {
|
|
561
|
-
return (0, clack_1.makeCodeSnippet)(true, (
|
|
607
|
+
return (0, clack_1.makeCodeSnippet)(true, (_unchanged, plus) => {
|
|
562
608
|
return plus(getInstrumentationClientFileContents(dsn, selectedFeaturesMap, spotlight));
|
|
563
609
|
});
|
|
564
610
|
}
|
|
@@ -571,13 +617,17 @@ import * as Sentry from "@sentry/nextjs";
|
|
|
571
617
|
import NextError from "next/error";
|
|
572
618
|
import { useEffect } from "react";
|
|
573
619
|
|
|
574
|
-
export default function GlobalError({
|
|
620
|
+
export default function GlobalError({
|
|
621
|
+
error,
|
|
622
|
+
}: {
|
|
623
|
+
error: Error & { digest?: string };
|
|
624
|
+
}) {
|
|
575
625
|
useEffect(() => {
|
|
576
626
|
Sentry.captureException(error);
|
|
577
627
|
}, [error]);
|
|
578
628
|
|
|
579
629
|
return (
|
|
580
|
-
<html>
|
|
630
|
+
<html lang="en">
|
|
581
631
|
<body>
|
|
582
632
|
{/* \`NextError\` is the default Next.js error page component. Its type
|
|
583
633
|
definition requires a \`statusCode\` prop. However, since the App Router
|
|
@@ -587,7 +637,8 @@ export default function GlobalError({ error }: { error: Error & { digest?: strin
|
|
|
587
637
|
</body>
|
|
588
638
|
</html>
|
|
589
639
|
);
|
|
590
|
-
}
|
|
640
|
+
}
|
|
641
|
+
`
|
|
591
642
|
: `"use client";
|
|
592
643
|
|
|
593
644
|
import * as Sentry from "@sentry/nextjs";
|
|
@@ -600,7 +651,7 @@ export default function GlobalError({ error }) {
|
|
|
600
651
|
}, [error]);
|
|
601
652
|
|
|
602
653
|
return (
|
|
603
|
-
<html>
|
|
654
|
+
<html lang="en">
|
|
604
655
|
<body>
|
|
605
656
|
{/* \`NextError\` is the default Next.js error page component. Its type
|
|
606
657
|
definition requires a \`statusCode\` prop. However, since the App Router
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../../src/nextjs/templates.ts"],"names":[],"mappings":"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","sourcesContent":["import chalk from 'chalk';\nimport { makeCodeSnippet } from '../utils/clack';\n\ntype WithSentryConfigOptions = {\n orgSlug: string;\n projectSlug: string;\n selfHosted: boolean;\n sentryUrl: string;\n tunnelRoute: boolean;\n};\n\nexport function getWithSentryConfigOptionsTemplate({\n orgSlug,\n projectSlug,\n selfHosted,\n tunnelRoute,\n sentryUrl,\n}: WithSentryConfigOptions): string {\n return `{\n // For all available options, see:\n // https://www.npmjs.com/package/@sentry/webpack-plugin#options\n\n org: \"${orgSlug}\",\n project: \"${projectSlug}\",${\n selfHosted ? `\\n sentryUrl: \"${sentryUrl}\",` : ''\n }\n\n // Only print logs for uploading source maps in CI\n silent: !process.env.CI,\n\n // For all available options, see:\n // https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/\n\n // Upload a larger set of source maps for prettier stack traces (increases build time)\n widenClientFileUpload: true,\n\n // ${\n tunnelRoute ? 'Route' : 'Uncomment to route'\n } browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers.\n // This can increase your server load as well as your hosting bill.\n // Note: Check that the configured route will not match with your Next.js middleware, otherwise reporting of client-\n // side errors will fail.\n ${tunnelRoute ? '' : '// '}tunnelRoute: \"/monitoring\",\n\n // Automatically tree-shake Sentry logger statements to reduce bundle size\n disableLogger: true,\n\n // Enables automatic instrumentation of Vercel Cron Monitors. (Does not yet work with App Router route handlers.)\n // See the following for more information:\n // https://docs.sentry.io/product/crons/\n // https://vercel.com/docs/cron-jobs\n automaticVercelMonitors: true,\n }`;\n}\n\nexport function getNextjsConfigCjsTemplate(\n withSentryConfigOptionsTemplate: string,\n): string {\n return `const { withSentryConfig } = require(\"@sentry/nextjs\");\n\n/** @type {import('next').NextConfig} */\nconst nextConfig = {};\n\nmodule.exports = withSentryConfig(\n nextConfig,\n ${withSentryConfigOptionsTemplate}\n);\n`;\n}\n\nexport function getNextjsConfigMjsTemplate(\n withSentryConfigOptionsTemplate: string,\n): string {\n return `import { withSentryConfig } from \"@sentry/nextjs\";\n\n/** @type {import('next').NextConfig} */\nconst nextConfig = {};\n\nexport default withSentryConfig(\n nextConfig,\n ${withSentryConfigOptionsTemplate}\n);\n`;\n}\n\nexport function getNextjsConfigCjsAppendix(\n withSentryConfigOptionsTemplate: string,\n): string {\n return `\n\n// Injected content via Sentry wizard below\n\nconst { withSentryConfig } = require(\"@sentry/nextjs\");\n\nmodule.exports = withSentryConfig(\n module.exports,\n ${withSentryConfigOptionsTemplate}\n);\n`;\n}\n\nexport function getNextjsConfigEsmCopyPasteSnippet(\n withSentryConfigOptionsTemplate: string,\n): string {\n return `\n\n// next.config.mjs\nimport { withSentryConfig } from \"@sentry/nextjs\";\n\nexport default withSentryConfig(\n yourNextConfig,\n ${withSentryConfigOptionsTemplate}\n);\n`;\n}\n\nfunction getClientIntegrationsSnippet(features: { replay: boolean }) {\n if (features.replay) {\n return `\n\n // Add optional integrations for additional features\n integrations: [\n Sentry.replayIntegration(),\n ],`;\n }\n\n return '';\n}\n\nfunction getSpotlightOption(spotlight: boolean): string {\n if (!spotlight) {\n return '';\n }\n\n return `\n\n // Spotlight enabled for local development (https://spotlightjs.com)\n spotlight: true,`;\n}\n\nexport function getSentryServersideConfigContents(\n dsn: string,\n config: 'server' | 'edge',\n selectedFeaturesMap: {\n replay: boolean;\n performance: boolean;\n logs: boolean;\n },\n spotlight = false,\n): string {\n let primer = '';\n if (config === 'server') {\n primer = `// This file configures the initialization of Sentry on the server.\n// The config you add here will be used whenever the server handles a request.\n// https://docs.sentry.io/platforms/javascript/guides/nextjs/`;\n } else if (config === 'edge') {\n primer = `// This file configures the initialization of Sentry for edge features (middleware, edge routes, and so on).\n// The config you add here will be used whenever one of the edge features is loaded.\n// Note that this config is unrelated to the Vercel Edge Runtime and is also required when running locally.\n// https://docs.sentry.io/platforms/javascript/guides/nextjs/`;\n }\n\n let performanceOptions = '';\n if (selectedFeaturesMap.performance) {\n performanceOptions += `\n\n // Define how likely traces are sampled. Adjust this value in production, or use tracesSampler for greater control.\n tracesSampleRate: 1,`;\n }\n\n let logsOptions = '';\n if (selectedFeaturesMap.logs) {\n logsOptions += `\n\n // Enable logs to be sent to Sentry\n enableLogs: true,`;\n }\n\n const spotlightOptions = getSpotlightOption(spotlight);\n\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n return `${primer}\n\nimport * as Sentry from \"@sentry/nextjs\";\n\nSentry.init({\n dsn: \"${dsn}\",${performanceOptions}${logsOptions}\n\n // Enable sending user PII (Personally Identifiable Information)\n // https://docs.sentry.io/platforms/javascript/guides/nextjs/configuration/options/#sendDefaultPii\n sendDefaultPii: true,${spotlightOptions}\n});\n`;\n}\n\nexport function getInstrumentationClientFileContents(\n dsn: string,\n selectedFeaturesMap: {\n replay: boolean;\n performance: boolean;\n logs: boolean;\n },\n spotlight = false,\n): string {\n const integrationsOptions = getClientIntegrationsSnippet({\n replay: selectedFeaturesMap.replay,\n });\n\n let replayOptions = '';\n\n if (selectedFeaturesMap.replay) {\n replayOptions += `\n\n // Define how likely Replay events are sampled.\n // This sets the sample rate to be 10%. You may want this to be 100% while\n // in development and sample at a lower rate in production\n replaysSessionSampleRate: 0.1,\n\n // Define how likely Replay events are sampled when an error occurs.\n replaysOnErrorSampleRate: 1.0,`;\n }\n\n let performanceOptions = '';\n if (selectedFeaturesMap.performance) {\n performanceOptions += `\n\n // Define how likely traces are sampled. Adjust this value in production, or use tracesSampler for greater control.\n tracesSampleRate: 1,`;\n }\n\n let logsOptions = '';\n if (selectedFeaturesMap.logs) {\n logsOptions += `\n // Enable logs to be sent to Sentry\n enableLogs: true,`;\n }\n\n const spotlightOptions = getSpotlightOption(spotlight);\n\n return `// This file configures the initialization of Sentry on the client.\n// The added config here will be used whenever a users loads a page in their browser.\n// https://docs.sentry.io/platforms/javascript/guides/nextjs/\n\nimport * as Sentry from \"@sentry/nextjs\";\n\nSentry.init({\n dsn: \"${dsn}\",${integrationsOptions}${performanceOptions}${logsOptions}${replayOptions}\n\n // Enable sending user PII (Personally Identifiable Information)\n // https://docs.sentry.io/platforms/javascript/guides/nextjs/configuration/options/#sendDefaultPii\n sendDefaultPii: true,${spotlightOptions}\n});\n\nexport const onRouterTransitionStart = Sentry.captureRouterTransitionStart;`;\n}\n\nexport function getSentryExamplePageContents(options: {\n selfHosted: boolean;\n sentryUrl: string;\n orgSlug: string;\n projectId: string;\n useClient: boolean;\n isTypeScript?: boolean;\n}): string {\n const issuesPageLink = options.selfHosted\n ? `${options.sentryUrl}organizations/${options.orgSlug}/issues/?project=${options.projectId}`\n : `https://${options.orgSlug}.sentry.io/issues/?project=${options.projectId}`;\n\n return `${\n options.useClient ? '\"use client\";\\n\\n' : ''\n }import Head from \"next/head\";\nimport * as Sentry from \"@sentry/nextjs\";\nimport { useState, useEffect } from \"react\";\n\nclass SentryExampleFrontendError extends Error {\n constructor(message${options.isTypeScript ? ': string | undefined' : ''}) {\n super(message);\n this.name = \"SentryExampleFrontendError\";\n }\n}\n\nexport default function Page() {\n const [hasSentError, setHasSentError] = useState(false);\n const [isConnected, setIsConnected] = useState(true);\n \n useEffect(() => {\n async function checkConnectivity() {\n const result = await Sentry.diagnoseSdkConnectivity();\n setIsConnected(result !== 'sentry-unreachable');\n }\n checkConnectivity();\n }, []);\n\n return (\n <div>\n <Head>\n <title>sentry-example-page</title>\n <meta name=\"description\" content=\"Test Sentry for your Next.js app!\" />\n </Head>\n\n <main>\n <div className=\"flex-spacer\" />\n <svg height=\"40\" width=\"40\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M21.85 2.995a3.698 3.698 0 0 1 1.353 1.354l16.303 28.278a3.703 3.703 0 0 1-1.354 5.053 3.694 3.694 0 0 1-1.848.496h-3.828a31.149 31.149 0 0 0 0-3.09h3.815a.61.61 0 0 0 .537-.917L20.523 5.893a.61.61 0 0 0-1.057 0l-3.739 6.494a28.948 28.948 0 0 1 9.63 10.453 28.988 28.988 0 0 1 3.499 13.78v1.542h-9.852v-1.544a19.106 19.106 0 0 0-2.182-8.85 19.08 19.08 0 0 0-6.032-6.829l-1.85 3.208a15.377 15.377 0 0 1 6.382 12.484v1.542H3.696A3.694 3.694 0 0 1 0 34.473c0-.648.17-1.286.494-1.849l2.33-4.074a8.562 8.562 0 0 1 2.689 1.536L3.158 34.17a.611.611 0 0 0 .538.917h8.448a12.481 12.481 0 0 0-6.037-9.09l-1.344-.772 4.908-8.545 1.344.77a22.16 22.16 0 0 1 7.705 7.444 22.193 22.193 0 0 1 3.316 10.193h3.699a25.892 25.892 0 0 0-3.811-12.033 25.856 25.856 0 0 0-9.046-8.796l-1.344-.772 5.269-9.136a3.698 3.698 0 0 1 3.2-1.849c.648 0 1.285.17 1.847.495Z\" fill=\"currentcolor\"/>\n </svg>\n <h1>\n sentry-example-page\n </h1>\n\n <p className=\"description\">\n Click the button below, and view the sample error on the Sentry <a target=\"_blank\" href=\"${issuesPageLink}\">Issues Page</a>.\n For more details about setting up Sentry, <a target=\"_blank\"\n href=\"https://docs.sentry.io/platforms/javascript/guides/nextjs/\">read our docs</a>.\n </p>\n\n <button\n type=\"button\"\n onClick={async () => {\n await Sentry.startSpan({\n name: 'Example Frontend/Backend Span',\n op: 'test'\n }, async () => {\n const res = await fetch(\"/api/sentry-example-api\");\n if (!res.ok) {\n setHasSentError(true);\n }\n });\n throw new SentryExampleFrontendError(\"This error is raised on the frontend of the example page.\");\n }}\n disabled={!isConnected}\n >\n <span>\n Throw Sample Error\n </span>\n </button>\n\n {hasSentError ? (\n <p className=\"success\">\n Error sent to Sentry.\n </p>\n ) : !isConnected ? (\n <div className=\"connectivity-error\">\n <p>It looks like network requests to Sentry are being blocked, which will prevent errors from being captured. Try disabling your ad-blocker to complete the test.</p>\n </div>\n ) : (\n <div className=\"success_placeholder\" />\n )}\n\n <div className=\"flex-spacer\" />\n \n </main>\n\n <style>{\\`\n main {\n display: flex;\n min-height: 100vh;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n gap: 16px;\n padding: 16px;\n font-family: system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", sans-serif;\n }\n\n h1 {\n padding: 0px 4px;\n border-radius: 4px;\n background-color: rgba(24, 20, 35, 0.03);\n font-family: monospace;\n font-size: 20px;\n line-height: 1.2;\n }\n\n p {\n margin: 0;\n font-size: 20px;\n }\n\n a {\n color: #6341F0;\n text-decoration: underline;\n cursor: pointer;\n\n @media (prefers-color-scheme: dark) {\n color: #B3A1FF;\n }\n }\n\n button {\n border-radius: 8px;\n color: white;\n cursor: pointer;\n background-color: #553DB8;\n border: none;\n padding: 0;\n margin-top: 4px;\n\n & > span {\n display: inline-block;\n padding: 12px 16px;\n border-radius: inherit;\n font-size: 20px;\n font-weight: bold;\n line-height: 1;\n background-color: #7553FF;\n border: 1px solid #553DB8;\n transform: translateY(-4px);\n }\n\n &:hover > span {\n transform: translateY(-8px);\n }\n\n &:active > span {\n transform: translateY(0);\n }\n\n &:disabled {\n\t cursor: not-allowed;\n\t opacity: 0.6;\n\t\n\t & > span {\n\t transform: translateY(0);\n\t border: none\n\t }\n\t }\n }\n\n .description {\n text-align: center;\n color: #6E6C75;\n max-width: 500px;\n line-height: 1.5;\n font-size: 20px;\n\n @media (prefers-color-scheme: dark) {\n color: #A49FB5;\n }\n }\n\n .flex-spacer {\n flex: 1;\n }\n\n .success {\n padding: 12px 16px;\n border-radius: 8px;\n font-size: 20px;\n line-height: 1;\n background-color: #00F261;\n border: 1px solid #00BF4D;\n color: #181423;\n }\n\n .success_placeholder {\n height: 46px;\n }\n\n .connectivity-error {\n padding: 12px 16px;\n background-color: #E50045;\n border-radius: 8px;\n width: 500px;\n color: #FFFFFF;\n border: 1px solid #A80033;\n text-align: center;\n margin: 0;\n }\n \n .connectivity-error a {\n color: #FFFFFF;\n text-decoration: underline;\n }\n \\`}</style>\n </div>\n );\n}\n`;\n}\n\nexport function getSentryExamplePagesDirApiRoute({\n isTypeScript,\n}: {\n isTypeScript: boolean;\n}) {\n return `// Custom error class for Sentry testing\nclass SentryExampleAPIError extends Error {\n constructor(message${isTypeScript ? ': string | undefined' : ''}) {\n super(message);\n this.name = \"SentryExampleAPIError\";\n }\n}\n// A faulty API route to test Sentry's error monitoring\nexport default function handler(_req, res) {\nthrow new SentryExampleAPIError(\"This error is raised on the backend called by the example page.\");\nres.status(200).json({ name: \"John Doe\" });\n}\n`;\n}\n\nexport function getSentryExampleAppDirApiRoute({\n isTypeScript,\n}: {\n isTypeScript: boolean;\n}) {\n return `import { NextResponse } from \"next/server\";\n\nexport const dynamic = \"force-dynamic\";\nclass SentryExampleAPIError extends Error {\n constructor(message${isTypeScript ? ': string | undefined' : ''}) {\n super(message);\n this.name = \"SentryExampleAPIError\";\n }\n}\n// A faulty API route to test Sentry's error monitoring\nexport function GET() {\n throw new SentryExampleAPIError(\"This error is raised on the backend called by the example page.\");\n return NextResponse.json({ data: \"Testing Sentry Error...\" });\n}\n`;\n}\n\nexport function getSentryDefaultUnderscoreErrorPage() {\n return `import * as Sentry from \"@sentry/nextjs\";\nimport Error from \"next/error\";\n\nconst CustomErrorComponent = (props) => {\n return <Error statusCode={props.statusCode} />;\n};\n\nCustomErrorComponent.getInitialProps = async (contextData) => {\n // In case this is running in a serverless function, await this in order to give Sentry\n // time to send the error before the lambda exits\n await Sentry.captureUnderscoreErrorException(contextData);\n\n // This will contain the status code of the response\n return Error.getInitialProps(contextData);\n};\n\nexport default CustomErrorComponent;\n`;\n}\n\nexport function getSimpleUnderscoreErrorCopyPasteSnippet() {\n return `\n${chalk.green(`import * as Sentry from '@sentry/nextjs';`)}\n${chalk.green(`import Error from \"next/error\";`)}\n\n${chalk.dim(\n '// Replace \"YourCustomErrorComponent\" with your custom error component!',\n)}\nYourCustomErrorComponent.getInitialProps = async (${chalk.green(\n 'contextData',\n )}) => {\n ${chalk.green('await Sentry.captureUnderscoreErrorException(contextData);')}\n\n ${chalk.dim('// ...other getInitialProps code')}\n\n return Error.getInitialProps(contextData);\n};\n`;\n}\n\nexport function getGenerateMetadataSnippet(isTs: boolean) {\n return makeCodeSnippet(true, (unchanged, plus) => {\n return plus(`\n import * as Sentry from '@sentry/nextjs';\n ${isTs ? `import type { Metadata } from 'next';` : ''}\n\n ${unchanged(\n '// Add or edit your \"generateMetadata\" to include the Sentry trace data:',\n )}\n export function generateMetadata()${isTs ? ': Metadata' : ''} {\n return {\n // ... your existing metadata\n other: {\n ...Sentry.getTraceData()\n }\n };\n }\n`);\n });\n}\n\nexport function getFullUnderscoreErrorCopyPasteSnippet(isTs: boolean) {\n return `\nimport * as Sentry from '@sentry/nextjs';${\n isTs ? '\\nimport type { NextPageContext } from \"next\";' : ''\n }\nimport Error from \"next/error\";\n\n${chalk.dim(\n '// Replace \"YourCustomErrorComponent\" with your custom error component!',\n)}\nYourCustomErrorComponent.getInitialProps = async (contextData${\n isTs ? ': NextPageContext' : ''\n }) => {\n await Sentry.captureUnderscoreErrorException(contextData);\n\n return Error.getInitialProps(contextData);\n};\n`;\n}\n\nexport function getInstrumentationHookContent(\n instrumentationHookLocation: 'src' | 'root',\n) {\n return `import * as Sentry from '@sentry/nextjs';\n\nexport async function register() {\n if (process.env.NEXT_RUNTIME === 'nodejs') {\n await import('${\n instrumentationHookLocation === 'root' ? '.' : '..'\n }/sentry.server.config');\n }\n\n if (process.env.NEXT_RUNTIME === 'edge') {\n await import('${\n instrumentationHookLocation === 'root' ? '.' : '..'\n }/sentry.edge.config');\n }\n}\n\nexport const onRequestError = Sentry.captureRequestError;\n`;\n}\n\nexport function getInstrumentationHookCopyPasteSnippet(\n instrumentationHookLocation: 'src' | 'root',\n) {\n return makeCodeSnippet(true, (unchanged, plus) => {\n return unchanged(`${plus(\"import * as Sentry from '@sentry/nextjs';\")}\n\nexport ${plus('async')} function register() {\n ${plus(`if (process.env.NEXT_RUNTIME === 'nodejs') {\n await import('${\n instrumentationHookLocation === 'root' ? '.' : '..'\n }/sentry.server.config');\n }\n\n if (process.env.NEXT_RUNTIME === 'edge') {\n await import('${\n instrumentationHookLocation === 'root' ? '.' : '..'\n }/sentry.edge.config');\n }`)}\n}\n\n${plus('export const onRequestError = Sentry.captureRequestError;')}\n`);\n });\n}\n\nexport function getInstrumentationClientHookCopyPasteSnippet(\n dsn: string,\n selectedFeaturesMap: {\n replay: boolean;\n performance: boolean;\n logs: boolean;\n },\n spotlight = false,\n) {\n return makeCodeSnippet(true, (unchanged, plus) => {\n return plus(\n getInstrumentationClientFileContents(dsn, selectedFeaturesMap, spotlight),\n );\n });\n}\n\nexport function getSentryDefaultGlobalErrorPage(isTs: boolean) {\n return isTs\n ? `\"use client\";\n\nimport * as Sentry from \"@sentry/nextjs\";\nimport NextError from \"next/error\";\nimport { useEffect } from \"react\";\n\nexport default function GlobalError({ error }: { error: Error & { digest?: string } }) {\n useEffect(() => {\n Sentry.captureException(error);\n }, [error]);\n\n return (\n <html>\n <body>\n {/* \\`NextError\\` is the default Next.js error page component. Its type\n definition requires a \\`statusCode\\` prop. However, since the App Router\n does not expose status codes for errors, we simply pass 0 to render a\n generic error message. */}\n <NextError statusCode={0} />\n </body>\n </html>\n );\n}`\n : `\"use client\";\n\nimport * as Sentry from \"@sentry/nextjs\";\nimport NextError from \"next/error\";\nimport { useEffect } from \"react\";\n\nexport default function GlobalError({ error }) {\n useEffect(() => {\n Sentry.captureException(error);\n }, [error]);\n\n return (\n <html>\n <body>\n {/* \\`NextError\\` is the default Next.js error page component. Its type\n definition requires a \\`statusCode\\` prop. However, since the App Router\n does not expose status codes for errors, we simply pass 0 to render a\n generic error message. */}\n <NextError statusCode={0} />\n </body>\n </html>\n );\n}\n`;\n}\n\nexport function getGlobalErrorCopyPasteSnippet(isTs: boolean) {\n if (isTs) {\n return `\"use client\";\n\n${chalk.green('import * as Sentry from \"@sentry/nextjs\";')}\n${chalk.green('import Error from \"next/error\";')}\n${chalk.green('import { useEffect } from \"react\";')}\n\nexport default function GlobalError(${chalk.green(\n '{ error }: { error: Error }',\n )}) {\n ${chalk.green(`useEffect(() => {\n Sentry.captureException(error);\n }, [error]);`)}\n\n return (\n <html>\n <body>\n {/* Your Error component here... */}\n </body>\n </html>\n );\n}\n`;\n }\n return `\"use client\";\n\n${chalk.green('import * as Sentry from \"@sentry/nextjs\";')}\n${chalk.green('import Error from \"next/error\";')}\n${chalk.green('import { useEffect } from \"react\";')}\n\nexport default function GlobalError(${chalk.green('{ error }')}) {\n ${chalk.green(`useEffect(() => {\n Sentry.captureException(error);\n }, [error]);`)}\n\n return (\n <html>\n <body>\n {/* Your Error component here... */}\n </body>\n </html>\n );\n}\n`;\n}\n\nexport const getRootLayout = (\n isTs: boolean,\n) => `// This file was generated by the Sentry wizard because we couldn't find a root layout file.\n// You can delete this file at any time.\n\nexport const metadata = {\n title: 'Sentry NextJS Example',\n description: 'Generated by Sentry',\n}\n\nexport default function RootLayout({\n children,\n}${\n isTs\n ? `: {\n children: React.ReactNode\n}`\n : ''\n}) {\n return (\n <html lang=\"en\">\n <body>{children}</body>\n </html>\n )\n}\n`;\n\nexport const getRootLayoutWithGenerateMetadata = (\n isTs: boolean,\n) => `// This file was generated by the Sentry wizard because we couldn't find a root layout file.\nimport * as Sentry from '@sentry/nextjs';\n${isTs ? `import type { Metadata } from 'next';` : ''}\n\nexport function generateMetadata()${isTs ? ': Metadata' : ''} {\n return {\n other: {\n ...Sentry.getTraceData(),\n }\n }\n};\n\nexport default function RootLayout({\n children,\n}${\n isTs\n ? `: {\n children: React.ReactNode\n}`\n : ''\n}) {\n return (\n <html lang=\"en\">\n <body>{children}</body>\n </html>\n )\n}\n`;\n"]}
|
|
1
|
+
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../../src/nextjs/templates.ts"],"names":[],"mappings":"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","sourcesContent":["import chalk from 'chalk';\nimport { makeCodeSnippet } from '../utils/clack';\n\ntype WithSentryConfigOptions = {\n orgSlug: string;\n projectSlug: string;\n selfHosted: boolean;\n sentryUrl: string;\n tunnelRoute: boolean;\n};\n\nexport function getWithSentryConfigOptionsTemplate({\n orgSlug,\n projectSlug,\n selfHosted,\n tunnelRoute,\n sentryUrl,\n}: WithSentryConfigOptions): string {\n return `{\n // For all available options, see:\n // https://www.npmjs.com/package/@sentry/webpack-plugin#options\n\n org: \"${orgSlug}\",\n project: \"${projectSlug}\",${\n selfHosted ? `\\n sentryUrl: \"${sentryUrl}\",` : ''\n }\n\n // Only print logs for uploading source maps in CI\n silent: !process.env.CI,\n\n // For all available options, see:\n // https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/\n\n // Upload a larger set of source maps for prettier stack traces (increases build time)\n widenClientFileUpload: true,\n\n // ${\n tunnelRoute ? 'Route' : 'Uncomment to route'\n } browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers.\n // This can increase your server load as well as your hosting bill.\n // Note: Check that the configured route will not match with your Next.js middleware, otherwise reporting of client-\n // side errors will fail.\n ${tunnelRoute ? '' : '// '}tunnelRoute: \"/monitoring\",\n\n webpack: {\n // Enables automatic instrumentation of Vercel Cron Monitors. (Does not yet work with App Router route handlers.)\n // See the following for more information:\n // https://docs.sentry.io/product/crons/\n // https://vercel.com/docs/cron-jobs\n automaticVercelMonitors: true,\n\n // Tree-shaking options for reducing bundle size\n treeshake: {\n // Automatically tree-shake Sentry logger statements to reduce bundle size\n removeDebugLogging: true,\n },\n },\n}`;\n}\n\nexport function getNextjsConfigCjsTemplate(\n withSentryConfigOptionsTemplate: string,\n): string {\n return `const { withSentryConfig } = require(\"@sentry/nextjs\");\n\n/** @type {import('next').NextConfig} */\nconst nextConfig = {};\n\nmodule.exports = withSentryConfig(nextConfig, ${withSentryConfigOptionsTemplate});\n`;\n}\n\nexport function getNextjsConfigMjsTemplate(\n withSentryConfigOptionsTemplate: string,\n): string {\n return `import { withSentryConfig } from \"@sentry/nextjs\";\n\n/** @type {import('next').NextConfig} */\nconst nextConfig = {};\n\nexport default withSentryConfig(nextConfig, ${withSentryConfigOptionsTemplate});\n`;\n}\n\nexport function getNextjsConfigCjsAppendix(\n withSentryConfigOptionsTemplate: string,\n): string {\n return `\n\n// Injected content via Sentry wizard below\n\nconst { withSentryConfig } = require(\"@sentry/nextjs\");\n\nmodule.exports = withSentryConfig(module.exports, ${withSentryConfigOptionsTemplate});\n`;\n}\n\nexport function getNextjsConfigEsmCopyPasteSnippet(\n withSentryConfigOptionsTemplate: string,\n): string {\n return `\n\n// next.config.mjs\nimport { withSentryConfig } from \"@sentry/nextjs\";\n\nexport default withSentryConfig(yourNextConfig, ${withSentryConfigOptionsTemplate});\n`;\n}\n\nfunction getClientIntegrationsSnippet(features: { replay: boolean }) {\n if (features.replay) {\n return `\n\n // Add optional integrations for additional features\n integrations: [Sentry.replayIntegration()],`;\n }\n\n return '';\n}\n\nfunction getSpotlightOption(spotlight: boolean): string {\n if (!spotlight) {\n return '';\n }\n\n return `\n\n // Spotlight enabled for local development (https://spotlightjs.com)\n spotlight: true,`;\n}\n\nexport function getSentryServersideConfigContents(\n dsn: string,\n config: 'server' | 'edge',\n selectedFeaturesMap: {\n replay: boolean;\n performance: boolean;\n logs: boolean;\n },\n spotlight = false,\n): string {\n let primer = '';\n if (config === 'server') {\n primer = `// This file configures the initialization of Sentry on the server.\n// The config you add here will be used whenever the server handles a request.\n// https://docs.sentry.io/platforms/javascript/guides/nextjs/`;\n } else if (config === 'edge') {\n primer = `// This file configures the initialization of Sentry for edge features (middleware, edge routes, and so on).\n// The config you add here will be used whenever one of the edge features is loaded.\n// Note that this config is unrelated to the Vercel Edge Runtime and is also required when running locally.\n// https://docs.sentry.io/platforms/javascript/guides/nextjs/`;\n }\n\n let performanceOptions = '';\n if (selectedFeaturesMap.performance) {\n performanceOptions += `\n\n // Define how likely traces are sampled. Adjust this value in production, or use tracesSampler for greater control.\n tracesSampleRate: 1,`;\n }\n\n let logsOptions = '';\n if (selectedFeaturesMap.logs) {\n logsOptions += `\n\n // Enable logs to be sent to Sentry\n enableLogs: true,`;\n }\n\n const spotlightOptions = getSpotlightOption(spotlight);\n\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n return `${primer}\n\nimport * as Sentry from \"@sentry/nextjs\";\n\nSentry.init({\n dsn: \"${dsn}\",${performanceOptions}${logsOptions}\n\n // Enable sending user PII (Personally Identifiable Information)\n // https://docs.sentry.io/platforms/javascript/guides/nextjs/configuration/options/#sendDefaultPii\n sendDefaultPii: true,${spotlightOptions}\n});\n`;\n}\n\nexport function getInstrumentationClientFileContents(\n dsn: string,\n selectedFeaturesMap: {\n replay: boolean;\n performance: boolean;\n logs: boolean;\n },\n spotlight = false,\n): string {\n const integrationsOptions = getClientIntegrationsSnippet({\n replay: selectedFeaturesMap.replay,\n });\n\n let replayOptions = '';\n\n if (selectedFeaturesMap.replay) {\n replayOptions += `\n\n // Define how likely Replay events are sampled.\n // This sets the sample rate to be 10%. You may want this to be 100% while\n // in development and sample at a lower rate in production\n replaysSessionSampleRate: 0.1,\n\n // Define how likely Replay events are sampled when an error occurs.\n replaysOnErrorSampleRate: 1.0,`;\n }\n\n let performanceOptions = '';\n if (selectedFeaturesMap.performance) {\n performanceOptions += `\n\n // Define how likely traces are sampled. Adjust this value in production, or use tracesSampler for greater control.\n tracesSampleRate: 1,`;\n }\n\n let logsOptions = '';\n if (selectedFeaturesMap.logs) {\n logsOptions += `\n // Enable logs to be sent to Sentry\n enableLogs: true,`;\n }\n\n const spotlightOptions = getSpotlightOption(spotlight);\n\n return `// This file configures the initialization of Sentry on the client.\n// The added config here will be used whenever a users loads a page in their browser.\n// https://docs.sentry.io/platforms/javascript/guides/nextjs/\n\nimport * as Sentry from \"@sentry/nextjs\";\n\nSentry.init({\n dsn: \"${dsn}\",${integrationsOptions}${performanceOptions}${logsOptions}${replayOptions}\n\n // Enable sending user PII (Personally Identifiable Information)\n // https://docs.sentry.io/platforms/javascript/guides/nextjs/configuration/options/#sendDefaultPii\n sendDefaultPii: true,${spotlightOptions}\n});\n\nexport const onRouterTransitionStart = Sentry.captureRouterTransitionStart;\n`;\n}\n\nexport function getSentryExamplePageContents(options: {\n selfHosted: boolean;\n sentryUrl: string;\n orgSlug: string;\n projectId: string;\n useClient: boolean;\n isTypeScript?: boolean;\n logsEnabled?: boolean;\n}): string {\n const issuesPageLink = options.selfHosted\n ? `${options.sentryUrl}organizations/${options.orgSlug}/issues/?project=${options.projectId}`\n : `https://${options.orgSlug}.sentry.io/issues/?project=${options.projectId}`;\n\n const loggerPageLoad = options.logsEnabled\n ? `\n Sentry.logger.info(\"Sentry example page loaded\");`\n : '';\n\n const loggerUserAction = options.logsEnabled\n ? `\n Sentry.logger.info(\"User clicked the button, throwing a sample error\");`\n : '';\n\n return `${\n options.useClient ? '\"use client\";\\n\\n' : ''\n }import * as Sentry from \"@sentry/nextjs\";\nimport Head from \"next/head\";\nimport { useEffect, useState } from \"react\";\n\nclass SentryExampleFrontendError extends Error {\n constructor(message${options.isTypeScript ? ': string | undefined' : ''}) {\n super(message);\n this.name = \"SentryExampleFrontendError\";\n }\n}\n\nexport default function Page() {\n const [hasSentError, setHasSentError] = useState(false);\n const [isConnected, setIsConnected] = useState(true);\n\n useEffect(() => {${loggerPageLoad}\n async function checkConnectivity() {\n const result = await Sentry.diagnoseSdkConnectivity();\n setIsConnected(result !== \"sentry-unreachable\");\n }\n checkConnectivity();\n }, []);\n\n return (\n <div>\n <Head>\n <title>sentry-example-page</title>\n <meta name=\"description\" content=\"Test Sentry for your Next.js app!\" />\n </Head>\n\n <main>\n <div className=\"flex-spacer\" />\n <svg\n height=\"40\"\n width=\"40\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n role=\"img\"\n aria-label=\"Sentry logo\"\n >\n <path\n d=\"M21.85 2.995a3.698 3.698 0 0 1 1.353 1.354l16.303 28.278a3.703 3.703 0 0 1-1.354 5.053 3.694 3.694 0 0 1-1.848.496h-3.828a31.149 31.149 0 0 0 0-3.09h3.815a.61.61 0 0 0 .537-.917L20.523 5.893a.61.61 0 0 0-1.057 0l-3.739 6.494a28.948 28.948 0 0 1 9.63 10.453 28.988 28.988 0 0 1 3.499 13.78v1.542h-9.852v-1.544a19.106 19.106 0 0 0-2.182-8.85 19.08 19.08 0 0 0-6.032-6.829l-1.85 3.208a15.377 15.377 0 0 1 6.382 12.484v1.542H3.696A3.694 3.694 0 0 1 0 34.473c0-.648.17-1.286.494-1.849l2.33-4.074a8.562 8.562 0 0 1 2.689 1.536L3.158 34.17a.611.611 0 0 0 .538.917h8.448a12.481 12.481 0 0 0-6.037-9.09l-1.344-.772 4.908-8.545 1.344.77a22.16 22.16 0 0 1 7.705 7.444 22.193 22.193 0 0 1 3.316 10.193h3.699a25.892 25.892 0 0 0-3.811-12.033 25.856 25.856 0 0 0-9.046-8.796l-1.344-.772 5.269-9.136a3.698 3.698 0 0 1 3.2-1.849c.648 0 1.285.17 1.847.495Z\"\n fill=\"currentcolor\"\n />\n </svg>\n <h1>sentry-example-page</h1>\n\n <p className=\"description\">\n Click the button below, and view the sample error on the Sentry{\" \"}\n <a\n target=\"_blank\"\n rel=\"noopener\"\n href=\"${issuesPageLink}\"\n >\n Issues Page\n </a>\n . For more details about setting up Sentry,{\" \"}\n <a\n target=\"_blank\"\n rel=\"noopener\"\n href=\"https://docs.sentry.io/platforms/javascript/guides/nextjs/\"\n >\n read our docs\n </a>\n .\n </p>\n\n <button\n type=\"button\"\n onClick={async () => {${loggerUserAction}\n await Sentry.startSpan(\n {\n name: \"Example Frontend/Backend Span\",\n op: \"test\",\n },\n async () => {\n const res = await fetch(\"/api/sentry-example-api\");\n if (!res.ok) {\n setHasSentError(true);\n }\n },\n );\n throw new SentryExampleFrontendError(\n \"This error is raised on the frontend of the example page.\",\n );\n }}\n disabled={!isConnected}\n >\n <span>Throw Sample Error</span>\n </button>\n\n {hasSentError ? (\n <p className=\"success\">Error sent to Sentry.</p>\n ) : !isConnected ? (\n <div className=\"connectivity-error\">\n <p>\n It looks like network requests to Sentry are being blocked, which\n will prevent errors from being captured. Try disabling your\n ad-blocker to complete the test.\n </p>\n </div>\n ) : (\n <div className=\"success_placeholder\" />\n )}\n\n <div className=\"flex-spacer\" />\n </main>\n\n <style>{\\`\n main {\n display: flex;\n min-height: 100vh;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n gap: 16px;\n padding: 16px;\n font-family: system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", sans-serif;\n }\n\n h1 {\n padding: 0px 4px;\n border-radius: 4px;\n background-color: rgba(24, 20, 35, 0.03);\n font-family: monospace;\n font-size: 20px;\n line-height: 1.2;\n }\n\n p {\n margin: 0;\n font-size: 20px;\n }\n\n a {\n color: #6341F0;\n text-decoration: underline;\n cursor: pointer;\n\n @media (prefers-color-scheme: dark) {\n color: #B3A1FF;\n }\n }\n\n button {\n border-radius: 8px;\n color: white;\n cursor: pointer;\n background-color: #553DB8;\n border: none;\n padding: 0;\n margin-top: 4px;\n\n & > span {\n display: inline-block;\n padding: 12px 16px;\n border-radius: inherit;\n font-size: 20px;\n font-weight: bold;\n line-height: 1;\n background-color: #7553FF;\n border: 1px solid #553DB8;\n transform: translateY(-4px);\n }\n\n &:hover > span {\n transform: translateY(-8px);\n }\n\n &:active > span {\n transform: translateY(0);\n }\n\n &:disabled {\n\t cursor: not-allowed;\n\t opacity: 0.6;\n\n\t & > span {\n\t transform: translateY(0);\n\t border: none\n\t }\n\t }\n }\n\n .description {\n text-align: center;\n color: #6E6C75;\n max-width: 500px;\n line-height: 1.5;\n font-size: 20px;\n\n @media (prefers-color-scheme: dark) {\n color: #A49FB5;\n }\n }\n\n .flex-spacer {\n flex: 1;\n }\n\n .success {\n padding: 12px 16px;\n border-radius: 8px;\n font-size: 20px;\n line-height: 1;\n background-color: #00F261;\n border: 1px solid #00BF4D;\n color: #181423;\n }\n\n .success_placeholder {\n height: 46px;\n }\n\n .connectivity-error {\n padding: 12px 16px;\n background-color: #E50045;\n border-radius: 8px;\n width: 500px;\n color: #FFFFFF;\n border: 1px solid #A80033;\n text-align: center;\n margin: 0;\n }\n\n .connectivity-error a {\n color: #FFFFFF;\n text-decoration: underline;\n }\n \\`}</style>\n </div>\n );\n}\n`;\n}\n\nexport function getSentryExamplePagesDirApiRoute({\n isTypeScript,\n logsEnabled,\n}: {\n isTypeScript: boolean;\n logsEnabled?: boolean;\n}) {\n const sentryImport = logsEnabled\n ? `import * as Sentry from \"@sentry/nextjs\";\n\n`\n : '';\n\n const loggerCall = logsEnabled\n ? ` Sentry.logger.info(\"Sentry example API called\");\n`\n : '';\n\n return `${sentryImport}// Custom error class for Sentry testing\nclass SentryExampleAPIError extends Error {\n constructor(message${isTypeScript ? ': string | undefined' : ''}) {\n super(message);\n this.name = \"SentryExampleAPIError\";\n }\n}\n// A faulty API route to test Sentry's error monitoring\nexport default function handler(_req, res) {\n${loggerCall}throw new SentryExampleAPIError(\"This error is raised on the backend called by the example page.\");\nres.status(200).json({ name: \"John Doe\" });\n}\n`;\n}\n\nexport function getSentryExampleAppDirApiRoute({\n isTypeScript,\n logsEnabled,\n}: {\n isTypeScript: boolean;\n logsEnabled?: boolean;\n}) {\n const sentryImport = logsEnabled\n ? `import * as Sentry from \"@sentry/nextjs\";\n`\n : '';\n\n const loggerCall = logsEnabled\n ? `\n Sentry.logger.info(\"Sentry example API called\");`\n : '';\n\n // Note: We intentionally don't have a return statement after throw - it would be unreachable code\n // We also don't import NextResponse since we don't use it (Biome noUnusedImports rule)\n return `${sentryImport}export const dynamic = \"force-dynamic\";\n\nclass SentryExampleAPIError extends Error {\n constructor(message${isTypeScript ? ': string | undefined' : ''}) {\n super(message);\n this.name = \"SentryExampleAPIError\";\n }\n}\n\n// A faulty API route to test Sentry's error monitoring\nexport function GET() {${loggerCall}\n throw new SentryExampleAPIError(\n \"This error is raised on the backend called by the example page.\",\n );\n}\n`;\n}\n\nexport function getSentryDefaultUnderscoreErrorPage() {\n return `import * as Sentry from \"@sentry/nextjs\";\nimport Error from \"next/error\";\n\nconst CustomErrorComponent = (props) => {\n return <Error statusCode={props.statusCode} />;\n};\n\nCustomErrorComponent.getInitialProps = async (contextData) => {\n // In case this is running in a serverless function, await this in order to give Sentry\n // time to send the error before the lambda exits\n await Sentry.captureUnderscoreErrorException(contextData);\n\n // This will contain the status code of the response\n return Error.getInitialProps(contextData);\n};\n\nexport default CustomErrorComponent;\n`;\n}\n\nexport function getSimpleUnderscoreErrorCopyPasteSnippet() {\n return `\n${chalk.green(`import * as Sentry from '@sentry/nextjs';`)}\n${chalk.green(`import Error from \"next/error\";`)}\n\n${chalk.dim(\n '// Replace \"YourCustomErrorComponent\" with your custom error component!',\n)}\nYourCustomErrorComponent.getInitialProps = async (${chalk.green(\n 'contextData',\n )}) => {\n ${chalk.green('await Sentry.captureUnderscoreErrorException(contextData);')}\n\n ${chalk.dim('// ...other getInitialProps code')}\n\n return Error.getInitialProps(contextData);\n};\n`;\n}\n\nexport function getGenerateMetadataSnippet(isTs: boolean) {\n return makeCodeSnippet(true, (unchanged, plus) => {\n return plus(`\n import * as Sentry from '@sentry/nextjs';\n ${isTs ? `import type { Metadata } from 'next';` : ''}\n\n ${unchanged(\n '// Add or edit your \"generateMetadata\" to include the Sentry trace data:',\n )}\n export function generateMetadata()${isTs ? ': Metadata' : ''} {\n return {\n // ... your existing metadata\n other: {\n ...Sentry.getTraceData()\n }\n };\n }\n`);\n });\n}\n\nexport function getFullUnderscoreErrorCopyPasteSnippet(isTs: boolean) {\n return `\nimport * as Sentry from '@sentry/nextjs';${\n isTs ? '\\nimport type { NextPageContext } from \"next\";' : ''\n }\nimport Error from \"next/error\";\n\n${chalk.dim(\n '// Replace \"YourCustomErrorComponent\" with your custom error component!',\n)}\nYourCustomErrorComponent.getInitialProps = async (contextData${\n isTs ? ': NextPageContext' : ''\n }) => {\n await Sentry.captureUnderscoreErrorException(contextData);\n\n return Error.getInitialProps(contextData);\n};\n`;\n}\n\nexport function getInstrumentationHookContent(\n instrumentationHookLocation: 'src' | 'root',\n) {\n return `import * as Sentry from \"@sentry/nextjs\";\n\nexport async function register() {\n if (process.env.NEXT_RUNTIME === \"nodejs\") {\n await import(\"${\n instrumentationHookLocation === 'root' ? '.' : '..'\n }/sentry.server.config\");\n }\n\n if (process.env.NEXT_RUNTIME === \"edge\") {\n await import(\"${\n instrumentationHookLocation === 'root' ? '.' : '..'\n }/sentry.edge.config\");\n }\n}\n\nexport const onRequestError = Sentry.captureRequestError;\n`;\n}\n\nexport function getInstrumentationHookCopyPasteSnippet(\n instrumentationHookLocation: 'src' | 'root',\n) {\n return makeCodeSnippet(true, (unchanged, plus) => {\n return unchanged(`${plus(\"import * as Sentry from '@sentry/nextjs';\")}\n\nexport ${plus('async')} function register() {\n ${plus(`if (process.env.NEXT_RUNTIME === 'nodejs') {\n await import('${\n instrumentationHookLocation === 'root' ? '.' : '..'\n }/sentry.server.config');\n }\n\n if (process.env.NEXT_RUNTIME === 'edge') {\n await import('${\n instrumentationHookLocation === 'root' ? '.' : '..'\n }/sentry.edge.config');\n }`)}\n}\n\n${plus('export const onRequestError = Sentry.captureRequestError;')}\n`);\n });\n}\n\nexport function getInstrumentationClientHookCopyPasteSnippet(\n dsn: string,\n selectedFeaturesMap: {\n replay: boolean;\n performance: boolean;\n logs: boolean;\n },\n spotlight = false,\n) {\n return makeCodeSnippet(true, (_unchanged, plus) => {\n return plus(\n getInstrumentationClientFileContents(dsn, selectedFeaturesMap, spotlight),\n );\n });\n}\n\nexport function getSentryDefaultGlobalErrorPage(isTs: boolean) {\n return isTs\n ? `\"use client\";\n\nimport * as Sentry from \"@sentry/nextjs\";\nimport NextError from \"next/error\";\nimport { useEffect } from \"react\";\n\nexport default function GlobalError({\n error,\n}: {\n error: Error & { digest?: string };\n}) {\n useEffect(() => {\n Sentry.captureException(error);\n }, [error]);\n\n return (\n <html lang=\"en\">\n <body>\n {/* \\`NextError\\` is the default Next.js error page component. Its type\n definition requires a \\`statusCode\\` prop. However, since the App Router\n does not expose status codes for errors, we simply pass 0 to render a\n generic error message. */}\n <NextError statusCode={0} />\n </body>\n </html>\n );\n}\n`\n : `\"use client\";\n\nimport * as Sentry from \"@sentry/nextjs\";\nimport NextError from \"next/error\";\nimport { useEffect } from \"react\";\n\nexport default function GlobalError({ error }) {\n useEffect(() => {\n Sentry.captureException(error);\n }, [error]);\n\n return (\n <html lang=\"en\">\n <body>\n {/* \\`NextError\\` is the default Next.js error page component. Its type\n definition requires a \\`statusCode\\` prop. However, since the App Router\n does not expose status codes for errors, we simply pass 0 to render a\n generic error message. */}\n <NextError statusCode={0} />\n </body>\n </html>\n );\n}\n`;\n}\n\nexport function getGlobalErrorCopyPasteSnippet(isTs: boolean) {\n if (isTs) {\n return `\"use client\";\n\n${chalk.green('import * as Sentry from \"@sentry/nextjs\";')}\n${chalk.green('import Error from \"next/error\";')}\n${chalk.green('import { useEffect } from \"react\";')}\n\nexport default function GlobalError(${chalk.green(\n '{ error }: { error: Error }',\n )}) {\n ${chalk.green(`useEffect(() => {\n Sentry.captureException(error);\n }, [error]);`)}\n\n return (\n <html>\n <body>\n {/* Your Error component here... */}\n </body>\n </html>\n );\n}\n`;\n }\n return `\"use client\";\n\n${chalk.green('import * as Sentry from \"@sentry/nextjs\";')}\n${chalk.green('import Error from \"next/error\";')}\n${chalk.green('import { useEffect } from \"react\";')}\n\nexport default function GlobalError(${chalk.green('{ error }')}) {\n ${chalk.green(`useEffect(() => {\n Sentry.captureException(error);\n }, [error]);`)}\n\n return (\n <html>\n <body>\n {/* Your Error component here... */}\n </body>\n </html>\n );\n}\n`;\n}\n\nexport const getRootLayout = (\n isTs: boolean,\n) => `// This file was generated by the Sentry wizard because we couldn't find a root layout file.\n// You can delete this file at any time.\n\nexport const metadata = {\n title: 'Sentry NextJS Example',\n description: 'Generated by Sentry',\n}\n\nexport default function RootLayout({\n children,\n}${\n isTs\n ? `: {\n children: React.ReactNode\n}`\n : ''\n}) {\n return (\n <html lang=\"en\">\n <body>{children}</body>\n </html>\n )\n}\n`;\n\nexport const getRootLayoutWithGenerateMetadata = (\n isTs: boolean,\n) => `// This file was generated by the Sentry wizard because we couldn't find a root layout file.\nimport * as Sentry from '@sentry/nextjs';\n${isTs ? `import type { Metadata } from 'next';` : ''}\n\nexport function generateMetadata()${isTs ? ': Metadata' : ''} {\n return {\n other: {\n ...Sentry.getTraceData(),\n }\n }\n};\n\nexport default function RootLayout({\n children,\n}${\n isTs\n ? `: {\n children: React.ReactNode\n}`\n : ''\n}) {\n return (\n <html lang=\"en\">\n <body>{children}</body>\n </html>\n )\n}\n`;\n"]}
|
|
@@ -30,8 +30,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
30
30
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
31
|
exports.instrumentClientEntry = void 0;
|
|
32
32
|
const recast = __importStar(require("recast"));
|
|
33
|
+
const path = __importStar(require("path"));
|
|
33
34
|
// @ts-expect-error - clack is ESM and TS complains about that. It works though
|
|
34
35
|
const prompts_1 = __importDefault(require("@clack/prompts"));
|
|
36
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
35
37
|
// @ts-expect-error - magicast is ESM and TS complains about that. It works though
|
|
36
38
|
const magicast_1 = require("magicast");
|
|
37
39
|
const ast_utils_1 = require("../../utils/ast-utils");
|
|
@@ -39,7 +41,8 @@ const utils_1 = require("./utils");
|
|
|
39
41
|
async function instrumentClientEntry(clientEntryPath, dsn, enableTracing, enableReplay, enableLogs) {
|
|
40
42
|
const clientEntryAst = await (0, magicast_1.loadFile)(clientEntryPath);
|
|
41
43
|
if ((0, ast_utils_1.hasSentryContent)(clientEntryAst.$ast)) {
|
|
42
|
-
|
|
44
|
+
const filename = path.basename(clientEntryPath);
|
|
45
|
+
prompts_1.default.log.info(`Sentry initialization found in ${chalk_1.default.cyan(filename)}`);
|
|
43
46
|
return;
|
|
44
47
|
}
|
|
45
48
|
clientEntryAst.imports.$add({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.entry.js","sourceRoot":"","sources":["../../../../src/react-router/codemods/client.entry.ts"],"names":[],"mappings":";AAAA,0DAA0D;AAC1D,+DAA+D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAE/D,+CAAiC;
|
|
1
|
+
{"version":3,"file":"client.entry.js","sourceRoot":"","sources":["../../../../src/react-router/codemods/client.entry.ts"],"names":[],"mappings":";AAAA,0DAA0D;AAC1D,+DAA+D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAE/D,+CAAiC;AACjC,2CAA6B;AAG7B,+EAA+E;AAC/E,6DAAmC;AACnC,kDAA0B;AAE1B,kFAAkF;AAClF,uCAA+C;AAC/C,qDAAyD;AACzD,mCAAwD;AAEjD,KAAK,UAAU,qBAAqB,CACzC,eAAuB,EACvB,GAAW,EACX,aAAsB,EACtB,YAAqB,EACrB,UAAmB;IAEnB,MAAM,cAAc,GAAG,MAAM,IAAA,mBAAQ,EAAC,eAAe,CAAC,CAAC;IAEvD,IAAI,IAAA,4BAAgB,EAAC,cAAc,CAAC,IAAiB,CAAC,EAAE;QACtD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;QAChD,iBAAK,CAAC,GAAG,CAAC,IAAI,CAAC,kCAAkC,eAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QACzE,OAAO;KACR;IAED,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC;QAC1B,IAAI,EAAE,sBAAsB;QAC5B,QAAQ,EAAE,GAAG;QACb,KAAK,EAAE,QAAQ;KAChB,CAAC,CAAC;IAEH,MAAM,YAAY,GAAG,EAAE,CAAC;IACxB,IAAI,aAAa,EAAE;QACjB,YAAY,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;KAC7D;IACD,IAAI,YAAY,EAAE;QAChB,YAAY,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;KACjD;IAED,MAAM,WAAW,GAAG;;UAEZ,GAAG;;mBAEM,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;IACtC,UAAU,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE;sBACnB,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAC7C,aAAa;QACX,CAAC,CAAC,8EAA8E;QAChF,CAAC,CAAC,EACN,GACE,YAAY;QACV,CAAC,CAAC,sEAAsE;QACxE,CAAC,CAAC,EACN;IACE,CAAC;IAEF,cAAc,CAAC,IAAkB,CAAC,IAAI,CAAC,MAAM,CAC5C,IAAA,qCAA6B,EAAC,cAAc,CAAC,IAAiB,CAAC,EAC/D,CAAC,EACD,GAAG,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,IAAI,CAC1C,CAAC;IAEF,MAAM,IAAA,oBAAS,EAAC,cAAc,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;AACxD,CAAC;AArDD,sDAqDC","sourcesContent":["/* eslint-disable @typescript-eslint/no-unsafe-argument */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n\nimport * as recast from 'recast';\nimport * as path from 'path';\nimport type { namedTypes as t } from 'ast-types';\n\n// @ts-expect-error - clack is ESM and TS complains about that. It works though\nimport clack from '@clack/prompts';\nimport chalk from 'chalk';\n\n// @ts-expect-error - magicast is ESM and TS complains about that. It works though\nimport { loadFile, writeFile } from 'magicast';\nimport { hasSentryContent } from '../../utils/ast-utils';\nimport { getAfterImportsInsertionIndex } from './utils';\n\nexport async function instrumentClientEntry(\n clientEntryPath: string,\n dsn: string,\n enableTracing: boolean,\n enableReplay: boolean,\n enableLogs: boolean,\n): Promise<void> {\n const clientEntryAst = await loadFile(clientEntryPath);\n\n if (hasSentryContent(clientEntryAst.$ast as t.Program)) {\n const filename = path.basename(clientEntryPath);\n clack.log.info(`Sentry initialization found in ${chalk.cyan(filename)}`);\n return;\n }\n\n clientEntryAst.imports.$add({\n from: '@sentry/react-router',\n imported: '*',\n local: 'Sentry',\n });\n\n const integrations = [];\n if (enableTracing) {\n integrations.push('Sentry.reactRouterTracingIntegration()');\n }\n if (enableReplay) {\n integrations.push('Sentry.replayIntegration()');\n }\n\n const initContent = `\nSentry.init({\n dsn: \"${dsn}\",\n sendDefaultPii: true,\n integrations: [${integrations.join(', ')}],\n ${enableLogs ? 'enableLogs: true,' : ''}\n tracesSampleRate: ${enableTracing ? '1.0' : '0'},${\n enableTracing\n ? '\\n tracePropagationTargets: [/^\\\\//, /^https:\\\\/\\\\/yourserver\\\\.io\\\\/api/],'\n : ''\n }${\n enableReplay\n ? '\\n replaysSessionSampleRate: 0.1,\\n replaysOnErrorSampleRate: 1.0,'\n : ''\n }\n});`;\n\n (clientEntryAst.$ast as t.Program).body.splice(\n getAfterImportsInsertionIndex(clientEntryAst.$ast as t.Program),\n 0,\n ...recast.parse(initContent).program.body,\n );\n\n await writeFile(clientEntryAst.$ast, clientEntryPath);\n}\n"]}
|