@sentry/wizard 3.4.0 → 3.6.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 (122) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/bin.ts +29 -20
  3. package/dist/bin.js +27 -19
  4. package/dist/bin.js.map +1 -1
  5. package/dist/lib/Constants.d.ts +2 -0
  6. package/dist/lib/Constants.js +5 -0
  7. package/dist/lib/Constants.js.map +1 -1
  8. package/dist/lib/Helper/Wizard.js +2 -9
  9. package/dist/lib/Helper/Wizard.js.map +1 -1
  10. package/dist/lib/Helper/__tests__/SentryCli.js +1 -0
  11. package/dist/lib/Helper/__tests__/SentryCli.js.map +1 -1
  12. package/dist/lib/Setup.js.map +1 -1
  13. package/dist/lib/Steps/ChooseIntegration.js +30 -10
  14. package/dist/lib/Steps/ChooseIntegration.js.map +1 -1
  15. package/dist/lib/Steps/Integrations/Apple.d.ts +10 -0
  16. package/dist/lib/Steps/Integrations/Apple.js +92 -0
  17. package/dist/lib/Steps/Integrations/Apple.js.map +1 -0
  18. package/dist/lib/Steps/Integrations/{NextJs.d.ts → NextJsShim.d.ts} +1 -1
  19. package/dist/lib/Steps/Integrations/{NextJs.js → NextJsShim.js} +14 -10
  20. package/dist/lib/Steps/Integrations/NextJsShim.js.map +1 -0
  21. package/dist/lib/Steps/Integrations/SourceMapsShim.js +5 -1
  22. package/dist/lib/Steps/Integrations/SourceMapsShim.js.map +1 -1
  23. package/dist/lib/Steps/Integrations/{SvelteKit.d.ts → SvelteKitShim.d.ts} +1 -1
  24. package/dist/lib/Steps/Integrations/{SvelteKit.js → SvelteKitShim.js} +14 -10
  25. package/dist/lib/Steps/Integrations/SvelteKitShim.js.map +1 -0
  26. package/dist/package.json +4 -4
  27. package/dist/src/apple/apple-wizard.d.ts +2 -0
  28. package/dist/src/apple/apple-wizard.js +197 -0
  29. package/dist/src/apple/apple-wizard.js.map +1 -0
  30. package/dist/src/apple/code-tools.d.ts +1 -0
  31. package/dist/src/apple/code-tools.js +100 -0
  32. package/dist/src/apple/code-tools.js.map +1 -0
  33. package/dist/src/apple/templates.d.ts +4 -0
  34. package/dist/src/apple/templates.js +19 -0
  35. package/dist/src/apple/templates.js.map +1 -0
  36. package/dist/src/apple/xcode-manager.d.ts +4 -0
  37. package/dist/src/apple/xcode-manager.js +145 -0
  38. package/dist/src/apple/xcode-manager.js.map +1 -0
  39. package/dist/src/nextjs/nextjs-wizard.d.ts +2 -5
  40. package/dist/src/nextjs/nextjs-wizard.js +1 -1
  41. package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
  42. package/dist/src/sourcemaps/sourcemaps-wizard.d.ts +2 -5
  43. package/dist/src/sourcemaps/sourcemaps-wizard.js +154 -67
  44. package/dist/src/sourcemaps/sourcemaps-wizard.js.map +1 -1
  45. package/dist/src/sourcemaps/tools/angular.d.ts +1 -0
  46. package/dist/src/sourcemaps/tools/angular.js +76 -0
  47. package/dist/src/sourcemaps/tools/angular.js.map +1 -0
  48. package/dist/src/sourcemaps/tools/create-react-app.d.ts +1 -0
  49. package/dist/src/sourcemaps/tools/create-react-app.js +69 -0
  50. package/dist/src/sourcemaps/tools/create-react-app.js.map +1 -0
  51. package/dist/src/sourcemaps/tools/esbuild.js +2 -1
  52. package/dist/src/sourcemaps/tools/esbuild.js.map +1 -1
  53. package/dist/src/sourcemaps/tools/rollup.js +2 -1
  54. package/dist/src/sourcemaps/tools/rollup.js.map +1 -1
  55. package/dist/src/sourcemaps/tools/sentry-cli.js +7 -1
  56. package/dist/src/sourcemaps/tools/sentry-cli.js.map +1 -1
  57. package/dist/src/sourcemaps/tools/vite.js +2 -1
  58. package/dist/src/sourcemaps/tools/vite.js.map +1 -1
  59. package/dist/src/sourcemaps/tools/webpack.js +2 -1
  60. package/dist/src/sourcemaps/tools/webpack.js.map +1 -1
  61. package/dist/src/sourcemaps/utils/detect-tool.d.ts +3 -0
  62. package/dist/src/sourcemaps/utils/detect-tool.js +73 -0
  63. package/dist/src/sourcemaps/utils/detect-tool.js.map +1 -0
  64. package/dist/src/sourcemaps/utils/other-wizards.d.ts +4 -0
  65. package/dist/src/sourcemaps/utils/other-wizards.js +183 -0
  66. package/dist/src/sourcemaps/utils/other-wizards.js.map +1 -0
  67. package/dist/src/sourcemaps/utils/sdk-version.d.ts +14 -0
  68. package/dist/src/sourcemaps/utils/sdk-version.js +276 -0
  69. package/dist/src/sourcemaps/utils/sdk-version.js.map +1 -0
  70. package/dist/src/sveltekit/sveltekit-wizard.d.ts +2 -5
  71. package/dist/src/sveltekit/sveltekit-wizard.js +3 -2
  72. package/dist/src/sveltekit/sveltekit-wizard.js.map +1 -1
  73. package/dist/src/telemetry.d.ts +1 -0
  74. package/dist/src/telemetry.js +7 -1
  75. package/dist/src/telemetry.js.map +1 -1
  76. package/dist/src/utils/bash.d.ts +3 -0
  77. package/dist/src/utils/bash.js +118 -0
  78. package/dist/src/utils/bash.js.map +1 -0
  79. package/dist/src/utils/clack-utils.d.ts +21 -9
  80. package/dist/src/utils/clack-utils.js +122 -56
  81. package/dist/src/utils/clack-utils.js.map +1 -1
  82. package/dist/src/utils/package-json.d.ts +19 -0
  83. package/dist/src/utils/package-json.js +29 -0
  84. package/dist/src/utils/package-json.js.map +1 -0
  85. package/dist/src/utils/types.d.ts +16 -0
  86. package/dist/src/utils/types.js +3 -0
  87. package/dist/src/utils/types.js.map +1 -0
  88. package/lib/Constants.ts +6 -0
  89. package/lib/Helper/Wizard.ts +3 -9
  90. package/lib/Helper/__tests__/SentryCli.ts +2 -1
  91. package/lib/Setup.ts +1 -0
  92. package/lib/Steps/ChooseIntegration.ts +39 -11
  93. package/lib/Steps/Integrations/Apple.ts +27 -0
  94. package/lib/Steps/Integrations/{NextJs.ts → NextJsShim.ts} +6 -2
  95. package/lib/Steps/Integrations/SourceMapsShim.ts +5 -1
  96. package/lib/Steps/Integrations/{SvelteKit.ts → SvelteKitShim.ts} +6 -2
  97. package/package-lock.json +8910 -0
  98. package/package.json +4 -4
  99. package/src/apple/apple-wizard.ts +150 -0
  100. package/src/apple/code-tools.ts +81 -0
  101. package/src/apple/templates.ts +39 -0
  102. package/src/apple/xcode-manager.ts +147 -0
  103. package/src/nextjs/nextjs-wizard.ts +3 -8
  104. package/src/sourcemaps/sourcemaps-wizard.ts +166 -91
  105. package/src/sourcemaps/tools/angular.ts +42 -0
  106. package/src/sourcemaps/tools/create-react-app.ts +19 -0
  107. package/src/sourcemaps/tools/esbuild.ts +1 -1
  108. package/src/sourcemaps/tools/rollup.ts +2 -4
  109. package/src/sourcemaps/tools/sentry-cli.ts +6 -1
  110. package/src/sourcemaps/tools/vite.ts +1 -1
  111. package/src/sourcemaps/tools/webpack.ts +1 -1
  112. package/src/sourcemaps/utils/detect-tool.ts +41 -0
  113. package/src/sourcemaps/utils/other-wizards.ts +148 -0
  114. package/src/sourcemaps/utils/sdk-version.ts +257 -0
  115. package/src/sveltekit/sveltekit-wizard.ts +4 -7
  116. package/src/telemetry.ts +8 -0
  117. package/src/utils/bash.ts +44 -0
  118. package/src/utils/clack-utils.ts +100 -51
  119. package/src/utils/package-json.ts +45 -0
  120. package/src/utils/types.ts +18 -0
  121. package/dist/lib/Steps/Integrations/NextJs.js.map +0 -1
  122. package/dist/lib/Steps/Integrations/SvelteKit.js.map +0 -1
@@ -9,6 +9,7 @@ import {
9
9
  askForSelfHosted,
10
10
  askForWizardLogin,
11
11
  confirmContinueEvenThoughNoGitRepo,
12
+ detectPackageManager,
12
13
  printWelcome,
13
14
  } from '../utils/clack-utils';
14
15
  import { isUnicodeSupported } from '../utils/vendor/is-unicorn-supported';
@@ -19,21 +20,29 @@ import { configureWebPackPlugin } from './tools/webpack';
19
20
  import { configureTscSourcemapGenerationFlow } from './tools/tsc';
20
21
  import { configureRollupPlugin } from './tools/rollup';
21
22
  import { configureEsbuildPlugin } from './tools/esbuild';
23
+ import { WizardOptions } from '../utils/types';
24
+ import { configureCRASourcemapGenerationFlow } from './tools/create-react-app';
25
+ import { ensureMinimumSdkVersionIsInstalled } from './utils/sdk-version';
26
+ import { traceStep, withTelemetry } from '../telemetry';
27
+ import { URL } from 'url';
28
+ import { checkIfMoreSuitableWizardExistsAndAskForRedirect } from './utils/other-wizards';
29
+ import { configureAngularSourcemapGenerationFlow } from './tools/angular';
30
+ import { detectUsedTool, SupportedTools } from './utils/detect-tool';
22
31
 
23
- interface SourceMapsWizardOptions {
24
- promoCode?: string;
32
+ export async function runSourcemapsWizard(
33
+ options: WizardOptions,
34
+ ): Promise<void> {
35
+ return withTelemetry(
36
+ {
37
+ enabled: options.telemetryEnabled,
38
+ integration: 'sourcemaps',
39
+ },
40
+ () => runSourcemapsWizardWithTelemetry(options),
41
+ );
25
42
  }
26
43
 
27
- type SupportedTools =
28
- | 'webpack'
29
- | 'vite'
30
- | 'rollup'
31
- | 'esbuild'
32
- | 'tsc'
33
- | 'sentry-cli';
34
-
35
- export async function runSourcemapsWizard(
36
- options: SourceMapsWizardOptions,
44
+ async function runSourcemapsWizardWithTelemetry(
45
+ options: WizardOptions,
37
46
  ): Promise<void> {
38
47
  printWelcome({
39
48
  wizardName: 'Sentry Source Maps Upload Configuration Wizard',
@@ -42,119 +51,94 @@ export async function runSourcemapsWizard(
42
51
  promoCode: options.promoCode,
43
52
  });
44
53
 
45
- await confirmContinueEvenThoughNoGitRepo();
46
-
47
- const { url: sentryUrl, selfHosted } = await askForSelfHosted();
48
-
49
- const { projects, apiKeys } = await askForWizardLogin({
50
- promoCode: options.promoCode,
51
- url: sentryUrl,
52
- });
53
-
54
- const selectedProject = await askForProjectSelection(projects);
55
-
56
- const selectedTool = await askForUsedBundlerTool();
57
-
58
- Sentry.setTag('selected-tool', selectedTool);
59
-
60
- await startToolSetupFlow(selectedTool, {
61
- selfHosted,
62
- orgSlug: selectedProject.organization.slug,
63
- projectSlug: selectedProject.slug,
64
- url: sentryUrl,
65
- authToken: apiKeys.token,
66
- });
67
-
68
- clack.log.step(
69
- 'Add the Sentry authentication token as an environment variable to your CI setup:',
54
+ const moreSuitableWizard = await traceStep(
55
+ 'check-framework-wizard',
56
+ checkIfMoreSuitableWizardExistsAndAskForRedirect,
70
57
  );
58
+ if (moreSuitableWizard) {
59
+ await traceStep('run-framework-wizard', () => moreSuitableWizard(options));
60
+ return;
61
+ }
71
62
 
72
- // Intentially logging directly to console here so that the code can be copied/pasted directly
73
- // eslint-disable-next-line no-console
74
- console.log(
75
- chalk.greenBright(`
76
- SENTRY_AUTH_TOKEN=${apiKeys.token}
77
- `),
78
- );
63
+ await traceStep('detect-git', confirmContinueEvenThoughNoGitRepo);
79
64
 
80
- clack.log.warn(
81
- chalk.yellow('DO NOT commit this auth token to your repository!'),
65
+ await traceStep('check-sdk-version', ensureMinimumSdkVersionIsInstalled);
66
+
67
+ const { url: sentryUrl, selfHosted } = await traceStep(
68
+ 'ask-self-hosted',
69
+ () => askForSelfHosted(options.url),
82
70
  );
83
71
 
84
- const addedEnvVarToCI = await abortIfCancelled(
85
- clack.select({
86
- message: 'Did you configure CI as shown above?',
87
- options: [
88
- { label: 'Yes, continue!', value: true },
89
- {
90
- label: "I'll do it later...",
91
- value: false,
92
- hint: chalk.yellow(
93
- 'You need to set the auth token to upload source maps in CI',
94
- ),
95
- },
96
- ],
97
- initialValue: true,
72
+ const { projects, apiKeys } = await traceStep('login', () =>
73
+ askForWizardLogin({
74
+ promoCode: options.promoCode,
75
+ url: sentryUrl,
98
76
  }),
99
77
  );
100
78
 
101
- Sentry.setTag('added-env-var-to-ci', addedEnvVarToCI);
102
-
103
- if (!addedEnvVarToCI) {
104
- clack.log.info("Don't forget! :)");
105
- }
79
+ const selectedProject = await traceStep('select-project', () =>
80
+ askForProjectSelection(projects),
81
+ );
106
82
 
107
- const arrow = isUnicodeSupported() ? '' : '->';
83
+ const selectedTool = await traceStep('select-tool', askForUsedBundlerTool);
108
84
 
109
- clack.outro(`${chalk.green("That's it - everything is set up!")}
85
+ Sentry.setTag('selected-tool', selectedTool);
110
86
 
111
- ${chalk.cyan(`Validate your setup with the following Steps:
87
+ await traceStep('tool-setup', () =>
88
+ startToolSetupFlow(selectedTool, {
89
+ selfHosted,
90
+ orgSlug: selectedProject.organization.slug,
91
+ projectSlug: selectedProject.slug,
92
+ url: sentryUrl,
93
+ authToken: apiKeys.token,
94
+ }),
95
+ );
112
96
 
113
- 1. Build your application in ${chalk.bold('production mode')}.
114
- ${chalk.gray(
115
- `${arrow} You should see source map upload logs in your console.`,
116
- )}
117
- 2. Run your application and throw a test error.
118
- ${chalk.gray(`${arrow} The error should be visible in Sentry.`)}
119
- 3. Open the error in Sentry and verify that it's source-mapped.
120
- ${chalk.gray(
121
- `${arrow} The stack trace should show your original source code.`,
122
- )}
123
- `)}
124
- ${chalk.dim(
125
- `If you encounter any issues, please refer to the Troubleshooting Guide:
126
- https://docs.sentry.io/platforms/javascript/sourcemaps/troubleshooting_js
97
+ await traceStep('ci-setup', () => setupCi(apiKeys.token));
127
98
 
128
- If the guide doesn't help or you encounter a bug, please let us know:
129
- https://github.com/getsentry/sentry-javascript/issues`,
130
- )}
131
- `);
99
+ traceStep('outro', () =>
100
+ printOutro(
101
+ sentryUrl,
102
+ selectedProject.organization.slug,
103
+ selectedProject.id,
104
+ ),
105
+ );
132
106
  }
133
107
 
134
108
  async function askForUsedBundlerTool(): Promise<SupportedTools> {
135
109
  const selectedTool: SupportedTools | symbol = await abortIfCancelled(
136
110
  clack.select({
137
- message: 'Which bundler or build tool are you using?',
111
+ message: 'Which framework, bundler or build tool are you using?',
138
112
  options: [
113
+ {
114
+ label: 'Angular',
115
+ value: 'angular',
116
+ hint: 'Select this option if you are using Angular.',
117
+ },
118
+ {
119
+ label: 'Create React App',
120
+ value: 'create-react-app',
121
+ hint: 'Select this option if you set up your app with Create React App.',
122
+ },
139
123
  {
140
124
  label: 'Webpack',
141
125
  value: 'webpack',
142
- hint: 'Configure source maps upload using Webpack',
126
+ hint: 'Select this if you are using Webpack and you have access to your Webpack config.',
143
127
  },
144
128
  {
145
129
  label: 'Vite',
146
130
  value: 'vite',
147
- hint: 'Configure source maps upload using Vite',
131
+ hint: 'Select this if you are using Vite and you have access to your Vite config.',
148
132
  },
149
133
  {
150
134
  label: 'esbuild',
151
135
  value: 'esbuild',
152
- hint: 'Configure source maps upload using esbuild',
136
+ hint: 'Select this if you are using esbuild and you have access to your esbuild config.',
153
137
  },
154
138
  {
155
139
  label: 'Rollup',
156
140
  value: 'rollup',
157
- hint: 'Configure source maps upload using Rollup',
141
+ hint: 'Select this if you are using Rollup and you have access to your Rollup config.',
158
142
  },
159
143
  {
160
144
  label: 'tsc',
@@ -167,6 +151,7 @@ async function askForUsedBundlerTool(): Promise<SupportedTools> {
167
151
  hint: 'This will configure source maps upload for you using sentry-cli',
168
152
  },
169
153
  ],
154
+ initialValue: await detectUsedTool(),
170
155
  }),
171
156
  );
172
157
 
@@ -193,8 +178,98 @@ async function startToolSetupFlow(
193
178
  case 'tsc':
194
179
  await configureSentryCLI(options, configureTscSourcemapGenerationFlow);
195
180
  break;
181
+ case 'create-react-app':
182
+ await configureSentryCLI(options, configureCRASourcemapGenerationFlow);
183
+ break;
184
+ case 'angular':
185
+ await configureSentryCLI(
186
+ options,
187
+ configureAngularSourcemapGenerationFlow,
188
+ );
189
+ break;
196
190
  default:
197
191
  await configureSentryCLI(options);
198
192
  break;
199
193
  }
200
194
  }
195
+
196
+ async function setupCi(authToken: string) {
197
+ clack.log.step(
198
+ 'Add the Sentry authentication token as an environment variable to your CI setup:',
199
+ );
200
+
201
+ // Intentially logging directly to console here so that the code can be copied/pasted directly
202
+ // eslint-disable-next-line no-console
203
+ console.log(
204
+ chalk.greenBright(`
205
+ SENTRY_AUTH_TOKEN=${authToken}
206
+ `),
207
+ );
208
+
209
+ clack.log.warn(
210
+ chalk.yellow('DO NOT commit this auth token to your repository!'),
211
+ );
212
+
213
+ const addedEnvVarToCI = await abortIfCancelled(
214
+ clack.select({
215
+ message: 'Did you configure CI as shown above?',
216
+ options: [
217
+ { label: 'Yes, continue!', value: true },
218
+ {
219
+ label: "I'll do it later...",
220
+ value: false,
221
+ hint: chalk.yellow(
222
+ 'You need to set the auth token to upload source maps in CI',
223
+ ),
224
+ },
225
+ ],
226
+ initialValue: true,
227
+ }),
228
+ );
229
+
230
+ Sentry.setTag('added-env-var-to-ci', addedEnvVarToCI);
231
+
232
+ if (!addedEnvVarToCI) {
233
+ clack.log.info("Don't forget! :)");
234
+ }
235
+ }
236
+
237
+ function printOutro(url: string, orgSlug: string, projectId: string) {
238
+ const pacMan = detectPackageManager() || 'npm';
239
+ const buildCommand = `'${pacMan}${pacMan === 'npm' ? ' run' : ''} build'`;
240
+
241
+ const urlObject = new URL(url);
242
+ urlObject.host = `${orgSlug}.${urlObject.host}`;
243
+ urlObject.pathname = '/issues/';
244
+ urlObject.searchParams.set('project', projectId);
245
+
246
+ const issueStreamUrl = urlObject.toString();
247
+
248
+ const arrow = isUnicodeSupported() ? '→' : '->';
249
+
250
+ clack.outro(`${chalk.green("That's it - everything is set up!")}
251
+
252
+ ${chalk.cyan(`Test and validate your setup locally with the following Steps:
253
+
254
+ 1. Build your application in ${chalk.bold('production mode')}.
255
+ ${chalk.gray(`${arrow} For example, run ${chalk.bold(buildCommand)}.`)}
256
+ ${chalk.gray(
257
+ `${arrow} You should see source map upload logs in your console.`,
258
+ )}
259
+ 2. Run your application and throw a test error.
260
+ ${chalk.gray(`${arrow} The error should appear in Sentry:`)}
261
+ ${chalk.gray(`${arrow} ${issueStreamUrl}`)}
262
+ 3. Open the error in Sentry and verify that it's source-mapped.
263
+ ${chalk.gray(
264
+ `${arrow} The stack trace should show your original source code.`,
265
+ )}
266
+ `)}
267
+ ${chalk.dim(
268
+ `If you encounter any issues, please refer to the Troubleshooting Guide:
269
+ https://docs.sentry.io/platforms/javascript/sourcemaps/troubleshooting_js
270
+
271
+ If the guide doesn't help or you encounter a bug, please let us know:
272
+ https://github.com/getsentry/sentry-javascript/issues`,
273
+ )}
274
+ `);
275
+ }
@@ -0,0 +1,42 @@
1
+ // @ts-ignore - clack is ESM and TS complains about that. It works though
2
+ import clack from '@clack/prompts';
3
+ import chalk from 'chalk';
4
+ import { abortIfCancelled } from '../../utils/clack-utils';
5
+
6
+ const angularJsonTemplate = chalk.gray(`{
7
+ "projects": {
8
+ "your-project": {
9
+ "architect": {
10
+ "build": {
11
+ "options": {
12
+ ${chalk.greenBright(`"sourceMap": true`)}
13
+ },
14
+ },
15
+ }
16
+ }
17
+ }
18
+ }`);
19
+
20
+ export async function configureAngularSourcemapGenerationFlow(): Promise<void> {
21
+ clack.log.info(
22
+ `Enable generating source maps in your ${chalk.bold('angular.json')} file:`,
23
+ );
24
+
25
+ // Intentially logging directly to console here so that the code can be copied/pasted directly
26
+ // eslint-disable-next-line no-console
27
+ console.log(angularJsonTemplate);
28
+
29
+ await abortIfCancelled(
30
+ clack.select({
31
+ message: `Verify that you are generating source maps when building your Angular app.`,
32
+ options: [
33
+ {
34
+ label: 'I checked!',
35
+ hint: 'My build output folder contains .js.map files after a build.',
36
+ value: true,
37
+ },
38
+ ],
39
+ initialValue: true,
40
+ }),
41
+ );
42
+ }
@@ -0,0 +1,19 @@
1
+ // @ts-ignore - clack is ESM and TS complains about that. It works though
2
+ import clack from '@clack/prompts';
3
+ import { abortIfCancelled } from '../../utils/clack-utils';
4
+
5
+ export async function configureCRASourcemapGenerationFlow(): Promise<void> {
6
+ await abortIfCancelled(
7
+ clack.select({
8
+ message: `Verify that you are generating source maps when building your React app.\nGenerally this should already happen unless you set the GENERATE_SOURCEMAPS environment variable to false.`,
9
+ options: [
10
+ {
11
+ label: 'I checked!',
12
+ hint: 'My build output folder contains .js.map files after a build.',
13
+ value: true,
14
+ },
15
+ ],
16
+ initialValue: true,
17
+ }),
18
+ );
19
+ }
@@ -5,9 +5,9 @@ import {
5
5
  abortIfCancelled,
6
6
  addDotEnvSentryBuildPluginFile,
7
7
  getPackageDotJson,
8
- hasPackageInstalled,
9
8
  installPackage,
10
9
  } from '../../utils/clack-utils';
10
+ import { hasPackageInstalled } from '../../utils/package-json';
11
11
 
12
12
  import {
13
13
  SourceMapUploadToolConfigurationFunction,
@@ -5,9 +5,9 @@ import {
5
5
  abortIfCancelled,
6
6
  addDotEnvSentryBuildPluginFile,
7
7
  getPackageDotJson,
8
- hasPackageInstalled,
9
8
  installPackage,
10
9
  } from '../../utils/clack-utils';
10
+ import { hasPackageInstalled } from '../../utils/package-json';
11
11
 
12
12
  import {
13
13
  SourceMapUploadToolConfigurationFunction,
@@ -49,9 +49,7 @@ export const configureRollupPlugin: SourceMapUploadToolConfigurationFunction =
49
49
  ),
50
50
  });
51
51
 
52
- clack.log.step(
53
- `Add the following code to your rollup config:`,
54
- );
52
+ clack.log.step(`Add the following code to your rollup config:`);
55
53
 
56
54
  // Intentially logging directly to console here so that the code can be copied/pasted directly
57
55
  // eslint-disable-next-line no-console
@@ -8,11 +8,11 @@ import {
8
8
  abortIfCancelled,
9
9
  addSentryCliRc,
10
10
  getPackageDotJson,
11
- hasPackageInstalled,
12
11
  installPackage,
13
12
  } from '../../utils/clack-utils';
14
13
 
15
14
  import { SourceMapUploadToolConfigurationOptions } from './types';
15
+ import { hasPackageInstalled } from '../../utils/package-json';
16
16
 
17
17
  export async function configureSentryCLI(
18
18
  options: SourceMapUploadToolConfigurationOptions,
@@ -32,6 +32,11 @@ export async function configureSentryCLI(
32
32
  clack.text({
33
33
  message: 'Where are your build artifacts located?',
34
34
  placeholder: `.${path.sep}out`,
35
+ validate(value) {
36
+ if (!value) {
37
+ return 'Please enter a path.';
38
+ }
39
+ },
35
40
  }),
36
41
  );
37
42
 
@@ -5,9 +5,9 @@ import {
5
5
  abortIfCancelled,
6
6
  addDotEnvSentryBuildPluginFile,
7
7
  getPackageDotJson,
8
- hasPackageInstalled,
9
8
  installPackage,
10
9
  } from '../../utils/clack-utils';
10
+ import { hasPackageInstalled } from '../../utils/package-json';
11
11
 
12
12
  import {
13
13
  SourceMapUploadToolConfigurationFunction,
@@ -5,9 +5,9 @@ import {
5
5
  abortIfCancelled,
6
6
  addDotEnvSentryBuildPluginFile,
7
7
  getPackageDotJson,
8
- hasPackageInstalled,
9
8
  installPackage,
10
9
  } from '../../utils/clack-utils';
10
+ import { hasPackageInstalled } from '../../utils/package-json';
11
11
 
12
12
  import {
13
13
  SourceMapUploadToolConfigurationFunction,
@@ -0,0 +1,41 @@
1
+ import { getPackageDotJson } from '../../utils/clack-utils';
2
+ import { findInstalledPackageFromList } from '../../utils/package-json';
3
+
4
+ export type SupportedTools =
5
+ | 'webpack'
6
+ | 'vite'
7
+ | 'rollup'
8
+ | 'esbuild'
9
+ | 'tsc'
10
+ | 'sentry-cli'
11
+ | 'create-react-app'
12
+ | 'angular';
13
+
14
+ // A map of package names pointing to the tool slug.
15
+ // The order is important, because we want to detect the most specific tool first.
16
+ // For instance, webpack needs to come before tsc because typescript c
17
+ // Similarly
18
+ export const TOOL_PACKAGE_MAP: Record<string, SupportedTools> = {
19
+ '@angular/core': 'angular',
20
+ 'create-react-app': 'create-react-app',
21
+ webpack: 'webpack',
22
+ vite: 'vite',
23
+ esbuild: 'esbuild',
24
+ rollup: 'rollup',
25
+ typescript: 'tsc',
26
+ };
27
+
28
+ export async function detectUsedTool(): Promise<SupportedTools> {
29
+ const packageJson = await getPackageDotJson();
30
+
31
+ const foundToolPackage = findInstalledPackageFromList(
32
+ Object.keys(TOOL_PACKAGE_MAP),
33
+ packageJson,
34
+ );
35
+
36
+ if (foundToolPackage) {
37
+ return TOOL_PACKAGE_MAP[foundToolPackage.name];
38
+ }
39
+
40
+ return 'sentry-cli';
41
+ }
@@ -0,0 +1,148 @@
1
+ // @ts-ignore - clack is ESM and TS complains about that. It works though
2
+ import clack from '@clack/prompts';
3
+ import chalk from 'chalk';
4
+ import { runNextjsWizard } from '../../nextjs/nextjs-wizard';
5
+ import { runSvelteKitWizard } from '../../sveltekit/sveltekit-wizard';
6
+
7
+ import {
8
+ abort,
9
+ abortIfCancelled,
10
+ getPackageDotJson,
11
+ } from '../../utils/clack-utils';
12
+ import {
13
+ findInstalledPackageFromList,
14
+ hasPackageInstalled,
15
+ } from '../../utils/package-json';
16
+
17
+ import * as Sentry from '@sentry/node';
18
+ import { WizardOptions } from '../../utils/types';
19
+
20
+ type WizardFunction = (options: WizardOptions) => Promise<void>;
21
+
22
+ type FrameworkInfo = {
23
+ frameworkName: string;
24
+ frameworkSlug: string;
25
+ frameworkPackage: string;
26
+ sourcemapsDocsLink: string;
27
+ wizard: WizardFunction;
28
+ };
29
+
30
+ const sdkMap: Record<string, FrameworkInfo> = {
31
+ '@sentry/nextjs': {
32
+ frameworkName: 'Next.js',
33
+ frameworkSlug: 'nextjs',
34
+ frameworkPackage: 'next',
35
+ sourcemapsDocsLink:
36
+ 'https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#configure-source-maps',
37
+ wizard: runNextjsWizard,
38
+ },
39
+ '@sentry/sveltekit': {
40
+ frameworkName: 'SvelteKit',
41
+ frameworkSlug: 'sveltekit',
42
+ frameworkPackage: '@sveltejs/kit',
43
+ sourcemapsDocsLink:
44
+ 'https://docs.sentry.io/platforms/javascript/guides/sveltekit/manual-setup/#configure-source-maps-upload',
45
+ wizard: runSvelteKitWizard,
46
+ },
47
+ };
48
+
49
+ export async function checkIfMoreSuitableWizardExistsAndAskForRedirect(): Promise<
50
+ WizardFunction | undefined
51
+ > {
52
+ const sdkName = await checkIfMoreSuitableWizardExists();
53
+
54
+ if (!sdkName) {
55
+ return undefined;
56
+ }
57
+
58
+ return await askForRedirect(sdkName);
59
+ }
60
+
61
+ async function checkIfMoreSuitableWizardExists(): Promise<string | undefined> {
62
+ Sentry.setTag('using-wrong-wizard', false);
63
+
64
+ const packageJson = await getPackageDotJson();
65
+
66
+ const installedSdkPackage = findInstalledPackageFromList(
67
+ Object.keys(sdkMap),
68
+ packageJson,
69
+ );
70
+
71
+ if (!installedSdkPackage) {
72
+ return undefined;
73
+ }
74
+
75
+ const sdkPackageName = installedSdkPackage.name;
76
+
77
+ const { frameworkPackage } = sdkMap[sdkPackageName];
78
+
79
+ if (!hasPackageInstalled(frameworkPackage, packageJson)) {
80
+ // The user has installed the SDK but not the framework.
81
+ // Maybe it's a false positive and the user is using a different framework.
82
+ // Let's not redirect them to the framework wizard in that case.
83
+ return undefined;
84
+ }
85
+
86
+ Sentry.setTag('using-wrong-wizard', true);
87
+
88
+ return sdkPackageName;
89
+ }
90
+
91
+ async function askForRedirect(
92
+ sdkName: string,
93
+ ): Promise<WizardFunction | undefined> {
94
+ const { frameworkName, sourcemapsDocsLink, frameworkSlug, wizard } =
95
+ sdkMap[sdkName];
96
+
97
+ clack.log.warn(
98
+ `${chalk.yellow(
99
+ `It seems like you're using this wizard in a ${frameworkName} project.`,
100
+ )}
101
+
102
+ We recommend using our dedicated ${frameworkName} wizard instead of this wizard.
103
+ The ${frameworkName} wizard will set up our ${sdkName} SDK and also configure uploading source maps for you.
104
+
105
+ If you already tried the ${frameworkName} wizard and it didn't work for you, check out the following guides:
106
+
107
+ Manual source maps configuration for ${frameworkName}:
108
+ ${sourcemapsDocsLink}
109
+
110
+ Troubleshooting Source Maps:
111
+ https://docs.sentry.io/platforms/javascript/guides/${frameworkSlug}/sourcemaps/troubleshooting_js/
112
+ `,
113
+ );
114
+
115
+ const nextStep: 'redirect' | 'continue' | 'stop' = await abortIfCancelled(
116
+ clack.select({
117
+ message: `Do you want to run the ${frameworkName} wizard now?`,
118
+ options: [
119
+ {
120
+ label: 'Yes',
121
+ value: 'redirect',
122
+ hint: `${chalk.green('Recommended')}`,
123
+ },
124
+ {
125
+ label: 'No, continue with this wizard',
126
+ value: 'continue',
127
+ },
128
+ {
129
+ label: "No, I'll check out the guides ",
130
+ value: 'stop',
131
+ hint: 'Exit this wizard',
132
+ },
133
+ ],
134
+ }),
135
+ );
136
+
137
+ Sentry.setTag('wrong-wizard-decision', nextStep);
138
+
139
+ switch (nextStep) {
140
+ case 'redirect':
141
+ return wizard;
142
+ case 'stop':
143
+ await abort('Exiting Wizard', 0);
144
+ break;
145
+ default:
146
+ return undefined;
147
+ }
148
+ }