@sentry/wizard 3.34.4 → 3.36.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 (88) hide show
  1. package/CHANGELOG.md +18 -1
  2. package/dist/e2e-tests/tests/nuxt-3.test.d.ts +1 -0
  3. package/dist/e2e-tests/tests/nuxt-3.test.js +257 -0
  4. package/dist/e2e-tests/tests/nuxt-3.test.js.map +1 -0
  5. package/dist/e2e-tests/tests/nuxt-4.test.d.ts +1 -0
  6. package/dist/e2e-tests/tests/nuxt-4.test.js +258 -0
  7. package/dist/e2e-tests/tests/nuxt-4.test.js.map +1 -0
  8. package/dist/e2e-tests/tests/remix.test.js +92 -27
  9. package/dist/e2e-tests/tests/remix.test.js.map +1 -1
  10. package/dist/e2e-tests/tests/sveltekit.test.js +102 -42
  11. package/dist/e2e-tests/tests/sveltekit.test.js.map +1 -1
  12. package/dist/e2e-tests/utils/index.d.ts +18 -1
  13. package/dist/e2e-tests/utils/index.js +31 -2
  14. package/dist/e2e-tests/utils/index.js.map +1 -1
  15. package/dist/lib/Constants.d.ts +1 -0
  16. package/dist/lib/Constants.js +1 -0
  17. package/dist/lib/Constants.js.map +1 -1
  18. package/dist/package.json +1 -1
  19. package/dist/src/android/templates.js +1 -1
  20. package/dist/src/android/templates.js.map +1 -1
  21. package/dist/src/apple/templates.js +2 -2
  22. package/dist/src/apple/templates.js.map +1 -1
  23. package/dist/src/nextjs/nextjs-wizard.js +1 -0
  24. package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
  25. package/dist/src/nuxt/nuxt-wizard.d.ts +3 -0
  26. package/dist/src/nuxt/nuxt-wizard.js +227 -0
  27. package/dist/src/nuxt/nuxt-wizard.js.map +1 -0
  28. package/dist/src/nuxt/sdk-example.d.ts +8 -0
  29. package/dist/src/nuxt/sdk-example.js +179 -0
  30. package/dist/src/nuxt/sdk-example.js.map +1 -0
  31. package/dist/src/nuxt/sdk-setup.d.ts +11 -0
  32. package/dist/src/nuxt/sdk-setup.js +326 -0
  33. package/dist/src/nuxt/sdk-setup.js.map +1 -0
  34. package/dist/src/nuxt/templates.d.ts +22 -0
  35. package/dist/src/nuxt/templates.js +84 -0
  36. package/dist/src/nuxt/templates.js.map +1 -0
  37. package/dist/src/nuxt/utils.d.ts +1 -0
  38. package/dist/src/nuxt/utils.js +71 -0
  39. package/dist/src/nuxt/utils.js.map +1 -0
  40. package/dist/src/remix/remix-wizard.js +2 -1
  41. package/dist/src/remix/remix-wizard.js.map +1 -1
  42. package/dist/src/run.d.ts +1 -1
  43. package/dist/src/run.js +30 -23
  44. package/dist/src/run.js.map +1 -1
  45. package/dist/src/sourcemaps/tools/rollup.js +1 -1
  46. package/dist/src/sourcemaps/tools/rollup.js.map +1 -1
  47. package/dist/src/sveltekit/sveltekit-wizard.js +2 -1
  48. package/dist/src/sveltekit/sveltekit-wizard.js.map +1 -1
  49. package/dist/src/utils/clack-utils.d.ts +9 -2
  50. package/dist/src/utils/clack-utils.js +93 -27
  51. package/dist/src/utils/clack-utils.js.map +1 -1
  52. package/dist/src/utils/package-json.d.ts +5 -0
  53. package/dist/src/utils/package-json.js.map +1 -1
  54. package/dist/src/utils/package-manager.d.ts +1 -0
  55. package/dist/src/utils/package-manager.js +129 -0
  56. package/dist/src/utils/package-manager.js.map +1 -1
  57. package/dist/test/nuxt/templates.test.d.ts +1 -0
  58. package/dist/test/nuxt/templates.test.js +70 -0
  59. package/dist/test/nuxt/templates.test.js.map +1 -0
  60. package/e2e-tests/README.md +59 -0
  61. package/e2e-tests/test-applications/nuxt-3-test-app/README.md +75 -0
  62. package/e2e-tests/test-applications/nuxt-3-test-app/nuxt.config.ts +5 -0
  63. package/e2e-tests/test-applications/nuxt-3-test-app/package.json +18 -0
  64. package/e2e-tests/test-applications/nuxt-3-test-app/public/favicon.ico +0 -0
  65. package/e2e-tests/test-applications/nuxt-3-test-app/public/robots.txt +1 -0
  66. package/e2e-tests/tests/nuxt-3.test.ts +192 -0
  67. package/e2e-tests/tests/nuxt-4.test.ts +191 -0
  68. package/e2e-tests/tests/remix.test.ts +163 -50
  69. package/e2e-tests/tests/sveltekit.test.ts +180 -79
  70. package/e2e-tests/utils/index.ts +34 -1
  71. package/lib/Constants.ts +1 -0
  72. package/package.json +1 -1
  73. package/src/android/templates.ts +0 -2
  74. package/src/apple/templates.ts +14 -2
  75. package/src/nextjs/nextjs-wizard.ts +1 -0
  76. package/src/nuxt/nuxt-wizard.ts +177 -0
  77. package/src/nuxt/sdk-example.ts +135 -0
  78. package/src/nuxt/sdk-setup.ts +248 -0
  79. package/src/nuxt/templates.ts +296 -0
  80. package/src/nuxt/utils.ts +32 -0
  81. package/src/remix/remix-wizard.ts +2 -1
  82. package/src/run.ts +7 -0
  83. package/src/sourcemaps/tools/rollup.ts +1 -1
  84. package/src/sveltekit/sveltekit-wizard.ts +2 -1
  85. package/src/utils/clack-utils.ts +74 -13
  86. package/src/utils/package-json.ts +5 -0
  87. package/src/utils/package-manager.ts +66 -0
  88. package/test/nuxt/templates.test.ts +228 -0
@@ -0,0 +1,296 @@
1
+ import { getIssueStreamUrl } from '../utils/url';
2
+
3
+ type SelectedSentryFeatures = {
4
+ performance: boolean;
5
+ replay: boolean;
6
+ };
7
+
8
+ export function getDefaultNuxtConfig(): string {
9
+ return `// https://nuxt.com/docs/api/configuration/nuxt-config
10
+ export default defineNuxtConfig({
11
+ compatibilityDate: '2024-04-03',
12
+ devtools: { enabled: true }
13
+ })
14
+ `;
15
+ }
16
+
17
+ export function getNuxtModuleFallbackTemplate(options: {
18
+ org: string;
19
+ project: string;
20
+ url: string;
21
+ selfHosted: boolean;
22
+ }): string {
23
+ return ` modules: ["@sentry/nuxt/module"],
24
+ sentry: {
25
+ sourceMapsUploadOptions: {
26
+ org: "${options.org}",
27
+ project: "${options.project}",${
28
+ options.selfHosted ? `\n url: "${options.url}",` : ''
29
+ }
30
+ },
31
+ },
32
+ sourcemap: { client: "hidden" },`;
33
+ }
34
+
35
+ export function getSentryConfigContents(
36
+ dsn: string,
37
+ config: 'client' | 'server',
38
+ selectedFeatures: SelectedSentryFeatures,
39
+ ): string {
40
+ if (config === 'client') {
41
+ return getSentryClientConfigContents(dsn, selectedFeatures);
42
+ }
43
+
44
+ return getSentryServerConfigContents(dsn, selectedFeatures);
45
+ }
46
+
47
+ const featuresConfigMap: Record<keyof SelectedSentryFeatures, string> = {
48
+ performance: [
49
+ ' // We recommend adjusting this value in production, or using tracesSampler',
50
+ ' // for finer control',
51
+ ' tracesSampleRate: 1.0,',
52
+ ].join('\n'),
53
+ replay: [
54
+ ' // This sets the sample rate to be 10%. You may want this to be 100% while',
55
+ ' // in development and sample at a lower rate in production',
56
+ ' replaysSessionSampleRate: 0.1,',
57
+ ' ',
58
+ ' // If the entire session is not sampled, use the below sample rate to sample',
59
+ ' // sessions when an error occurs.',
60
+ ' replaysOnErrorSampleRate: 1.0,',
61
+ ' ',
62
+ " // If you don't want to use Session Replay, just remove the line below:",
63
+ ' integrations: [Sentry.replayIntegration()],',
64
+ ].join('\n'),
65
+ };
66
+
67
+ const featuresMap: Record<
68
+ 'client' | 'server',
69
+ Array<keyof SelectedSentryFeatures>
70
+ > = {
71
+ client: ['performance', 'replay'],
72
+ server: ['performance'],
73
+ };
74
+
75
+ export function getConfigBody(
76
+ dsn: string,
77
+ variant: 'client' | 'server',
78
+ selectedFeatures: SelectedSentryFeatures,
79
+ ) {
80
+ return [
81
+ `dsn: "${dsn}",`,
82
+ Object.entries(selectedFeatures)
83
+ .map(([feature, activated]: [keyof SelectedSentryFeatures, boolean]) => {
84
+ return featuresMap[variant].includes(feature) && activated
85
+ ? featuresConfigMap[feature]
86
+ : null;
87
+ })
88
+ .filter(Boolean)
89
+ .join('\n\n'),
90
+ ]
91
+ .filter(Boolean)
92
+ .join('\n\n');
93
+ }
94
+
95
+ function getSentryClientConfigContents(
96
+ dsn: string,
97
+ selectedFeatures: SelectedSentryFeatures,
98
+ ): string {
99
+ return `import * as Sentry from "@sentry/nuxt";
100
+
101
+ Sentry.init({
102
+ // If set up, you can use your runtime config here
103
+ // dsn: useRuntimeConfig().public.sentry.dsn,
104
+ ${getConfigBody(dsn, 'client', selectedFeatures)}
105
+
106
+ // Setting this option to true will print useful information to the console while you're setting up Sentry.
107
+ debug: false,
108
+ });
109
+ `;
110
+ }
111
+
112
+ function getSentryServerConfigContents(
113
+ dsn: string,
114
+ selectedFeatures: SelectedSentryFeatures,
115
+ ): string {
116
+ return `import * as Sentry from "@sentry/nuxt";
117
+
118
+ Sentry.init({
119
+ ${getConfigBody(dsn, 'server', selectedFeatures)}
120
+
121
+ // Setting this option to true will print useful information to the console while you're setting up Sentry.
122
+ debug: false,
123
+ });
124
+ `;
125
+ }
126
+
127
+ export function getIndexRouteTemplate(): string {
128
+ return `<!--
129
+ This is just to verify the sentry-example-page.
130
+ Feel free to delete this file.
131
+ -->
132
+
133
+ <template></template>`;
134
+ }
135
+
136
+ export function getSentryExamplePageTemplate(options: {
137
+ url: string;
138
+ org: string;
139
+ projectId: string;
140
+ }): string {
141
+ const { url, org, projectId } = options;
142
+ const issuesPageLink = getIssueStreamUrl({ url, orgSlug: org, projectId });
143
+
144
+ return `<!--
145
+ This is just a very simple page with a button to throw an example error.
146
+ Feel free to delete this file.
147
+ -->
148
+
149
+ <script setup>
150
+ import * as Sentry from '@sentry/nuxt';
151
+ import { useFetch} from '#imports'
152
+
153
+ function getSentryData() {
154
+ Sentry.startSpan(
155
+ {
156
+ name: 'Example Frontend Span',
157
+ op: 'test'
158
+ },
159
+ async () => {
160
+ const { error } = await useFetch('/api/sentry-example-api');
161
+ if (error.value) {
162
+ throw new Error('Sentry Example Frontend Error');
163
+ }
164
+ }
165
+ )
166
+ }
167
+ </script>
168
+
169
+ <template>
170
+ <title>Sentry Onboarding</title>
171
+ <div>
172
+ <main>
173
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 44">
174
+ <path
175
+ fill="currentColor"
176
+ 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"
177
+ />
178
+ </svg>
179
+ <p>
180
+ Get Started with this <strong>simple Example:</strong>
181
+ </p>
182
+
183
+ <p>1. Send us a sample error:</p>
184
+ <button type="button" @click="getSentryData"> Throw error! </button>
185
+
186
+ <p>
187
+ 2. Look for the error on the
188
+ <a href="${issuesPageLink}">Issues Page</a>.
189
+ </p>
190
+ <p style="margin-top: 24px;">
191
+ For more information, take a look at the
192
+ <a href="https://docs.sentry.io/platforms/javascript/guides/nuxt/">
193
+ Sentry Nuxt Documentation
194
+ </a>
195
+ </p>
196
+ </main>
197
+ </div>
198
+ </template>
199
+
200
+ <style scoped>
201
+ main {
202
+ display: flex;
203
+ flex-direction: column;
204
+ justify-content: center;
205
+ align-items: center;
206
+ }
207
+
208
+ svg {
209
+ font-size: 4rem;
210
+ margin: 14px 0;
211
+ height: 1em;
212
+ }
213
+
214
+ button {
215
+ padding: 12px;
216
+ cursor: pointer;
217
+ background-color: rgb(54, 45, 89);
218
+ border-radius: 4px;
219
+ border: none;
220
+ color: white;
221
+ font-size: 1em;
222
+ margin: 1em;
223
+ transition: all 0.25s ease-in-out;
224
+ }
225
+ button:hover {
226
+ background-color: #8c5393;
227
+ box-shadow: 4px;
228
+ box-shadow: 0px 0px 15px 2px rgba(140, 83, 147, 0.5);
229
+ }
230
+ button:active {
231
+ background-color: #c73852;
232
+ }
233
+ </style>
234
+ `;
235
+ }
236
+
237
+ export function getSentryExampleApiTemplate() {
238
+ return `// This is just a very simple API route that throws an example error.
239
+ // Feel free to delete this file.
240
+ import { defineEventHandler } from '#imports';
241
+
242
+ export default defineEventHandler(event => {
243
+ throw new Error("Sentry Example API Route Error");
244
+ });
245
+ `;
246
+ }
247
+
248
+ export function getSentryErrorButtonTemplate() {
249
+ return `<!--
250
+ This is just a very simple component that throws an example error.
251
+ Feel free to delete this file.
252
+ -->
253
+
254
+ <script setup>
255
+ import * as Sentry from '@sentry/nuxt';
256
+
257
+ const throwError = () => {
258
+ Sentry.startSpan(
259
+ {
260
+ name: 'Example Frontend Span',
261
+ op: 'test'
262
+ },
263
+ () => {
264
+ throw new Error('Sentry Example Error');
265
+ }
266
+ )
267
+ };
268
+ </script>
269
+
270
+ <template>
271
+ <button id="errorBtn" @click="throwError"> Throw Error! </button>
272
+ </template>
273
+
274
+ <style scoped>
275
+ button {
276
+ padding: 12px;
277
+ cursor: pointer;
278
+ background-color: rgb(54, 45, 89);
279
+ border-radius: 4px;
280
+ border: none;
281
+ color: white;
282
+ font-size: 1em;
283
+ margin: 1em;
284
+ transition: all 0.25s ease-in-out;
285
+ }
286
+ button:hover {
287
+ background-color: #8c5393;
288
+ box-shadow: 4px;
289
+ box-shadow: 0px 0px 15px 2px rgba(140, 83, 147, 0.5);
290
+ }
291
+ button:active {
292
+ background-color: #c73852;
293
+ }
294
+ </style>
295
+ `;
296
+ }
@@ -0,0 +1,32 @@
1
+ import { gte, minVersion } from 'semver';
2
+ // @ts-expect-error - magicast is ESM and TS complains about that. It works though
3
+ import { loadFile } from 'magicast';
4
+
5
+ export async function isNuxtV4(
6
+ nuxtConfig: string,
7
+ packageVersion: string | undefined,
8
+ ) {
9
+ if (!packageVersion) {
10
+ return false;
11
+ }
12
+
13
+ const minVer = minVersion(packageVersion);
14
+ if (minVer && gte(minVer, '4.0.0')) {
15
+ return true;
16
+ }
17
+
18
+ // At the time of writing, nuxt 4 is not on its own
19
+ // major yet. We must read the `compatibilityVersion`
20
+ // from the nuxt config.
21
+ const mod = await loadFile(nuxtConfig);
22
+ const config =
23
+ mod.exports.default.$type === 'function-call'
24
+ ? mod.exports.default.$args[0]
25
+ : mod.exports.default;
26
+
27
+ if (config && config.future && config.future.compatibilityVersion === 4) {
28
+ return true;
29
+ }
30
+
31
+ return false;
32
+ }
@@ -70,7 +70,8 @@ async function runRemixWizardWithTelemetry(
70
70
  await getOrAskForProjectData(options, 'javascript-remix');
71
71
 
72
72
  await installPackage({
73
- packageName: '@sentry/remix',
73
+ packageName: '@sentry/remix@^8',
74
+ packageNameDisplayLabel: '@sentry/remix',
74
75
  alreadyInstalled: hasPackageInstalled('@sentry/remix', packageJson),
75
76
  });
76
77
 
package/src/run.ts CHANGED
@@ -8,6 +8,7 @@ import type { PreselectedProject, WizardOptions } from './utils/types';
8
8
  import { runAndroidWizard } from './android/android-wizard';
9
9
  import { runAppleWizard } from './apple/apple-wizard';
10
10
  import { runNextjsWizard } from './nextjs/nextjs-wizard';
11
+ import { runNuxtWizard } from './nuxt/nuxt-wizard';
11
12
  import { runRemixWizard } from './remix/remix-wizard';
12
13
  import { runSvelteKitWizard } from './sveltekit/sveltekit-wizard';
13
14
  import { runSourcemapsWizard } from './sourcemaps/sourcemaps-wizard';
@@ -22,6 +23,7 @@ type WizardIntegration =
22
23
  | 'cordova'
23
24
  | 'electron'
24
25
  | 'nextjs'
26
+ | 'nuxt'
25
27
  | 'remix'
26
28
  | 'sveltekit'
27
29
  | 'sourcemaps';
@@ -103,6 +105,7 @@ export async function run(argv: Args) {
103
105
  { value: 'cordova', label: 'Cordova' },
104
106
  { value: 'electron', label: 'Electron' },
105
107
  { value: 'nextjs', label: 'Next.js' },
108
+ { value: 'nuxt', label: 'Nuxt' },
106
109
  { value: 'remix', label: 'Remix' },
107
110
  { value: 'sveltekit', label: 'SvelteKit' },
108
111
  { value: 'sourcemaps', label: 'Configure Source Maps Upload' },
@@ -148,6 +151,10 @@ export async function run(argv: Args) {
148
151
  await runNextjsWizard(wizardOptions);
149
152
  break;
150
153
 
154
+ case 'nuxt':
155
+ await runNuxtWizard(wizardOptions);
156
+ break;
157
+
151
158
  case 'remix':
152
159
  await runRemixWizard(wizardOptions);
153
160
  break;
@@ -51,7 +51,7 @@ export const configureRollupPlugin: SourceMapUploadToolConfigurationFunction =
51
51
 
52
52
  clack.log.step(`Add the following code to your rollup config:`);
53
53
 
54
- // Intentially logging directly to console here so that the code can be copied/pasted directly
54
+ // Intentionally logging directly to console here so that the code can be copied/pasted directly
55
55
  // eslint-disable-next-line no-console
56
56
  console.log(getCodeSnippet(options));
57
57
 
@@ -95,7 +95,8 @@ export async function runSvelteKitWizardWithTelemetry(
95
95
  Sentry.setTag('sdk-already-installed', sdkAlreadyInstalled);
96
96
 
97
97
  await installPackage({
98
- packageName: '@sentry/sveltekit',
98
+ packageName: '@sentry/sveltekit@^8',
99
+ packageNameDisplayLabel: '@sentry/sveltekit',
99
100
  alreadyInstalled: sdkAlreadyInstalled,
100
101
  });
101
102
 
@@ -354,17 +354,23 @@ export async function installPackage({
354
354
  packageName,
355
355
  alreadyInstalled,
356
356
  askBeforeUpdating = true,
357
+ packageNameDisplayLabel,
358
+ packageManager,
357
359
  }: {
360
+ /** The string that is passed to the package manager CLI as identifier to install (e.g. `@sentry/nextjs`, or `@sentry/nextjs@^8`) */
358
361
  packageName: string;
359
362
  alreadyInstalled: boolean;
360
363
  askBeforeUpdating?: boolean;
364
+ /** Overrides what is shown in the installation logs in place of the `packageName` option. Useful if the `packageName` is ugly (e.g. `@sentry/nextjs@^8`) */
365
+ packageNameDisplayLabel?: string;
366
+ packageManager?: PackageManager;
361
367
  }): Promise<{ packageManager?: PackageManager }> {
362
368
  return traceStep('install-package', async () => {
363
369
  if (alreadyInstalled && askBeforeUpdating) {
364
370
  const shouldUpdatePackage = await abortIfCancelled(
365
371
  clack.confirm({
366
372
  message: `The ${chalk.bold.cyan(
367
- packageName,
373
+ packageNameDisplayLabel ?? packageName,
368
374
  )} package is already installed. Do you want to update it to the latest version?`,
369
375
  }),
370
376
  );
@@ -376,18 +382,18 @@ export async function installPackage({
376
382
 
377
383
  const sdkInstallSpinner = clack.spinner();
378
384
 
379
- const packageManager = await getPackageManager();
385
+ const pkgManager = packageManager || (await getPackageManager());
380
386
 
381
387
  sdkInstallSpinner.start(
382
388
  `${alreadyInstalled ? 'Updating' : 'Installing'} ${chalk.bold.cyan(
383
- packageName,
384
- )} with ${chalk.bold(packageManager.label)}.`,
389
+ packageNameDisplayLabel ?? packageName,
390
+ )} with ${chalk.bold(pkgManager.label)}.`,
385
391
  );
386
392
 
387
393
  try {
388
394
  await new Promise<void>((resolve, reject) => {
389
395
  childProcess.exec(
390
- `${packageManager.installCommand} ${packageName} ${packageManager.flags}`,
396
+ `${pkgManager.installCommand} ${packageName} ${pkgManager.flags}`,
391
397
  (err, stdout, stderr) => {
392
398
  if (err) {
393
399
  // Write a log file so we can better troubleshoot issues
@@ -425,11 +431,11 @@ export async function installPackage({
425
431
 
426
432
  sdkInstallSpinner.stop(
427
433
  `${alreadyInstalled ? 'Updated' : 'Installed'} ${chalk.bold.cyan(
428
- packageName,
429
- )} with ${chalk.bold(packageManager.label)}.`,
434
+ packageNameDisplayLabel ?? packageName,
435
+ )} with ${chalk.bold(pkgManager.label)}.`,
430
436
  );
431
437
 
432
- return { packageManager };
438
+ return { packageManager: pkgManager };
433
439
  });
434
440
  }
435
441
 
@@ -593,7 +599,7 @@ SENTRY_AUTH_TOKEN=${authToken}
593
599
 
594
600
  if (hasAuthToken) {
595
601
  clack.log.warn(
596
- `${chalk.bold(
602
+ `${chalk.bold.cyan(
597
603
  SENTRY_DOT_ENV_FILE,
598
604
  )} already has auth token. Will not add one.`,
599
605
  );
@@ -608,11 +614,11 @@ SENTRY_AUTH_TOKEN=${authToken}
608
614
  },
609
615
  );
610
616
  clack.log.success(
611
- `Added auth token to ${chalk.bold(SENTRY_DOT_ENV_FILE)}`,
617
+ `Added auth token to ${chalk.bold.cyan(SENTRY_DOT_ENV_FILE)}`,
612
618
  );
613
619
  } catch {
614
620
  clack.log.warning(
615
- `Failed to add auth token to ${chalk.bold(
621
+ `Failed to add auth token to ${chalk.bold.cyan(
616
622
  SENTRY_DOT_ENV_FILE,
617
623
  )}. Uploading source maps during build will likely not work locally.`,
618
624
  );
@@ -625,13 +631,13 @@ SENTRY_AUTH_TOKEN=${authToken}
625
631
  flag: 'w',
626
632
  });
627
633
  clack.log.success(
628
- `Created ${chalk.bold(
634
+ `Created ${chalk.bold.cyan(
629
635
  SENTRY_DOT_ENV_FILE,
630
636
  )} with auth token for you to test source map uploading locally.`,
631
637
  );
632
638
  } catch {
633
639
  clack.log.warning(
634
- `Failed to create ${chalk.bold(
640
+ `Failed to create ${chalk.bold.cyan(
635
641
  SENTRY_DOT_ENV_FILE,
636
642
  )} with auth token. Uploading source maps during build will likely not work locally.`,
637
643
  );
@@ -804,6 +810,26 @@ export async function getPackageDotJson(): Promise<PackageDotJson> {
804
810
  return packageJson || {};
805
811
  }
806
812
 
813
+ export async function updatePackageDotJson(
814
+ packageDotJson: PackageDotJson,
815
+ ): Promise<void> {
816
+ try {
817
+ await fs.promises.writeFile(
818
+ path.join(process.cwd(), 'package.json'),
819
+ // TODO: maybe figure out the original indentation
820
+ JSON.stringify(packageDotJson, null, 2),
821
+ {
822
+ encoding: 'utf8',
823
+ flag: 'w',
824
+ },
825
+ );
826
+ } catch {
827
+ clack.log.error(`Unable to update your ${chalk.cyan('package.json')}.`);
828
+
829
+ await abort();
830
+ }
831
+ }
832
+
807
833
  export async function getPackageManager(): Promise<PackageManager> {
808
834
  const detectedPackageManager = detectPackageManger();
809
835
 
@@ -850,6 +876,7 @@ export async function getOrAskForProjectData(
850
876
  options: WizardOptions,
851
877
  platform?:
852
878
  | 'javascript-nextjs'
879
+ | 'javascript-nuxt'
853
880
  | 'javascript-remix'
854
881
  | 'javascript-sveltekit'
855
882
  | 'apple-ios'
@@ -1011,6 +1038,7 @@ async function askForWizardLogin(options: {
1011
1038
  promoCode?: string;
1012
1039
  platform?:
1013
1040
  | 'javascript-nextjs'
1041
+ | 'javascript-nuxt'
1014
1042
  | 'javascript-remix'
1015
1043
  | 'javascript-sveltekit'
1016
1044
  | 'apple-ios'
@@ -1413,6 +1441,24 @@ export async function askShouldCreateExamplePage(
1413
1441
  );
1414
1442
  }
1415
1443
 
1444
+ export async function askShouldCreateExampleComponent(): Promise<boolean> {
1445
+ return traceStep('ask-create-example-component', () =>
1446
+ abortIfCancelled(
1447
+ clack.select({
1448
+ message: `Do you want to create an example component to test your Sentry setup?`,
1449
+ options: [
1450
+ {
1451
+ value: true,
1452
+ label: 'Yes',
1453
+ hint: 'Recommended - Check your git status before committing!',
1454
+ },
1455
+ { value: false, label: 'No' },
1456
+ ],
1457
+ }),
1458
+ ),
1459
+ );
1460
+ }
1461
+
1416
1462
  export async function featureSelectionPrompt<F extends ReadonlyArray<Feature>>(
1417
1463
  features: F,
1418
1464
  ): Promise<{ [key in F[number]['id']]: boolean }> {
@@ -1445,3 +1491,18 @@ export async function featureSelectionPrompt<F extends ReadonlyArray<Feature>>(
1445
1491
  return selectedFeatures as { [key in F[number]['id']]: boolean };
1446
1492
  });
1447
1493
  }
1494
+
1495
+ export async function askShouldAddPackageOverride(
1496
+ pkgName: string,
1497
+ pkgVersion: string,
1498
+ ): Promise<boolean> {
1499
+ return traceStep(`ask-add-package-override`, () =>
1500
+ abortIfCancelled(
1501
+ clack.confirm({
1502
+ message: `Do you want to add an override for ${chalk.cyan(
1503
+ pkgName,
1504
+ )} version ${chalk.cyan(pkgVersion)}?`,
1505
+ }),
1506
+ ),
1507
+ );
1508
+ }
@@ -3,6 +3,11 @@ export type PackageDotJson = {
3
3
  scripts?: Record<string, string | undefined>;
4
4
  dependencies?: Record<string, string>;
5
5
  devDependencies?: Record<string, string>;
6
+ resolutions?: Record<string, string>;
7
+ overrides?: Record<string, string>;
8
+ pnpm?: {
9
+ overrides?: Record<string, string>;
10
+ };
6
11
  };
7
12
 
8
13
  type NpmPackage = {