@sentry/wizard 3.35.0 → 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.
@@ -44,13 +44,36 @@ async function runWizardOnNuxtProject(projectDir: string): Promise<void> {
44
44
  'Please select your package manager.',
45
45
  );
46
46
 
47
- const tracingOptionPrompted =
47
+ const nitropackOverridePrompted =
48
48
  packageManagerPrompted &&
49
49
  (await wizardInstance.sendStdinAndWaitForOutput(
50
50
  // Selecting `yarn` as the package manager
51
51
  [KEYS.DOWN, KEYS.ENTER],
52
+ // Do you want to install version 2.9.7 of nitropack and add an override to package.json?
53
+ 'Do you want to add an override for nitropack version ~2.9.7?',
54
+ {
55
+ timeout: 240_000,
56
+ },
57
+ ));
58
+
59
+ const nftOverridePrompted =
60
+ nitropackOverridePrompted &&
61
+ (await wizardInstance.sendStdinAndWaitForOutput(
62
+ // Selecting `yes` to downgrade nitropack
63
+ KEYS.ENTER,
64
+ 'Do you want to add an override for @vercel/nft version ^0.27.4?',
65
+ // 'Do you want to install version',
66
+ {
67
+ timeout: 240_000,
68
+ },
69
+ ));
70
+
71
+ const tracingOptionPrompted =
72
+ nftOverridePrompted &&
73
+ (await wizardInstance.sendStdinAndWaitForOutput(
74
+ KEYS.ENTER,
52
75
  // "Do you want to enable Tracing", sometimes doesn't work as `Tracing` can be printed in bold.
53
- 'to track the performance of your application?',
76
+ 'Do you want to enable',
54
77
  {
55
78
  timeout: 240_000,
56
79
  },
@@ -59,7 +82,7 @@ async function runWizardOnNuxtProject(projectDir: string): Promise<void> {
59
82
  const replayOptionPrompted =
60
83
  tracingOptionPrompted &&
61
84
  (await wizardInstance.sendStdinAndWaitForOutput(
62
- [KEYS.ENTER],
85
+ KEYS.ENTER,
63
86
  // "Do you want to enable Sentry Session Replay", sometimes doesn't work as `Sentry Session Replay` can be printed in bold.
64
87
  'to get a video-like reproduction of errors during a user session?',
65
88
  ));
@@ -43,13 +43,36 @@ async function runWizardOnNuxtProject(projectDir: string): Promise<void> {
43
43
  'Please select your package manager.',
44
44
  );
45
45
 
46
- const tracingOptionPrompted =
46
+ const nitropackOverridePrompted =
47
47
  packageManagerPrompted &&
48
48
  (await wizardInstance.sendStdinAndWaitForOutput(
49
49
  // Selecting `yarn` as the package manager
50
50
  [KEYS.DOWN, KEYS.ENTER],
51
+ // Do you want to install version 2.9.7 of nitropack and add an override to package.json?
52
+ 'Do you want to add an override for nitropack version ~2.9.7?',
53
+ {
54
+ timeout: 240_000,
55
+ },
56
+ ));
57
+
58
+ const nftOverridePrompted =
59
+ nitropackOverridePrompted &&
60
+ (await wizardInstance.sendStdinAndWaitForOutput(
61
+ // Selecting `yes` to downgrade nitropack
62
+ KEYS.ENTER,
63
+ 'Do you want to add an override for @vercel/nft version ^0.27.4?',
64
+ // 'Do you want to install version',
65
+ {
66
+ timeout: 240_000,
67
+ },
68
+ ));
69
+
70
+ const tracingOptionPrompted =
71
+ nftOverridePrompted &&
72
+ (await wizardInstance.sendStdinAndWaitForOutput(
73
+ KEYS.ENTER,
51
74
  // "Do you want to enable Tracing", sometimes doesn't work as `Tracing` can be printed in bold.
52
- 'to track the performance of your application?',
75
+ 'Do you want to enable',
53
76
  {
54
77
  timeout: 240_000,
55
78
  },
@@ -243,7 +243,10 @@ export function createFile(filePath: string, content?: string) {
243
243
  * @param oldContent
244
244
  * @param newContent
245
245
  */
246
- export function modifyFile(filePath: string, replaceMap: Record<string, string>) {
246
+ export function modifyFile(
247
+ filePath: string,
248
+ replaceMap: Record<string, string>,
249
+ ) {
247
250
  const fileContent = fs.readFileSync(filePath, 'utf-8');
248
251
  let newFileContent = fileContent;
249
252
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/wizard",
3
- "version": "3.35.0",
3
+ "version": "3.36.0",
4
4
  "homepage": "https://github.com/getsentry/sentry-wizard",
5
5
  "repository": "https://github.com/getsentry/sentry-wizard",
6
6
  "description": "Sentry wizard helping you to configure your project",
@@ -33,8 +33,6 @@ export const manifest = (dsn: string) => `
33
33
 
34
34
  <!-- enable the performance API by setting a sample-rate, adjust in production env -->
35
35
  <meta-data android:name="io.sentry.traces.sample-rate" android:value="1.0" />
36
- <!-- enable profiling when starting transactions, adjust in production env -->
37
- <meta-data android:name="io.sentry.traces.profiling.sample-rate" android:value="1.0" />
38
36
  `;
39
37
 
40
38
  export const sentryImport = `import io.sentry.Sentry;\n`;
@@ -1,6 +1,7 @@
1
1
  // @ts-ignore - clack is ESM and TS complains about that. It works though
2
2
  import * as clack from '@clack/prompts';
3
3
  import * as Sentry from '@sentry/node';
4
+ import chalk from 'chalk';
4
5
  import { lt, minVersion } from 'semver';
5
6
  import type { WizardOptions } from '../utils/types';
6
7
  import { traceStep, withTelemetry } from '../telemetry';
@@ -14,19 +15,24 @@ import {
14
15
  ensurePackageIsInstalled,
15
16
  getOrAskForProjectData,
16
17
  getPackageDotJson,
18
+ getPackageManager,
17
19
  installPackage,
18
20
  printWelcome,
19
21
  runPrettierIfInstalled,
20
22
  } from '../utils/clack-utils';
21
23
  import { getPackageVersion, hasPackageInstalled } from '../utils/package-json';
22
- import { addSDKModule, getNuxtConfig, createConfigFiles } from './sdk-setup';
24
+ import {
25
+ addSDKModule,
26
+ getNuxtConfig,
27
+ createConfigFiles,
28
+ addNuxtOverrides,
29
+ } from './sdk-setup';
23
30
  import {
24
31
  createExampleComponent,
25
32
  createExamplePage,
26
33
  supportsExamplePage,
27
34
  } from './sdk-example';
28
35
  import { isNuxtV4 } from './utils';
29
- import chalk from 'chalk';
30
36
 
31
37
  export function runNuxtWizard(options: WizardOptions) {
32
38
  return withTelemetry(
@@ -85,12 +91,17 @@ export async function runNuxtWizardWithTelemetry(
85
91
  const { authToken, selectedProject, selfHosted, sentryUrl } =
86
92
  await getOrAskForProjectData(options, 'javascript-nuxt');
87
93
 
94
+ const packageManager = await getPackageManager();
95
+
96
+ await addNuxtOverrides(packageManager, minVer);
97
+
88
98
  const sdkAlreadyInstalled = hasPackageInstalled('@sentry/nuxt', packageJson);
89
99
  Sentry.setTag('sdk-already-installed', sdkAlreadyInstalled);
90
100
 
91
101
  await installPackage({
92
102
  packageName: '@sentry/nuxt',
93
103
  alreadyInstalled: sdkAlreadyInstalled,
104
+ packageManager,
94
105
  });
95
106
 
96
107
  await addDotEnvSentryBuildPluginFile(authToken);
@@ -17,10 +17,13 @@ import {
17
17
  import {
18
18
  abort,
19
19
  abortIfCancelled,
20
+ askShouldAddPackageOverride,
20
21
  featureSelectionPrompt,
21
22
  isUsingTypeScript,
22
23
  } from '../utils/clack-utils';
23
24
  import { traceStep } from '../telemetry';
25
+ import { lt, SemVer } from 'semver';
26
+ import { PackageManager } from '../utils/package-manager';
24
27
 
25
28
  const possibleNuxtConfig = [
26
29
  'nuxt.config.js',
@@ -207,3 +210,39 @@ export async function createConfigFiles(dsn: string) {
207
210
  });
208
211
  }
209
212
  }
213
+
214
+ export async function addNuxtOverrides(
215
+ packageManager: PackageManager,
216
+ nuxtMinVer: SemVer | null,
217
+ ) {
218
+ const overrides = [
219
+ {
220
+ pkgName: 'nitropack',
221
+ pkgVersion: '~2.9.7',
222
+ },
223
+ {
224
+ pkgName: '@vercel/nft',
225
+ pkgVersion: '^0.27.4',
226
+ },
227
+ ...(nuxtMinVer && lt(nuxtMinVer, '3.14.0')
228
+ ? [{ pkgName: 'ofetch', pkgVersion: '^1.4.0' }]
229
+ : []),
230
+ ];
231
+
232
+ clack.log.warn(
233
+ `To ensure Sentry can properly instrument your code it needs to add version overrides for some Nuxt dependencies.\n\nFor more info see: ${chalk.cyan(
234
+ 'https://github.com/getsentry/sentry-javascript/issues/14514',
235
+ )}`,
236
+ );
237
+
238
+ for (const { pkgName, pkgVersion } of overrides) {
239
+ const shouldAddOverride = await askShouldAddPackageOverride(
240
+ pkgName,
241
+ pkgVersion,
242
+ );
243
+
244
+ if (shouldAddOverride) {
245
+ await packageManager.addOverride(pkgName, pkgVersion);
246
+ }
247
+ }
248
+ }
@@ -355,6 +355,7 @@ export async function installPackage({
355
355
  alreadyInstalled,
356
356
  askBeforeUpdating = true,
357
357
  packageNameDisplayLabel,
358
+ packageManager,
358
359
  }: {
359
360
  /** The string that is passed to the package manager CLI as identifier to install (e.g. `@sentry/nextjs`, or `@sentry/nextjs@^8`) */
360
361
  packageName: string;
@@ -362,6 +363,7 @@ export async function installPackage({
362
363
  askBeforeUpdating?: boolean;
363
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`) */
364
365
  packageNameDisplayLabel?: string;
366
+ packageManager?: PackageManager;
365
367
  }): Promise<{ packageManager?: PackageManager }> {
366
368
  return traceStep('install-package', async () => {
367
369
  if (alreadyInstalled && askBeforeUpdating) {
@@ -380,18 +382,18 @@ export async function installPackage({
380
382
 
381
383
  const sdkInstallSpinner = clack.spinner();
382
384
 
383
- const packageManager = await getPackageManager();
385
+ const pkgManager = packageManager || (await getPackageManager());
384
386
 
385
387
  sdkInstallSpinner.start(
386
388
  `${alreadyInstalled ? 'Updating' : 'Installing'} ${chalk.bold.cyan(
387
389
  packageNameDisplayLabel ?? packageName,
388
- )} with ${chalk.bold(packageManager.label)}.`,
390
+ )} with ${chalk.bold(pkgManager.label)}.`,
389
391
  );
390
392
 
391
393
  try {
392
394
  await new Promise<void>((resolve, reject) => {
393
395
  childProcess.exec(
394
- `${packageManager.installCommand} ${packageName} ${packageManager.flags}`,
396
+ `${pkgManager.installCommand} ${packageName} ${pkgManager.flags}`,
395
397
  (err, stdout, stderr) => {
396
398
  if (err) {
397
399
  // Write a log file so we can better troubleshoot issues
@@ -430,10 +432,10 @@ export async function installPackage({
430
432
  sdkInstallSpinner.stop(
431
433
  `${alreadyInstalled ? 'Updated' : 'Installed'} ${chalk.bold.cyan(
432
434
  packageNameDisplayLabel ?? packageName,
433
- )} with ${chalk.bold(packageManager.label)}.`,
435
+ )} with ${chalk.bold(pkgManager.label)}.`,
434
436
  );
435
437
 
436
- return { packageManager };
438
+ return { packageManager: pkgManager };
437
439
  });
438
440
  }
439
441
 
@@ -808,6 +810,26 @@ export async function getPackageDotJson(): Promise<PackageDotJson> {
808
810
  return packageJson || {};
809
811
  }
810
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
+
811
833
  export async function getPackageManager(): Promise<PackageManager> {
812
834
  const detectedPackageManager = detectPackageManger();
813
835
 
@@ -1469,3 +1491,18 @@ export async function featureSelectionPrompt<F extends ReadonlyArray<Feature>>(
1469
1491
  return selectedFeatures as { [key in F[number]['id']]: boolean };
1470
1492
  });
1471
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 = {
@@ -4,6 +4,7 @@ import * as path from 'path';
4
4
 
5
5
  import * as Sentry from '@sentry/node';
6
6
  import { traceStep } from '../telemetry';
7
+ import { getPackageDotJson, updatePackageDotJson } from './clack-utils';
7
8
 
8
9
  export interface PackageManager {
9
10
  name: string;
@@ -15,6 +16,7 @@ export interface PackageManager {
15
16
  runScriptCommand: string;
16
17
  flags: string;
17
18
  detect: () => boolean;
19
+ addOverride: (pkgName: string, pkgVersion: string) => Promise<void>;
18
20
  }
19
21
 
20
22
  export const BUN: PackageManager = {
@@ -26,6 +28,18 @@ export const BUN: PackageManager = {
26
28
  runScriptCommand: 'bun run',
27
29
  flags: '',
28
30
  detect: () => fs.existsSync(path.join(process.cwd(), BUN.lockFile)),
31
+ addOverride: async (pkgName, pkgVersion): Promise<void> => {
32
+ const packageDotJson = await getPackageDotJson();
33
+ const overrides = packageDotJson.overrides || {};
34
+
35
+ await updatePackageDotJson({
36
+ ...packageDotJson,
37
+ overrides: {
38
+ ...overrides,
39
+ [pkgName]: pkgVersion,
40
+ },
41
+ });
42
+ },
29
43
  };
30
44
  export const YARN_V1: PackageManager = {
31
45
  name: 'yarn',
@@ -45,6 +59,18 @@ export const YARN_V1: PackageManager = {
45
59
  return false;
46
60
  }
47
61
  },
62
+ addOverride: async (pkgName, pkgVersion): Promise<void> => {
63
+ const packageDotJson = await getPackageDotJson();
64
+ const resolutions = packageDotJson.resolutions || {};
65
+
66
+ await updatePackageDotJson({
67
+ ...packageDotJson,
68
+ resolutions: {
69
+ ...resolutions,
70
+ [pkgName]: pkgVersion,
71
+ },
72
+ });
73
+ },
48
74
  };
49
75
  /** YARN V2/3/4 */
50
76
  export const YARN_V2: PackageManager = {
@@ -65,6 +91,18 @@ export const YARN_V2: PackageManager = {
65
91
  return false;
66
92
  }
67
93
  },
94
+ addOverride: async (pkgName, pkgVersion): Promise<void> => {
95
+ const packageDotJson = await getPackageDotJson();
96
+ const resolutions = packageDotJson.resolutions || {};
97
+
98
+ await updatePackageDotJson({
99
+ ...packageDotJson,
100
+ resolutions: {
101
+ ...resolutions,
102
+ [pkgName]: pkgVersion,
103
+ },
104
+ });
105
+ },
68
106
  };
69
107
  export const PNPM: PackageManager = {
70
108
  name: 'pnpm',
@@ -75,6 +113,22 @@ export const PNPM: PackageManager = {
75
113
  runScriptCommand: 'pnpm',
76
114
  flags: '--ignore-workspace-root-check',
77
115
  detect: () => fs.existsSync(path.join(process.cwd(), PNPM.lockFile)),
116
+ addOverride: async (pkgName, pkgVersion): Promise<void> => {
117
+ const packageDotJson = await getPackageDotJson();
118
+ const pnpm = packageDotJson.pnpm || {};
119
+ const overrides = pnpm.overrides || {};
120
+
121
+ await updatePackageDotJson({
122
+ ...packageDotJson,
123
+ pnpm: {
124
+ ...pnpm,
125
+ overrides: {
126
+ ...overrides,
127
+ [pkgName]: pkgVersion,
128
+ },
129
+ },
130
+ });
131
+ },
78
132
  };
79
133
  export const NPM: PackageManager = {
80
134
  name: 'npm',
@@ -85,6 +139,18 @@ export const NPM: PackageManager = {
85
139
  runScriptCommand: 'npm run',
86
140
  flags: '',
87
141
  detect: () => fs.existsSync(path.join(process.cwd(), NPM.lockFile)),
142
+ addOverride: async (pkgName, pkgVersion): Promise<void> => {
143
+ const packageDotJson = await getPackageDotJson();
144
+ const overrides = packageDotJson.overrides || {};
145
+
146
+ await updatePackageDotJson({
147
+ ...packageDotJson,
148
+ overrides: {
149
+ ...overrides,
150
+ [pkgName]: pkgVersion,
151
+ },
152
+ });
153
+ },
88
154
  };
89
155
 
90
156
  export const packageManagers = [BUN, YARN_V1, YARN_V2, PNPM, NPM];