@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.
Files changed (46) hide show
  1. package/CHANGELOG.md +36 -1
  2. package/dist/e2e-tests/tests/nextjs-14.test.js +6 -6
  3. package/dist/e2e-tests/tests/nextjs-14.test.js.map +1 -1
  4. package/dist/e2e-tests/tests/nextjs-15.test.js +6 -6
  5. package/dist/e2e-tests/tests/nextjs-15.test.js.map +1 -1
  6. package/dist/e2e-tests/tests/nextjs-16.test.d.ts +1 -0
  7. package/dist/e2e-tests/tests/nextjs-16.test.js +120 -0
  8. package/dist/e2e-tests/tests/nextjs-16.test.js.map +1 -0
  9. package/dist/e2e-tests/utils/index.d.ts +6 -0
  10. package/dist/e2e-tests/utils/index.js +16 -1
  11. package/dist/e2e-tests/utils/index.js.map +1 -1
  12. package/dist/src/nextjs/nextjs-wizard.js +46 -8
  13. package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
  14. package/dist/src/nextjs/templates.d.ts +6 -3
  15. package/dist/src/nextjs/templates.js +144 -93
  16. package/dist/src/nextjs/templates.js.map +1 -1
  17. package/dist/src/react-router/codemods/client.entry.js +4 -1
  18. package/dist/src/react-router/codemods/client.entry.js.map +1 -1
  19. package/dist/src/react-router/sdk-example.js +5 -2
  20. package/dist/src/react-router/sdk-example.js.map +1 -1
  21. package/dist/src/sourcemaps/tools/sentry-cli.js +1 -1
  22. package/dist/src/sourcemaps/tools/sentry-cli.js.map +1 -1
  23. package/dist/src/sourcemaps/tools/wrangler.js +1 -1
  24. package/dist/src/sourcemaps/tools/wrangler.js.map +1 -1
  25. package/dist/src/sveltekit/sveltekit-wizard.js +2 -2
  26. package/dist/src/sveltekit/sveltekit-wizard.js.map +1 -1
  27. package/dist/src/telemetry.d.ts +1 -1
  28. package/dist/src/telemetry.js +52 -31
  29. package/dist/src/telemetry.js.map +1 -1
  30. package/dist/src/utils/clack/index.d.ts +17 -0
  31. package/dist/src/utils/clack/index.js +174 -12
  32. package/dist/src/utils/clack/index.js.map +1 -1
  33. package/dist/src/version.d.ts +1 -1
  34. package/dist/src/version.js +1 -1
  35. package/dist/src/version.js.map +1 -1
  36. package/dist/test/apple/cocoapod.test.js +7 -3
  37. package/dist/test/apple/cocoapod.test.js.map +1 -1
  38. package/dist/test/apple/code-tools.test.js +8 -2
  39. package/dist/test/apple/code-tools.test.js.map +1 -1
  40. package/dist/test/nextjs/templates.test.js +156 -87
  41. package/dist/test/nextjs/templates.test.js.map +1 -1
  42. package/dist/test/nextjs/wizard-double-wrap-prevention.test.js +12 -7
  43. package/dist/test/nextjs/wizard-double-wrap-prevention.test.js.map +1 -1
  44. package/dist/test/utils/clack/index.test.js +37 -29
  45. package/dist/test/utils/clack/index.test.js.map +1 -1
  46. 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
- // For all available options, see:
12
- // https://www.npmjs.com/package/@sentry/webpack-plugin#options
11
+ // For all available options, see:
12
+ // https://www.npmjs.com/package/@sentry/webpack-plugin#options
13
13
 
14
- org: "${orgSlug}",
15
- project: "${projectSlug}",${selfHosted ? `\n sentryUrl: "${sentryUrl}",` : ''}
14
+ org: "${orgSlug}",
15
+ project: "${projectSlug}",${selfHosted ? `\n sentryUrl: "${sentryUrl}",` : ''}
16
16
 
17
- // Only print logs for uploading source maps in CI
18
- silent: !process.env.CI,
17
+ // Only print logs for uploading source maps in CI
18
+ silent: !process.env.CI,
19
19
 
20
- // For all available options, see:
21
- // https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/
20
+ // For all available options, see:
21
+ // https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/
22
22
 
23
- // Upload a larger set of source maps for prettier stack traces (increases build time)
24
- widenClientFileUpload: true,
23
+ // Upload a larger set of source maps for prettier stack traces (increases build time)
24
+ widenClientFileUpload: true,
25
25
 
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",
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
- return `${options.useClient ? '"use client";\n\n' : ''}import Head from "next/head";
211
- import * as Sentry from "@sentry/nextjs";
212
- import { useState, useEffect } from "react";
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 !== 'sentry-unreachable');
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 height="40" width="40" fill="none" xmlns="http://www.w3.org/2000/svg">
243
- <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"/>
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 <a target="_blank" href="${issuesPageLink}">Issues Page</a>.
251
- For more details about setting up Sentry, <a target="_blank"
252
- href="https://docs.sentry.io/platforms/javascript/guides/nextjs/">read our docs</a>.
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
- name: 'Example Frontend/Backend Span',
260
- op: 'test'
261
- }, async () => {
262
- const res = await fetch("/api/sentry-example-api");
263
- if (!res.ok) {
264
- setHasSentError(true);
265
- }
266
- });
267
- throw new SentryExampleFrontendError("This error is raised on the frontend of the example page.");
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>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>
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
- return `// Custom error class for Sentry testing
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
- return `import { NextResponse } from "next/server";
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("This error is raised on the backend called by the example page.");
449
- return NextResponse.json({ data: "Testing Sentry Error..." });
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 '@sentry/nextjs';
571
+ return `import * as Sentry from "@sentry/nextjs";
526
572
 
527
573
  export async function register() {
528
- if (process.env.NEXT_RUNTIME === 'nodejs') {
529
- await import('${instrumentationHookLocation === 'root' ? '.' : '..'}/sentry.server.config');
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 === 'edge') {
533
- await import('${instrumentationHookLocation === 'root' ? '.' : '..'}/sentry.edge.config');
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, (unchanged, plus) => {
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({ error }: { error: Error & { digest?: string } }) {
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
- prompts_1.default.log.info(`Sentry initialization found in ${clientEntryPath}`);
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;AAGjC,+EAA+E;AAC/E,6DAAmC;AAEnC,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,iBAAK,CAAC,GAAG,CAAC,IAAI,CAAC,kCAAkC,eAAe,EAAE,CAAC,CAAC;QACpE,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;AApDD,sDAoDC","sourcesContent":["/* eslint-disable @typescript-eslint/no-unsafe-argument */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n\nimport * as recast from 'recast';\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';\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 clack.log.info(`Sentry initialization found in ${clientEntryPath}`);\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"]}
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"]}