@sentry/wizard 3.1.0-beta.0 → 3.2.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 (108) hide show
  1. package/CHANGELOG.md +17 -2
  2. package/bin.ts +5 -1
  3. package/dist/bin.js +6 -1
  4. package/dist/bin.js.map +1 -1
  5. package/dist/lib/Constants.d.ts +2 -1
  6. package/dist/lib/Constants.js +5 -0
  7. package/dist/lib/Constants.js.map +1 -1
  8. package/dist/lib/Helper/File.js +25 -2
  9. package/dist/lib/Helper/File.js.map +1 -1
  10. package/dist/lib/Helper/Git.d.ts +7 -0
  11. package/dist/lib/Helper/Git.js +94 -0
  12. package/dist/lib/Helper/Git.js.map +1 -0
  13. package/dist/lib/Helper/Logging.d.ts +1 -0
  14. package/dist/lib/Helper/Logging.js +9 -2
  15. package/dist/lib/Helper/Logging.js.map +1 -1
  16. package/dist/lib/Helper/MergeConfig.js +24 -1
  17. package/dist/lib/Helper/MergeConfig.js.map +1 -1
  18. package/dist/lib/Helper/Package.d.ts +9 -0
  19. package/dist/lib/Helper/Package.js +39 -2
  20. package/dist/lib/Helper/Package.js.map +1 -1
  21. package/dist/lib/Helper/PackageManager.d.ts +1 -1
  22. package/dist/lib/Helper/PackageManager.js +32 -11
  23. package/dist/lib/Helper/PackageManager.js.map +1 -1
  24. package/dist/lib/Helper/SentryCli.d.ts +11 -0
  25. package/dist/lib/Helper/SentryCli.js +141 -2
  26. package/dist/lib/Helper/SentryCli.js.map +1 -1
  27. package/dist/lib/Helper/Wizard.js +24 -1
  28. package/dist/lib/Helper/Wizard.js.map +1 -1
  29. package/dist/lib/Helper/__tests__/MergeConfig.js +25 -2
  30. package/dist/lib/Helper/__tests__/MergeConfig.js.map +1 -1
  31. package/dist/lib/Setup.js +25 -2
  32. package/dist/lib/Setup.js.map +1 -1
  33. package/dist/lib/Steps/ChooseIntegration.js +28 -1
  34. package/dist/lib/Steps/ChooseIntegration.js.map +1 -1
  35. package/dist/lib/Steps/Initial.js +25 -2
  36. package/dist/lib/Steps/Initial.js.map +1 -1
  37. package/dist/lib/Steps/Integrations/BaseIntegration.js +24 -1
  38. package/dist/lib/Steps/Integrations/BaseIntegration.js.map +1 -1
  39. package/dist/lib/Steps/Integrations/Cordova.js +25 -2
  40. package/dist/lib/Steps/Integrations/Cordova.js.map +1 -1
  41. package/dist/lib/Steps/Integrations/Electron.js +26 -3
  42. package/dist/lib/Steps/Integrations/Electron.js.map +1 -1
  43. package/dist/lib/Steps/Integrations/MobileProject.js +24 -1
  44. package/dist/lib/Steps/Integrations/MobileProject.js.map +1 -1
  45. package/dist/lib/Steps/Integrations/NextJs.d.ts +5 -11
  46. package/dist/lib/Steps/Integrations/NextJs.js +14 -343
  47. package/dist/lib/Steps/Integrations/NextJs.js.map +1 -1
  48. package/dist/lib/Steps/Integrations/ReactNative.d.ts +1 -0
  49. package/dist/lib/Steps/Integrations/ReactNative.js +67 -6
  50. package/dist/lib/Steps/Integrations/ReactNative.js.map +1 -1
  51. package/dist/lib/Steps/Integrations/SvelteKit.d.ts +13 -0
  52. package/dist/lib/Steps/Integrations/SvelteKit.js +95 -0
  53. package/dist/lib/Steps/Integrations/SvelteKit.js.map +1 -0
  54. package/dist/lib/Steps/Integrations/__tests__/ReactNative.js +28 -5
  55. package/dist/lib/Steps/Integrations/__tests__/ReactNative.js.map +1 -1
  56. package/dist/lib/Steps/PromptForParameters.js +24 -1
  57. package/dist/lib/Steps/PromptForParameters.js.map +1 -1
  58. package/dist/lib/Steps/SentryProjectSelector.js +25 -1
  59. package/dist/lib/Steps/SentryProjectSelector.js.map +1 -1
  60. package/dist/lib/__tests__/Setup.js +24 -1
  61. package/dist/lib/__tests__/Setup.js.map +1 -1
  62. package/dist/src/nextjs/nextjs-wizard.js +326 -0
  63. package/dist/src/nextjs/nextjs-wizard.js.map +1 -0
  64. package/dist/src/sveltekit/sdk-example.d.ts +10 -0
  65. package/dist/src/sveltekit/sdk-example.js +106 -0
  66. package/dist/src/sveltekit/sdk-example.js.map +1 -0
  67. package/dist/src/sveltekit/sdk-setup.d.ts +13 -0
  68. package/dist/src/sveltekit/sdk-setup.js +451 -0
  69. package/dist/src/sveltekit/sdk-setup.js.map +1 -0
  70. package/dist/src/sveltekit/sentry-cli-setup.d.ts +2 -0
  71. package/dist/src/sveltekit/sentry-cli-setup.js +71 -0
  72. package/dist/src/sveltekit/sentry-cli-setup.js.map +1 -0
  73. package/dist/src/sveltekit/sveltekit-wizard.d.ts +5 -0
  74. package/dist/src/sveltekit/sveltekit-wizard.js +147 -0
  75. package/dist/src/sveltekit/sveltekit-wizard.js.map +1 -0
  76. package/dist/src/templates/nextjs-templates.d.ts +13 -0
  77. package/dist/src/templates/nextjs-templates.js +54 -0
  78. package/dist/src/templates/nextjs-templates.js.map +1 -0
  79. package/dist/src/templates/sveltekit-templates.d.ts +12 -0
  80. package/dist/src/templates/sveltekit-templates.js +26 -0
  81. package/dist/src/templates/sveltekit-templates.js.map +1 -0
  82. package/dist/src/{clack-utils.d.ts → utils/clack-utils.d.ts} +7 -0
  83. package/dist/src/{clack-utils.js → utils/clack-utils.js} +127 -42
  84. package/dist/src/utils/clack-utils.js.map +1 -0
  85. package/lib/Constants.ts +5 -0
  86. package/lib/Helper/Git.ts +39 -0
  87. package/lib/Helper/Logging.ts +4 -0
  88. package/lib/Helper/Package.ts +17 -0
  89. package/lib/Helper/PackageManager.ts +4 -9
  90. package/lib/Helper/SentryCli.ts +74 -0
  91. package/lib/Steps/ChooseIntegration.ts +4 -0
  92. package/lib/Steps/Integrations/NextJs.ts +7 -397
  93. package/lib/Steps/Integrations/ReactNative.ts +49 -3
  94. package/lib/Steps/Integrations/SvelteKit.ts +29 -0
  95. package/lib/Steps/SentryProjectSelector.ts +1 -0
  96. package/package.json +1 -1
  97. package/src/{nextjs-wizard.ts → nextjs/nextjs-wizard.ts} +45 -273
  98. package/src/sveltekit/sdk-example.ts +56 -0
  99. package/src/sveltekit/sdk-setup.ts +430 -0
  100. package/src/sveltekit/sentry-cli-setup.ts +27 -0
  101. package/src/sveltekit/sveltekit-wizard.ts +116 -0
  102. package/src/templates/nextjs-templates.ts +252 -0
  103. package/src/templates/sveltekit-templates.ts +172 -0
  104. package/src/{clack-utils.ts → utils/clack-utils.ts} +73 -11
  105. package/dist/src/clack-utils.js.map +0 -1
  106. package/dist/src/nextjs-wizard.js +0 -346
  107. package/dist/src/nextjs-wizard.js.map +0 -1
  108. /package/dist/src/{nextjs-wizard.d.ts → nextjs/nextjs-wizard.d.ts} +0 -0
@@ -1,7 +1,9 @@
1
1
  /* eslint-disable max-lines */
2
- import * as clack from '@clack/prompts';
2
+ // @ts-ignore - clack is ESM and TS complains about that. It works though
3
+ import clack from '@clack/prompts';
3
4
  import chalk from 'chalk';
4
5
  import * as fs from 'fs';
6
+ // @ts-ignore - magicast is ESM and TS complains about that. It works though
5
7
  import { builders, generateCode, parseModule } from 'magicast';
6
8
  import * as path from 'path';
7
9
 
@@ -12,10 +14,22 @@ import {
12
14
  askForSelfHosted,
13
15
  askForWizardLogin,
14
16
  confirmContinueEvenThoughNoGitRepo,
17
+ ensurePackageIsInstalled,
18
+ getPackageDotJson,
15
19
  installPackage,
16
20
  printWelcome,
17
21
  SentryProjectData,
18
- } from './clack-utils';
22
+ } from '../utils/clack-utils';
23
+ import {
24
+ getNextjsConfigCjsAppendix,
25
+ getNextjsConfigCjsTemplate,
26
+ getNextjsConfigEsmCopyPasteSnippet,
27
+ getNextjsSentryBuildOptionsTemplate,
28
+ getNextjsWebpackPluginOptionsTemplate,
29
+ getSentryConfigContents,
30
+ getSentryExampleApiRoute,
31
+ getSentryExamplePageContents,
32
+ } from '../templates/nextjs-templates';
19
33
 
20
34
  interface NextjsWizardOptions {
21
35
  promoCode?: string;
@@ -32,43 +46,8 @@ export async function runNextjsWizard(
32
46
 
33
47
  await confirmContinueEvenThoughNoGitRepo();
34
48
 
35
- const packageJsonFileContents = await fs.promises
36
- .readFile(path.join(process.cwd(), 'package.json'), 'utf8')
37
- .catch(() => {
38
- clack.log.error(
39
- 'Could not find package.json. Make sure to run the wizard in the root of your Next.js app!',
40
- );
41
- abort();
42
- });
43
-
44
- let packageJson:
45
- | { dependencies?: { ['@sentry/nextjs']: string; ['next']: string } }
46
- | undefined = undefined;
47
-
48
- try {
49
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
50
- packageJson = JSON.parse(packageJsonFileContents);
51
- } catch (e) {
52
- clack.log.error(
53
- 'Unable to parse your package.json. Make sure it has a valid format!',
54
- );
55
-
56
- abort();
57
- }
58
-
59
- if (!packageJson?.dependencies?.['next']) {
60
- const continueWithoutNext = await clack.confirm({
61
- message:
62
- 'Next.js does not seem to be installed. Do you still want to continue?',
63
- initialValue: false,
64
- });
65
-
66
- abortIfCancelled(continueWithoutNext);
67
-
68
- if (!continueWithoutNext) {
69
- abort();
70
- }
71
- }
49
+ const packageJson = await getPackageDotJson();
50
+ await ensurePackageIsInstalled(packageJson, 'next', 'Next.js');
72
51
 
73
52
  const { url: sentryUrl, selfHosted } = await askForSelfHosted();
74
53
 
@@ -79,7 +58,7 @@ export async function runNextjsWizard(
79
58
 
80
59
  const selectedProject: SentryProjectData | symbol = await clack.select({
81
60
  message: 'Select your Sentry project.',
82
- options: projects.map(project => {
61
+ options: projects.map((project) => {
83
62
  return {
84
63
  value: project,
85
64
  label: `${project.organization.slug}/${project.slug}`,
@@ -99,7 +78,7 @@ export async function runNextjsWizard(
99
78
  isUsingTypescript = fs.existsSync(
100
79
  path.join(process.cwd(), 'tsconfig.json'),
101
80
  );
102
- } catch (e) {
81
+ } catch {
103
82
  // noop - Default to assuming user is not using typescript
104
83
  }
105
84
 
@@ -162,48 +141,11 @@ export async function runNextjsWizard(
162
141
  }
163
142
  }
164
143
 
165
- const webpackOptionsTemplate = `{
166
- // For all available options, see:
167
- // https://github.com/getsentry/sentry-webpack-plugin#options
168
-
169
- // Suppresses source map uploading logs during build
170
- silent: true,
171
-
172
- org: "${selectedProject.organization.slug}",
173
- project: "${selectedProject.slug}",
174
- }`;
175
-
176
- const sentryBuildOptionsTemplate = `{
177
- // For all available options, see:
178
- // https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/
179
-
180
- // Upload a larger set of source maps for prettier stack traces (increases build time)
181
- widenClientFileUpload: true,
182
-
183
- // Transpiles SDK to be compatible with IE11 (increases bundle size)
184
- transpileClientSDK: true,
185
-
186
- // Routes browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers (increases server load)
187
- tunnelRoute: "/monitoring",
188
-
189
- // Hides source maps from generated client bundles
190
- hideSourceMaps: true,
191
-
192
- // Automatically tree-shake Sentry logger statements to reduce bundle size
193
- disableLogger: true,
194
- }`;
195
-
196
- const newNextConfigTemplate = `const { withSentryConfig } = require("@sentry/nextjs");
197
-
198
- /** @type {import('next').NextConfig} */
199
- const nextConfig = {};
200
-
201
- module.exports = withSentryConfig(
202
- nextConfig,
203
- ${webpackOptionsTemplate},
204
- ${sentryBuildOptionsTemplate}
205
- );
206
- `;
144
+ const sentryWebpackOptionsTemplate = getNextjsWebpackPluginOptionsTemplate(
145
+ selectedProject.organization.slug,
146
+ selectedProject.slug,
147
+ );
148
+ const sentryBuildOptionsTemplate = getNextjsSentryBuildOptionsTemplate();
207
149
 
208
150
  const nextConfigJs = 'next.config.js';
209
151
  const nextConfigMjs = 'next.config.mjs';
@@ -218,7 +160,10 @@ module.exports = withSentryConfig(
218
160
  if (!nextConfigJsExists && !nextConfigMjsExists) {
219
161
  await fs.promises.writeFile(
220
162
  path.join(process.cwd(), nextConfigJs),
221
- newNextConfigTemplate,
163
+ getNextjsConfigCjsTemplate(
164
+ sentryWebpackOptionsTemplate,
165
+ sentryBuildOptionsTemplate,
166
+ ),
222
167
  { encoding: 'utf8', flag: 'w' },
223
168
  );
224
169
 
@@ -242,7 +187,7 @@ module.exports = withSentryConfig(
242
187
  if (probablyIncludesSdk) {
243
188
  const injectAnyhow = await clack.confirm({
244
189
  message: `${chalk.bold(
245
- nextConfigMjs,
190
+ nextConfigJs,
246
191
  )} already contains Sentry SDK configuration. Should the wizard modify it anyways?`,
247
192
  });
248
193
 
@@ -252,21 +197,12 @@ module.exports = withSentryConfig(
252
197
  }
253
198
 
254
199
  if (shouldInject) {
255
- const cjsAppendix = `
256
-
257
- // Inected Content via Sentry Wizard Below
258
-
259
- const { withSentryConfig } = require("@sentry/nextjs");
260
-
261
- module.exports = withSentryConfig(
262
- module.exports,
263
- ${webpackOptionsTemplate},
264
- ${sentryBuildOptionsTemplate}
265
- );
266
- `;
267
- fs.appendFileSync(
200
+ await fs.promises.appendFile(
268
201
  path.join(process.cwd(), nextConfigJs),
269
- cjsAppendix,
202
+ getNextjsConfigCjsAppendix(
203
+ sentryWebpackOptionsTemplate,
204
+ sentryBuildOptionsTemplate,
205
+ ),
270
206
  'utf8',
271
207
  );
272
208
 
@@ -314,7 +250,7 @@ module.exports = withSentryConfig(
314
250
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
315
251
  mod.exports.default = builders.raw(`withSentryConfig(
316
252
  ${expressionToWrap},
317
- ${webpackOptionsTemplate},
253
+ ${sentryWebpackOptionsTemplate},
318
254
  ${sentryBuildOptionsTemplate}
319
255
  )`);
320
256
  const newCode = mod.generate().code;
@@ -333,7 +269,7 @@ module.exports = withSentryConfig(
333
269
  )}. ${chalk.dim('(you probably want to clean this up a bit!)')}`,
334
270
  );
335
271
  }
336
- } catch (e) {
272
+ } catch {
337
273
  clack.log.warn(
338
274
  chalk.yellow(
339
275
  `Something went wrong writing to ${chalk.bold(nextConfigMjs)}`,
@@ -346,15 +282,12 @@ module.exports = withSentryConfig(
346
282
  );
347
283
 
348
284
  // eslint-disable-next-line no-console
349
- console.log(`\n
350
- // next.config.mjs
351
- import { withSentryConfig } from "@sentry/nextjs";
352
-
353
- export default withSentryConfig(
354
- yourNextConfig,
355
- ${webpackOptionsTemplate},
356
- ${sentryBuildOptionsTemplate}
357
- );\n`);
285
+ console.log(
286
+ getNextjsConfigEsmCopyPasteSnippet(
287
+ sentryWebpackOptionsTemplate,
288
+ sentryBuildOptionsTemplate,
289
+ ),
290
+ );
358
291
 
359
292
  const shouldContinue = await clack.confirm({
360
293
  message: `Are you done putting the snippet above into ${chalk.bold(
@@ -391,7 +324,7 @@ export default withSentryConfig(
391
324
  }
392
325
 
393
326
  if (pagesLocation) {
394
- const examplePageContents = createExamplePage({
327
+ const examplePageContents = getSentryExamplePageContents({
395
328
  selfHosted,
396
329
  orgSlug: selectedProject.organization.slug,
397
330
  projectId: selectedProject.id,
@@ -421,7 +354,7 @@ export default withSentryConfig(
421
354
  'api',
422
355
  'sentry-example-api.js',
423
356
  ),
424
- exampleApiRoute,
357
+ getSentryExampleApiRoute(),
425
358
  { encoding: 'utf8', flag: 'w' },
426
359
  );
427
360
 
@@ -456,164 +389,3 @@ ${
456
389
  )}`,
457
390
  );
458
391
  }
459
-
460
- function getSentryConfigContents(
461
- dsn: string,
462
- config: 'server' | 'client' | 'edge',
463
- ): string {
464
- let primer;
465
- if (config === 'server') {
466
- primer = `// This file configures the initialization of Sentry on the server.
467
- // The config you add here will be used whenever the server handles a request.
468
- // https://docs.sentry.io/platforms/javascript/guides/nextjs/`;
469
- } else if (config === 'client') {
470
- primer = `// This file configures the initialization of Sentry on the client.
471
- // The config you add here will be used whenever a users loads a page in their browser.
472
- // https://docs.sentry.io/platforms/javascript/guides/nextjs/`;
473
- } else if (config === 'edge') {
474
- primer = `// This file configures the initialization of Sentry for edge features (middleware, edge routes, and so on).
475
- // The config you add here will be used whenever one of the edge features is loaded.
476
- // Note that this config is unrelated to the Verel Edge Runtime and is also required when running locally.
477
- // https://docs.sentry.io/platforms/javascript/guides/nextjs/`;
478
- }
479
-
480
- let additionalOptions = '';
481
- if (config === 'client') {
482
- additionalOptions = `
483
-
484
- replaysOnErrorSampleRate: 1.0,
485
-
486
- // This sets the sample rate to be 10%. You may want this to be 100% while
487
- // in development and sample at a lower rate in production
488
- replaysSessionSampleRate: 0.1,
489
-
490
- // You can remove this option if you're not planning to use the Sentry Session Replay feature:
491
- integrations: [
492
- new Sentry.Replay({
493
- // Additional Replay configuration goes in here, for example:
494
- maskAllText: true,
495
- blockAllMedia: true,
496
- }),
497
- ],`;
498
- }
499
-
500
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
501
- return `${primer}
502
-
503
- import * as Sentry from "@sentry/nextjs";
504
-
505
- Sentry.init({
506
- dsn: "${dsn}",
507
-
508
- // Adjust this value in production, or use tracesSampler for greater control
509
- tracesSampleRate: 1,
510
-
511
- // Setting this option to true will print useful information to the console while you're setting up Sentry.
512
- debug: false,${additionalOptions}
513
- });
514
- `;
515
- }
516
-
517
- function createExamplePage(options: {
518
- selfHosted: boolean;
519
- url: string;
520
- orgSlug: string;
521
- projectId: string;
522
- }): string {
523
- const issuesPageLink = options.selfHosted
524
- ? `${options.url}organizations/${options.orgSlug}/issues/?project=${options.projectId}`
525
- : `https://${options.orgSlug}.sentry.io/issues/?project=${options.projectId}`;
526
-
527
- return `import Head from "next/head";
528
- import * as Sentry from "@sentry/nextjs";
529
-
530
- export default function Home() {
531
- return (
532
- <div>
533
- <Head>
534
- <title>Sentry Onboarding</title>
535
- <meta name="description" content="Test Sentry for your Next.js app!" />
536
- </Head>
537
-
538
- <main
539
- style={{
540
- minHeight: "100vh",
541
- display: "flex",
542
- flexDirection: "column",
543
- justifyContent: "center",
544
- alignItems: "center",
545
- }}
546
- >
547
- <h1 style={{ fontSize: "4rem", margin: "14px 0" }}>
548
- <svg
549
- style={{
550
- height: "1em",
551
- }}
552
- xmlns="http://www.w3.org/2000/svg"
553
- viewBox="0 0 200 44"
554
- >
555
- <path
556
- fill="currentColor"
557
- d="M124.32,28.28,109.56,9.22h-3.68V34.77h3.73V15.19l15.18,19.58h3.26V9.22h-3.73ZM87.15,23.54h13.23V20.22H87.14V12.53h14.93V9.21H83.34V34.77h18.92V31.45H87.14ZM71.59,20.3h0C66.44,19.06,65,18.08,65,15.7c0-2.14,1.89-3.59,4.71-3.59a12.06,12.06,0,0,1,7.07,2.55l2-2.83a14.1,14.1,0,0,0-9-3c-5.06,0-8.59,3-8.59,7.27,0,4.6,3,6.19,8.46,7.52C74.51,24.74,76,25.78,76,28.11s-2,3.77-5.09,3.77a12.34,12.34,0,0,1-8.3-3.26l-2.25,2.69a15.94,15.94,0,0,0,10.42,3.85c5.48,0,9-2.95,9-7.51C79.75,23.79,77.47,21.72,71.59,20.3ZM195.7,9.22l-7.69,12-7.64-12h-4.46L186,24.67V34.78h3.84V24.55L200,9.22Zm-64.63,3.46h8.37v22.1h3.84V12.68h8.37V9.22H131.08ZM169.41,24.8c3.86-1.07,6-3.77,6-7.63,0-4.91-3.59-8-9.38-8H154.67V34.76h3.8V25.58h6.45l6.48,9.2h4.44l-7-9.82Zm-10.95-2.5V12.6h7.17c3.74,0,5.88,1.77,5.88,4.84s-2.29,4.86-5.84,4.86Z M29,2.26a4.67,4.67,0,0,0-8,0L14.42,13.53A32.21,32.21,0,0,1,32.17,40.19H27.55A27.68,27.68,0,0,0,12.09,17.47L6,28a15.92,15.92,0,0,1,9.23,12.17H4.62A.76.76,0,0,1,4,39.06l2.94-5a10.74,10.74,0,0,0-3.36-1.9l-2.91,5a4.54,4.54,0,0,0,1.69,6.24A4.66,4.66,0,0,0,4.62,44H19.15a19.4,19.4,0,0,0-8-17.31l2.31-4A23.87,23.87,0,0,1,23.76,44H36.07a35.88,35.88,0,0,0-16.41-31.8l4.67-8a.77.77,0,0,1,1.05-.27c.53.29,20.29,34.77,20.66,35.17a.76.76,0,0,1-.68,1.13H40.6q.09,1.91,0,3.81h4.78A4.59,4.59,0,0,0,50,39.43a4.49,4.49,0,0,0-.62-2.28Z"
558
- ></path>
559
- </svg>
560
- </h1>
561
-
562
- <p>Get started by sending us a sample error:</p>
563
- <button
564
- type="button"
565
- style={{
566
- padding: "12px",
567
- cursor: "pointer",
568
- backgroundColor: "#AD6CAA",
569
- borderRadius: "4px",
570
- border: "none",
571
- color: "white",
572
- fontSize: "14px",
573
- margin: "18px",
574
- }}
575
- onClick={async () => {
576
- const transaction = Sentry.startTransaction({
577
- name: "Example Frontend Transaction",
578
- });
579
-
580
- Sentry.configureScope((scope) => {
581
- scope.setSpan(transaction);
582
- });
583
-
584
- try {
585
- const res = await fetch("/api/sentry-example-api");
586
- if (!res.ok) {
587
- throw new Error("Sentry Example Frontend Error");
588
- }
589
- } finally {
590
- transaction.finish();
591
- }
592
- }}
593
- >
594
- Throw error!
595
- </button>
596
-
597
- <p>
598
- Next, look for the error on the{" "}
599
- <a href="${issuesPageLink}">Issues Page</a>.
600
- </p>
601
- <p style={{ marginTop: "24px" }}>
602
- For more information, see{" "}
603
- <a href="https://docs.sentry.io/platforms/javascript/guides/nextjs/">
604
- https://docs.sentry.io/platforms/javascript/guides/nextjs/
605
- </a>
606
- </p>
607
- </main>
608
- </div>
609
- );
610
- }
611
- `;
612
- }
613
-
614
- const exampleApiRoute = `// A faulty API route to test Sentry's error monitoring
615
- export default function handler(_req, res) {
616
- throw new Error("Sentry Example API Route Error");
617
- res.status(200).json({ name: "John Doe" });
618
- }
619
- `;
@@ -0,0 +1,56 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ // @ts-ignore - clack is ESM and TS complains about that. It works though
4
+ import clack from '@clack/prompts';
5
+
6
+ import { PartialSvelteConfig } from './sdk-setup';
7
+ import {
8
+ getSentryExampleApiRoute,
9
+ getSentryExampleSveltePage,
10
+ } from '../templates/sveltekit-templates';
11
+
12
+ /**
13
+ * Creates example page and API route to test Sentry
14
+ */
15
+ export async function createExamplePage(
16
+ svelteConfig: PartialSvelteConfig,
17
+ projectProps: {
18
+ selfHosted: boolean;
19
+ url: string;
20
+ orgSlug: string;
21
+ projectId: string;
22
+ },
23
+ ): Promise<void> {
24
+ const routesDirectory = svelteConfig.kit?.files?.routes || 'src/routes';
25
+ const exampleRoutePath = path.resolve(
26
+ path.join(routesDirectory, 'sentry-example'),
27
+ );
28
+
29
+ if (!fs.existsSync(routesDirectory)) {
30
+ clack.log.warn(
31
+ `Couldn't find your routes directory. Creating it now: ${routesDirectory}`,
32
+ );
33
+ fs.mkdirSync(routesDirectory, { recursive: true });
34
+ }
35
+
36
+ if (!fs.existsSync(exampleRoutePath)) {
37
+ fs.mkdirSync(exampleRoutePath);
38
+ } else {
39
+ clack.log.warn(
40
+ `It seems like a sentry example page already exists (${path.basename(
41
+ exampleRoutePath,
42
+ )}). Skipping creation of example route.`,
43
+ );
44
+ return;
45
+ }
46
+
47
+ await fs.promises.writeFile(
48
+ path.join(exampleRoutePath, '+page.svelte'),
49
+ getSentryExampleSveltePage(projectProps),
50
+ );
51
+
52
+ await fs.promises.writeFile(
53
+ path.join(exampleRoutePath, '+server.js'),
54
+ getSentryExampleApiRoute(),
55
+ );
56
+ }